[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.
This commit is contained in:
Carlo-Bramini 2018-08-06 20:23:12 +02:00 committed by Hermès Bélusca-Maïto
parent f6c565bc22
commit 0b107f2e30
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
8 changed files with 331 additions and 34 deletions

View file

@ -8,6 +8,7 @@ list(APPEND SOURCE
utl_ieee.c utl_ieee.c
winmain.c winmain.c
htmlhelp.c htmlhelp.c
theme.c
calc.h) calc.h)
file(GLOB calc_rc_deps res/*.*) file(GLOB calc_rc_deps res/*.*)

View file

@ -17,6 +17,9 @@
#endif #endif
#include <limits.h> #include <limits.h>
/* RESOURCES */
#include "resource.h"
/* Messages reserved for the main dialog */ /* Messages reserved for the main dialog */
#define WM_CLOSE_STATS (WM_APP+1) #define WM_CLOSE_STATS (WM_APP+1)
#define WM_HANDLE_CLIPBOARD (WM_APP+2) #define WM_HANDLE_CLIPBOARD (WM_APP+2)
@ -41,12 +44,6 @@
#endif #endif
#include "resource.h"
#ifndef IDC_STATIC
#define IDC_STATIC ((DWORD)-1)
#endif
#define CALC_VERSION _T("1.12") #define CALC_VERSION _T("1.12")
#define MAX_CALC_SIZE 256 #define MAX_CALC_SIZE 256
@ -67,6 +64,34 @@ extern type_HtmlHelpW calc_HtmlHelpW;
void HtmlHelp_Start(HINSTANCE hInstance); void HtmlHelp_Start(HINSTANCE hInstance);
void HtmlHelp_Stop(void); 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 USE_KEYBOARD_HOOK*/
#define SIZEOF(_ar) (sizeof(_ar)/sizeof(_ar[1])) #define SIZEOF(_ar) (sizeof(_ar)/sizeof(_ar[1]))
@ -144,6 +169,8 @@ typedef struct {
HHOOK hKeyboardHook; HHOOK hKeyboardHook;
#endif #endif
HWND hWnd; HWND hWnd;
HICON hBgIcon;
HICON hSmIcon;
DWORD layout; DWORD layout;
TCHAR buffer[MAX_CALC_SIZE]; TCHAR buffer[MAX_CALC_SIZE];
TCHAR source[MAX_CALC_SIZE]; TCHAR source[MAX_CALC_SIZE];

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -1,5 +1,9 @@
#pragma once #pragma once
#ifndef IDC_STATIC
#define IDC_STATIC -1
#endif
#define IDS_CALC_NAME 1 #define IDS_CALC_NAME 1
#define IDS_MATH_ERROR 2 #define IDS_MATH_ERROR 2
#define IDS_QUICKHELP 3 #define IDS_QUICKHELP 3
@ -11,8 +15,7 @@
#define IDR_MENU_SCIENTIFIC_1 106 #define IDR_MENU_SCIENTIFIC_1 106
#define IDR_MENU_SCIENTIFIC_2 107 #define IDR_MENU_SCIENTIFIC_2 107
#define IDR_MENU_STANDARD 108 #define IDR_MENU_STANDARD 108
#define IDI_CALC_BIG 110 #define IDI_CALC 110
#define IDI_CALC_SMALL 111
#define IDC_RADIO_HEX 1002 #define IDC_RADIO_HEX 1002
#define IDC_RADIO_DEC 1003 #define IDC_RADIO_DEC 1003
#define IDC_RADIO_OCT 1004 #define IDC_RADIO_OCT 1004

View file

@ -10,18 +10,14 @@
#include "resource.h" #include "resource.h"
#ifndef IDC_STATIC
#define IDC_STATIC -1
#endif
/* Common resources */ /* Common resources */
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
/* Icons */ /* Icons */
IDI_CALC_BIG ICON "res/calc.ico" IDI_CALC ICON DISCARDABLE "res/calc.ico"
IDI_CALC_SMALL ICON "res/calc_sm.ico"
/* Manifest */
#include <reactos/manifest_exe.rc> #include <reactos/manifest_exe.rc>
/* UTF-8 */ /* UTF-8 */

View file

@ -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;
}

View file

@ -48,9 +48,9 @@
#define BITMASK_OCT_MASK 0x02 #define BITMASK_OCT_MASK 0x02
#define BITMASK_BIN_MASK 0x01 #define BITMASK_BIN_MASK 0x01
#define CALC_CLR_RED 0x000000FF #define CALC_CLR_RED RGB(0xFF, 0x00, 0x00)
#define CALC_CLR_BLUE 0x00FF0000 #define CALC_CLR_BLUE RGB(0x00, 0x00, 0xFF)
#define CALC_CLR_PURP 0x00FF00FF #define CALC_CLR_PURP RGB(0xFF, 0x00, 0xFF)
typedef struct { typedef struct {
CHAR key; // Virtual key identifier CHAR key; // Virtual key identifier
@ -233,11 +233,23 @@ static const function_table_t function_table[] = {
{ IDC_BUTTON_LEFTPAR, NO_CHAIN, 0, run_lpar, NULL, NULL, NULL, }, { 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) static void load_config(void)
{ {
DWORD tmp; DWORD tmp;
@ -326,7 +338,7 @@ static LRESULT post_key_press(LPARAM lParam, WORD idc)
if (!GetClassName(hCtlWnd, ClassName, SIZEOF(ClassName))) if (!GetClassName(hCtlWnd, ClassName, SIZEOF(ClassName)))
return 1; return 1;
if (!_tcscmp(ClassName, TEXT("Button"))) { if (!_tcscmp(ClassName, WC_BUTTON)) {
DWORD dwStyle = GetWindowLongPtr(hCtlWnd, GWL_STYLE) & 0xF; DWORD dwStyle = GetWindowLongPtr(hCtlWnd, GWL_STYLE) & 0xF;
/* Set states for press/release, but only for push buttons */ /* 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) static LRESULT CALLBACK SubclassButtonProc(HWND hWnd, WPARAM wp, LPARAM lp)
{ {
LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lp; LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lp;
DWORD dwStyle;
UINT dwText; UINT dwText;
TCHAR text[64]; TCHAR text[64];
int dx, dy, len; int dx, dy, len;
SIZE size; SIZE size;
POINT pt; 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 * little exception: 1/x has different color
* in standard and scientific modes * in standard and scientific modes
@ -1236,21 +1292,20 @@ static LRESULT CALLBACK SubclassButtonProc(HWND hWnd, WPARAM wp, LPARAM lp)
break; break;
} }
} }
/* button text to write */
len = GetWindowText(dis->hwndItem, text, SIZEOF(text)); /* No background, to avoid corruption of the texture */
/* default state: unpushed & enabled */ SetBkMode(dis->hDC, TRANSPARENT);
dwStyle = 0;
/* Default state: enabled */
dwText = 0; dwText = 0;
if ((dis->itemState & ODS_DISABLED)) if ((dis->itemState & ODS_DISABLED))
dwText = DSS_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); GetTextExtentPoint32(dis->hDC, text, len, &size);
dx = ((dis->rcItem.right-dis->rcItem.left) - size.cx) >> 1; dx = ((dis->rcItem.right-dis->rcItem.left) - size.cx) >> 1;
dy = ((dis->rcItem.bottom-dis->rcItem.top) - size.cy) >> 1; dy = ((dis->rcItem.bottom-dis->rcItem.top) - size.cy) >> 1;
if ((dwStyle & DFCS_PUSHED)) { if ((dis->itemState & ODS_SELECTED)) {
dx++; dx++;
dy++; dy++;
} }
@ -1261,6 +1316,61 @@ static LRESULT CALLBACK SubclassButtonProc(HWND hWnd, WPARAM wp, LPARAM lp)
return 1L; 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) static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{ {
unsigned int x; 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); EnableMenuItem(GetMenu(hWnd), IDM_HELP_HELP, MF_BYCOMMAND | MF_GRAYED);
#endif #endif
calc.hWnd=hWnd; calc.hWnd=hWnd;
/* Enumerate children and apply hover function */
BtnCount = 0;
EnumChildWindows(hWnd, EnumChildProc, (LPARAM)&BtnCount);
#ifdef USE_KEYBOARD_HOOK #ifdef USE_KEYBOARD_HOOK
calc.hKeyboardHook=SetWindowsHookEx( calc.hKeyboardHook=SetWindowsHookEx(
@ -1300,8 +1413,8 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
/* remove keyboard focus */ /* remove keyboard focus */
SetFocus(GetDlgItem(hWnd, IDC_BUTTON_FOCUS)); SetFocus(GetDlgItem(hWnd, IDC_BUTTON_FOCUS));
/* set our calc icon */ /* set our calc icon */
SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(calc.hInstance, MAKEINTRESOURCE(IDI_CALC_BIG))); SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)calc.hBgIcon);
SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(calc.hInstance, MAKEINTRESOURCE(IDI_CALC_SMALL))); SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)calc.hSmIcon);
/* Sets the state of the option to group digits */ /* Sets the state of the option to group digits */
hMenu = GetSubMenu(GetMenu(hWnd), 1); 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]; TCHAR infotext[200];
LoadString(calc.hInstance, IDS_CALC_NAME, infotitle, SIZEOF(infotitle)); LoadString(calc.hInstance, IDS_CALC_NAME, infotitle, SIZEOF(infotitle));
LoadString(calc.hInstance, IDS_AUTHOR, infotext, SIZEOF(infotext)); 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; return TRUE;
} }
case IDM_HELP_HELP: case IDM_HELP_HELP:
@ -1791,6 +1904,10 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
case WM_EXITMENULOOP: case WM_EXITMENULOOP:
calc.is_menu_on = FALSE; calc.is_menu_on = FALSE;
break; break;
case WM_THEMECHANGED:
InvalidateRect(hWnd, NULL, FALSE);
break;
} }
return FALSE; return FALSE;
} }
@ -1804,6 +1921,7 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
MSG msg; MSG msg;
DWORD dwLayout; DWORD dwLayout;
/* Initialize controls for theming & manifest support */
InitCommonControls(); InitCommonControls();
calc.hInstance = hInstance; calc.hInstance = hInstance;
@ -1816,6 +1934,24 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
HtmlHelp_Start(hInstance); 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 { do {
/* ignore hwnd: dialogs are already visible! */ /* ignore hwnd: dialogs are already visible! */
if (calc.layout == CALC_LAYOUT_SCIENTIFIC) if (calc.layout == CALC_LAYOUT_SCIENTIFIC)
@ -1841,8 +1977,15 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
} }
} while (calc.action != IDC_STATIC); } while (calc.action != IDC_STATIC);
if (calc.hBgIcon != NULL)
DestroyIcon(calc.hBgIcon);
if (calc.hSmIcon != NULL)
DestroyIcon(calc.hSmIcon);
stop_rpn_engine(); stop_rpn_engine();
Theme_Stop();
HtmlHelp_Stop(); HtmlHelp_Stop();
return 0; return 0;