2024-01-05 12:04
BullseyeCoverage 9.6.4
calc/ Calculator.cpp
1 // Win32 calculator sample application
2
3 #include <windows.h>
4 #include "CalcCore.h"
5
6 // Layout dimensions
7 enum Layout {
8 // Number of columns and rows
9 colCount = 4,
10 rowCount = 5,
11 // Space between buttons
12 margin = 10,
13 // Width and height of button
14 buttonSize = 44,
15 // Display size
16 displayWidth = colCount * (buttonSize + margin) - margin,
17 displayHeight = 20,
18 // Window size
19 width = margin + colCount * (buttonSize + margin),
20 height = margin * 2 + displayHeight + rowCount * (buttonSize + margin),
21 };
22 // Button arrangement
23 const wchar_t buttonGrid[Layout::rowCount][Layout::colCount] = {
24 { 'C', L'²', L'√', L'÷' },
25 { '7', '8', '9', L'×' },
26 { '4', '5', '6', '-' },
27 { '1', '2', '3', '+' },
28 { L'±', '0', '.', '=' },
29 };
30 CalcCore core;
31 HWND display;
32 HINSTANCE instance;
33
34 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
35 {
36 LRESULT result = 0;
37 switch (message) {
38 case WM_COMMAND:
39 switch (wParam) {
40 case '+':
41 core.apply(CalcCore::Operation::add);
42 break;
43 case '-':
44 core.apply(CalcCore::Operation::subtract);
45 break;
46 case '.':
47a case '0':
47b case '1':
47c case '2':
47d case '3':
47e case '4':
47f case '5':
47g case '6':
47h case '7':
47i case '8':
47j case '9':
48 core.addNumberChar(char(wParam));
49 break;
50 case '=':
51 core.apply();
52 break;
53 case 'C':
54 core.clear();
55 break;
56 case L'√':
57 core.apply(CalcCore::Operation::sqrt);
58 break;
59 case L'±':
60 core.apply(CalcCore::Operation::negate);
61 break;
62 case L'²':
63 core.apply(CalcCore::Operation::pow2);
64 break;
65 case L'×':
66 core.apply(CalcCore::Operation::multiply);
67 break;
68 case L'÷':
69 core.apply(CalcCore::Operation::divide);
70 break;
71 default:
72 throw "unknown command";
73 }
74 SetWindowTextA(display, core.display());
75 break;
76 case WM_CREATE:
77 display = CreateWindowEx(0, L"STATIC", L"0", SS_RIGHT | WS_CHILD | WS_VISIBLE, Layout::margin, Layout::margin, Layout::displayWidth, Layout::displayHeight, hWnd, 0, instance, nullptr);
78 {
79 for (unsigned i = 0; i < Layout::colCount; i++) {
80 for (unsigned j = 0; j < Layout::rowCount; j++) {
81 const wchar_t c = buttonGrid[j][i];
82 const wchar_t text[2] = { c, 0 };
83 const int x = Layout::margin + i * (Layout::buttonSize + Layout::margin);
84 const int y = 2 * margin + Layout::displayHeight + j * (Layout::buttonSize + Layout::margin);
85 CreateWindowEx(0, L"BUTTON", text, WS_CHILD | WS_TABSTOP | WS_VISIBLE, x, y, Layout::buttonSize, Layout::buttonSize, hWnd, HMENU(c), instance, nullptr);
86 }
87 }
88 }
89 break;
90 case WM_DESTROY:
91 PostQuitMessage(0);
92 break;
93 default:
94 result = DefWindowProc(hWnd, message, wParam, lParam);
95 break;
96 }
97 return result;
98 }
99
100 int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int)
101 {
102 CalcCore::unitTest();
103 instance = hInstance;
104 // Register window class
105 WNDCLASS wc = { };
106 wc.lpfnWndProc = WndProc;
107 wc.hInstance = hInstance;
108 wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
109 wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
110 wc.hbrBackground = HBRUSH(GetStockObject(WHITE_BRUSH));
111 wc.lpszClassName = L"CalculatorWndClass";
112 RegisterClass(&wc);
113 // Calculate main window size
114 RECT rect{ 0, 0, Layout::width, Layout::height };
115 AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW & ~WS_OVERLAPPED, false);
116 const SIZE size{ rect.right - rect.left, rect.bottom - rect.top };
117 // Create main window
118 const HWND hWnd = CreateWindowEx(0, wc.lpszClassName, L"Calculator", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, size.cx, size.cy, nullptr, nullptr, hInstance, nullptr);
119 // Message pump
120 try {
121 MSG msg;
122 while (GetMessage(&msg, 0, 0, 0)) {
123 DispatchMessage(&msg);
124 }
125 }
126 catch (const char* string) {
127 MessageBoxA(hWnd, string, "Error", MB_OK);
128 }
129 return 0;
130 }