|
1
|
1 #include "stdafx.h"
|
|
|
2 #include "CEditWithButtons.h"
|
|
|
3
|
|
|
4
|
|
|
5 void CEditWithButtons::AddMoreButton(std::function<void()> f) {
|
|
|
6 AddButton(L"more", f, nullptr, L"\x2026");
|
|
|
7 }
|
|
|
8 void CEditWithButtons::AddClearButton(const wchar_t * clearVal, bool bHandleEsc) {
|
|
|
9 std::wstring clearValCopy(clearVal);
|
|
|
10 auto handler = [this, clearValCopy] {
|
|
|
11 this->SetWindowText(clearValCopy.c_str());
|
|
|
12 };
|
|
|
13 auto condition = [clearValCopy](const wchar_t * txt) -> bool {
|
|
|
14 return clearValCopy != txt;
|
|
|
15 };
|
|
|
16 // Present "clear" to accessibility APIs but actually draw a multiplication x sign
|
|
|
17 AddButton(L"clear", handler, condition, L"\x00D7");
|
|
|
18
|
|
|
19 if (bHandleEsc) {
|
|
|
20 this->onEscKey = handler;
|
|
|
21 }
|
|
|
22
|
|
|
23 }
|
|
|
24
|
|
|
25 void CEditWithButtons::AddButton(const wchar_t * str, handler_t handler, condition_t condition, const wchar_t * drawAlternateText) {
|
|
|
26 PFC_ASSERT(GetStyle() & WS_CLIPCHILDREN);
|
|
|
27 Button_t btn;
|
|
|
28 btn.handler = handler;
|
|
|
29 btn.title = str;
|
|
|
30 btn.condition = condition;
|
|
|
31 btn.visible = EvalCondition(btn, nullptr);
|
|
|
32
|
|
|
33 if (drawAlternateText != nullptr) {
|
|
|
34 btn.titleDraw = drawAlternateText;
|
|
|
35 }
|
|
|
36
|
|
|
37 m_buttons.push_back(std::move(btn));
|
|
|
38 RefreshButtons();
|
|
|
39 }
|
|
|
40
|
|
|
41 CRect CEditWithButtons::RectOfButton(const wchar_t * text) {
|
|
|
42 for (auto i = m_buttons.begin(); i != m_buttons.end(); ++i) {
|
|
|
43 if (i->title == text && i->wnd != NULL) {
|
|
|
44 CRect rc;
|
|
|
45 if (i->wnd.GetWindowRect(rc)) return rc;
|
|
|
46 }
|
|
|
47 }
|
|
|
48 return CRect();
|
|
|
49 }
|
|
|
50
|
|
|
51 void CEditWithButtons::TabCycleButtons(HWND wnd) {
|
|
|
52 for (auto i = m_buttons.begin(); i != m_buttons.end(); ++i) {
|
|
|
53 if (i->wnd == wnd) {
|
|
|
54 if (IsShiftPressed()) {
|
|
|
55 // back
|
|
|
56 for (;; ) {
|
|
|
57 if (i == m_buttons.begin()) {
|
|
|
58 TabFocusThis(m_hWnd); break;
|
|
|
59 } else {
|
|
|
60 --i;
|
|
|
61 if (i->visible) {
|
|
|
62 TabFocusThis(i->wnd);
|
|
|
63 break;
|
|
|
64 }
|
|
|
65 }
|
|
|
66 }
|
|
|
67 } else {
|
|
|
68 // forward
|
|
|
69 for (;; ) {
|
|
|
70 ++i;
|
|
|
71 if (i == m_buttons.end()) {
|
|
|
72 TabFocusThis(m_hWnd);
|
|
|
73 TabFocusPrevNext(false);
|
|
|
74 break;
|
|
|
75 } else {
|
|
|
76 if (i->visible) {
|
|
|
77 TabFocusThis(i->wnd);
|
|
|
78 break;
|
|
|
79 }
|
|
|
80 }
|
|
|
81 }
|
|
|
82 }
|
|
|
83
|
|
|
84 return;
|
|
|
85 }
|
|
|
86 }
|
|
|
87 }
|
|
|
88
|
|
|
89
|
|
|
90 bool CEditWithButtons::ButtonWantTab(HWND wnd) {
|
|
|
91 if (IsShiftPressed()) return true;
|
|
|
92 if (m_buttons.size() == 0) return false; // should not be possible
|
|
|
93 auto last = m_buttons.rbegin();
|
|
|
94 if (wnd == last->wnd) return false; // not for last button
|
|
|
95 return true;
|
|
|
96 }
|
|
|
97 bool CEditWithButtons::EvalCondition(Button_t & btn, const wchar_t * newText) {
|
|
|
98 if (!btn.condition) return true;
|
|
|
99 if (newText != nullptr) return btn.condition(newText);
|
|
|
100 TCHAR text[256] = {};
|
|
|
101 GetWindowText(text, 256);
|
|
|
102 text[255] = 0;
|
|
|
103 return btn.condition(text);
|
|
|
104 }
|
|
|
105 void CEditWithButtons::RefreshConditions(const wchar_t * newText) {
|
|
|
106 bool changed = false;
|
|
|
107 for (auto i = m_buttons.begin(); i != m_buttons.end(); ++i) {
|
|
|
108 bool status = EvalCondition(*i, newText);
|
|
|
109 if (status != i->visible) {
|
|
|
110 i->visible = status; changed = true;
|
|
|
111 }
|
|
|
112 }
|
|
|
113 if (changed) {
|
|
|
114 Layout();
|
|
|
115 }
|
|
|
116 }
|
|
|
117
|
|
|
118 void CEditWithButtons::Layout(CSize size, CFontHandle fontSetMe) {
|
|
|
119 if (m_buttons.size() == 0) return;
|
|
|
120
|
|
|
121 int walk = size.cx;
|
|
|
122
|
|
|
123 HDWP dwp = BeginDeferWindowPos((int)m_buttons.size());
|
|
|
124 for (auto iter = m_buttons.rbegin(); iter != m_buttons.rend(); ++iter) {
|
|
|
125 if (!iter->visible) {
|
|
|
126 if (::GetFocus() == iter->wnd) {
|
|
|
127 this->SetFocus();
|
|
|
128 }
|
|
|
129 ::DeferWindowPos(dwp, iter->wnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOCOPYBITS);
|
|
|
130 continue;
|
|
|
131 }
|
|
|
132
|
|
|
133 if (iter->wnd == NULL) {
|
|
|
134 auto* b = &iter->wnd;
|
|
|
135 b->Create(*this, NULL, iter->title.c_str());
|
|
|
136 if (iter->titleDraw.length() > 0) b->DrawAlternateText(iter->titleDraw.c_str());
|
|
|
137 CFontHandle font = fontSetMe;
|
|
|
138 if (font == NULL) font = GetFont();
|
|
|
139 b->SetFont(font);
|
|
|
140 b->ClickHandler = iter->handler;
|
|
|
141 b->CtlColorHandler = [=](CDCHandle dc) -> HBRUSH {
|
|
|
142 return this->OnColorBtn(dc, NULL);
|
|
|
143 };
|
|
|
144 b->TabCycleHandler = [=](HWND wnd) {
|
|
|
145 TabCycleButtons(wnd);
|
|
|
146 };
|
|
|
147 b->WantTabCheck = [=](HWND wnd) -> bool {
|
|
|
148 return ButtonWantTab(wnd);
|
|
|
149 };
|
|
|
150 if (!IsWindowEnabled()) b->EnableWindow(FALSE);
|
|
|
151 } else if (fontSetMe) {
|
|
|
152 iter->wnd.SetFont(fontSetMe);
|
|
|
153 }
|
|
|
154
|
|
|
155 unsigned delta = MeasureButton(*iter);
|
|
|
156 int left = walk - delta;
|
|
|
157
|
|
|
158 if (iter->wnd != NULL) {
|
|
|
159 CRect rc;
|
|
|
160 rc.top = 0;
|
|
|
161 rc.bottom = size.cy;
|
|
|
162 rc.left = left;
|
|
|
163 rc.right = walk;
|
|
|
164 ::DeferWindowPos(dwp, iter->wnd, NULL, rc.left, rc.top, rc.Width(), rc.Height(), SWP_NOZORDER | SWP_SHOWWINDOW | SWP_NOCOPYBITS);
|
|
|
165 }
|
|
|
166
|
|
|
167 walk = left;
|
|
|
168 }
|
|
|
169 EndDeferWindowPos(dwp);
|
|
|
170 this->SetMargins(0, size.cx - walk, EC_RIGHTMARGIN);
|
|
|
171 }
|
|
|
172
|
|
|
173 unsigned CEditWithButtons::MeasureButton(Button_t const & button) {
|
|
|
174 if (m_fixedWidthAuto && m_fixedWidth == 0) {
|
|
|
175 CWindowDC dc(*this);
|
|
|
176 SelectObjectScope fontScope(dc, GetFont());
|
|
|
177 SIZE sz = {};
|
|
|
178 WIN32_OP_D( dc.GetTextExtent(L"#", 1, &sz) );
|
|
|
179 m_fixedWidth = MulDiv(sz.cx, 3, 2);
|
|
|
180 }
|
|
|
181 if (m_fixedWidth != 0) return m_fixedWidth;
|
|
|
182
|
|
|
183 return button.wnd.Measure();
|
|
|
184 }
|
|
|
185
|
|
|
186 void CEditWithButtons::OnSetFont(CFontHandle font, BOOL bRedraw) {
|
|
|
187 (void)bRedraw;
|
|
|
188
|
|
|
189 if ( m_fixedWidthAuto ) m_fixedWidth = 0; // require re-calculation
|
|
|
190
|
|
|
191 DefWindowProc();
|
|
|
192 CRect rc;
|
|
|
193 if (GetClientRect(&rc)) {
|
|
|
194 Layout(rc.Size(), font);
|
|
|
195 }
|
|
|
196 }
|