Mercurial > foo_out_sdl
view 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 |
line wrap: on
line source
#pragma once #include <list> #include <string> #include <functional> #include <memory> #include "wtl-pp.h" #include "CButtonLite.h" class CEditWithButtons : public CEditPPHooks { public: CEditWithButtons(::ATL::CMessageMap * hookMM = nullptr, int hookMMID = 0) : CEditPPHooks(hookMM, hookMMID) {} static constexpr UINT MSG_CHECKCONDITIONS = WM_USER + 13; static constexpr WPARAM MSG_CHECKCONDITIONS_MAGIC1 = 0xaec66f0c; static constexpr LPARAM MSG_CHECKCONDITIONS_MAGIC2 = 0x180c2f35; BEGIN_MSG_MAP_EX(CEditWithButtons) MSG_WM_CREATE(OnCreate) MSG_WM_SETFONT(OnSetFont) MSG_WM_WINDOWPOSCHANGED(OnPosChanged) MSG_WM_CTLCOLORBTN(OnColorBtn) MESSAGE_HANDLER_EX(WM_GETDLGCODE, OnGetDlgCode) MSG_WM_KEYDOWN(OnKeyDown) MSG_WM_CHAR(OnChar) // MSG_WM_SETFOCUS( OnSetFocus ) // MSG_WM_KILLFOCUS( OnKillFocus ) MSG_WM_ENABLE(OnEnable) MSG_WM_SETTEXT( OnSetText ) MESSAGE_HANDLER_EX(WM_PAINT, CheckConditionsTrigger) MESSAGE_HANDLER_EX(WM_CUT, CheckConditionsTrigger) MESSAGE_HANDLER_EX(WM_PASTE, CheckConditionsTrigger) MESSAGE_HANDLER_EX(MSG_CHECKCONDITIONS, OnCheckConditions) CHAIN_MSG_MAP(CEditPPHooks) END_MSG_MAP() BOOL SubclassWindow( HWND wnd ) { if (!CEditPPHooks::SubclassWindow(wnd)) return FALSE; m_initialParent = GetParent(); this->ModifyStyle(0, WS_CLIPCHILDREN); RefreshButtons(); return TRUE; } typedef std::function<void () > handler_t; typedef std::function<bool (const wchar_t*) > condition_t; void AddMoreButton( std::function<void ()> f ); void AddClearButton( const wchar_t * clearVal = L"", bool bHandleEsc = false); void AddButton( const wchar_t * str, handler_t handler, condition_t condition = nullptr, const wchar_t * drawAlternateText = nullptr ); void SetFixedWidth(unsigned fw) { m_fixedWidth = fw; m_fixedWidthAuto = false; RefreshButtons(); } void SetFixedWidth() { m_fixedWidth = 0; m_fixedWidthAuto = true; RefreshButtons(); } CRect RectOfButton( const wchar_t * text ); void Invalidate() { __super::Invalidate(); for( auto & i : m_buttons ) { if (i.wnd != NULL) i.wnd.Invalidate(); } } void SetShellFolderAutoComplete() { SetShellAutoComplete(SHACF_FILESYS_DIRS); } void SetShellFileAutoComplete() { SetShellAutoComplete(SHACF_FILESYS_ONLY); } void SetShellAutoComplete(DWORD flags) { SHAutoComplete(*this, flags); SetHasAutoComplete(); } void SetHasAutoComplete(bool bValue = true) { m_hasAutoComplete = bValue; } void RefreshConditions(const wchar_t * newText = nullptr); private: int OnCreate(LPCREATESTRUCT lpCreateStruct) { m_initialParent = GetParent(); SetMsgHandled(FALSE); return 0; } LRESULT OnCheckConditions( UINT msg, WPARAM wp, LPARAM lp ) { if ( msg == MSG_CHECKCONDITIONS && wp == MSG_CHECKCONDITIONS_MAGIC1 && lp == MSG_CHECKCONDITIONS_MAGIC2 ) { this->RefreshConditions(); } else { SetMsgHandled(FALSE); } return 0; } bool HaveConditions() { for( auto i = m_buttons.begin(); i != m_buttons.end(); ++i ) { if ( i->condition ) return true; } return false; } void PostCheckConditions() { if ( HaveConditions() ) { PostMessage( MSG_CHECKCONDITIONS, MSG_CHECKCONDITIONS_MAGIC1, MSG_CHECKCONDITIONS_MAGIC2 ); } } LRESULT CheckConditionsTrigger( UINT, WPARAM, LPARAM ) { PostCheckConditions(); SetMsgHandled(FALSE); return 0; } int OnSetText(LPCTSTR) { PostCheckConditions(); SetMsgHandled(FALSE); return 0; } void OnEnable(BOOL bEnable) { for( auto & i : m_buttons ) { if ( i.wnd != NULL ) { i.wnd.EnableWindow( bEnable ); } } SetMsgHandled(FALSE); } void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { (void)nRepCnt; (void)nFlags; if (nChar == VK_TAB ) { return; } PostCheckConditions(); SetMsgHandled(FALSE); } void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { (void)nRepCnt; (void)nFlags; if ( nChar == VK_TAB ) { return; } SetMsgHandled(FALSE); } bool canStealTab() { if (m_hasAutoComplete) return false; if (IsShiftPressed()) return false; if (m_buttons.size() == 0) return false; return true; } UINT OnGetDlgCode(UINT, WPARAM wp, LPARAM) { if ( wp == VK_TAB && canStealTab() ) { for (auto i = m_buttons.begin(); i != m_buttons.end(); ++ i ) { if ( i->visible ) { TabFocusThis(i->wnd); return DLGC_WANTTAB; } } } SetMsgHandled(FALSE); return 0; } void OnSetFocus(HWND) { this->ModifyStyleEx(0, WS_EX_CONTROLPARENT ); SetMsgHandled(FALSE); } void OnKillFocus(HWND) { this->ModifyStyleEx(WS_EX_CONTROLPARENT, 0 ); SetMsgHandled(FALSE); } HBRUSH OnColorBtn(CDCHandle dc, CButton) { if ( (this->GetStyle() & ES_READONLY) != 0 || !this->IsWindowEnabled() ) { return (HBRUSH) GetParent().SendMessage( WM_CTLCOLORSTATIC, (WPARAM) dc.m_hDC, (LPARAM) m_hWnd ); } else { return (HBRUSH) GetParent().SendMessage( WM_CTLCOLOREDIT, (WPARAM) dc.m_hDC, (LPARAM) m_hWnd ); } } void OnPosChanged(LPWINDOWPOS) { Layout(); SetMsgHandled(FALSE); } struct Button_t { std::wstring title, titleDraw; handler_t handler; CButtonLite wnd; bool visible; condition_t condition; }; void OnSetFont(CFontHandle font, BOOL bRedraw); void RefreshButtons() { if ( m_hWnd != NULL && m_buttons.size() > 0 ) { Layout(); } } void Layout( ) { CRect rc; if (GetClientRect(&rc)) { Layout(rc.Size(), NULL); } } static bool IsShiftPressed() { return (GetKeyState(VK_SHIFT) & 0x8000) ? true : false; } CWindow FindDialog() { // Return a window that we can send WM_NEXTDLGCTL to // 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 // Assume our initial parent window to be the right thing to talk to PFC_ASSERT(m_initialParent != NULL); return m_initialParent; } void TabFocusThis(HWND wnd) { FindDialog().PostMessage(WM_NEXTDLGCTL, (WPARAM) wnd, TRUE ); } void TabFocusPrevNext(bool bPrev) { FindDialog().PostMessage(WM_NEXTDLGCTL, bPrev ? TRUE : FALSE, FALSE); } void TabCycleButtons(HWND wnd); bool ButtonWantTab( HWND wnd ); bool EvalCondition( Button_t & btn, const wchar_t * newText ); void Layout(CSize size, CFontHandle fontSetMe); unsigned MeasureButton(Button_t const & button ); unsigned m_fixedWidth = 0; bool m_fixedWidthAuto = false; std::list< Button_t > m_buttons; bool m_hasAutoComplete = false; CWindow m_initialParent; };
