https://git.reactos.org/?p=reactos.git;a=commitdiff;h=0b107f2e309cac23a42dd…
commit 0b107f2e309cac23a42dddb9f36ac413a3a571b6
Author: Carlo-Bramini <carlo_bramini(a)users.sourceforge.net>
AuthorDate: Mon Aug 6 20:23:12 2018 +0200
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)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