From c0fa77405e0cc1e231dfef357b9ca6e1645c1fe3 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Fri, 4 Jun 2021 13:35:35 -0500 Subject: Require separate images for thmutil graphic Buttons and Progressbars. --- src/libs/dutil/WixToolset.DUtil/inc/thmutil.h | 44 ++- src/libs/dutil/WixToolset.DUtil/thmutil.cpp | 532 +++++++++++++++++--------- 2 files changed, 389 insertions(+), 187 deletions(-) (limited to 'src') diff --git a/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h b/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h index 2a7cabb9..d21c3e17 100644 --- a/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h +++ b/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h @@ -188,12 +188,38 @@ struct THEME_CONTROL LPWSTR sczVisibleCondition; BOOL fDisableVariableFunctionality; - THEME_IMAGE_REFERENCE imageRef; - HBITMAP hImage; - HICON hIcon; + union + { + struct + { + THEME_IMAGE_REFERENCE rgImageRef[4]; + } Button; + struct + { + HBITMAP hImage; + HICON hIcon; + + DWORD cConditionalNotes; + THEME_CONDITIONAL_TEXT* rgConditionalNotes; + } CommandLink; + struct + { + THEME_IMAGE_REFERENCE imageRef; + } Image; + struct + { + // Don't free these; it's just a handle to the central image lists stored in THEME. The handle is freed once, there. + HIMAGELIST rghImageList[4]; - // Don't free these; it's just a handle to the central image lists stored in THEME. The handle is freed once, there. - HIMAGELIST rghImageList[4]; + THEME_COLUMN* ptcColumns; + DWORD cColumns; + } ListView; + struct + { + DWORD cImageRef; + THEME_IMAGE_REFERENCE* rgImageRef; + } ProgressBar; + }; DWORD dwStyle; DWORD dwExtendedStyle; @@ -218,10 +244,6 @@ struct THEME_CONTROL DWORD dwFontHoverId; DWORD dwFontSelectedId; - // Used by listview controls - THEME_COLUMN *ptcColumns; - DWORD cColumns; - // Used by radio button controls BOOL fLastRadioButton; LPWSTR sczValue; @@ -235,10 +257,6 @@ struct THEME_CONTROL DWORD cConditionalText; THEME_CONDITIONAL_TEXT* rgConditionalText; - // Used by command link controls - DWORD cConditionalNotes; - THEME_CONDITIONAL_TEXT* rgConditionalNotes; - // state variables that should be ignored HWND hWnd; DWORD dwData; // type specific data diff --git a/src/libs/dutil/WixToolset.DUtil/thmutil.cpp b/src/libs/dutil/WixToolset.DUtil/thmutil.cpp index 363c3be1..5292d1e3 100644 --- a/src/libs/dutil/WixToolset.DUtil/thmutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/thmutil.cpp @@ -100,6 +100,15 @@ static HRESULT GetAttributeImageFileOrResource( __out Gdiplus::Bitmap** ppBitmap ); static HRESULT ParseOwnerDrawImage( + __in_opt HMODULE hModule, + __in_z_opt LPCWSTR wzRelativePath, + __in THEME* pTheme, + __in IXMLDOMNode* pElement, + __in_z LPCWSTR wzElementName, + __in THEME_CONTROL* pControl, + __in THEME_IMAGE_REFERENCE* pImageRef + ); +static HRESULT ParseButtonImages( __in_opt HMODULE hModule, __in_z_opt LPCWSTR wzRelativePath, __in THEME* pTheme, @@ -112,6 +121,13 @@ static HRESULT ParseCommandLinkImage( __in IXMLDOMNode* pElement, __in THEME_CONTROL* pControl ); +static HRESULT ParseProgressBarImages( + __in_opt HMODULE hModule, + __in_z_opt LPCWSTR wzRelativePath, + __in THEME* pTheme, + __in IXMLDOMNode* pElement, + __in THEME_CONTROL* pControl + ); static HRESULT GetAttributeCoordinateOrDimension( __in IXMLDOMNode* pixn, __in LPCWSTR wzAttribute, @@ -1528,11 +1544,14 @@ DAPI_(HRESULT) ThemeSetProgressControlColor( THEME_CONTROL* pControl = const_cast(FindControlFromHWnd(pTheme, hWnd)); // Only set color on owner draw progress bars. - if (pControl && (pControl->dwInternalStyle & INTERNAL_CONTROL_STYLE_OWNER_DRAW)) + if (pControl && (pControl->dwInternalStyle & INTERNAL_CONTROL_STYLE_OWNER_DRAW) && THEME_CONTROL_TYPE_PROGRESSBAR == pControl->type) { - DWORD dwCurrentColor = HIWORD(pControl->dwData); + if (pControl->ProgressBar.cImageRef <= dwColorIndex) + { + ThmExitWithRootFailure(hr, E_INVALIDARG, "Invalid progress bar color index: %u", dwColorIndex); + } - if (dwCurrentColor != dwColorIndex) + if (HIWORD(pControl->dwData) != dwColorIndex) { DWORD dwCurrentProgress = LOWORD(pControl->dwData); pControl->dwData = MAKEDWORD(dwCurrentProgress, dwColorIndex); @@ -1923,7 +1942,9 @@ static HRESULT ParseOwnerDrawImage( __in_z_opt LPCWSTR wzRelativePath, __in THEME* pTheme, __in IXMLDOMNode* pElement, - __in THEME_CONTROL* pControl + __in_z LPCWSTR wzElementName, + __in THEME_CONTROL* pControl, + __in THEME_IMAGE_REFERENCE* pImageRef ) { HRESULT hr = S_OK; @@ -1937,15 +1958,15 @@ static HRESULT ParseOwnerDrawImage( if (fXmlFound) { - hr = AddStandaloneImage(pTheme, &pBitmap, &pControl->imageRef.dwImageInstanceIndex); + hr = AddStandaloneImage(pTheme, &pBitmap, &pImageRef->dwImageInstanceIndex); ThmExitOnFailure(hr, "Failed to store owner draw image."); - pControl->imageRef.type = THEME_IMAGE_REFERENCE_TYPE_COMPLETE; + pImageRef->type = THEME_IMAGE_REFERENCE_TYPE_COMPLETE; fFoundImage = TRUE; } - hr = ParseSourceXY(pElement, pTheme, pControl->nWidth, pControl->nHeight, &pControl->imageRef); + hr = ParseSourceXY(pElement, pTheme, pControl->nWidth, pControl->nHeight, pImageRef); ThmExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get control SourceX and SourceY attributes."); if (fXmlFound) @@ -1962,9 +1983,9 @@ static HRESULT ParseOwnerDrawImage( fFoundImage = TRUE; } - if (THEME_CONTROL_TYPE_IMAGE == pControl->type && !fFoundImage) + if (!fFoundImage) { - ThmExitWithRootFailure(hr, E_INVALIDDATA, "Image control didn't specify an image."); + ThmExitWithRootFailure(hr, E_INVALIDDATA, "%ls didn't specify an image.", wzElementName); } LExit: @@ -1977,6 +1998,97 @@ LExit: } +static HRESULT ParseButtonImages( + __in_opt HMODULE hModule, + __in_z_opt LPCWSTR wzRelativePath, + __in THEME* pTheme, + __in IXMLDOMNode* pElement, + __in THEME_CONTROL* pControl + ) +{ + HRESULT hr = S_OK; + DWORD i = 0; + IXMLDOMNodeList* pixnl = NULL; + IXMLDOMNode* pixnChild = NULL; + BSTR bstrType = NULL; + THEME_IMAGE_REFERENCE* pImageRef = NULL; + THEME_IMAGE_REFERENCE* pDefaultImageRef = NULL; + THEME_IMAGE_REFERENCE* pFocusImageRef = NULL; + THEME_IMAGE_REFERENCE* pHoverImageRef = NULL; + THEME_IMAGE_REFERENCE* pSelectedImageRef = NULL; + + hr = XmlSelectNodes(pElement, L"ButtonImage|ButtonFocusImage|ButtonHoverImage|ButtonSelectedImage", &pixnl); + ThmExitOnFailure(hr, "Failed to select child ButtonImage nodes."); + + i = 0; + while (S_OK == (hr = XmlNextElement(pixnl, &pixnChild, &bstrType))) + { + if (!bstrType) + { + hr = E_UNEXPECTED; + ThmExitOnFailure(hr, "Null element encountered!"); + } + + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrType, -1, L"ButtonFocusImage", -1)) + { + if (pFocusImageRef) + { + ThmExitWithRootFailure(hr, E_INVALIDDATA, "Duplicate ButtonFocusImage element."); + } + + pImageRef = pFocusImageRef = pControl->Button.rgImageRef + 3; + } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrType, -1, L"ButtonHoverImage", -1)) + { + if (pHoverImageRef) + { + ThmExitWithRootFailure(hr, E_INVALIDDATA, "Duplicate ButtonHoverImage element."); + } + + pImageRef = pHoverImageRef = pControl->Button.rgImageRef + 1; + } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrType, -1, L"ButtonSelectedImage", -1)) + { + if (pSelectedImageRef) + { + ThmExitWithRootFailure(hr, E_INVALIDDATA, "Duplicate ButtonSelectedImage element."); + } + + pImageRef = pSelectedImageRef = pControl->Button.rgImageRef + 2; + } + else + { + if (pDefaultImageRef) + { + ThmExitWithRootFailure(hr, E_INVALIDDATA, "Duplicate ButtonImage element."); + } + + pImageRef = pDefaultImageRef = pControl->Button.rgImageRef; + } + + hr = ParseOwnerDrawImage(hModule, wzRelativePath, pTheme, pixnChild, bstrType, pControl, pImageRef); + ThmExitOnFailure(hr, "Failed when parsing %ls", bstrType); + + ReleaseBSTR(bstrType); + ReleaseNullObject(pixnChild); + ++i; + } + + if (!pDefaultImageRef && (pFocusImageRef || pHoverImageRef || pSelectedImageRef) || + pDefaultImageRef && (!pHoverImageRef || !pSelectedImageRef)) + { + ThmExitWithRootFailure(hr, E_INVALIDDATA, "Graphic buttons require ButtonImage, ButtonHoverImage, and ButtonSelectedImage."); + } + +LExit: + ReleaseObject(pixnl); + ReleaseObject(pixnChild); + ReleaseBSTR(bstrType); + + return hr; +} + + static HRESULT ParseCommandLinkImage( __in_opt HMODULE hModule, __in_z_opt LPCWSTR wzRelativePath, @@ -1997,7 +2109,7 @@ static HRESULT ParseCommandLinkImage( if (pBitmap) { - hr = GdipBitmapToGdiBitmap(pBitmap, &pControl->hImage); + hr = GdipBitmapToGdiBitmap(pBitmap, &pControl->CommandLink.hImage); ThmExitOnFailure(hr, "Failed to convert bitmap for CommandLink."); } @@ -2011,8 +2123,8 @@ static HRESULT ParseCommandLinkImage( ThmExitWithRootFailure(hr, E_INVALIDDATA, "Unexpected IconResource attribute with image attribute."); } - pControl->hIcon = reinterpret_cast(::LoadImageW(hModule, MAKEINTRESOURCEW(wResourceId), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE)); - ThmExitOnNullWithLastError(pControl->hIcon, hr, "Failed to load icon."); + pControl->CommandLink.hIcon = reinterpret_cast(::LoadImageW(hModule, MAKEINTRESOURCEW(wResourceId), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE)); + ThmExitOnNullWithLastError(pControl->CommandLink.hIcon, hr, "Failed to load icon."); } hr = XmlGetAttribute(pElement, L"IconFile", &bstr); @@ -2024,7 +2136,7 @@ static HRESULT ParseCommandLinkImage( { ThmExitWithRootFailure(hr, E_INVALIDDATA, "Unexpected IconFile attribute with image attribute."); } - else if (pControl->hIcon) + else if (pControl->CommandLink.hIcon) { ThmExitWithRootFailure(hr, E_INVALIDDATA, "IconFile attribute can't be specified with IconResource attribute."); } @@ -2040,8 +2152,8 @@ static HRESULT ParseCommandLinkImage( ThmExitOnFailure(hr, "Failed to get image filename."); } - pControl->hIcon = reinterpret_cast(::LoadImageW(NULL, sczIconFile, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE)); - ThmExitOnNullWithLastError(pControl->hIcon, hr, "Failed to load icon: %ls.", sczIconFile); + pControl->CommandLink.hIcon = reinterpret_cast(::LoadImageW(NULL, sczIconFile, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE)); + ThmExitOnNullWithLastError(pControl->CommandLink.hIcon, hr, "Failed to load icon: %ls.", sczIconFile); } ThmExitOnUnexpectedAttribute(hr, pElement, L"CommandLink", L"SourceX"); @@ -2060,6 +2172,53 @@ LExit: } +static HRESULT ParseProgressBarImages( + __in_opt HMODULE hModule, + __in_z_opt LPCWSTR wzRelativePath, + __in THEME* pTheme, + __in IXMLDOMNode* pElement, + __in THEME_CONTROL* pControl + ) +{ + HRESULT hr = S_OK; + DWORD i = 0; + IXMLDOMNodeList* pixnl = NULL; + IXMLDOMNode* pixnChild = NULL; + + hr = XmlSelectNodes(pElement, L"ProgressbarImage", &pixnl); + ThmExitOnFailure(hr, "Failed to select child ProgressbarImage nodes."); + + hr = pixnl->get_length(reinterpret_cast(&pControl->ProgressBar.cImageRef)); + ThmExitOnFailure(hr, "Failed to count the number of ProgressbarImage nodes."); + + if (!pControl->ProgressBar.cImageRef) + { + ExitFunction(); + } + + MemAllocArray(reinterpret_cast(&pControl->ProgressBar.rgImageRef), sizeof(THEME_IMAGE_REFERENCE), pControl->ProgressBar.cImageRef); + ThmExitOnNull(pControl->ProgressBar.rgImageRef, hr, E_OUTOFMEMORY, "Failed to allocate progress bar images."); + + i = 0; + while (S_OK == (hr = XmlNextElement(pixnl, &pixnChild, NULL))) + { + THEME_IMAGE_REFERENCE* pImageRef = pControl->ProgressBar.rgImageRef + i; + + hr = ParseOwnerDrawImage(hModule, wzRelativePath, pTheme, pixnChild, L"ProgressbarImage", pControl, pImageRef); + ThmExitOnFailure(hr, "Failed when parsing ProgressbarImage image: %u.", i); + + ReleaseNullObject(pixnChild); + ++i; + } + +LExit: + ReleaseObject(pixnl); + ReleaseObject(pixnChild); + + return hr; +} + + static HRESULT GetAttributeCoordinateOrDimension( __in IXMLDOMNode* pixn, __in LPCWSTR wzAttribute, @@ -3005,10 +3164,16 @@ static HRESULT ParseControl( ThmExitOnFailure(hr, "Failed while parsing CommandLink image."); break; case THEME_CONTROL_TYPE_BUTTON: + hr = ParseButtonImages(hModule, wzRelativePath, pTheme, pixn, pControl); + ThmExitOnFailure(hr, "Failed while parsing Button images."); + break; case THEME_CONTROL_TYPE_IMAGE: + hr = ParseOwnerDrawImage(hModule, wzRelativePath, pTheme, pixn, wzElementName, pControl, &pControl->Image.imageRef); + ThmExitOnFailure(hr, "Failed while parsing ImageControl image."); + break; case THEME_CONTROL_TYPE_PROGRESSBAR: - hr = ParseOwnerDrawImage(hModule, wzRelativePath, pTheme, pixn, pControl); - ThmExitOnFailure(hr, "Failed while parsing OwnerDraw image."); + hr = ParseProgressBarImages(hModule, wzRelativePath, pTheme, pixn, pControl); + ThmExitOnFailure(hr, "Failed while parsing Progressbar images."); break; default: ThmExitOnUnexpectedAttribute(hr, pixn, wzElementName, L"ImageId"); @@ -3161,7 +3326,7 @@ static HRESULT ParseControl( if (fXmlFound) { - hr = FindImageList(pTheme, bstrText, &pControl->rghImageList[0]); + hr = FindImageList(pTheme, bstrText, &pControl->ListView.rghImageList[0]); ThmExitOnFailure(hr, "Failed to find image list %ls while setting ImageList for ListView.", bstrText); } @@ -3170,7 +3335,7 @@ static HRESULT ParseControl( if (fXmlFound) { - hr = FindImageList(pTheme, bstrText, &pControl->rghImageList[1]); + hr = FindImageList(pTheme, bstrText, &pControl->ListView.rghImageList[1]); ThmExitOnFailure(hr, "Failed to find image list %ls while setting ImageListSmall for ListView.", bstrText); } @@ -3179,7 +3344,7 @@ static HRESULT ParseControl( if (fXmlFound) { - hr = FindImageList(pTheme, bstrText, &pControl->rghImageList[2]); + hr = FindImageList(pTheme, bstrText, &pControl->ListView.rghImageList[2]); ThmExitOnFailure(hr, "Failed to find image list %ls while setting ImageListState for ListView.", bstrText); } @@ -3188,7 +3353,7 @@ static HRESULT ParseControl( if (fXmlFound) { - hr = FindImageList(pTheme, bstrText, &pControl->rghImageList[3]); + hr = FindImageList(pTheme, bstrText, &pControl->ListView.rghImageList[3]); ThmExitOnFailure(hr, "Failed to find image list %ls while setting ImageListGroupHeader for ListView.", bstrText); } @@ -3446,18 +3611,18 @@ static HRESULT ParseColumns( hr = XmlSelectNodes(pixn, L"Column", &pixnl); ThmExitOnFailure(hr, "Failed to select child column nodes."); - hr = pixnl->get_length(reinterpret_cast(&pControl->cColumns)); + hr = pixnl->get_length(reinterpret_cast(&pControl->ListView.cColumns)); ThmExitOnFailure(hr, "Failed to count the number of control columns."); - if (0 < pControl->cColumns) + if (0 < pControl->ListView.cColumns) { - hr = MemAllocArray(reinterpret_cast(&pControl->ptcColumns), sizeof(THEME_COLUMN), pControl->cColumns); + hr = MemAllocArray(reinterpret_cast(&pControl->ListView.ptcColumns), sizeof(THEME_COLUMN), pControl->ListView.cColumns); ThmExitOnFailure(hr, "Failed to allocate column structs."); i = 0; while (S_OK == (hr = XmlNextElement(pixnl, &pixnChild, NULL))) { - THEME_COLUMN* pColumn = pControl->ptcColumns + i; + THEME_COLUMN* pColumn = pControl->ListView.ptcColumns + i; hr = XmlGetText(pixnChild, &bstrText); ThmExitOnFailure(hr, "Failed to get inner text of column element."); @@ -3794,23 +3959,23 @@ static HRESULT ParseNotes( hr = XmlSelectNodes(pixn, L"Note", &pixnl); ThmExitOnFailure(hr, "Failed to select child Note nodes."); - hr = pixnl->get_length(reinterpret_cast(&pControl->cConditionalNotes)); + hr = pixnl->get_length(reinterpret_cast(&pControl->CommandLink.cConditionalNotes)); ThmExitOnFailure(hr, "Failed to count the number of Note nodes."); if (pfAnyChildren) { - *pfAnyChildren = 0 < pControl->cConditionalNotes; + *pfAnyChildren = 0 < pControl->CommandLink.cConditionalNotes; } - if (0 < pControl->cConditionalNotes) + if (0 < pControl->CommandLink.cConditionalNotes) { - MemAllocArray(reinterpret_cast(&pControl->rgConditionalNotes), sizeof(THEME_CONDITIONAL_TEXT), pControl->cConditionalNotes); - ThmExitOnNull(pControl->rgConditionalNotes, hr, E_OUTOFMEMORY, "Failed to allocate note THEME_CONDITIONAL_TEXT structs."); + MemAllocArray(reinterpret_cast(&pControl->CommandLink.rgConditionalNotes), sizeof(THEME_CONDITIONAL_TEXT), pControl->CommandLink.cConditionalNotes); + ThmExitOnNull(pControl->CommandLink.rgConditionalNotes, hr, E_OUTOFMEMORY, "Failed to allocate note THEME_CONDITIONAL_TEXT structs."); i = 0; while (S_OK == (hr = XmlNextElement(pixnl, &pixnChild, NULL))) { - THEME_CONDITIONAL_TEXT* pConditionalNote = pControl->rgConditionalNotes + i; + THEME_CONDITIONAL_TEXT* pConditionalNote = pControl->CommandLink.rgConditionalNotes + i; hr = XmlGetAttributeEx(pixnChild, L"Condition", &pConditionalNote->sczCondition); if (E_NOTFOUND == hr) @@ -3843,7 +4008,7 @@ static HRESULT ParseNotes( ThmExitOnFailure(hr, "Failed to copy text to command link control."); // Unconditional note entries aren't stored in the conditional notes list. - --pControl->cConditionalNotes; + --pControl->CommandLink.cConditionalNotes; } } @@ -3992,57 +4157,43 @@ static HRESULT DrawButton( ) { HRESULT hr = S_OK; - THEME_IMAGE_REFERENCE buttonImageRef = { }; - const THEME_IMAGE_INSTANCE* pInstance = NULL; + const THEME_IMAGE_REFERENCE* pImageRef = NULL; + BOOL fDrawFocusRect = FALSE; int nHeight = pdis->rcItem.bottom - pdis->rcItem.top; int nWidth = pdis->rcItem.right - pdis->rcItem.left; - buttonImageRef.type = THEME_IMAGE_REFERENCE_TYPE_PARTIAL; - buttonImageRef.dwImageInstanceIndex = pControl->imageRef.dwImageInstanceIndex; - GetImageInstance(pTheme, &pControl->imageRef, &pInstance); - - if (THEME_IMAGE_REFERENCE_TYPE_PARTIAL == pControl->imageRef.type) - { - buttonImageRef.nX = pControl->imageRef.nX; - buttonImageRef.nY = pControl->imageRef.nY; - buttonImageRef.nWidth = pControl->imageRef.nWidth; - buttonImageRef.nHeight = pControl->imageRef.nHeight; - } - else if (THEME_IMAGE_REFERENCE_TYPE_COMPLETE == pControl->imageRef.type) - { - buttonImageRef.nX = 0; - buttonImageRef.nY = 0; - buttonImageRef.nWidth = pInstance->pBitmap->GetWidth(); - buttonImageRef.nHeight = pInstance->pBitmap->GetHeight() / 4; - } - else - { - AssertSz(FALSE, "Invalid image reference type for drawing"); - ExitFunction1(hr = E_INVALIDARG); - } - - DWORD_PTR dwStyle = ::GetWindowLongPtrW(pdis->hwndItem, GWL_STYLE); // "clicked" gets priority if (ODS_SELECTED & pdis->itemState) { - buttonImageRef.nY += buttonImageRef.nHeight * 2; + pImageRef = pControl->Button.rgImageRef + 2; } // then hover else if (pControl->dwData & THEME_CONTROL_DATA_HOVER) { - buttonImageRef.nY += buttonImageRef.nHeight; + pImageRef = pControl->Button.rgImageRef + 1; } // then focused - else if ((WS_TABSTOP & dwStyle) && (ODS_FOCUS & pdis->itemState)) + else if ((WS_TABSTOP & ::GetWindowLongPtrW(pdis->hwndItem, GWL_STYLE)) && (ODS_FOCUS & pdis->itemState)) { - buttonImageRef.nY += buttonImageRef.nHeight * 3; + if (THEME_IMAGE_REFERENCE_TYPE_NONE != pControl->Button.rgImageRef[3].type) + { + pImageRef = pControl->Button.rgImageRef + 3; + } + else + { + fDrawFocusRect = TRUE; + pImageRef = pControl->Button.rgImageRef; + } + } + else + { + pImageRef = pControl->Button.rgImageRef; } - hr = DrawImageReference(pTheme, &buttonImageRef, pdis->hDC, 0, 0, nWidth, nHeight); + hr = DrawImageReference(pTheme, pImageRef, pdis->hDC, 0, 0, nWidth, nHeight); - DrawControlText(pTheme, pdis, pControl, TRUE, FALSE); + DrawControlText(pTheme, pdis, pControl, TRUE, fDrawFocusRect); -LExit: return hr; } @@ -4068,47 +4219,44 @@ static void DrawControlText( { HRESULT hr = S_OK; WCHAR wzText[256] = { }; - DWORD cchText = 0; THEME_FONT* pFont = NULL; THEME_FONT_INSTANCE* pFontInstance = NULL; HFONT hfPrev = NULL; + DWORD cchText = ::GetWindowTextW(pdis->hwndItem, wzText, countof(wzText)); - if (0 == (cchText = ::GetWindowTextW(pdis->hwndItem, wzText, countof(wzText)))) + if (cchText) { - // nothing to do - return; - } + if (ODS_SELECTED & pdis->itemState) + { + pFont = pTheme->rgFonts + (THEME_INVALID_ID != pControl->dwFontSelectedId ? pControl->dwFontSelectedId : pControl->dwFontId); + } + else if (pControl->dwData & THEME_CONTROL_DATA_HOVER) + { + pFont = pTheme->rgFonts + (THEME_INVALID_ID != pControl->dwFontHoverId ? pControl->dwFontHoverId : pControl->dwFontId); + } + else + { + pFont = pTheme->rgFonts + pControl->dwFontId; + } - if (ODS_SELECTED & pdis->itemState) - { - pFont = pTheme->rgFonts + (THEME_INVALID_ID != pControl->dwFontSelectedId ? pControl->dwFontSelectedId : pControl->dwFontId); - } - else if (pControl->dwData & THEME_CONTROL_DATA_HOVER) - { - pFont = pTheme->rgFonts + (THEME_INVALID_ID != pControl->dwFontHoverId ? pControl->dwFontHoverId : pControl->dwFontId); - } - else - { - pFont = pTheme->rgFonts + pControl->dwFontId; - } + hr = EnsureFontInstance(pTheme, pFont, &pFontInstance); + if (SUCCEEDED(hr)) + { + hfPrev = SelectFont(pdis->hDC, pFontInstance->hFont); + } - hr = EnsureFontInstance(pTheme, pFont, &pFontInstance); - if (SUCCEEDED(hr)) - { - hfPrev = SelectFont(pdis->hDC, pFontInstance->hFont); - } + ::DrawTextExW(pdis->hDC, wzText, cchText, &pdis->rcItem, DT_SINGLELINE | (fCentered ? (DT_CENTER | DT_VCENTER) : 0), NULL); - ::DrawTextExW(pdis->hDC, wzText, cchText, &pdis->rcItem, DT_SINGLELINE | (fCentered ? (DT_CENTER | DT_VCENTER) : 0), NULL); + if (hfPrev) + { + SelectFont(pdis->hDC, hfPrev); + } + } if (fDrawFocusRect && (WS_TABSTOP & ::GetWindowLongPtrW(pdis->hwndItem, GWL_STYLE)) && (ODS_FOCUS & pdis->itemState)) { ::DrawFocusRect(pdis->hDC, &pdis->rcItem); } - - if (hfPrev) - { - SelectFont(pdis->hDC, hfPrev); - } } @@ -4122,7 +4270,7 @@ static HRESULT DrawImage( int nHeight = pdis->rcItem.bottom - pdis->rcItem.top; int nWidth = pdis->rcItem.right - pdis->rcItem.left; - hr = DrawImageReference(pTheme, &pControl->imageRef, pdis->hDC, 0, 0, nWidth, nHeight); + hr = DrawImageReference(pTheme, &pControl->Image.imageRef, pdis->hDC, 0, 0, nWidth, nHeight); return hr; } @@ -4240,8 +4388,9 @@ static HRESULT DrawProgressBar( { const int nSideWidth = 1; HRESULT hr = S_OK; - WORD wProgressColor = HIWORD(pControl->dwData); + WORD wProgressColorIndex = HIWORD(pControl->dwData); WORD wProgressPercentage = LOWORD(pControl->dwData); + const THEME_IMAGE_REFERENCE* pImageRef = pControl->ProgressBar.rgImageRef + wProgressColorIndex; const THEME_IMAGE_INSTANCE* pInstance = NULL; int nHeight = pdis->rcItem.bottom - pdis->rcItem.top; int nSourceHeight = 0; @@ -4255,19 +4404,19 @@ static HRESULT DrawProgressBar( ExitFunction1(hr = S_FALSE); } - GetImageInstance(pTheme, &pControl->imageRef, &pInstance); + GetImageInstance(pTheme, pImageRef, &pInstance); - if (THEME_IMAGE_REFERENCE_TYPE_PARTIAL == pControl->imageRef.type) + if (THEME_IMAGE_REFERENCE_TYPE_PARTIAL == pImageRef->type) { - nSourceHeight = pControl->imageRef.nHeight; - nSourceX = pControl->imageRef.nX; - nSourceY = pControl->imageRef.nY + (wProgressColor * nSourceHeight); + nSourceHeight = pImageRef->nHeight; + nSourceX = pImageRef->nX; + nSourceY = pImageRef->nY; } - else if (THEME_IMAGE_REFERENCE_TYPE_COMPLETE == pControl->imageRef.type) + else if (THEME_IMAGE_REFERENCE_TYPE_COMPLETE == pImageRef->type) { - nSourceHeight = pControl->nDefaultDpiHeight; + nSourceHeight = pInstance->pBitmap->GetHeight(); nSourceX = 0; - nSourceY = wProgressColor * nSourceHeight; + nSourceY = 0; } else { @@ -4411,9 +4560,34 @@ static void FreeControl( ReleaseStr(pControl->sczValue); ReleaseStr(pControl->sczVariable); - if (pControl->hImage) + switch (pControl->type) { - ::DeleteBitmap(pControl->hImage); + case THEME_CONTROL_TYPE_COMMANDLINK: + if (pControl->CommandLink.hImage) + { + ::DeleteBitmap(pControl->CommandLink.hImage); + } + + if (pControl->CommandLink.hIcon) + { + ::DestroyIcon(pControl->CommandLink.hIcon); + } + + for (DWORD i = 0; i < pControl->CommandLink.cConditionalNotes; ++i) + { + FreeConditionalText(pControl->CommandLink.rgConditionalNotes + i); + } + + ReleaseMem(pControl->CommandLink.rgConditionalNotes); + break; + case THEME_CONTROL_TYPE_LISTVIEW: + for (DWORD i = 0; i < pControl->ListView.cColumns; ++i) + { + FreeColumn(pControl->ListView.ptcColumns + i); + } + + ReleaseMem(pControl->ListView.ptcColumns); + break; } for (DWORD i = 0; i < pControl->cControls; ++i) @@ -4426,30 +4600,18 @@ static void FreeControl( FreeAction(&(pControl->rgActions[i])); } - for (DWORD i = 0; i < pControl->cColumns; ++i) - { - FreeColumn(&(pControl->ptcColumns[i])); - } - for (DWORD i = 0; i < pControl->cConditionalText; ++i) { FreeConditionalText(&(pControl->rgConditionalText[i])); } - for (DWORD i = 0; i < pControl->cConditionalNotes; ++i) - { - FreeConditionalText(&(pControl->rgConditionalNotes[i])); - } - for (DWORD i = 0; i < pControl->cTabs; ++i) { FreeTab(&(pControl->pttTabs[i])); } ReleaseMem(pControl->rgActions) - ReleaseMem(pControl->ptcColumns); ReleaseMem(pControl->rgConditionalText); - ReleaseMem(pControl->rgConditionalNotes); ReleaseMem(pControl->pttTabs); } } @@ -4945,6 +5107,7 @@ static HRESULT SizeListViewColumns( RECT rcParent = { }; int cNumExpandingColumns = 0; int iExtraAvailableSize; + THEME_COLUMN* pColumn = NULL; if (!::GetWindowRect(pControl->hWnd, &rcParent)) { @@ -4953,31 +5116,35 @@ static HRESULT SizeListViewColumns( iExtraAvailableSize = rcParent.right - rcParent.left; - for (DWORD i = 0; i < pControl->cColumns; ++i) + for (DWORD i = 0; i < pControl->ListView.cColumns; ++i) { - if (pControl->ptcColumns[i].fExpands) + pColumn = pControl->ListView.ptcColumns + i; + + if (pColumn->fExpands) { ++cNumExpandingColumns; } - iExtraAvailableSize -= pControl->ptcColumns[i].nBaseWidth; + iExtraAvailableSize -= pColumn->nBaseWidth; } // Leave room for a vertical scroll bar just in case. iExtraAvailableSize -= ::GetSystemMetrics(SM_CXVSCROLL); - for (DWORD i = 0; i < pControl->cColumns; ++i) + for (DWORD i = 0; i < pControl->ListView.cColumns; ++i) { - if (pControl->ptcColumns[i].fExpands) + pColumn = pControl->ListView.ptcColumns + i; + + if (pColumn->fExpands) { - pControl->ptcColumns[i].nWidth = pControl->ptcColumns[i].nBaseWidth + (iExtraAvailableSize / cNumExpandingColumns); + pColumn->nWidth = pColumn->nBaseWidth + (iExtraAvailableSize / cNumExpandingColumns); // In case there is any remainder, use it up the first chance we get. - pControl->ptcColumns[i].nWidth += iExtraAvailableSize % cNumExpandingColumns; + pColumn->nWidth += iExtraAvailableSize % cNumExpandingColumns; iExtraAvailableSize -= iExtraAvailableSize % cNumExpandingColumns; } else { - pControl->ptcColumns[i].nWidth = pControl->ptcColumns[i].nBaseWidth; + pColumn->nWidth = pColumn->nBaseWidth; } } @@ -5082,22 +5249,25 @@ static HRESULT ShowControl( } } - for (DWORD j = 0; j < pControl->cConditionalNotes; ++j) + if (THEME_CONTROL_TYPE_COMMANDLINK == pControl->type) { - THEME_CONDITIONAL_TEXT* pConditionalNote = pControl->rgConditionalNotes + j; - wzNote = pConditionalNote->sczText; - - if (pConditionalNote->sczCondition) + for (DWORD j = 0; j < pControl->CommandLink.cConditionalNotes; ++j) { - BOOL fCondition = FALSE; + THEME_CONDITIONAL_TEXT* pConditionalNote = pControl->CommandLink.rgConditionalNotes + j; + wzNote = pConditionalNote->sczText; - hr = pTheme->pfnEvaluateCondition(pConditionalNote->sczCondition, &fCondition, pTheme->pvVariableContext); - ThmExitOnFailure(hr, "Failed to evaluate note condition: %ls", pConditionalNote->sczCondition); - - if (fCondition) + if (pConditionalNote->sczCondition) { - wzNote = pConditionalNote->sczText; - break; + BOOL fCondition = FALSE; + + hr = pTheme->pfnEvaluateCondition(pConditionalNote->sczCondition, &fCondition, pTheme->pvVariableContext); + ThmExitOnFailure(hr, "Failed to evaluate note condition: %ls", pConditionalNote->sczCondition); + + if (fCondition) + { + wzNote = pConditionalNote->sczText; + break; + } } } } @@ -5497,7 +5667,6 @@ static HRESULT LoadControls( LPCWSTR wzWindowClass = NULL; DWORD dwWindowBits = WS_CHILD; DWORD dwWindowExBits = 0; - BOOL fOwnerDrawImage = THEME_IMAGE_REFERENCE_TYPE_NONE != pControl->imageRef.type; if (fStartNewGroup) { @@ -5522,7 +5691,7 @@ static HRESULT LoadControls( __fallthrough; case THEME_CONTROL_TYPE_BUTTON: wzWindowClass = WC_BUTTONW; - if (fOwnerDrawImage) + if (THEME_IMAGE_REFERENCE_TYPE_NONE != pControl->Button.rgImageRef[0].type) { dwWindowBits |= BS_OWNERDRAW; pControl->dwInternalStyle |= INTERNAL_CONTROL_STYLE_OWNER_DRAW; @@ -5556,7 +5725,7 @@ static HRESULT LoadControls( break; case THEME_CONTROL_TYPE_IMAGE: // images are basically just owner drawn static controls (so we can draw .jpgs and .pngs instead of just bitmaps). - if (fOwnerDrawImage) + if (THEME_IMAGE_REFERENCE_TYPE_NONE != pControl->Image.imageRef.type) { wzWindowClass = THEME_WC_STATICOWNERDRAW; dwWindowBits |= SS_OWNERDRAW; @@ -5575,7 +5744,7 @@ static HRESULT LoadControls( case THEME_CONTROL_TYPE_LISTVIEW: // If thmutil is handling the image list for this listview, tell Windows not to free it when the control is destroyed. - if (pControl->rghImageList[0] || pControl->rghImageList[1] || pControl->rghImageList[2] || pControl->rghImageList[3]) + if (pControl->ListView.rghImageList[0] || pControl->ListView.rghImageList[1] || pControl->ListView.rghImageList[2] || pControl->ListView.rghImageList[3]) { pControl->dwStyle |= LVS_SHAREIMAGELISTS; } @@ -5583,7 +5752,7 @@ static HRESULT LoadControls( break; case THEME_CONTROL_TYPE_PROGRESSBAR: - if (fOwnerDrawImage) + if (pControl->ProgressBar.cImageRef) { wzWindowClass = THEME_WC_STATICOWNERDRAW; // no such thing as an owner drawn progress bar so we'll make our own out of a static control. dwWindowBits |= SS_OWNERDRAW; @@ -5721,13 +5890,13 @@ static HRESULT LoadControls( ::SendMessageW(pControl->hWnd, BCM_SETNOTE, 0, reinterpret_cast(pControl->sczNote)); } - if (pControl->hImage) + if (pControl->CommandLink.hImage) { - ::SendMessageW(pControl->hWnd, BM_SETIMAGE, IMAGE_BITMAP, reinterpret_cast(pControl->hImage)); + ::SendMessageW(pControl->hWnd, BM_SETIMAGE, IMAGE_BITMAP, reinterpret_cast(pControl->CommandLink.hImage)); } - else if (pControl->hIcon) + else if (pControl->CommandLink.hIcon) { - ::SendMessageW(pControl->hWnd, BM_SETIMAGE, IMAGE_ICON, reinterpret_cast(pControl->hIcon)); + ::SendMessageW(pControl->hWnd, BM_SETIMAGE, IMAGE_ICON, reinterpret_cast(pControl->CommandLink.hIcon)); } } else if (THEME_CONTROL_TYPE_EDITBOX == pControl->type) @@ -5744,13 +5913,13 @@ static HRESULT LoadControls( hr = SizeListViewColumns(pControl); ThmExitOnFailure(hr, "Failed to get size of list view columns."); - for (DWORD j = 0; j < pControl->cColumns; ++j) + for (DWORD j = 0; j < pControl->ListView.cColumns; ++j) { LVCOLUMNW lvc = { }; lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; - lvc.cx = pControl->ptcColumns[j].nWidth; + lvc.cx = pControl->ListView.ptcColumns[j].nWidth; lvc.iSubItem = j; - lvc.pszText = pControl->ptcColumns[j].pszName; + lvc.pszText = pControl->ListView.ptcColumns[j].pszName; lvc.fmt = LVCFMT_LEFT; lvc.cchTextMax = 4; @@ -5760,21 +5929,21 @@ static HRESULT LoadControls( } // Return value tells us the old image list, we don't care. - if (pControl->rghImageList[0]) + if (pControl->ListView.rghImageList[0]) { - ::SendMessageW(pControl->hWnd, LVM_SETIMAGELIST, static_cast(LVSIL_NORMAL), reinterpret_cast(pControl->rghImageList[0])); + ::SendMessageW(pControl->hWnd, LVM_SETIMAGELIST, static_cast(LVSIL_NORMAL), reinterpret_cast(pControl->ListView.rghImageList[0])); } - else if (pControl->rghImageList[1]) + else if (pControl->ListView.rghImageList[1]) { - ::SendMessageW(pControl->hWnd, LVM_SETIMAGELIST, static_cast(LVSIL_SMALL), reinterpret_cast(pControl->rghImageList[1])); + ::SendMessageW(pControl->hWnd, LVM_SETIMAGELIST, static_cast(LVSIL_SMALL), reinterpret_cast(pControl->ListView.rghImageList[1])); } - else if (pControl->rghImageList[2]) + else if (pControl->ListView.rghImageList[2]) { - ::SendMessageW(pControl->hWnd, LVM_SETIMAGELIST, static_cast(LVSIL_STATE), reinterpret_cast(pControl->rghImageList[2])); + ::SendMessageW(pControl->hWnd, LVM_SETIMAGELIST, static_cast(LVSIL_STATE), reinterpret_cast(pControl->ListView.rghImageList[2])); } - else if (pControl->rghImageList[3]) + else if (pControl->ListView.rghImageList[3]) { - ::SendMessageW(pControl->hWnd, LVM_SETIMAGELIST, static_cast(LVSIL_GROUPHEADER), reinterpret_cast(pControl->rghImageList[3])); + ::SendMessageW(pControl->hWnd, LVM_SETIMAGELIST, static_cast(LVSIL_GROUPHEADER), reinterpret_cast(pControl->ListView.rghImageList[3])); } } } @@ -5909,16 +6078,24 @@ static HRESULT LocalizeControl( ThmExitOnFailure(hr, "Failed to localize conditional text."); } - for (DWORD j = 0; j < pControl->cConditionalNotes; ++j) + switch (pControl->type) { - hr = LocLocalizeString(pWixLoc, &pControl->rgConditionalNotes[j].sczText); - ThmExitOnFailure(hr, "Failed to localize conditional note."); - } + case THEME_CONTROL_TYPE_COMMANDLINK: + for (DWORD j = 0; j < pControl->CommandLink.cConditionalNotes; ++j) + { + hr = LocLocalizeString(pWixLoc, &pControl->CommandLink.rgConditionalNotes[j].sczText); + ThmExitOnFailure(hr, "Failed to localize conditional note."); + } - for (DWORD j = 0; j < pControl->cColumns; ++j) - { - hr = LocLocalizeString(pWixLoc, &pControl->ptcColumns[j].pszName); - ThmExitOnFailure(hr, "Failed to localize column text."); + break; + case THEME_CONTROL_TYPE_LISTVIEW: + for (DWORD j = 0; j < pControl->ListView.cColumns; ++j) + { + hr = LocLocalizeString(pWixLoc, &pControl->ListView.ptcColumns[j].pszName); + ThmExitOnFailure(hr, "Failed to localize column text."); + } + + break; } for (DWORD j = 0; j < pControl->cTabs; ++j) @@ -6002,13 +6179,20 @@ static HRESULT LoadControlString( hr = ResReadString(hResModule, pControl->uStringId, &pControl->sczText); ThmExitOnFailure(hr, "Failed to load control text."); - for (DWORD j = 0; j < pControl->cColumns; ++j) + switch (pControl->type) { - if (UINT_MAX != pControl->ptcColumns[j].uStringId) + case THEME_CONTROL_TYPE_LISTVIEW: + for (DWORD j = 0; j < pControl->ListView.cColumns; ++j) { - hr = ResReadString(hResModule, pControl->ptcColumns[j].uStringId, &pControl->ptcColumns[j].pszName); - ThmExitOnFailure(hr, "Failed to load column text."); + THEME_COLUMN* pColumn = pControl->ListView.ptcColumns + j; + if (UINT_MAX != pColumn->uStringId) + { + hr = ResReadString(hResModule, pColumn->uStringId, &pColumn->pszName); + ThmExitOnFailure(hr, "Failed to load column text."); + } } + + break; } for (DWORD j = 0; j < pControl->cTabs; ++j) @@ -6066,9 +6250,9 @@ static void ResizeControl( { SizeListViewColumns(pControl); - for (DWORD j = 0; j < pControl->cColumns; ++j) + for (DWORD j = 0; j < pControl->ListView.cColumns; ++j) { - if (-1 == ::SendMessageW(pControl->hWnd, LVM_SETCOLUMNWIDTH, (WPARAM) (int) (j), (LPARAM) (pControl->ptcColumns[j].nWidth))) + if (-1 == ::SendMessageW(pControl->hWnd, LVM_SETCOLUMNWIDTH, (WPARAM) (int) (j), (LPARAM) (pControl->ListView.ptcColumns[j].nWidth))) { Trace(REPORT_DEBUG, "Failed to resize listview column %u with error %u", j, ::GetLastError()); return; @@ -6167,9 +6351,9 @@ static void ScaleControl( if (THEME_CONTROL_TYPE_LISTVIEW == pControl->type) { - for (DWORD i = 0; i < pControl->cColumns; ++i) + for (DWORD i = 0; i < pControl->ListView.cColumns; ++i) { - THEME_COLUMN* pColumn = pControl->ptcColumns + i; + THEME_COLUMN* pColumn = pControl->ListView.ptcColumns + i; pColumn->nBaseWidth = DpiuScaleValue(pColumn->nDefaultDpiBaseWidth, nDpi); } -- cgit v1.2.3-55-g6feb