[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
winmain.c
htmlhelp.c
theme.c
calc.h)
file(GLOB calc_rc_deps res/*.*)

View file

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

View file

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

View file

@ -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 */

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_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;
calc_t calc;
/*
* Global variable declaration
*/
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;