Mercurial > foo_out_sdl
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foosdk/sdk/libPPUI/CButtonLite.h Mon Jan 05 02:15:46 2026 -0500 @@ -0,0 +1,259 @@ +#pragma once + +#include <functional> +#include <vsstyle.h> +#include "wtl-pp.h" +#include "win32_op.h" +#include "DarkMode.h" + +typedef CWinTraits<WS_CHILD|WS_TABSTOP,0> CButtonLiteTraits; + +class CButtonLite : public CWindowImpl<CButtonLite, CWindow, CButtonLiteTraits > { +public: + BEGIN_MSG_MAP_EX(CButtonLite) + MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, MousePassThru) + MSG_WM_MOUSELEAVE(OnMouseLeave) + MSG_WM_SETTEXT(OnSetText) + MSG_WM_PAINT( OnPaint ) + MSG_WM_MOUSEMOVE(OnMouseMove) + MSG_WM_LBUTTONDOWN(OnLButtonDown) + MSG_WM_SETFOCUS(OnSetFocus) + MSG_WM_KILLFOCUS(OnKillFocus) + MSG_WM_KEYDOWN(OnKeyDown) + MSG_WM_KEYUP(OnKeyUp) + MSG_WM_CHAR(OnChar) + MSG_WM_ENABLE(OnEnable) + MESSAGE_HANDLER_EX(WM_GETDLGCODE, OnGetDlgCode) + MSG_WM_SETFONT(OnSetFont) + MSG_WM_GETFONT(OnGetFont) + MSG_WM_CREATE(OnCreate) + END_MSG_MAP() + std::function<void () > ClickHandler; + + unsigned Measure() const { + auto font = myGetFont(); + LOGFONT lf; + WIN32_OP_D(font.GetLogFont(lf)); + MakeBoldFont( lf ); + CFont bold; + WIN32_OP_D(bold.CreateFontIndirect(&lf)); + CWindowDC dc(*this); + auto oldFont = dc.SelectFont( bold ); + CSize size (0,0); + + { + CString measure; + measure = L"#"; + measure += m_textDrawMe; + WIN32_OP_D(dc.GetTextExtent(measure, measure.GetLength(), &size)); + } + + dc.SelectFont( oldFont ); + + return size.cx; + } + std::function< void (HWND) > TabCycleHandler; + std::function< HBRUSH (CDCHandle) > CtlColorHandler; + std::function< bool (HWND) > WantTabCheck; + CWindow WndCtlColorTarget; + + // Rationale: sometimes you want a different text to be presented to accessibility APIs than actually drawn + // For an example, a clear button looks best with a multiplication sign, but the narrator should say "clear" or so when focused + void DrawAlternateText( const wchar_t * textDrawMe ) { + m_textDrawMe = textDrawMe; + } + +protected: + LRESULT MousePassThru(UINT cMsg, WPARAM cFlags, LPARAM lParam) { + SetMsgHandled(FALSE); + CPoint cPoint(lParam); + const DWORD maskButtons = MK_LBUTTON | MK_RBUTTON | MK_MBUTTON | MK_XBUTTON1 | MK_XBUTTON2; + if (cMsg == WM_MOUSEWHEEL || cMsg == WM_MOUSEHWHEEL || (cFlags & maskButtons) != 0) { + ToggleHot(false); + } + if (cMsg == WM_MOUSEWHEEL || cMsg == WM_MOUSEHWHEEL) { + TogglePressed(false); + } + if (cMsg == WM_LBUTTONUP) { + bool wasPressed = m_pressed; + TogglePressed(false); + if (wasPressed) OnClicked(); + SetMsgHandled(TRUE); + } + return 0; + } + CFontHandle m_font; + void OnSetFont(HFONT font, BOOL bRedraw) { + m_font = font; if (bRedraw) Invalidate(); + } + HFONT OnGetFont() { + return m_font; + } + LRESULT OnGetDlgCode(UINT, WPARAM wp, LPARAM) { + if ( wp == VK_TAB && TabCycleHandler != NULL) { + if ( WantTabCheck == NULL || WantTabCheck(m_hWnd) ) { + TabCycleHandler( m_hWnd ); + return DLGC_WANTTAB; + } + } + SetMsgHandled(FALSE); return 0; + } + void OnChar(UINT, UINT, UINT) { + } + void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { + (void)nRepCnt; (void)nFlags; + switch(nChar) { + case VK_SPACE: + case VK_RETURN: + TogglePressed(true); break; + } + } + void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) { + (void)nRepCnt; (void)nFlags; + switch(nChar) { + case VK_SPACE: + case VK_RETURN: + TogglePressed(false); + OnClicked(); + break; + } + } + void OnSetFocus(CWindow) { + m_focused = true; Invalidate(); + } + void OnKillFocus(CWindow) { + m_focused = false; Invalidate(); + } + CFontHandle myGetFont() const { + auto f = GetFont(); + if ( f == NULL ) f = (HFONT) GetStockObject(DEFAULT_GUI_FONT); + return f; + } + static void MakeBoldFont(LOGFONT & lf ) { + lf.lfWeight += 300; + if (lf.lfWeight > 1000 ) lf.lfWeight = 1000; + } + + CWindow GetCtlColorTarget() { + CWindow target = WndCtlColorTarget; + if (target == NULL) target = GetParent(); + return target; + } + virtual void DrawBackground( CDCHandle dc, CRect rcClient ) { + { + HBRUSH brush = NULL; + if (CtlColorHandler) { + brush = CtlColorHandler(dc); + } else { + brush = (HBRUSH)GetCtlColorTarget().SendMessage(WM_CTLCOLORBTN, (WPARAM)dc.m_hDC, (LPARAM)this->m_hWnd); + } + if (brush != NULL) { + dc.FillRect(rcClient, brush); + dc.SetBkMode(TRANSPARENT); + } + } + if ( IsPressed() ) { + CTheme theme; + if (theme.OpenThemeData(*this, L"BUTTON" )) { + DrawThemeBackground(theme, dc, BP_PUSHBUTTON, PBS_PRESSED, rcClient, rcClient ); + } else { + DrawFrameControl( dc, rcClient, DFC_BUTTON, DFCS_PUSHED ); + } + } else if (m_hot) { + CTheme theme; + if (theme.OpenThemeData(*this, L"BUTTON")) { + DrawThemeBackground(theme, dc, BP_PUSHBUTTON, PBS_HOT, rcClient, rcClient); + } else { + DrawFrameControl(dc, rcClient, DFC_BUTTON, DFCS_HOT); + } + } + } + + virtual void OnPaint(CDCHandle) { + CPaintDC pdc(*this); + + CRect rcClient; + if (! GetClientRect( &rcClient ) ) return; + + auto font = myGetFont(); + /* + CFont fontOverride; + if ( IsPressed() ) { + LOGFONT lf; + font.GetLogFont( lf ); + MakeBoldFont( lf ); + fontOverride.CreateFontIndirect( & lf ); + font = fontOverride; + } + */ + HFONT oldFont = pdc.SelectFont( font ); + + DrawBackground( pdc.m_hDC, rcClient ); + + pdc.SetBkMode( TRANSPARENT ); + if ( !IsWindowEnabled() ) { + pdc.SetTextColor( DarkMode::GetSysColor(COLOR_GRAYTEXT) ); + } else if ( m_focused ) { + pdc.SetTextColor( DarkMode::GetSysColor(COLOR_HIGHLIGHT) ); + } + pdc.DrawText( m_textDrawMe, m_textDrawMe.GetLength(), &rcClient, DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_NOPREFIX ); + + pdc.SelectFont( oldFont ); + } + virtual void OnClicked() { + if ( ClickHandler ) { + ClickHandler(); + } else { + GetParent().PostMessage( WM_COMMAND, MAKEWPARAM( this->GetDlgCtrlID(), BN_CLICKED ), (LPARAM) m_hWnd ); + } + } + bool IsPressed() {return m_pressed; } +private: + int OnCreate(LPCREATESTRUCT lpCreateStruct) { + DarkMode::ApplyDarkThemeCtrl(*this, DarkMode::IsDialogDark(GetCtlColorTarget(), WM_CTLCOLORBTN)); + if ( lpCreateStruct->lpszName != nullptr ) this->m_textDrawMe = lpCreateStruct->lpszName; + SetMsgHandled(FALSE); return 0; + } + void OnEnable(BOOL) { + Invalidate(); SetMsgHandled(FALSE); + } + void ToggleHot( bool bHot ) { + if ( bHot != m_hot ) { + m_hot = bHot; Invalidate(); + } + } + void OnMouseMove(UINT nFlags, CPoint) { + const DWORD maskButtons = MK_LBUTTON | MK_RBUTTON | MK_MBUTTON | MK_XBUTTON1 | MK_XBUTTON2; + if ((nFlags & maskButtons) != 0) return; + ToggleHot(true); + TrackMouseLeave(); + } + void OnLButtonDown(UINT nFlags, CPoint) { + const DWORD maskButtons = MK_LBUTTON | MK_RBUTTON | MK_MBUTTON | MK_XBUTTON1 | MK_XBUTTON2; + if ( ( nFlags & maskButtons ) != MK_LBUTTON ) return; + TogglePressed( true ); + TrackMouseLeave(); + } + void TogglePressed( bool bPressed ) { + if ( bPressed != m_pressed ) { + m_pressed = bPressed; Invalidate(); + } + } + int OnSetText(LPCTSTR lpstrText) { + m_textDrawMe = lpstrText; + Invalidate(); SetMsgHandled(FALSE); + return 0; + } + void TrackMouseLeave() { + TRACKMOUSEEVENT tme = { sizeof(tme) }; + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = m_hWnd; + TrackMouseEvent(&tme); + } + void OnMouseLeave() { + ToggleHot(false); TogglePressed(false); + } + + bool m_pressed = false, m_focused = false, m_hot = false; + CString m_textDrawMe; +};
