Something went wrong. Try again.
A simple, small calculator placed discreetly near the Windows Taskbar or anywhere on the screen taskbar-calculator.marcomaroni.it
Something went wrong. Try again.
taskbar-calculator CalculatorWindow.cpp
22 kB · 876 lines
C++
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877#include "StdAfx.h"#include "CalculatorWindow.h"//#include "DateFormat.h"#include "VisualStyle.h"#include "Utils.h"#include "Calculator.h"#include "Settings.h"
////////////////////////////////////////////////////////////////////////////////// const UINT_PTR UPDATE_TIMER_ID = 1;
WNDPROC wpOrigEditProc;LRESULT CALLBACK WndEditProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
////////////////////////////////////////////////////////////////////////////////// class SelectGdiObject{public: SelectGdiObject(HDC hDC, HGDIOBJ hGdiObj) : m_hDC(hDC), m_hGdiObj(hGdiObj), m_hSaveGdiObj(::SelectObject(hDC, hGdiObj)) { ATLASSERT(m_hSaveGdiObj && m_hSaveGdiObj != HGDI_ERROR); }
~SelectGdiObject() { if(m_hSaveGdiObj && m_hSaveGdiObj != HGDI_ERROR) ::SelectObject(m_hDC, m_hSaveGdiObj); }
operator HGDIOBJ() const { return m_hGdiObj; }
private: HDC m_hDC; HGDIOBJ m_hGdiObj; HGDIOBJ m_hSaveGdiObj;
private: // not copyable SelectGdiObject(const SelectGdiObject&); SelectGdiObject& operator=(const SelectGdiObject&);};
class DoubleBufferPaint{public: DoubleBufferPaint(HWND hWnd, DWORD dwRop = SRCCOPY) : m_hWnd(hWnd), m_dwRop(dwRop) { m_hdc = ::BeginPaint(m_hWnd, &m_ps);
int x, y, cx, cy; InitDims(&x, &y, &cx, &cy);
m_hdcMem = ::CreateCompatibleDC(m_hdc); m_hbmMem = ::CreateCompatibleBitmap(m_hdc, cx, cy); m_hbmSave = ::SelectObject(m_hdcMem, m_hbmMem); ::SetWindowOrgEx(m_hdcMem, x, y, NULL); }
~DoubleBufferPaint() { int x, y, cx, cy; InitDims(&x, &y, &cx, &cy);
::BitBlt(m_hdc, x, y, cx, cy, m_hdcMem, x, y, m_dwRop);
::SelectObject(m_hdcMem, m_hbmSave); ::DeleteObject(m_hbmMem); ::DeleteDC(m_hdcMem);
::EndPaint(m_hWnd, &m_ps); }
HDC GetDC() const { return m_hdcMem; } const RECT& GetPaintRect() const { return m_ps.rcPaint; }
private: void InitDims(int* px, int* py, int* pcx, int* pcy) const { *px = m_ps.rcPaint.left; *py = m_ps.rcPaint.top; *pcx = m_ps.rcPaint.right - m_ps.rcPaint.left; *pcy = m_ps.rcPaint.bottom - m_ps.rcPaint.top; }
private: HWND m_hWnd; DWORD m_dwRop;
HDC m_hdc; HDC m_hdcMem; HGDIOBJ m_hbmMem; HGDIOBJ m_hbmSave; PAINTSTRUCT m_ps;
private: // not copyable DoubleBufferPaint(const DoubleBufferPaint&); DoubleBufferPaint& operator=(const DoubleBufferPaint&);};
////////////////////////////////////////////////////////////////////////////////// CCalculatorWindowCCalculatorWindow::CCalculatorWindow() : m_fHasFocus(FALSE), m_ptrVisualStyle(CVisualStyle::Create()), m_calc(){// ::GetLocalTime(&m_stLocalTime);
// m_unformatInputString[0] = '\0';// m_unformatOutputString[0] = '\0';
m_numDecimalDigit = 2;
ReadRegionalSettings();}
CCalculatorWindow::~CCalculatorWindow(){}
//////////////////////////////////////////////////////////////////////////////////
BOOL CCalculatorWindow::CreateStandalone(){ RECT rc = { 0, 0, 220, 48 }; // Top-level popup, always-on-top, tool window (no taskbar/Alt-Tab button). // Created with the full "active" frame (caption + sizing border) so the // window is resizable from the first show; ApplyFrameStyle strips it back // to a clean look when the window is inactive. m_captionVisible (true) // matches this initial style. HWND hwnd = __super::Create(NULL, rc, L"Taskbar Calculator", WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME, 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, 0, 0, 0, 0, m_hWnd, NULL, _AtlBaseModule.GetModuleInstance(), 0);
wpOrigEditProc = (WNDPROC)::SetWindowLongPtr(m_hwndEdit, GWLP_WNDPROC, (LONG_PTR)WndEditProc); if (wpOrigEditProc == 0) return FALSE; ::SetWindowLongPtr(m_hwndEdit, GWLP_USERDATA, (LONG_PTR)this);
// Build the font and size the window for this window's DPI. RebuildForDpi(::GetDpiForWindow(m_hWnd));
PlaceInitial(); return TRUE;}
void CCalculatorWindow::RebuildForDpi(UINT dpi){ m_dpi = dpi;
// Rebuild the themed font/colors for this DPI. m_ptrVisualStyle.Free(); m_ptrVisualStyle.Attach(CVisualStyle::Create(CVisualStyle::Auto, dpi));
if (::IsWindow(m_hwndEdit)) SetWindowFont(m_hwndEdit, m_ptrVisualStyle->GetFont(), TRUE);
// Size the CLIENT area from the (now DPI-scaled) font, scaling the fixed // paddings/minimums by the same DPI, then adjust for the current frame. POINTL ideal = CalcIdealSize();
// Width: a saved custom width (normalized to 96 DPI) scaled to this DPI, // otherwise the default auto-fit width. Never below the 5-digit minimum. const LONG minClientW = MinClientWidth(dpi); LONG clientW; DWORD w96; if (Settings::LoadWindowWidth(w96)) clientW = ::MulDiv((LONG)w96, (int)dpi, 96); else clientW = ideal.x + ::MulDiv(24, (int)dpi, 96); if (clientW < minClientW) clientW = minClientW;
LONG clientH = ideal.y + ::MulDiv(8, (int)dpi, 96); LONG minH = ::MulDiv(28, (int)dpi, 96); if (clientH < minH) clientH = minH;
RECT r = { 0, 0, clientW, clientH }; ::AdjustWindowRectExForDpi(&r, (DWORD)GetWindowLongPtr(GWL_STYLE), FALSE, (DWORD)GetWindowLongPtr(GWL_EXSTYLE), dpi); SetWindowPos(NULL, 0, 0, r.right - r.left, r.bottom - r.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);}
void CCalculatorWindow::PlaceInitial(){ RECT wr; GetWindowRect(&wr); int w = wr.right - wr.left, h = wr.bottom - wr.top;
POINT pt; if (Settings::LoadWindowPos(pt)) { // Saved point is canonical (client origin). Convert to the window // origin for the style currently in effect. RECT r = { pt.x, pt.y, pt.x + 1, pt.y + 1 }; AdjustWindowRectEx(&r, (DWORD)GetWindowLongPtr(GWL_STYLE), FALSE, (DWORD)GetWindowLongPtr(GWL_EXSTYLE)); // Only restore the saved position if it still lands on a connected // monitor. Otherwise (e.g. the window was left on an external display // that is no longer attached) the point is off-screen and the window // would be invisible; fall through to first-run anchoring instead. RECT full = { r.left, r.top, r.left + w, r.top + h }; if (::MonitorFromRect(&full, MONITOR_DEFAULTTONULL) != NULL) { SetWindowPos(NULL, r.left, r.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER); ClampToWorkArea(); // pull it out of the taskbar if the saved pos overlapped return; } } // First run: anchor bottom-right, just above the notification area. APPBARDATA abd{}; abd.cbSize = sizeof(abd); RECT work; SystemParametersInfo(SPI_GETWORKAREA, 0, &work, 0); int x = work.right - w - 8; int y = work.bottom - h - 8; if (SHAppBarMessage(ABM_GETTASKBARPOS, &abd)) { if (abd.rc.top > work.top) y = abd.rc.top - h - 8; } SetWindowPos(NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);}
void CCalculatorWindow::ClampToWorkArea(){ RECT wr; GetWindowRect(&wr); const int w = wr.right - wr.left; const int h = wr.bottom - wr.top;
MONITORINFO mi = { sizeof(mi) }; if (!::GetMonitorInfo(::MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST), &mi)) return; const RECT& work = mi.rcWork;
// Keep the whole window inside the work area (which excludes the taskbar). // Push in from the right/bottom first, then clamp to the top/left so a // window larger than the work area still anchors at its top-left corner. int x = wr.left, y = wr.top; if (x + w > work.right) x = work.right - w; if (y + h > work.bottom) y = work.bottom - h; if (x < work.left) x = work.left; if (y < work.top) y = work.top;
if (x != wr.left || y != wr.top) SetWindowPos(NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);}
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; } Settings::SaveVisible(m_shown);}
POINTL CCalculatorWindow::CalcMinimalSize() const{ POINTL pt = { ::GetSystemMetrics(SM_CXMIN), ::GetSystemMetrics(SM_CYMIN) };
return pt;}
SIZE CCalculatorWindow::MeasureString(LPCTSTR text) const{ SIZE size = { 0 }; HDC hic = ::CreateIC(_T("DISPLAY"), NULL, NULL, NULL); { SelectGdiObject gdiFont(hic, m_ptrVisualStyle->GetFont()); const BOOL bRes = ::GetTextExtentPoint32(hic, text, (int)_tcslen(text), &size); ATLASSERT(bRes); } ::DeleteDC(hic); return size;}
POINTL CCalculatorWindow::CalcIdealSize() const{ if(!IsWindow()) return CalcMinimalSize();
const SIZE size = MeasureString(TEXT("99.999,99")); const POINTL pt = { size.cx, size.cy }; return pt;}
LONG CCalculatorWindow::MinClientWidth(UINT dpi) const{ // Worst-case 5 digits: sign + thousands separator + five digits. const SIZE size = MeasureString(TEXT("-99.999")); return size.cx + ::MulDiv(24, (int)dpi, 96);}
BOOL CCalculatorWindow::HasFocus() const{ return m_fHasFocus;}
////////////////////////////////////////////////////////////////////////////////// Message handlers
LRESULT CCalculatorWindow::OnFocus( UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/){ m_fHasFocus = (uMsg == WM_SETFOCUS);
if ( m_fHasFocus ) ReadRegionalSettings();
return 0L;}
LRESULT CCalculatorWindow::OnDestroy( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/){ KillTimer(UPDATE_TIMER_ID);
if(::IsWindow(m_hwndEdit)) { ::SetWindowLongPtr(m_hwndEdit, GWLP_WNDPROC, (LONG_PTR)wpOrigEditProc); ::DestroyWindow(m_hwndEdit); }
return 0;}
LRESULT CCalculatorWindow::OnEraseBackground( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/){ return 1;}
LRESULT CCalculatorWindow::OnPaint( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/){ DoubleBufferPaint dbuffPaint(m_hWnd); //Paint(dbuffPaint.GetDC(), dbuffPaint.GetPaintRect()); m_ptrVisualStyle->DrawBackground(m_hWnd, dbuffPaint.GetDC(), dbuffPaint.GetPaintRect());
::SetBkMode(dbuffPaint.GetDC(), TRANSPARENT);
RECT rc; GetClientRect(&rc);
#if _DEBUG CString str; str.Format(_T("RECT (TOP: %ld, LEFT: %ld, BOTTOM: %ld, RIGHT: %ld)\n"), rc.top, rc.left, rc.bottom, rc.right); OutputDebugString(str);#endif //#ifdef BIGFONT// const UINT defaultHeight = 40;//#else// const UINT defaultHeight = 22;//#endif
::SetWindowPos(m_hwndEdit, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_SHOWWINDOW | SWP_NOZORDER);
return 0;}
LRESULT CCalculatorWindow::OnPowerBroadcast( UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/){ if(wParam == PBT_APMRESUMECRITICAL || wParam == PBT_APMRESUMESUSPEND || wParam == PBT_APMRESUMESTANDBY) { // re-enable timer //ATLVERIFY(SetUpdateTimer() != 0); }
return 0;}
LRESULT CCalculatorWindow::OnThemeChanged( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/){ // re-create theme style at the current DPI (also refreshes the edit font // and size). RebuildForDpi(m_dpi);
return 0;}
LRESULT CCalculatorWindow::OnDpiChanged( UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/){ const UINT dpi = HIWORD(wParam); RebuildForDpi(dpi); // recreate font + resize for the new DPI
// Move to the position Windows suggests for the new monitor, keeping the // size we just computed from the DPI-scaled font. const RECT* prc = (const RECT*)lParam; RECT wr; GetWindowRect(&wr); SetWindowPos(NULL, prc->left, prc->top, wr.right - wr.left, wr.bottom - wr.top, SWP_NOZORDER | SWP_NOACTIVATE); return 0;}
LRESULT CCalculatorWindow::OnClose(UINT, WPARAM, LPARAM, BOOL&){ // Hide to tray instead of destroying. ShowWindow(SW_HIDE); m_shown = false; Settings::SaveVisible(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;}
LRESULT CCalculatorWindow::OnExitSizeMove(UINT, WPARAM, LPARAM, BOOL&){ // Keep the window within the monitor work area so it never sits over (and // then behind) the taskbar. ClampToWorkArea();
// Persist the canonical position (client origin) and, only if this was an // actual resize, the width (normalized to 96 DPI so it scales // proportionally on other monitors). A plain move keeps the auto-fit width. RECT rc; GetClientRect(&rc); if (m_didResize) Settings::SaveWindowWidth((DWORD)::MulDiv(rc.right - rc.left, 96, (int)m_dpi)); ::MapWindowPoints(m_hWnd, NULL, (LPPOINT)&rc, 2); Settings::SaveWindowPos(POINT{ rc.left, rc.top }); return 0;}
LRESULT CCalculatorWindow::OnEnterSizeMove(UINT, WPARAM, LPARAM, BOOL&){ // Capture the values the interactive-resize handler needs. Height is // locked; width cannot go below the 5-digit minimum for the active frame. m_didResize = false; RECT wr; GetWindowRect(&wr); m_fixedFrameHeight = wr.bottom - wr.top;
RECT r = { 0, 0, MinClientWidth(m_dpi), 100 }; ::AdjustWindowRectExForDpi(&r, (DWORD)GetWindowLongPtr(GWL_STYLE), FALSE, (DWORD)GetWindowLongPtr(GWL_EXSTYLE), m_dpi); m_minResizeWidth = r.right - r.left; return 0;}
LRESULT CCalculatorWindow::OnSizing(UINT, WPARAM wParam, LPARAM lParam, BOOL&){ RECT* rc = (RECT*)lParam; m_didResize = true;
// Horizontal only: keep the height fixed. rc->bottom = rc->top + m_fixedFrameHeight;
// Enforce the minimum width by adjusting whichever edge is being dragged. if ((rc->right - rc->left) < m_minResizeWidth) { switch (wParam) { case WMSZ_LEFT: case WMSZ_TOPLEFT: case WMSZ_BOTTOMLEFT: rc->left = rc->right - m_minResizeWidth; break; default: rc->right = rc->left + m_minResizeWidth; break; } } return TRUE;}
LRESULT CCalculatorWindow::OnActivate(UINT, WPARAM wParam, LPARAM, BOOL& bHandled){ // Caption + close button only while the window is active. ApplyFrameStyle(LOWORD(wParam) != WA_INACTIVE); bHandled = FALSE; // let default activation processing run too return 0;}
void CCalculatorWindow::ApplyFrameStyle(bool visible){ if (visible == m_captionVisible) return; m_captionVisible = visible;
// The client rect must not move on screen: capture it before the style change. RECT rc; GetClientRect(&rc); ::MapWindowPoints(m_hWnd, NULL, (LPPOINT)&rc, 2);
LONG_PTR style = GetWindowLongPtr(GWL_STYLE); if (visible) style |= (WS_CAPTION | WS_SYSMENU | WS_THICKFRAME); else style &= ~(WS_CAPTION | WS_SYSMENU | WS_THICKFRAME); SetWindowLongPtr(GWL_STYLE, style);
RECT r = rc; AdjustWindowRectExForDpi(&r, (DWORD)style, FALSE, (DWORD)GetWindowLongPtr(GWL_EXSTYLE), m_dpi);
// Guard: never push the top edge above the work area of the window's monitor. MONITORINFO mi = { sizeof(mi) }; if (::GetMonitorInfo(::MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST), &mi) && r.top < mi.rcWork.top) ::OffsetRect(&r, 0, mi.rcWork.top - r.top);
SetWindowPos(NULL, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE);}
void CCalculatorWindow::Paint(HDC hdc, const RECT& rcPaint) const{ m_ptrVisualStyle->DrawBackground(m_hWnd, hdc, rcPaint);
RECT rcClient = { 0 }; GetClientRect(&rcClient);
SelectGdiObject gdiFont(hdc, m_ptrVisualStyle->GetFont()); ::SetBkMode(hdc, TRANSPARENT);
::SetTextColor(hdc, m_ptrVisualStyle->GetTextColor());
// ::DrawText(hdc, m_sDateString, m_sDateString.GetLength(), &rcClient, DT_CENTER | DT_SINGLELINE | DT_VCENTER);}
LRESULT CCalculatorWindow::OnEditKeyDown(HWND hWnd, WPARAM wParam, LPARAM /*lParam*/){ TCHAR c = '0'; bool bChangeState = true;
switch (wParam) { case VK_NUMPAD0: c = CALC_0; break; case VK_NUMPAD1: c = CALC_1; break; case VK_NUMPAD2: c = CALC_2; break; case VK_NUMPAD3: c = CALC_3; break; case VK_NUMPAD4: c = CALC_4; break; case VK_NUMPAD5: c = CALC_5; break; case VK_NUMPAD6: c = CALC_6; break; case VK_NUMPAD7: c = CALC_7; break; case VK_NUMPAD8: c = CALC_8; break; case VK_NUMPAD9: c = CALC_9; break; case VK_RETURN: c = CALC_TOT; break; case VK_MULTIPLY: c = CALC_MUL; break; case VK_ADD: c = CALC_ADD; break; case VK_SUBTRACT: c = CALC_SUB; break; case VK_DECIMAL: c = CALC_P; break; case VK_DIVIDE: c = CALC_DIV; break; case VK_ESCAPE: c = CALC_RESET; break; case VK_DELETE: case VK_LEFT: case VK_RIGHT: return 0; case VK_BACK: { UINT len = m_unformatOutputString.GetLength(); if (len > 1) m_unformatOutputString.Delete(len - 1, 1); else m_unformatOutputString = CALC_STR_0; } c = '_'; break; default: bChangeState = false; }
if (bChangeState) ProcessChar(hWnd, c);
return (bChangeState ? 0 : 1);}
LRESULT CCalculatorWindow::OnEditChar(HWND hWnd, WPARAM wParam, LPARAM /*lParam*/){ TCHAR c = '0'; bool bChangeState = true;
switch (wParam) { case CALC_0: case CALC_1: case CALC_2: case CALC_3: case CALC_4: case CALC_5: case CALC_6: case CALC_7: case CALC_8: case CALC_9: case CALC_TOT: case CALC_RESET: case CALC_MUL: case CALC_ADD: case CALC_SUB: case CALC_P: case CALC_DIV: case CALC_SQRT: case CALC_000: case CALC_NEG: case CALC_PERC: case CALC_I: c = (TCHAR)wParam; break; case 'z': c = CALC_000; break; case 'n': c = CALC_RESET; break; case 'q': c = CALC_SQRT; break; case 'i': c = CALC_I; break; case 'p': c = CALC_NEG; break; default: bChangeState = false; }
if (bChangeState) ProcessChar(hWnd, c);
return (bChangeState ? 0 : 1);}
void CCalculatorWindow::ProcessChar(HWND hWnd, TCHAR c){ //char oldString[1024]; TCHAR newString[1024];
m_unformatInputString = m_unformatOutputString;
LPTSTR unformatOutputString = m_unformatOutputString.GetBuffer(1024); m_calc.change_state(c, m_unformatInputString.GetString(), unformatOutputString);
m_unformatOutputString.ReleaseBuffer(-1);
if (m_unformatOutputString != ERR_STR_OVERFLOW && m_unformatOutputString != ERR_STR_DIVBYZERO) { FormatString(m_unformatOutputString, newString); } else lstrcpy(newString, m_unformatOutputString);
::SetWindowText(hWnd, (LPCTSTR)newString);
int l = lstrlen(newString);
::SendMessage(hWnd, EM_SETSEL, l, l);}
bool CCalculatorWindow::FormatString(LPCTSTR strInput, LPTSTR strOutput){ _tcscpy_s(strOutput, 1024, strInput);
{ LPTSTR cDecSep = _tcschr(strOutput, CALC_P); if (cDecSep != NULL) *cDecSep = m_cDecSepStandard;
_tcsrev(strOutput);
size_t len = _tcslen(strOutput);
TCHAR strBuffer[1024];
INT y = -1; UINT j = 0; UINT numDecimalDigit = 0;
bool bStartFormatting = false; if (cDecSep == NULL) { bStartFormatting = true; y = 0; }
for (UINT i = 0; i<len; i++) { if (strOutput[i] == m_cDecSepStandard) { numDecimalDigit = i; bStartFormatting = true; }
if (bStartFormatting) { if (y == 3 && strOutput[i] != CALC_SUB) { strBuffer[j++] = m_cMigSepStandard; y = 0; } y++; }
strBuffer[j++] = strOutput[i]; } strBuffer[j] = '\0';
_tcsrev(strBuffer); _tcscpy_s(strOutput, 1024, strBuffer); }
return true;}
bool CCalculatorWindow::ReadRegionalSettings(){ TCHAR strBuf[256];
m_cDecSepStandard = ','; m_cMigSepStandard = '.';
HKEY hKey; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\International"), 0, KEY_QUERY_VALUE, &hKey)) { DWORD dwDataType; DWORD dwDataSize = 256; if (ERROR_SUCCESS == RegQueryValueEx(hKey, TEXT("sDecimal"), NULL, &dwDataType, (LPBYTE)strBuf, &dwDataSize)) { if (strBuf[0] != '\0') m_cDecSepStandard = strBuf[0]; }
dwDataSize = 256; if (ERROR_SUCCESS == RegQueryValueEx(hKey, TEXT("sThousand"), NULL, &dwDataType, (LPBYTE)strBuf, &dwDataSize)) { if (strBuf[0] != '\0') m_cMigSepStandard = strBuf[0]; }
dwDataSize = 256; if (ERROR_SUCCESS == RegQueryValueEx(hKey, TEXT("iDigits"), NULL, &dwDataType, (LPBYTE)strBuf, &dwDataSize)) { if (strBuf[0] != '\0') m_numDecimalDigit = atoi((const char*)strBuf);
m_calc.set_precision(m_numDecimalDigit); }
RegCloseKey(hKey); }
return true;}
////////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WndEditProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam){ CCalculatorWindow *pThis = (CCalculatorWindow*)::GetWindowLongPtr(hWnd, GWLP_USERDATA); static bool bKeyAlreadyProcessd = false;
switch (uMessage) { case WM_GETDLGCODE: return DLGC_WANTALLKEYS;
case WM_KEYDOWN: if (pThis->OnEditKeyDown(hWnd, wParam, lParam) == 0) { bKeyAlreadyProcessd = true; return 0; } else bKeyAlreadyProcessd = false; break;
case WM_CHAR: if (bKeyAlreadyProcessd) return 0; if (pThis->OnEditChar(hWnd, wParam, lParam) == 0) return 0; break;
case WM_SETFOCUS: ::HideCaret(hWnd); //pThis->OnSetFocus(); break;
case WM_KILLFOCUS: //pThis->OnKillFocus(); break; case WM_SETTINGCHANGE: pThis->ReadRegionalSettings(); pThis->ProcessChar(hWnd, '_'); break; }
return ::CallWindowProc(wpOrigEditProc, hWnd, uMessage, wParam, lParam);}