Mercurial > foo_out_sdl
comparison foosdk/sdk/libPPUI/CEditWithButtons.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 <list> | |
| 4 #include <string> | |
| 5 #include <functional> | |
| 6 #include <memory> | |
| 7 #include "wtl-pp.h" | |
| 8 | |
| 9 #include "CButtonLite.h" | |
| 10 | |
| 11 class CEditWithButtons : public CEditPPHooks { | |
| 12 public: | |
| 13 CEditWithButtons(::ATL::CMessageMap * hookMM = nullptr, int hookMMID = 0) : CEditPPHooks(hookMM, hookMMID) {} | |
| 14 | |
| 15 static constexpr UINT MSG_CHECKCONDITIONS = WM_USER + 13; | |
| 16 static constexpr WPARAM MSG_CHECKCONDITIONS_MAGIC1 = 0xaec66f0c; | |
| 17 static constexpr LPARAM MSG_CHECKCONDITIONS_MAGIC2 = 0x180c2f35; | |
| 18 | |
| 19 BEGIN_MSG_MAP_EX(CEditWithButtons) | |
| 20 MSG_WM_CREATE(OnCreate) | |
| 21 MSG_WM_SETFONT(OnSetFont) | |
| 22 MSG_WM_WINDOWPOSCHANGED(OnPosChanged) | |
| 23 MSG_WM_CTLCOLORBTN(OnColorBtn) | |
| 24 MESSAGE_HANDLER_EX(WM_GETDLGCODE, OnGetDlgCode) | |
| 25 MSG_WM_KEYDOWN(OnKeyDown) | |
| 26 MSG_WM_CHAR(OnChar) | |
| 27 // MSG_WM_SETFOCUS( OnSetFocus ) | |
| 28 // MSG_WM_KILLFOCUS( OnKillFocus ) | |
| 29 MSG_WM_ENABLE(OnEnable) | |
| 30 MSG_WM_SETTEXT( OnSetText ) | |
| 31 MESSAGE_HANDLER_EX(WM_PAINT, CheckConditionsTrigger) | |
| 32 MESSAGE_HANDLER_EX(WM_CUT, CheckConditionsTrigger) | |
| 33 MESSAGE_HANDLER_EX(WM_PASTE, CheckConditionsTrigger) | |
| 34 MESSAGE_HANDLER_EX(MSG_CHECKCONDITIONS, OnCheckConditions) | |
| 35 CHAIN_MSG_MAP(CEditPPHooks) | |
| 36 END_MSG_MAP() | |
| 37 | |
| 38 BOOL SubclassWindow( HWND wnd ) { | |
| 39 if (!CEditPPHooks::SubclassWindow(wnd)) return FALSE; | |
| 40 m_initialParent = GetParent(); | |
| 41 this->ModifyStyle(0, WS_CLIPCHILDREN); | |
| 42 RefreshButtons(); | |
| 43 return TRUE; | |
| 44 } | |
| 45 typedef std::function<void () > handler_t; | |
| 46 typedef std::function<bool (const wchar_t*) > condition_t; | |
| 47 | |
| 48 void AddMoreButton( std::function<void ()> f ); | |
| 49 void AddClearButton( const wchar_t * clearVal = L"", bool bHandleEsc = false); | |
| 50 void AddButton( const wchar_t * str, handler_t handler, condition_t condition = nullptr, const wchar_t * drawAlternateText = nullptr ); | |
| 51 | |
| 52 void SetFixedWidth(unsigned fw) { | |
| 53 m_fixedWidth = fw; m_fixedWidthAuto = false; | |
| 54 RefreshButtons(); | |
| 55 } | |
| 56 void SetFixedWidth() { | |
| 57 m_fixedWidth = 0; m_fixedWidthAuto = true; | |
| 58 RefreshButtons(); | |
| 59 } | |
| 60 CRect RectOfButton( const wchar_t * text ); | |
| 61 | |
| 62 void Invalidate() { | |
| 63 __super::Invalidate(); | |
| 64 for( auto & i : m_buttons ) { | |
| 65 if (i.wnd != NULL) i.wnd.Invalidate(); | |
| 66 } | |
| 67 } | |
| 68 void SetShellFolderAutoComplete() { | |
| 69 SetShellAutoComplete(SHACF_FILESYS_DIRS); | |
| 70 } | |
| 71 void SetShellFileAutoComplete() { | |
| 72 SetShellAutoComplete(SHACF_FILESYS_ONLY); | |
| 73 } | |
| 74 void SetShellAutoComplete(DWORD flags) { | |
| 75 SHAutoComplete(*this, flags); | |
| 76 SetHasAutoComplete(); | |
| 77 } | |
| 78 void SetHasAutoComplete(bool bValue = true) { | |
| 79 m_hasAutoComplete = bValue; | |
| 80 } | |
| 81 void RefreshConditions(const wchar_t * newText = nullptr); | |
| 82 private: | |
| 83 int OnCreate(LPCREATESTRUCT lpCreateStruct) { | |
| 84 m_initialParent = GetParent(); | |
| 85 SetMsgHandled(FALSE); | |
| 86 return 0; | |
| 87 } | |
| 88 LRESULT OnCheckConditions( UINT msg, WPARAM wp, LPARAM lp ) { | |
| 89 if ( msg == MSG_CHECKCONDITIONS && wp == MSG_CHECKCONDITIONS_MAGIC1 && lp == MSG_CHECKCONDITIONS_MAGIC2 ) { | |
| 90 this->RefreshConditions(); | |
| 91 } else { | |
| 92 SetMsgHandled(FALSE); | |
| 93 } | |
| 94 return 0; | |
| 95 } | |
| 96 bool HaveConditions() { | |
| 97 for( auto i = m_buttons.begin(); i != m_buttons.end(); ++i ) { | |
| 98 if ( i->condition ) return true; | |
| 99 } | |
| 100 return false; | |
| 101 } | |
| 102 void PostCheckConditions() { | |
| 103 if ( HaveConditions() ) { | |
| 104 PostMessage( MSG_CHECKCONDITIONS, MSG_CHECKCONDITIONS_MAGIC1, MSG_CHECKCONDITIONS_MAGIC2 ); | |
| 105 } | |
| 106 } | |
| 107 LRESULT CheckConditionsTrigger( UINT, WPARAM, LPARAM ) { | |
| 108 PostCheckConditions(); | |
| 109 SetMsgHandled(FALSE); | |
| 110 return 0; | |
| 111 } | |
| 112 int OnSetText(LPCTSTR) { | |
| 113 PostCheckConditions(); | |
| 114 SetMsgHandled(FALSE); | |
| 115 return 0; | |
| 116 } | |
| 117 void OnEnable(BOOL bEnable) { | |
| 118 for( auto & i : m_buttons ) { | |
| 119 if ( i.wnd != NULL ) { | |
| 120 i.wnd.EnableWindow( bEnable ); | |
| 121 } | |
| 122 } | |
| 123 SetMsgHandled(FALSE); | |
| 124 } | |
| 125 void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { | |
| 126 (void)nRepCnt; (void)nFlags; | |
| 127 if (nChar == VK_TAB ) { | |
| 128 return; | |
| 129 } | |
| 130 PostCheckConditions(); | |
| 131 SetMsgHandled(FALSE); | |
| 132 } | |
| 133 void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { | |
| 134 (void)nRepCnt; (void)nFlags; | |
| 135 if ( nChar == VK_TAB ) { | |
| 136 return; | |
| 137 } | |
| 138 SetMsgHandled(FALSE); | |
| 139 } | |
| 140 bool canStealTab() { | |
| 141 if (m_hasAutoComplete) return false; | |
| 142 if (IsShiftPressed()) return false; | |
| 143 if (m_buttons.size() == 0) return false; | |
| 144 return true; | |
| 145 } | |
| 146 UINT OnGetDlgCode(UINT, WPARAM wp, LPARAM) { | |
| 147 if ( wp == VK_TAB && canStealTab() ) { | |
| 148 for (auto i = m_buttons.begin(); i != m_buttons.end(); ++ i ) { | |
| 149 if ( i->visible ) { | |
| 150 TabFocusThis(i->wnd); | |
| 151 return DLGC_WANTTAB; | |
| 152 } | |
| 153 } | |
| 154 } | |
| 155 SetMsgHandled(FALSE); return 0; | |
| 156 } | |
| 157 void OnSetFocus(HWND) { | |
| 158 this->ModifyStyleEx(0, WS_EX_CONTROLPARENT ); SetMsgHandled(FALSE); | |
| 159 } | |
| 160 void OnKillFocus(HWND) { | |
| 161 this->ModifyStyleEx(WS_EX_CONTROLPARENT, 0 ); SetMsgHandled(FALSE); | |
| 162 } | |
| 163 HBRUSH OnColorBtn(CDCHandle dc, CButton) { | |
| 164 if ( (this->GetStyle() & ES_READONLY) != 0 || !this->IsWindowEnabled() ) { | |
| 165 return (HBRUSH) GetParent().SendMessage( WM_CTLCOLORSTATIC, (WPARAM) dc.m_hDC, (LPARAM) m_hWnd ); | |
| 166 } else { | |
| 167 return (HBRUSH) GetParent().SendMessage( WM_CTLCOLOREDIT, (WPARAM) dc.m_hDC, (LPARAM) m_hWnd ); | |
| 168 } | |
| 169 } | |
| 170 void OnPosChanged(LPWINDOWPOS) { | |
| 171 Layout(); SetMsgHandled(FALSE); | |
| 172 } | |
| 173 | |
| 174 struct Button_t { | |
| 175 std::wstring title, titleDraw; | |
| 176 handler_t handler; | |
| 177 CButtonLite wnd; | |
| 178 bool visible; | |
| 179 condition_t condition; | |
| 180 }; | |
| 181 | |
| 182 void OnSetFont(CFontHandle font, BOOL bRedraw); | |
| 183 | |
| 184 void RefreshButtons() { | |
| 185 if ( m_hWnd != NULL && m_buttons.size() > 0 ) { | |
| 186 Layout(); | |
| 187 } | |
| 188 } | |
| 189 void Layout( ) { | |
| 190 CRect rc; | |
| 191 if (GetClientRect(&rc)) { | |
| 192 Layout(rc.Size(), NULL); | |
| 193 } | |
| 194 } | |
| 195 static bool IsShiftPressed() { | |
| 196 return (GetKeyState(VK_SHIFT) & 0x8000) ? true : false; | |
| 197 } | |
| 198 CWindow FindDialog() { | |
| 199 // Return a window that we can send WM_NEXTDLGCTL to | |
| 200 // PROBLEM: There is no clear way of obtaining one - something in our GetParent() hierarchy is usually a dialog, but we don't know which one | |
| 201 // Assume our initial parent window to be the right thing to talk to | |
| 202 PFC_ASSERT(m_initialParent != NULL); | |
| 203 return m_initialParent; | |
| 204 } | |
| 205 void TabFocusThis(HWND wnd) { | |
| 206 FindDialog().PostMessage(WM_NEXTDLGCTL, (WPARAM) wnd, TRUE ); | |
| 207 } | |
| 208 void TabFocusPrevNext(bool bPrev) { | |
| 209 FindDialog().PostMessage(WM_NEXTDLGCTL, bPrev ? TRUE : FALSE, FALSE); | |
| 210 } | |
| 211 void TabCycleButtons(HWND wnd); | |
| 212 | |
| 213 bool ButtonWantTab( HWND wnd ); | |
| 214 bool EvalCondition( Button_t & btn, const wchar_t * newText ); | |
| 215 void Layout(CSize size, CFontHandle fontSetMe); | |
| 216 unsigned MeasureButton(Button_t const & button ); | |
| 217 | |
| 218 unsigned m_fixedWidth = 0; | |
| 219 bool m_fixedWidthAuto = false; | |
| 220 std::list< Button_t > m_buttons; | |
| 221 bool m_hasAutoComplete = false; | |
| 222 CWindow m_initialParent; | |
| 223 }; |
