https://git.reactos.org/?p=reactos.git;a=commitdiff;h=0b107f2e309cac23a42ddd...
commit 0b107f2e309cac23a42dddb9f36ac413a3a571b6 Author: Carlo-Bramini carlo_bramini@users.sourceforge.net AuthorDate: Mon Aug 6 20:23:12 2018 +0200 Commit: Hermès Bélusca-Maïto hermes.belusca-maito@reactos.org CommitDate: Mon Mar 18 01:34:02 2019 +0100
[CALC] Add theming support, requires Windows XP or later. CORE-13343
- Fix errors if a theme api is missing. - Add callback to functions for drawing themed transparent background. - Fix drawing glitch when theming is applied. - Redraw on theme change: automatically redraw the window if the theme is changed while the application is active. - Colours are now declared though RGB() macro. - Removed safe DS_SHELLFONT declaration. --- base/applications/calc/CMakeLists.txt | 1 + base/applications/calc/calc.h | 39 +++++-- base/applications/calc/res/calc_sm.ico | Bin 2550 -> 0 bytes base/applications/calc/resource.h | 7 +- base/applications/calc/resource.rc | 8 +- base/applications/calc/theme.c | 127 +++++++++++++++++++++++ base/applications/calc/winmain.c | 181 +++++++++++++++++++++++++++++---- base/applications/calc/wmmsg.h | 0 8 files changed, 330 insertions(+), 33 deletions(-)
diff --git a/base/applications/calc/CMakeLists.txt b/base/applications/calc/CMakeLists.txt index ffe0ee3a5e..d273f10250 100644 --- a/base/applications/calc/CMakeLists.txt +++ b/base/applications/calc/CMakeLists.txt @@ -8,6 +8,7 @@ list(APPEND SOURCE utl_ieee.c winmain.c htmlhelp.c + theme.c calc.h)
file(GLOB calc_rc_deps res/*.*) diff --git a/base/applications/calc/calc.h b/base/applications/calc/calc.h index db984f0760..f6c2c7c863 100644 --- a/base/applications/calc/calc.h +++ b/base/applications/calc/calc.h @@ -17,6 +17,9 @@ #endif #include <limits.h>
+/* RESOURCES */ +#include "resource.h" + /* Messages reserved for the main dialog */ #define WM_CLOSE_STATS (WM_APP+1) #define WM_HANDLE_CLIPBOARD (WM_APP+2) @@ -41,12 +44,6 @@
#endif
-#include "resource.h" - -#ifndef IDC_STATIC -#define IDC_STATIC ((DWORD)-1) -#endif - #define CALC_VERSION _T("1.12")
#define MAX_CALC_SIZE 256 @@ -67,6 +64,34 @@ extern type_HtmlHelpW calc_HtmlHelpW; void HtmlHelp_Start(HINSTANCE hInstance); void HtmlHelp_Stop(void);
+/* THEMING SUPPORT */ +#if (_WIN32_WINNT >= 0x0600) +#include <vssym32.h> +#include <vsstyle.h> +#else +#include <tmschema.h> +#endif +#include <uxtheme.h> + +void Theme_Start(HINSTANCE hInstance); +void Theme_Stop(void); + +typedef HTHEME (WINAPI* type_OpenThemeData)(HWND,const WCHAR*); +typedef HRESULT (WINAPI* type_CloseThemeData)(HTHEME); +typedef HRESULT (WINAPI* type_DrawThemeBackground)(HTHEME,HDC,int,int,const RECT*,const RECT*); +typedef BOOL (WINAPI* type_IsAppThemed)(void); +typedef BOOL (WINAPI* type_IsThemeActive)(void); +typedef BOOL (WINAPI* type_IsThemeBackgroundPartiallyTransparent)(HTHEME, int, int); +typedef HRESULT (WINAPI* type_DrawThemeParentBackground)(HWND, HDC, RECT *); + +extern type_OpenThemeData calc_OpenThemeData; +extern type_CloseThemeData calc_CloseThemeData; +extern type_DrawThemeBackground calc_DrawThemeBackground; +extern type_IsAppThemed calc_IsAppThemed; +extern type_IsThemeActive calc_IsThemeActive; +extern type_IsThemeBackgroundPartiallyTransparent calc_IsThemeBackgroundPartiallyTransparent; +extern type_DrawThemeParentBackground calc_DrawThemeParentBackground; + /*#define USE_KEYBOARD_HOOK*/
#define SIZEOF(_ar) (sizeof(_ar)/sizeof(_ar[1])) @@ -144,6 +169,8 @@ typedef struct { HHOOK hKeyboardHook; #endif HWND hWnd; + HICON hBgIcon; + HICON hSmIcon; DWORD layout; TCHAR buffer[MAX_CALC_SIZE]; TCHAR source[MAX_CALC_SIZE]; diff --git a/base/applications/calc/res/calc_sm.ico b/base/applications/calc/res/calc_sm.ico deleted file mode 100644 index c6e151d1f0..0000000000 Binary files a/base/applications/calc/res/calc_sm.ico and /dev/null differ diff --git a/base/applications/calc/resource.h b/base/applications/calc/resource.h index c9a3ac0e21..08e985cf73 100644 --- a/base/applications/calc/resource.h +++ b/base/applications/calc/resource.h @@ -1,5 +1,9 @@ #pragma once
+#ifndef IDC_STATIC +#define IDC_STATIC -1 +#endif + #define IDS_CALC_NAME 1 #define IDS_MATH_ERROR 2 #define IDS_QUICKHELP 3 @@ -11,8 +15,7 @@ #define IDR_MENU_SCIENTIFIC_1 106 #define IDR_MENU_SCIENTIFIC_2 107 #define IDR_MENU_STANDARD 108 -#define IDI_CALC_BIG 110 -#define IDI_CALC_SMALL 111 +#define IDI_CALC 110 #define IDC_RADIO_HEX 1002 #define IDC_RADIO_DEC 1003 #define IDC_RADIO_OCT 1004 diff --git a/base/applications/calc/resource.rc b/base/applications/calc/resource.rc index 7272276d59..9bb5620d8a 100644 --- a/base/applications/calc/resource.rc +++ b/base/applications/calc/resource.rc @@ -10,18 +10,14 @@
#include "resource.h"
-#ifndef IDC_STATIC -#define IDC_STATIC -1 -#endif - /* Common resources */
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
/* Icons */ -IDI_CALC_BIG ICON "res/calc.ico" -IDI_CALC_SMALL ICON "res/calc_sm.ico" +IDI_CALC ICON DISCARDABLE "res/calc.ico"
+/* Manifest */ #include <reactos/manifest_exe.rc>
/* UTF-8 */ diff --git a/base/applications/calc/theme.c b/base/applications/calc/theme.c new file mode 100644 index 0000000000..8055b36283 --- /dev/null +++ b/base/applications/calc/theme.c @@ -0,0 +1,127 @@ +/* + * ReactOS Calc (Theming support) + * + * Copyright 2007-2017, Carlo Bramini + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "calc.h" + +#define GET_CB(name) \ + calc_##name = (type_##name)GetProcAddress(hUxTheme, #name); \ + if (calc_##name == NULL) calc_##name = dummy_##name; + +static HTHEME WINAPI +dummy_OpenThemeData(HWND hwnd, const WCHAR *pszClassList); + +static HRESULT WINAPI +dummy_CloseThemeData(HTHEME hTheme); + +static HRESULT WINAPI +dummy_DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, + const RECT *prc, const RECT *prcClip); + +static BOOL WINAPI +dummy_IsAppThemed(void); + +static BOOL WINAPI +dummy_IsThemeActive(void); + +static BOOL WINAPI +dummy_IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId, int iStateId); + +static HRESULT WINAPI +dummy_DrawThemeParentBackground(HWND hWnd, HDC hdc, RECT *prc); + + +type_OpenThemeData calc_OpenThemeData = dummy_OpenThemeData; +type_CloseThemeData calc_CloseThemeData = dummy_CloseThemeData; +type_DrawThemeBackground calc_DrawThemeBackground = dummy_DrawThemeBackground; +type_IsAppThemed calc_IsAppThemed = dummy_IsAppThemed; +type_IsThemeActive calc_IsThemeActive = dummy_IsThemeActive; +type_IsThemeBackgroundPartiallyTransparent calc_IsThemeBackgroundPartiallyTransparent = \ + dummy_IsThemeBackgroundPartiallyTransparent; +type_DrawThemeParentBackground calc_DrawThemeParentBackground = \ + dummy_DrawThemeParentBackground; + +static HMODULE hUxTheme; + +static HTHEME WINAPI +dummy_OpenThemeData(HWND hwnd, const WCHAR* pszClassList) +{ + return NULL; +} + +static HRESULT WINAPI +dummy_CloseThemeData(HTHEME hTheme) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI +dummy_DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, + const RECT* prc, const RECT* prcClip) +{ + return E_NOTIMPL; +} + +static BOOL WINAPI +dummy_IsAppThemed(void) +{ + return FALSE; +} + +static BOOL WINAPI +dummy_IsThemeActive(void) +{ + return FALSE; +} + +static BOOL WINAPI +dummy_IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId, int iStateId) +{ + return FALSE; +} + +static HRESULT WINAPI +dummy_DrawThemeParentBackground(HWND hWnd, HDC hdc, RECT *prc) +{ + return E_NOTIMPL; +} + +void Theme_Start(HINSTANCE hInstance) +{ + hUxTheme = LoadLibrary(_T("UXTHEME")); + if (hUxTheme == NULL) + return; + + GET_CB(OpenThemeData) + GET_CB(CloseThemeData) + GET_CB(DrawThemeBackground) + GET_CB(IsAppThemed) + GET_CB(IsThemeActive) + GET_CB(IsThemeBackgroundPartiallyTransparent) + GET_CB(DrawThemeParentBackground) +} + +void Theme_Stop(void) +{ + if(hUxTheme == NULL) + return; + + FreeLibrary(hUxTheme); + hUxTheme = NULL; +} diff --git a/base/applications/calc/winmain.c b/base/applications/calc/winmain.c index 696e3ee9df..fceb41fc96 100644 --- a/base/applications/calc/winmain.c +++ b/base/applications/calc/winmain.c @@ -48,9 +48,9 @@ #define BITMASK_OCT_MASK 0x02 #define BITMASK_BIN_MASK 0x01
-#define CALC_CLR_RED 0x000000FF -#define CALC_CLR_BLUE 0x00FF0000 -#define CALC_CLR_PURP 0x00FF00FF +#define CALC_CLR_RED RGB(0xFF, 0x00, 0x00) +#define CALC_CLR_BLUE RGB(0x00, 0x00, 0xFF) +#define CALC_CLR_PURP RGB(0xFF, 0x00, 0xFF)
typedef struct { CHAR key; // Virtual key identifier @@ -233,10 +233,22 @@ static const function_table_t function_table[] = { { IDC_BUTTON_LEFTPAR, NO_CHAIN, 0, run_lpar, NULL, NULL, NULL, }, };
+/* Sub-classing information for theming support */ +typedef struct{ + BOOL bHover; + WNDPROC oldProc; +} BTNINFO,*LPBTNINFO; + + /* -*/ + * Global variable declaration + */ + +calc_t calc;
-calc_t calc; +/* Hot-state info for theming support */ +BTNINFO BtnInfo[255]; +UINT BtnCount;
static void load_config(void) { @@ -326,7 +338,7 @@ static LRESULT post_key_press(LPARAM lParam, WORD idc) if (!GetClassName(hCtlWnd, ClassName, SIZEOF(ClassName))) return 1;
- if (!_tcscmp(ClassName, TEXT("Button"))) { + if (!_tcscmp(ClassName, WC_BUTTON)) { DWORD dwStyle = GetWindowLongPtr(hCtlWnd, GWL_STYLE) & 0xF;
/* Set states for press/release, but only for push buttons */ @@ -1213,14 +1225,58 @@ static void run_lpar(calc_number_t *c) static LRESULT CALLBACK SubclassButtonProc(HWND hWnd, WPARAM wp, LPARAM lp) { LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lp; - DWORD dwStyle; UINT dwText; TCHAR text[64]; int dx, dy, len; SIZE size; POINT pt;
- if(dis->CtlType == ODT_BUTTON) { + if(dis->CtlType == ODT_BUTTON) + { + HTHEME hTheme = NULL; + LPBTNINFO lpBtnInfo; + + if (calc_IsAppThemed() && calc_IsThemeActive()) + hTheme = calc_OpenThemeData(hWnd, L"Button"); + + if (hTheme) + { + int iState = 0; + + if ((dis->itemState & ODS_DISABLED)) + iState |= PBS_DISABLED; + if ((dis->itemState & ODS_SELECTED)) + iState |= PBS_PRESSED; + + lpBtnInfo = (LPBTNINFO)GetWindowLongPtr(dis->hwndItem, GWLP_USERDATA); + if (lpBtnInfo != NULL) + { + if (lpBtnInfo->bHover) + iState |= PBS_HOT; + } + + if (calc_IsThemeBackgroundPartiallyTransparent(hTheme, BP_PUSHBUTTON, iState)) + { + calc_DrawThemeParentBackground(dis->hwndItem, dis->hDC, &dis->rcItem); + } + + // Draw the frame around the control + calc_DrawThemeBackground(hTheme, dis->hDC, BP_PUSHBUTTON, iState, &dis->rcItem, NULL); + + calc_CloseThemeData(hTheme); + } else { + /* default state: unpushed */ + DWORD dwStyle = 0; + + if ((dis->itemState & ODS_SELECTED)) + dwStyle = DFCS_PUSHED; + + DrawFrameControl(dis->hDC, &dis->rcItem, DFC_BUTTON, DFCS_BUTTONPUSH | dwStyle); + } + + /* button text to write */ + len = GetWindowText(dis->hwndItem, text, SIZEOF(text)); + /* * little exception: 1/x has different color * in standard and scientific modes @@ -1236,21 +1292,20 @@ static LRESULT CALLBACK SubclassButtonProc(HWND hWnd, WPARAM wp, LPARAM lp) break; } } - /* button text to write */ - len = GetWindowText(dis->hwndItem, text, SIZEOF(text)); - /* default state: unpushed & enabled */ - dwStyle = 0; + + /* No background, to avoid corruption of the texture */ + SetBkMode(dis->hDC, TRANSPARENT); + + /* Default state: enabled */ dwText = 0; if ((dis->itemState & ODS_DISABLED)) dwText = DSS_DISABLED; - if ((dis->itemState & ODS_SELECTED)) - dwStyle = DFCS_PUSHED;
- DrawFrameControl(dis->hDC, &dis->rcItem, DFC_BUTTON, DFCS_BUTTONPUSH | dwStyle); + /* Draw the text in the button */ GetTextExtentPoint32(dis->hDC, text, len, &size); dx = ((dis->rcItem.right-dis->rcItem.left) - size.cx) >> 1; dy = ((dis->rcItem.bottom-dis->rcItem.top) - size.cy) >> 1; - if ((dwStyle & DFCS_PUSHED)) { + if ((dis->itemState & ODS_SELECTED)) { dx++; dy++; } @@ -1261,6 +1316,61 @@ static LRESULT CALLBACK SubclassButtonProc(HWND hWnd, WPARAM wp, LPARAM lp) return 1L; }
+static INT_PTR CALLBACK HotButtonProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) +{ + LPBTNINFO lpBtnInfo = (LPBTNINFO)GetWindowLongPtr(hWnd, GWLP_USERDATA); + TRACKMOUSEEVENT mouse_event; + + switch (msg) { + case WM_MOUSEMOVE: + mouse_event.cbSize = sizeof(TRACKMOUSEEVENT); + mouse_event.dwFlags = TME_QUERY; + if (!TrackMouseEvent(&mouse_event) || !(mouse_event.dwFlags & (TME_HOVER|TME_LEAVE))) + { + mouse_event.dwFlags = TME_HOVER|TME_LEAVE; + mouse_event.hwndTrack = hWnd; + mouse_event.dwHoverTime = 1; + TrackMouseEvent(&mouse_event); + } + break; + + case WM_MOUSEHOVER: + lpBtnInfo->bHover = TRUE; + InvalidateRect(hWnd, NULL, FALSE); + break; + + case WM_MOUSELEAVE: + lpBtnInfo->bHover = FALSE; + InvalidateRect(hWnd, NULL, FALSE); + break; + } + + return CallWindowProc(lpBtnInfo->oldProc, hWnd, msg, wp, lp); +} + +static BOOL CALLBACK EnumChildProc(HWND hWnd, LPARAM lParam) +{ + TCHAR szClass[64]; + + if (!GetClassName(hWnd, szClass, SIZEOF(szClass))) + return TRUE; + + if (!_tcscmp(szClass, WC_BUTTON)) + { + int *pnCtrls = (int *)lParam; + int nCtrls = *pnCtrls; + + BtnInfo[nCtrls].oldProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC); + BtnInfo[nCtrls].bHover = FALSE; + + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)&BtnInfo[nCtrls]); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)HotButtonProc); + + *pnCtrls = ++nCtrls; + } + return TRUE; +} + static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { unsigned int x; @@ -1276,6 +1386,9 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) EnableMenuItem(GetMenu(hWnd), IDM_HELP_HELP, MF_BYCOMMAND | MF_GRAYED); #endif calc.hWnd=hWnd; + /* Enumerate children and apply hover function */ + BtnCount = 0; + EnumChildWindows(hWnd, EnumChildProc, (LPARAM)&BtnCount);
#ifdef USE_KEYBOARD_HOOK calc.hKeyboardHook=SetWindowsHookEx( @@ -1300,8 +1413,8 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) /* remove keyboard focus */ SetFocus(GetDlgItem(hWnd, IDC_BUTTON_FOCUS)); /* set our calc icon */ - SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(calc.hInstance, MAKEINTRESOURCE(IDI_CALC_BIG))); - SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(calc.hInstance, MAKEINTRESOURCE(IDI_CALC_SMALL))); + SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)calc.hBgIcon); + SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)calc.hSmIcon);
/* Sets the state of the option to group digits */ hMenu = GetSubMenu(GetMenu(hWnd), 1); @@ -1354,7 +1467,7 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) TCHAR infotext[200]; LoadString(calc.hInstance, IDS_CALC_NAME, infotitle, SIZEOF(infotitle)); LoadString(calc.hInstance, IDS_AUTHOR, infotext, SIZEOF(infotext)); - ShellAbout(hWnd, infotitle, infotext, (HICON)LoadIcon(calc.hInstance, MAKEINTRESOURCE(IDI_CALC_BIG))); + ShellAbout(hWnd, infotitle, infotext, calc.hBgIcon); return TRUE; } case IDM_HELP_HELP: @@ -1791,6 +1904,10 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) case WM_EXITMENULOOP: calc.is_menu_on = FALSE; break; + + case WM_THEMECHANGED: + InvalidateRect(hWnd, NULL, FALSE); + break; } return FALSE; } @@ -1804,6 +1921,7 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL MSG msg; DWORD dwLayout;
+ /* Initialize controls for theming & manifest support */ InitCommonControls();
calc.hInstance = hInstance; @@ -1816,6 +1934,24 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
HtmlHelp_Start(hInstance);
+ Theme_Start(hInstance); + + calc.hBgIcon = LoadImage( + hInstance, + MAKEINTRESOURCE(IDI_CALC), + IMAGE_ICON, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON), + 0); + + calc.hSmIcon = LoadImage( + hInstance, + MAKEINTRESOURCE(IDI_CALC), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + 0); + do { /* ignore hwnd: dialogs are already visible! */ if (calc.layout == CALC_LAYOUT_SCIENTIFIC) @@ -1841,8 +1977,15 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL } } while (calc.action != IDC_STATIC);
+ if (calc.hBgIcon != NULL) + DestroyIcon(calc.hBgIcon); + + if (calc.hSmIcon != NULL) + DestroyIcon(calc.hSmIcon); + stop_rpn_engine();
+ Theme_Stop(); HtmlHelp_Stop();
return 0; diff --git a/base/applications/calc/wmmsg.h b/base/applications/calc/wmmsg.h deleted file mode 100644 index e69de29bb2..0000000000