aboutsummaryrefslogtreecommitdiff
path: root/src/libs
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2022-08-10 19:24:45 -0500
committerSean Hall <r.sean.hall@gmail.com>2022-08-10 20:27:48 -0500
commit0a97d7aafcbb564b7bc9f4e754f39055fd38ae4f (patch)
tree9806619cb509dcb18a36f990ce9a2f37e30d1cdd /src/libs
parent3756ae7c8dc60d459511d0b067ebef5efb052746 (diff)
downloadwix-0a97d7aafcbb564b7bc9f4e754f39055fd38ae4f.tar.gz
wix-0a97d7aafcbb564b7bc9f4e754f39055fd38ae4f.tar.bz2
wix-0a97d7aafcbb564b7bc9f4e754f39055fd38ae4f.zip
Allow wixstdba special controls to have declarative text.
Fixes 6855
Diffstat (limited to 'src/libs')
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/thmutil.h25
-rw-r--r--src/libs/dutil/WixToolset.DUtil/thmutil.cpp167
2 files changed, 109 insertions, 83 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h b/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
index 8cf7dc92..45e4fc51 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
@@ -57,6 +57,20 @@ typedef enum THEME_CONTROL_DATA
57 THEME_CONTROL_DATA_HOVER = 1, 57 THEME_CONTROL_DATA_HOVER = 1,
58} THEME_CONTROL_DATA; 58} THEME_CONTROL_DATA;
59 59
60typedef enum THEME_CONTROL_AUTOMATIC_BEHAVIOR_TYPE
61{
62 THEME_CONTROL_AUTOMATIC_BEHAVIOR_ALL = 0x0,
63 THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_ENABLED = 0x1,
64 THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_VISIBLE = 0x2,
65 THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_ACTION = 0x4,
66 // For form controls like editboxes and checkboxes,
67 // the value will not be automatically persisted to a variable and
68 // the control's value will only be changed by the user.
69 THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_VALUE = 0x8,
70 // This has no effect on editboxes since their text is their value.
71 THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_TEXT = 0x10,
72} THEME_CONTROL_AUTOMATIC_BEHAVIOR_TYPE;
73
60typedef enum THEME_CONTROL_TYPE 74typedef enum THEME_CONTROL_TYPE
61{ 75{
62 THEME_CONTROL_TYPE_UNKNOWN, 76 THEME_CONTROL_TYPE_UNKNOWN,
@@ -196,7 +210,7 @@ struct THEME_ASSIGN_CONTROL_ID
196 WORD wId; // id to apply to control 210 WORD wId; // id to apply to control
197 LPCWSTR wzName; // name of control to match 211 LPCWSTR wzName; // name of control to match
198 const THEME_CONTROL** ppControl; 212 const THEME_CONTROL** ppControl;
199 BOOL fDisableAutomaticFunctionality; // prevent declarative functionality from interfering with the application's imperative code 213 DWORD dwAutomaticBehaviorType; // prevent declarative functionality from interfering with the application's imperative code
200}; 214};
201 215
202const WORD THEME_FIRST_ASSIGN_CONTROL_ID = 0x4000; // Recommended first control id to be assigned. 216const WORD THEME_FIRST_ASSIGN_CONTROL_ID = 0x4000; // Recommended first control id to be assigned.
@@ -224,7 +238,12 @@ typedef struct _THEME_CONTROL
224 238
225 LPWSTR sczEnableCondition; 239 LPWSTR sczEnableCondition;
226 LPWSTR sczVisibleCondition; 240 LPWSTR sczVisibleCondition;
227 BOOL fDisableAutomaticFunctionality; 241
242 BOOL fAutomaticEnabled;
243 BOOL fAutomaticVisible;
244 BOOL fAutomaticAction;
245 BOOL fAutomaticValue;
246 BOOL fAutomaticText;
228 247
229 union 248 union
230 { 249 {
@@ -472,7 +491,7 @@ typedef struct _THEME_LOADINGCONTROL_RESULTS
472 // Due to this value being packed into 16 bits for many system window messages, this is restricted to a WORD. 491 // Due to this value being packed into 16 bits for many system window messages, this is restricted to a WORD.
473 WORD wId; 492 WORD wId;
474 // Used to prevent declarative functionality from interfering with the application's imperative code. 493 // Used to prevent declarative functionality from interfering with the application's imperative code.
475 BOOL fDisableAutomaticFunctionality; 494 DWORD dwAutomaticBehaviorType;
476} THEME_LOADINGCONTROL_RESULTS; 495} THEME_LOADINGCONTROL_RESULTS;
477 496
478 497
diff --git a/src/libs/dutil/WixToolset.DUtil/thmutil.cpp b/src/libs/dutil/WixToolset.DUtil/thmutil.cpp
index f7f7c5b6..c3dbe3e9 100644
--- a/src/libs/dutil/WixToolset.DUtil/thmutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/thmutil.cpp
@@ -296,7 +296,7 @@ static HRESULT OnLoadingControl(
296 __in THEME* pTheme, 296 __in THEME* pTheme,
297 __in const THEME_CONTROL* pControl, 297 __in const THEME_CONTROL* pControl,
298 __inout WORD* pwId, 298 __inout WORD* pwId,
299 __inout BOOL* pfDisableAutomaticFunctionality 299 __inout DWORD* pdwAutomaticBehaviorType
300 ); 300 );
301static HRESULT LoadControls( 301static HRESULT LoadControls(
302 __in THEME* pTheme, 302 __in THEME* pTheme,
@@ -5016,7 +5016,7 @@ static void OnBrowseDirectory(
5016 } 5016 }
5017 5017
5018 // Since editbox changes aren't immediately saved off, we have to treat them differently. 5018 // Since editbox changes aren't immediately saved off, we have to treat them differently.
5019 if (pTargetControl && !pTargetControl->fDisableAutomaticFunctionality && (!fSetVariable || THEME_CONTROL_TYPE_EDITBOX == pTargetControl->type)) 5019 if (pTargetControl && pTargetControl->fAutomaticValue && THEME_CONTROL_TYPE_EDITBOX == pTargetControl->type)
5020 { 5020 {
5021 fSetVariable = FALSE; 5021 fSetVariable = FALSE;
5022 hr = ThemeSetTextControl(pTargetControl, sczPath); 5022 hr = ThemeSetTextControl(pTargetControl, sczPath);
@@ -5045,7 +5045,7 @@ static BOOL OnButtonClicked(
5045 5045
5046 if (THEME_CONTROL_TYPE_BUTTON == pControl->type || THEME_CONTROL_TYPE_COMMANDLINK == pControl->type) 5046 if (THEME_CONTROL_TYPE_BUTTON == pControl->type || THEME_CONTROL_TYPE_COMMANDLINK == pControl->type)
5047 { 5047 {
5048 if (!pControl->fDisableAutomaticFunctionality && pControl->cActions) 5048 if (pControl->fAutomaticAction && pControl->cActions)
5049 { 5049 {
5050 fHandled = TRUE; 5050 fHandled = TRUE;
5051 THEME_ACTION* pChosenAction = pControl->pDefaultAction; 5051 THEME_ACTION* pChosenAction = pControl->pDefaultAction;
@@ -5103,7 +5103,7 @@ static BOOL OnButtonClicked(
5103 } 5103 }
5104 } 5104 }
5105 } 5105 }
5106 else if (!pControl->fDisableAutomaticFunctionality && (pTheme->pfnSetNumericVariable || pTheme->pfnSetStringVariable)) 5106 else if (pControl->fAutomaticValue && (pTheme->pfnSetNumericVariable || pTheme->pfnSetStringVariable))
5107 { 5107 {
5108 BOOL fRefresh = FALSE; 5108 BOOL fRefresh = FALSE;
5109 5109
@@ -5558,7 +5558,7 @@ static HRESULT ShowControl(
5558 THEME_PAGE* pPage = ThemeGetPage(pTheme, dwPageId); 5558 THEME_PAGE* pPage = ThemeGetPage(pTheme, dwPageId);
5559 5559
5560 // Save the editbox value if necessary (other control types save their values immediately). 5560 // Save the editbox value if necessary (other control types save their values immediately).
5561 if (pTheme->pfnSetStringVariable && !pControl->fDisableAutomaticFunctionality && 5561 if (pTheme->pfnSetStringVariable && pControl->fAutomaticValue &&
5562 fSaveEditboxes && THEME_CONTROL_TYPE_EDITBOX == pControl->type && pControl->sczName && *pControl->sczName) 5562 fSaveEditboxes && THEME_CONTROL_TYPE_EDITBOX == pControl->type && pControl->sczName && *pControl->sczName)
5563 { 5563 {
5564 hr = ThemeGetTextControl(pControl, &sczText); 5564 hr = ThemeGetTextControl(pControl, &sczText);
@@ -5585,102 +5585,102 @@ static HRESULT ShowControl(
5585 BOOL fEnabled = !(pControl->dwInternalStyle & INTERNAL_CONTROL_STYLE_DISABLED); 5585 BOOL fEnabled = !(pControl->dwInternalStyle & INTERNAL_CONTROL_STYLE_DISABLED);
5586 BOOL fVisible = !(pControl->dwInternalStyle & INTERNAL_CONTROL_STYLE_HIDDEN); 5586 BOOL fVisible = !(pControl->dwInternalStyle & INTERNAL_CONTROL_STYLE_HIDDEN);
5587 5587
5588 if (!pControl->fDisableAutomaticFunctionality) 5588 if (pTheme->pfnEvaluateCondition)
5589 { 5589 {
5590 if (pTheme->pfnEvaluateCondition) 5590 // If the control has a VisibleCondition, check if it's true.
5591 if (pControl->sczVisibleCondition && pControl->fAutomaticVisible)
5591 { 5592 {
5592 // If the control has a VisibleCondition, check if it's true. 5593 hr = pTheme->pfnEvaluateCondition(pControl->sczVisibleCondition, &fVisible, pTheme->pvVariableContext);
5593 if (pControl->sczVisibleCondition) 5594 ThmExitOnFailure(hr, "Failed to evaluate VisibleCondition: %ls", pControl->sczVisibleCondition);
5594 {
5595 hr = pTheme->pfnEvaluateCondition(pControl->sczVisibleCondition, &fVisible, pTheme->pvVariableContext);
5596 ThmExitOnFailure(hr, "Failed to evaluate VisibleCondition: %ls", pControl->sczVisibleCondition);
5597 }
5598
5599 // If the control has an EnableCondition, check if it's true.
5600 if (pControl->sczEnableCondition)
5601 {
5602 hr = pTheme->pfnEvaluateCondition(pControl->sczEnableCondition, &fEnabled, pTheme->pvVariableContext);
5603 ThmExitOnFailure(hr, "Failed to evaluate EnableCondition: %ls", pControl->sczEnableCondition);
5604 }
5605 } 5595 }
5606 5596
5607 // Try to format each control's text based on context, except for editboxes since their text comes from the user. 5597 // If the control has an EnableCondition, check if it's true.
5608 if (pTheme->pfnFormatString && ((pControl->sczText && *pControl->sczText) || pControl->cConditionalText) && THEME_CONTROL_TYPE_EDITBOX != pControl->type) 5598 if (pControl->sczEnableCondition && pControl->fAutomaticEnabled)
5609 { 5599 {
5610 LPCWSTR wzText = pControl->sczText; 5600 hr = pTheme->pfnEvaluateCondition(pControl->sczEnableCondition, &fEnabled, pTheme->pvVariableContext);
5611 LPCWSTR wzNote = pControl->sczNote; 5601 ThmExitOnFailure(hr, "Failed to evaluate EnableCondition: %ls", pControl->sczEnableCondition);
5602 }
5603 }
5612 5604
5613 if (pTheme->pfnEvaluateCondition) 5605 // Try to format each control's text based on context, except for editboxes since their text comes from the user.
5606 if (pTheme->pfnFormatString && pControl->fAutomaticText && ((pControl->sczText && *pControl->sczText) || pControl->cConditionalText) && THEME_CONTROL_TYPE_EDITBOX != pControl->type)
5607 {
5608 LPCWSTR wzText = pControl->sczText;
5609 LPCWSTR wzNote = pControl->sczNote;
5610
5611 if (pTheme->pfnEvaluateCondition)
5612 {
5613 // As documented in the xsd, if there are multiple conditions that are true at the same time then the behavior is undefined.
5614 // This is the current implementation and can change at any time.
5615 for (DWORD j = 0; j < pControl->cConditionalText; ++j)
5614 { 5616 {
5615 // As documented in the xsd, if there are multiple conditions that are true at the same time then the behavior is undefined. 5617 THEME_CONDITIONAL_TEXT* pConditionalText = pControl->rgConditionalText + j;
5616 // This is the current implementation and can change at any time.
5617 for (DWORD j = 0; j < pControl->cConditionalText; ++j)
5618 {
5619 THEME_CONDITIONAL_TEXT* pConditionalText = pControl->rgConditionalText + j;
5620 5618
5621 if (pConditionalText->sczCondition) 5619 if (pConditionalText->sczCondition)
5622 { 5620 {
5623 BOOL fCondition = FALSE; 5621 BOOL fCondition = FALSE;
5624 5622
5625 hr = pTheme->pfnEvaluateCondition(pConditionalText->sczCondition, &fCondition, pTheme->pvVariableContext); 5623 hr = pTheme->pfnEvaluateCondition(pConditionalText->sczCondition, &fCondition, pTheme->pvVariableContext);
5626 ThmExitOnFailure(hr, "Failed to evaluate condition: %ls", pConditionalText->sczCondition); 5624 ThmExitOnFailure(hr, "Failed to evaluate condition: %ls", pConditionalText->sczCondition);
5627 5625
5628 if (fCondition) 5626 if (fCondition)
5629 { 5627 {
5630 wzText = pConditionalText->sczText; 5628 wzText = pConditionalText->sczText;
5631 break; 5629 break;
5632 }
5633 } 5630 }
5634 } 5631 }
5632 }
5635 5633
5636 if (THEME_CONTROL_TYPE_COMMANDLINK == pControl->type) 5634 if (THEME_CONTROL_TYPE_COMMANDLINK == pControl->type)
5635 {
5636 for (DWORD j = 0; j < pControl->CommandLink.cConditionalNotes; ++j)
5637 { 5637 {
5638 for (DWORD j = 0; j < pControl->CommandLink.cConditionalNotes; ++j) 5638 THEME_CONDITIONAL_TEXT* pConditionalNote = pControl->CommandLink.rgConditionalNotes + j;
5639 {
5640 THEME_CONDITIONAL_TEXT* pConditionalNote = pControl->CommandLink.rgConditionalNotes + j;
5641 5639
5642 if (pConditionalNote->sczCondition) 5640 if (pConditionalNote->sczCondition)
5643 { 5641 {
5644 BOOL fCondition = FALSE; 5642 BOOL fCondition = FALSE;
5645 5643
5646 hr = pTheme->pfnEvaluateCondition(pConditionalNote->sczCondition, &fCondition, pTheme->pvVariableContext); 5644 hr = pTheme->pfnEvaluateCondition(pConditionalNote->sczCondition, &fCondition, pTheme->pvVariableContext);
5647 ThmExitOnFailure(hr, "Failed to evaluate note condition: %ls", pConditionalNote->sczCondition); 5645 ThmExitOnFailure(hr, "Failed to evaluate note condition: %ls", pConditionalNote->sczCondition);
5648 5646
5649 if (fCondition) 5647 if (fCondition)
5650 { 5648 {
5651 wzNote = pConditionalNote->sczText; 5649 wzNote = pConditionalNote->sczText;
5652 break; 5650 break;
5653 }
5654 } 5651 }
5655 } 5652 }
5656 } 5653 }
5657 } 5654 }
5655 }
5658 5656
5659 if (wzText && *wzText) 5657 if (wzText && *wzText)
5660 { 5658 {
5661 hr = pTheme->pfnFormatString(wzText, &sczText, pTheme->pvVariableContext); 5659 hr = pTheme->pfnFormatString(wzText, &sczText, pTheme->pvVariableContext);
5662 ThmExitOnFailure(hr, "Failed to format string: %ls", wzText); 5660 ThmExitOnFailure(hr, "Failed to format string: %ls", wzText);
5663 } 5661 }
5664 else 5662 else
5665 { 5663 {
5666 ReleaseNullStr(sczText); 5664 ReleaseNullStr(sczText);
5667 } 5665 }
5668
5669 ThemeSetTextControl(pControl, sczText);
5670 5666
5671 if (wzNote && *wzNote) 5667 ThemeSetTextControl(pControl, sczText);
5672 {
5673 hr = pTheme->pfnFormatString(wzNote, &sczText, pTheme->pvVariableContext);
5674 ThmExitOnFailure(hr, "Failed to format note: %ls", wzNote);
5675 }
5676 else
5677 {
5678 ReleaseNullStr(sczText);
5679 }
5680 5668
5681 ::SendMessageW(pControl->hWnd, BCM_SETNOTE, 0, reinterpret_cast<WPARAM>(sczText)); 5669 if (wzNote && *wzNote)
5670 {
5671 hr = pTheme->pfnFormatString(wzNote, &sczText, pTheme->pvVariableContext);
5672 ThmExitOnFailure(hr, "Failed to format note: %ls", wzNote);
5673 }
5674 else
5675 {
5676 ReleaseNullStr(sczText);
5682 } 5677 }
5683 5678
5679 ::SendMessageW(pControl->hWnd, BCM_SETNOTE, 0, reinterpret_cast<WPARAM>(sczText));
5680 }
5681
5682 if (pControl->fAutomaticValue)
5683 {
5684 // If this is a named control, do variable magic. 5684 // If this is a named control, do variable magic.
5685 if (pControl->sczName && *pControl->sczName) 5685 if (pControl->sczName && *pControl->sczName)
5686 { 5686 {
@@ -6010,7 +6010,7 @@ static HRESULT OnLoadingControl(
6010 __in THEME* pTheme, 6010 __in THEME* pTheme,
6011 __in const THEME_CONTROL* pControl, 6011 __in const THEME_CONTROL* pControl,
6012 __inout WORD* pwId, 6012 __inout WORD* pwId,
6013 __inout BOOL* pfDisableAutomaticFunctionality 6013 __inout DWORD* pdwAutomaticBehaviorType
6014 ) 6014 )
6015{ 6015{
6016 HRESULT hr = S_OK; 6016 HRESULT hr = S_OK;
@@ -6030,7 +6030,7 @@ static HRESULT OnLoadingControl(
6030 if (SUCCEEDED(hr)) 6030 if (SUCCEEDED(hr))
6031 { 6031 {
6032 *pwId = loadingControlResults.wId; 6032 *pwId = loadingControlResults.wId;
6033 *pfDisableAutomaticFunctionality = loadingControlResults.fDisableAutomaticFunctionality; 6033 *pdwAutomaticBehaviorType = loadingControlResults.dwAutomaticBehaviorType;
6034 } 6034 }
6035 } 6035 }
6036 6036
@@ -6232,9 +6232,16 @@ static HRESULT LoadControls(
6232 6232
6233 // Default control ids to the next id, unless there is a specific id to assign to a control. 6233 // Default control ids to the next id, unless there is a specific id to assign to a control.
6234 WORD wControlId = THEME_FIRST_AUTO_ASSIGN_CONTROL_ID; 6234 WORD wControlId = THEME_FIRST_AUTO_ASSIGN_CONTROL_ID;
6235 hr = OnLoadingControl(pTheme, pControl, &wControlId, &pControl->fDisableAutomaticFunctionality); 6235 DWORD dwAutomaticBehaviorType = THEME_CONTROL_AUTOMATIC_BEHAVIOR_ALL;
6236 hr = OnLoadingControl(pTheme, pControl, &wControlId, &dwAutomaticBehaviorType);
6236 ThmExitOnFailure(hr, "ThmLoadingControl failed."); 6237 ThmExitOnFailure(hr, "ThmLoadingControl failed.");
6237 6238
6239 pControl->fAutomaticEnabled = THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_ENABLED != (THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_ENABLED & dwAutomaticBehaviorType);
6240 pControl->fAutomaticVisible = THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_VISIBLE != (THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_VISIBLE & dwAutomaticBehaviorType);
6241 pControl->fAutomaticAction = THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_ACTION != (THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_ACTION & dwAutomaticBehaviorType);
6242 pControl->fAutomaticText = THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_TEXT != (THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_TEXT & dwAutomaticBehaviorType);
6243 pControl->fAutomaticValue = THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_VALUE != (THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_VALUE & dwAutomaticBehaviorType);
6244
6238 // This range is reserved for thmutil. The process will run out of available window handles before reaching the end of the range. 6245 // This range is reserved for thmutil. The process will run out of available window handles before reaching the end of the range.
6239 if (THEME_FIRST_AUTO_ASSIGN_CONTROL_ID <= wControlId && THEME_FIRST_ASSIGN_CONTROL_ID > wControlId) 6246 if (THEME_FIRST_AUTO_ASSIGN_CONTROL_ID <= wControlId && THEME_FIRST_ASSIGN_CONTROL_ID > wControlId)
6240 { 6247 {
@@ -6250,7 +6257,7 @@ static HRESULT LoadControls(
6250 BOOL fDisabled = pControl->dwStyle & WS_DISABLED; 6257 BOOL fDisabled = pControl->dwStyle & WS_DISABLED;
6251 6258
6252 // If the control is supposed to be initially visible and it has a VisibleCondition, check if it's true. 6259 // If the control is supposed to be initially visible and it has a VisibleCondition, check if it's true.
6253 if (fVisible && pControl->sczVisibleCondition && pTheme->pfnEvaluateCondition && !pControl->fDisableAutomaticFunctionality) 6260 if (fVisible && pControl->sczVisibleCondition && pTheme->pfnEvaluateCondition && pControl->fAutomaticVisible)
6254 { 6261 {
6255 hr = pTheme->pfnEvaluateCondition(pControl->sczVisibleCondition, &fVisible, pTheme->pvVariableContext); 6262 hr = pTheme->pfnEvaluateCondition(pControl->sczVisibleCondition, &fVisible, pTheme->pvVariableContext);
6256 ThmExitOnFailure(hr, "Failed to evaluate VisibleCondition: %ls", pControl->sczVisibleCondition); 6263 ThmExitOnFailure(hr, "Failed to evaluate VisibleCondition: %ls", pControl->sczVisibleCondition);
@@ -6269,7 +6276,7 @@ static HRESULT LoadControls(
6269 } 6276 }
6270 6277
6271 // If the control is supposed to be initially enabled and it has an EnableCondition, check if it's true. 6278 // If the control is supposed to be initially enabled and it has an EnableCondition, check if it's true.
6272 if (!fDisabled && pControl->sczEnableCondition && pTheme->pfnEvaluateCondition && !pControl->fDisableAutomaticFunctionality) 6279 if (!fDisabled && pControl->sczEnableCondition && pTheme->pfnEvaluateCondition && pControl->fAutomaticEnabled)
6273 { 6280 {
6274 BOOL fEnable = TRUE; 6281 BOOL fEnable = TRUE;
6275 6282