comparison foosdk/sdk/libPPUI/CButtonLite.h @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
comparison
equal deleted inserted replaced
0:e9bb126753e7 1:20d02a178406
1 #pragma once
2
3 #include <functional>
4 #include <vsstyle.h>
5 #include "wtl-pp.h"
6 #include "win32_op.h"
7 #include "DarkMode.h"
8
9 typedef CWinTraits<WS_CHILD|WS_TABSTOP,0> CButtonLiteTraits;
10
11 class CButtonLite : public CWindowImpl<CButtonLite, CWindow, CButtonLiteTraits > {
12 public:
13 BEGIN_MSG_MAP_EX(CButtonLite)
14 MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, MousePassThru)
15 MSG_WM_MOUSELEAVE(OnMouseLeave)
16 MSG_WM_SETTEXT(OnSetText)
17 MSG_WM_PAINT( OnPaint )
18 MSG_WM_MOUSEMOVE(OnMouseMove)
19 MSG_WM_LBUTTONDOWN(OnLButtonDown)
20 MSG_WM_SETFOCUS(OnSetFocus)
21 MSG_WM_KILLFOCUS(OnKillFocus)
22 MSG_WM_KEYDOWN(OnKeyDown)
23 MSG_WM_KEYUP(OnKeyUp)
24 MSG_WM_CHAR(OnChar)
25 MSG_WM_ENABLE(OnEnable)
26 MESSAGE_HANDLER_EX(WM_GETDLGCODE, OnGetDlgCode)
27 MSG_WM_SETFONT(OnSetFont)
28 MSG_WM_GETFONT(OnGetFont)
29 MSG_WM_CREATE(OnCreate)
30 END_MSG_MAP()
31 std::function<void () > ClickHandler;
32
33 unsigned Measure() const {
34 auto font = myGetFont();
35 LOGFONT lf;
36 WIN32_OP_D(font.GetLogFont(lf));
37 MakeBoldFont( lf );
38 CFont bold;
39 WIN32_OP_D(bold.CreateFontIndirect(&lf));
40 CWindowDC dc(*this);
41 auto oldFont = dc.SelectFont( bold );
42 CSize size (0,0);
43
44 {
45 CString measure;
46 measure = L"#";
47 measure += m_textDrawMe;
48 WIN32_OP_D(dc.GetTextExtent(measure, measure.GetLength(), &size));
49 }
50
51 dc.SelectFont( oldFont );
52
53 return size.cx;
54 }
55 std::function< void (HWND) > TabCycleHandler;
56 std::function< HBRUSH (CDCHandle) > CtlColorHandler;
57 std::function< bool (HWND) > WantTabCheck;
58 CWindow WndCtlColorTarget;
59
60 // Rationale: sometimes you want a different text to be presented to accessibility APIs than actually drawn
61 // For an example, a clear button looks best with a multiplication sign, but the narrator should say "clear" or so when focused
62 void DrawAlternateText( const wchar_t * textDrawMe ) {
63 m_textDrawMe = textDrawMe;
64 }
65
66 protected:
67 LRESULT MousePassThru(UINT cMsg, WPARAM cFlags, LPARAM lParam) {
68 SetMsgHandled(FALSE);
69 CPoint cPoint(lParam);
70 const DWORD maskButtons = MK_LBUTTON | MK_RBUTTON | MK_MBUTTON | MK_XBUTTON1 | MK_XBUTTON2;
71 if (cMsg == WM_MOUSEWHEEL || cMsg == WM_MOUSEHWHEEL || (cFlags & maskButtons) != 0) {
72 ToggleHot(false);
73 }
74 if (cMsg == WM_MOUSEWHEEL || cMsg == WM_MOUSEHWHEEL) {
75 TogglePressed(false);
76 }
77 if (cMsg == WM_LBUTTONUP) {
78 bool wasPressed = m_pressed;
79 TogglePressed(false);
80 if (wasPressed) OnClicked();
81 SetMsgHandled(TRUE);
82 }
83 return 0;
84 }
85 CFontHandle m_font;
86 void OnSetFont(HFONT font, BOOL bRedraw) {
87 m_font = font; if (bRedraw) Invalidate();
88 }
89 HFONT OnGetFont() {
90 return m_font;
91 }
92 LRESULT OnGetDlgCode(UINT, WPARAM wp, LPARAM) {
93 if ( wp == VK_TAB && TabCycleHandler != NULL) {
94 if ( WantTabCheck == NULL || WantTabCheck(m_hWnd) ) {
95 TabCycleHandler( m_hWnd );
96 return DLGC_WANTTAB;
97 }
98 }
99 SetMsgHandled(FALSE); return 0;
100 }
101 void OnChar(UINT, UINT, UINT) {
102 }
103 void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {
104 (void)nRepCnt; (void)nFlags;
105 switch(nChar) {
106 case VK_SPACE:
107 case VK_RETURN:
108 TogglePressed(true); break;
109 }
110 }
111 void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) {
112 (void)nRepCnt; (void)nFlags;
113 switch(nChar) {
114 case VK_SPACE:
115 case VK_RETURN:
116 TogglePressed(false);
117 OnClicked();
118 break;
119 }
120 }
121 void OnSetFocus(CWindow) {
122 m_focused = true; Invalidate();
123 }
124 void OnKillFocus(CWindow) {
125 m_focused = false; Invalidate();
126 }
127 CFontHandle myGetFont() const {
128 auto f = GetFont();
129 if ( f == NULL ) f = (HFONT) GetStockObject(DEFAULT_GUI_FONT);
130 return f;
131 }
132 static void MakeBoldFont(LOGFONT & lf ) {
133 lf.lfWeight += 300;
134 if (lf.lfWeight > 1000 ) lf.lfWeight = 1000;
135 }
136
137 CWindow GetCtlColorTarget() {
138 CWindow target = WndCtlColorTarget;
139 if (target == NULL) target = GetParent();
140 return target;
141 }
142 virtual void DrawBackground( CDCHandle dc, CRect rcClient ) {
143 {
144 HBRUSH brush = NULL;
145 if (CtlColorHandler) {
146 brush = CtlColorHandler(dc);
147 } else {
148 brush = (HBRUSH)GetCtlColorTarget().SendMessage(WM_CTLCOLORBTN, (WPARAM)dc.m_hDC, (LPARAM)this->m_hWnd);
149 }
150 if (brush != NULL) {
151 dc.FillRect(rcClient, brush);
152 dc.SetBkMode(TRANSPARENT);
153 }
154 }
155 if ( IsPressed() ) {
156 CTheme theme;
157 if (theme.OpenThemeData(*this, L"BUTTON" )) {
158 DrawThemeBackground(theme, dc, BP_PUSHBUTTON, PBS_PRESSED, rcClient, rcClient );
159 } else {
160 DrawFrameControl( dc, rcClient, DFC_BUTTON, DFCS_PUSHED );
161 }
162 } else if (m_hot) {
163 CTheme theme;
164 if (theme.OpenThemeData(*this, L"BUTTON")) {
165 DrawThemeBackground(theme, dc, BP_PUSHBUTTON, PBS_HOT, rcClient, rcClient);
166 } else {
167 DrawFrameControl(dc, rcClient, DFC_BUTTON, DFCS_HOT);
168 }
169 }
170 }
171
172 virtual void OnPaint(CDCHandle) {
173 CPaintDC pdc(*this);
174
175 CRect rcClient;
176 if (! GetClientRect( &rcClient ) ) return;
177
178 auto font = myGetFont();
179 /*
180 CFont fontOverride;
181 if ( IsPressed() ) {
182 LOGFONT lf;
183 font.GetLogFont( lf );
184 MakeBoldFont( lf );
185 fontOverride.CreateFontIndirect( & lf );
186 font = fontOverride;
187 }
188 */
189 HFONT oldFont = pdc.SelectFont( font );
190
191 DrawBackground( pdc.m_hDC, rcClient );
192
193 pdc.SetBkMode( TRANSPARENT );
194 if ( !IsWindowEnabled() ) {
195 pdc.SetTextColor( DarkMode::GetSysColor(COLOR_GRAYTEXT) );
196 } else if ( m_focused ) {
197 pdc.SetTextColor( DarkMode::GetSysColor(COLOR_HIGHLIGHT) );
198 }
199 pdc.DrawText( m_textDrawMe, m_textDrawMe.GetLength(), &rcClient, DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_NOPREFIX );
200
201 pdc.SelectFont( oldFont );
202 }
203 virtual void OnClicked() {
204 if ( ClickHandler ) {
205 ClickHandler();
206 } else {
207 GetParent().PostMessage( WM_COMMAND, MAKEWPARAM( this->GetDlgCtrlID(), BN_CLICKED ), (LPARAM) m_hWnd );
208 }
209 }
210 bool IsPressed() {return m_pressed; }
211 private:
212 int OnCreate(LPCREATESTRUCT lpCreateStruct) {
213 DarkMode::ApplyDarkThemeCtrl(*this, DarkMode::IsDialogDark(GetCtlColorTarget(), WM_CTLCOLORBTN));
214 if ( lpCreateStruct->lpszName != nullptr ) this->m_textDrawMe = lpCreateStruct->lpszName;
215 SetMsgHandled(FALSE); return 0;
216 }
217 void OnEnable(BOOL) {
218 Invalidate(); SetMsgHandled(FALSE);
219 }
220 void ToggleHot( bool bHot ) {
221 if ( bHot != m_hot ) {
222 m_hot = bHot; Invalidate();
223 }
224 }
225 void OnMouseMove(UINT nFlags, CPoint) {
226 const DWORD maskButtons = MK_LBUTTON | MK_RBUTTON | MK_MBUTTON | MK_XBUTTON1 | MK_XBUTTON2;
227 if ((nFlags & maskButtons) != 0) return;
228 ToggleHot(true);
229 TrackMouseLeave();
230 }
231 void OnLButtonDown(UINT nFlags, CPoint) {
232 const DWORD maskButtons = MK_LBUTTON | MK_RBUTTON | MK_MBUTTON | MK_XBUTTON1 | MK_XBUTTON2;
233 if ( ( nFlags & maskButtons ) != MK_LBUTTON ) return;
234 TogglePressed( true );
235 TrackMouseLeave();
236 }
237 void TogglePressed( bool bPressed ) {
238 if ( bPressed != m_pressed ) {
239 m_pressed = bPressed; Invalidate();
240 }
241 }
242 int OnSetText(LPCTSTR lpstrText) {
243 m_textDrawMe = lpstrText;
244 Invalidate(); SetMsgHandled(FALSE);
245 return 0;
246 }
247 void TrackMouseLeave() {
248 TRACKMOUSEEVENT tme = { sizeof(tme) };
249 tme.dwFlags = TME_LEAVE;
250 tme.hwndTrack = m_hWnd;
251 TrackMouseEvent(&tme);
252 }
253 void OnMouseLeave() {
254 ToggleHot(false); TogglePressed(false);
255 }
256
257 bool m_pressed = false, m_focused = false, m_hot = false;
258 CString m_textDrawMe;
259 };