diff foosdk/sdk/libPPUI/CEditWithButtons.cpp @ 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/CEditWithButtons.cpp	Mon Jan 05 02:15:46 2026 -0500
@@ -0,0 +1,196 @@
+#include "stdafx.h"
+#include "CEditWithButtons.h"
+
+
+void CEditWithButtons::AddMoreButton(std::function<void()> f) {
+	AddButton(L"more", f, nullptr, L"\x2026");
+}
+void CEditWithButtons::AddClearButton(const wchar_t * clearVal, bool bHandleEsc) {
+	std::wstring clearValCopy(clearVal);
+	auto handler = [this, clearValCopy] {
+		this->SetWindowText(clearValCopy.c_str());
+	};
+	auto condition = [clearValCopy](const wchar_t * txt) -> bool {
+		return clearValCopy != txt;
+	};
+	// Present "clear" to accessibility APIs but actually draw a multiplication x sign
+	AddButton(L"clear", handler, condition, L"\x00D7");
+
+	if (bHandleEsc) {
+		this->onEscKey = handler;
+	}
+	
+}
+
+void CEditWithButtons::AddButton(const wchar_t * str, handler_t handler, condition_t condition, const wchar_t * drawAlternateText) {
+	PFC_ASSERT(GetStyle() & WS_CLIPCHILDREN);
+	Button_t btn;
+	btn.handler = handler;
+	btn.title = str;
+	btn.condition = condition;
+	btn.visible = EvalCondition(btn, nullptr);
+
+	if (drawAlternateText != nullptr) {
+		btn.titleDraw = drawAlternateText;
+	}
+
+	m_buttons.push_back(std::move(btn));
+	RefreshButtons();
+}
+
+CRect CEditWithButtons::RectOfButton(const wchar_t * text) {
+	for (auto i = m_buttons.begin(); i != m_buttons.end(); ++i) {
+		if (i->title == text && i->wnd != NULL) {
+			CRect rc;
+			if (i->wnd.GetWindowRect(rc)) return rc;
+		}
+	}
+	return CRect();
+}
+
+void CEditWithButtons::TabCycleButtons(HWND wnd) {
+	for (auto i = m_buttons.begin(); i != m_buttons.end(); ++i) {
+		if (i->wnd == wnd) {
+			if (IsShiftPressed()) {
+				// back
+				for (;; ) {
+					if (i == m_buttons.begin()) {
+						TabFocusThis(m_hWnd); break;
+					} else {
+						--i;
+						if (i->visible) {
+							TabFocusThis(i->wnd);
+							break;
+						}
+					}
+				}
+			} else {
+				// forward
+				for (;; ) {
+					++i;
+					if (i == m_buttons.end()) {
+						TabFocusThis(m_hWnd);
+						TabFocusPrevNext(false);
+						break;
+					} else {
+						if (i->visible) {
+							TabFocusThis(i->wnd);
+							break;
+						}
+					}
+				}
+			}
+
+			return;
+		}
+	}
+}
+
+
+bool CEditWithButtons::ButtonWantTab(HWND wnd) {
+	if (IsShiftPressed()) return true;
+	if (m_buttons.size() == 0) return false; // should not be possible
+	auto last = m_buttons.rbegin();
+	if (wnd == last->wnd) return false; // not for last button
+	return true;
+}
+bool CEditWithButtons::EvalCondition(Button_t & btn, const wchar_t * newText) {
+	if (!btn.condition) return true;
+	if (newText != nullptr) return btn.condition(newText);
+	TCHAR text[256] = {};
+	GetWindowText(text, 256);
+	text[255] = 0;
+	return btn.condition(text);
+}
+void CEditWithButtons::RefreshConditions(const wchar_t * newText) {
+	bool changed = false;
+	for (auto i = m_buttons.begin(); i != m_buttons.end(); ++i) {
+		bool status = EvalCondition(*i, newText);
+		if (status != i->visible) {
+			i->visible = status; changed = true;
+		}
+	}
+	if (changed) {
+		Layout();
+	}
+}
+
+void CEditWithButtons::Layout(CSize size, CFontHandle fontSetMe) {
+	if (m_buttons.size() == 0) return;
+
+	int walk = size.cx;
+
+	HDWP dwp = BeginDeferWindowPos((int)m_buttons.size());
+	for (auto iter = m_buttons.rbegin(); iter != m_buttons.rend(); ++iter) {
+		if (!iter->visible) {
+			if (::GetFocus() == iter->wnd) {
+				this->SetFocus();
+			}
+			::DeferWindowPos(dwp, iter->wnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOCOPYBITS);
+			continue;
+		}
+
+		if (iter->wnd == NULL) {
+			auto* b = &iter->wnd;
+			b->Create(*this, NULL, iter->title.c_str());
+			if (iter->titleDraw.length() > 0) b->DrawAlternateText(iter->titleDraw.c_str());
+			CFontHandle font = fontSetMe;
+			if (font == NULL) font = GetFont();
+			b->SetFont(font);
+			b->ClickHandler = iter->handler;
+			b->CtlColorHandler = [=](CDCHandle dc) -> HBRUSH {
+				return this->OnColorBtn(dc, NULL);
+			};
+			b->TabCycleHandler = [=](HWND wnd) {
+				TabCycleButtons(wnd);
+			};
+			b->WantTabCheck = [=](HWND wnd) -> bool {
+				return ButtonWantTab(wnd);
+			};
+			if (!IsWindowEnabled()) b->EnableWindow(FALSE);
+		} else if (fontSetMe) {
+			iter->wnd.SetFont(fontSetMe);
+		}
+
+		unsigned delta = MeasureButton(*iter);
+		int left = walk - delta;
+
+		if (iter->wnd != NULL) {
+			CRect rc;
+			rc.top = 0;
+			rc.bottom = size.cy;
+			rc.left = left;
+			rc.right = walk;
+			::DeferWindowPos(dwp, iter->wnd, NULL, rc.left, rc.top, rc.Width(), rc.Height(), SWP_NOZORDER | SWP_SHOWWINDOW | SWP_NOCOPYBITS);
+		}
+
+		walk = left;
+	}
+	EndDeferWindowPos(dwp);
+	this->SetMargins(0, size.cx - walk, EC_RIGHTMARGIN);
+}
+
+unsigned CEditWithButtons::MeasureButton(Button_t const & button) {
+	if (m_fixedWidthAuto && m_fixedWidth == 0) {
+		CWindowDC dc(*this);
+		SelectObjectScope fontScope(dc, GetFont());
+		SIZE sz = {};
+		WIN32_OP_D( dc.GetTextExtent(L"#", 1, &sz) );
+		m_fixedWidth = MulDiv(sz.cx, 3, 2);
+	}
+	if (m_fixedWidth != 0) return m_fixedWidth;
+
+	return button.wnd.Measure();
+}
+
+void CEditWithButtons::OnSetFont(CFontHandle font, BOOL bRedraw) {
+	(void)bRedraw;
+
+	if ( m_fixedWidthAuto ) m_fixedWidth = 0; // require re-calculation
+
+	DefWindowProc();
+	CRect rc;
+	if (GetClientRect(&rc)) {
+		Layout(rc.Size(), font);
+	}
+}