From 1fa8e05f32956fac7fa65047b6ca96193105c656 Mon Sep 17 00:00:00 2001 From: Marco Maroni <166719395+marcomaroni-github@users.noreply.github.com> Date: Tue, 14 Jul 2026 15:21:36 +0200 Subject: [PATCH] feat: standalone always-on-top calculator window, reusing input/formatting Co-Authored-By: Claude Opus 4.8 (1M context) --- App.cpp | 10 ++- CalculatorWindow.cpp | 125 ++++++++++++------------------ CalculatorWindow.h | 14 ++-- TaskbarCalculator.vcxproj | 1 + TaskbarCalculator.vcxproj.filters | 1 + 5 files changed, 66 insertions(+), 85 deletions(-) diff --git a/App.cpp b/App.cpp index ad8a661..b3e2309 100644 --- a/App.cpp +++ b/App.cpp @@ -3,6 +3,7 @@ #include #include "TrayIcon.h" #include "StartupManager.h" +#include "CalculatorWindow.h" #include "resource.h" enum { IDM_SHOWHIDE = 1, IDM_STARTUP = 2, IDM_ABOUT = 3, IDM_EXIT = 4 }; @@ -11,11 +12,11 @@ static const UINT TRAY_ICON_ID = 1; UINT g_wmTaskbarCreated = 0; static TrayIcon g_tray; +static CCalculatorWindow* g_calc = nullptr; INT_PTR CALLBACK AboutDialogProc(HWND, UINT, WPARAM, LPARAM); // AboutDialog.cpp -// Placeholder until Task 10 introduces the calculator window. -static void ToggleCalculator() { /* wired in Task 10 */ } +static void ToggleCalculator() { if (g_calc) g_calc->ToggleVisible(); } static LRESULT CALLBACK OwnerWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -87,11 +88,16 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, int) g_tray.Add(owner, WM_TRAY_CALLBACK, TRAY_ICON_ID, L"Taskbar Calculator"); + g_calc = new CCalculatorWindow(); + g_calc->CreateStandalone(); + MSG m; while (GetMessage(&m, nullptr, 0, 0)) { TranslateMessage(&m); DispatchMessage(&m); } + delete g_calc; + g_calc = nullptr; if (mutex) { ReleaseMutex(mutex); CloseHandle(mutex); } return (int)m.wParam; } diff --git a/CalculatorWindow.cpp b/CalculatorWindow.cpp index 427fa7f..c323d86 100644 --- a/CalculatorWindow.cpp +++ b/CalculatorWindow.cpp @@ -105,7 +105,6 @@ private: //////////////////////////////////////////////////////////////////////////////// // CCalculatorWindow CCalculatorWindow::CCalculatorWindow() : - m_pDeskBand(NULL), m_fHasFocus(FALSE), m_ptrVisualStyle(CVisualStyle::Create()), m_calc() @@ -127,46 +126,42 @@ CCalculatorWindow::~CCalculatorWindow() //////////////////////////////////////////////////////////////////////////////// // -BOOL CCalculatorWindow::Create( - HWND hwndParent, - LPUNKNOWN pDeskBand, - LPUNKNOWN pInputObjectSite) +BOOL CCalculatorWindow::CreateStandalone() { - if(!__super::Create(hwndParent)) - return FALSE; - - ATLASSERT(pDeskBand); - m_pDeskBand = pDeskBand; - - ATLASSERT(pInputObjectSite); - m_spInputObjectSite = pInputObjectSite; - - m_hwndEdit = CreateWindowEx( - WS_EX_CLIENTEDGE, - TEXT("EDIT"), - TEXT("0"), - WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | ES_RIGHT | ES_NUMBER, - 0, - 0, - 0, - 0, - m_hWnd, - NULL, - _AtlBaseModule.GetModuleInstance(), - 0); - - SetWindowFont(m_hwndEdit, m_ptrVisualStyle->GetFont(), TRUE); - - wpOrigEditProc = (WNDPROC)::SetWindowLongPtr(m_hwndEdit, GWLP_WNDPROC, (LONG_PTR)WndEditProc); - if (wpOrigEditProc == 0) - return FALSE; - - ::SetWindowLongPtr(m_hwndEdit, GWLP_USERDATA, (LONG_PTR)this); - - + RECT rc = { 0, 0, 220, 48 }; + // Top-level popup, always-on-top, tool window (no taskbar/Alt-Tab button). + HWND hwnd = __super::Create(NULL, rc, L"Taskbar Calculator", + WS_POPUP | WS_CAPTION | WS_SYSMENU, + WS_EX_TOPMOST | WS_EX_TOOLWINDOW); + if (!hwnd) return FALSE; + + m_hwndEdit = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT("0"), + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | ES_RIGHT | ES_NUMBER, + 0, 0, 0, 0, m_hWnd, NULL, _AtlBaseModule.GetModuleInstance(), 0); + + SetWindowFont(m_hwndEdit, m_ptrVisualStyle->GetFont(), TRUE); + wpOrigEditProc = (WNDPROC)::SetWindowLongPtr(m_hwndEdit, GWLP_WNDPROC, (LONG_PTR)WndEditProc); + if (wpOrigEditProc == 0) return FALSE; + ::SetWindowLongPtr(m_hwndEdit, GWLP_USERDATA, (LONG_PTR)this); + + POINTL ideal = CalcIdealSize(); + SetWindowPos(NULL, 0, 0, ideal.x + 24, ideal.y + 16, SWP_NOMOVE | SWP_NOZORDER); return TRUE; } +void CCalculatorWindow::ToggleVisible() +{ + if (m_shown) { + ShowWindow(SW_HIDE); + m_shown = false; + } else { + SetWindowPos(HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); + SetForegroundWindow(m_hWnd); + ::SetFocus(m_hwndEdit); + m_shown = true; + } +} + POINTL CCalculatorWindow::CalcMinimalSize() const { POINTL pt = { @@ -219,9 +214,6 @@ LRESULT CCalculatorWindow::OnFocus( { m_fHasFocus = (uMsg == WM_SETFOCUS); - if(m_spInputObjectSite) - m_spInputObjectSite->OnFocusChangeIS(m_pDeskBand, m_fHasFocus); - if ( m_fHasFocus ) ReadRegionalSettings(); @@ -319,6 +311,22 @@ LRESULT CCalculatorWindow::OnThemeChanged( return 0; } +LRESULT CCalculatorWindow::OnClose(UINT, WPARAM, LPARAM, BOOL&) +{ + // Hide to tray instead of destroying. + ShowWindow(SW_HIDE); + m_shown = false; + return 0; +} + +LRESULT CCalculatorWindow::OnLButtonDown(UINT, WPARAM, LPARAM, BOOL&) +{ + // Allow dragging the window by its body. + ReleaseCapture(); + SendMessage(WM_NCLBUTTONDOWN, HTCAPTION, 0); + return 0; +} + void CCalculatorWindow::Paint(HDC hdc, const RECT& rcPaint) const { m_ptrVisualStyle->DrawBackground(m_hWnd, hdc, rcPaint); @@ -444,16 +452,7 @@ LRESULT CCalculatorWindow::OnEditChar(HWND hWnd, WPARAM wParam, LPARAM /*lParam* case CALC_000: case CALC_NEG: case CALC_PERC: - case CALC_EURO: - case CALC_L: - case CALC_X: case CALC_I: - case CALC_A: - case CALC_B: - case CALC_C: - case CALC_D: - case CALC_E: - case CALC_F: c = (TCHAR)wParam; break; case 'z': @@ -471,33 +470,6 @@ LRESULT CCalculatorWindow::OnEditChar(HWND hWnd, WPARAM wParam, LPARAM /*lParam* case 'p': c = CALC_NEG; break; - case 'r': - c = CALC_EURO; - break; - case 'l': - c = CALC_L; - break; - case 'x': - c = CALC_X; - break; - case 'a': - c = CALC_A; - break; - case 'b': - c = CALC_B; - break; - case 'c': - c = CALC_C; - break; - case 'd': - c = CALC_D; - break; - case 'e': - c = CALC_E; - break; - case 'f': - c = CALC_F; - break; default: bChangeState = false; } @@ -540,7 +512,6 @@ bool CCalculatorWindow::FormatString(LPCTSTR strInput, LPTSTR strOutput) { _tcscpy_s(strOutput, 1024, strInput); - if (m_calc.get_current_base() == calc::decimal) { LPTSTR cDecSep = _tcschr(strOutput, CALC_P); if (cDecSep != NULL) diff --git a/CalculatorWindow.h b/CalculatorWindow.h index d3f4e20..20acd7a 100644 --- a/CalculatorWindow.h +++ b/CalculatorWindow.h @@ -13,10 +13,9 @@ public: CCalculatorWindow(); ~CCalculatorWindow(); - BOOL Create( - HWND hwndParent, - LPUNKNOWN pDeskBand, - LPUNKNOWN pInputObjectSite); + BOOL CreateStandalone(); + void ToggleVisible(); + bool IsShown() const { return m_shown; } POINTL CalcMinimalSize() const; POINTL CalcIdealSize() const; @@ -39,6 +38,8 @@ BEGIN_MSG_MAP(CCalculatorWindow) MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus) MESSAGE_HANDLER(WM_POWERBROADCAST, OnPowerBroadcast) MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged) + MESSAGE_HANDLER(WM_CLOSE, OnClose) + MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) END_MSG_MAP() // Handler prototypes: @@ -53,6 +54,8 @@ private: LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnPowerBroadcast(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); void Paint(HDC hdc, const RECT& rcPaint) const; // UINT_PTR SetUpdateTimer(); @@ -68,9 +71,8 @@ private: private: - IUnknown* m_pDeskBand; BOOL m_fHasFocus; - CComQIPtr m_spInputObjectSite; + bool m_shown = false; CAutoPtr m_ptrVisualStyle; //const DateFormat* m_pDateFormat; diff --git a/TaskbarCalculator.vcxproj b/TaskbarCalculator.vcxproj index 3eef5bd..714472d 100644 --- a/TaskbarCalculator.vcxproj +++ b/TaskbarCalculator.vcxproj @@ -99,6 +99,7 @@ NotUsing + diff --git a/TaskbarCalculator.vcxproj.filters b/TaskbarCalculator.vcxproj.filters index 9e2e338..b7f11cf 100644 --- a/TaskbarCalculator.vcxproj.filters +++ b/TaskbarCalculator.vcxproj.filters @@ -19,6 +19,7 @@ Source Files Source Files Source Files + Source Files Source Files Source Files Source Files -- 2.51.2