[CHARMAP]
[reactos.git] / reactos / base / applications / charmap_new / GridView.cpp
1 /*
2 * PROJECT: ReactOS Character Map
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/charmap/GridView.cpp
5 * PURPOSE: Class for for the window which contains the font matrix
6 * COPYRIGHT: Copyright 2015 Ged Murphy <gedmurphy@reactos.org>
7 */
8
9
10 #include "precomp.h"
11 #include "GridView.h"
12 #include "Cell.h"
13
14
15 /* DATA *****************************************************/
16
17 extern HINSTANCE g_hInstance;
18
19
20 /* PUBLIC METHODS **********************************************/
21
22 CGridView::CGridView() :
23 m_xNumCells(20),
24 m_yNumCells(10)
25 {
26 m_szMapWndClass = L"CharGridWClass";
27 }
28
29 CGridView::~CGridView()
30 {
31 }
32
33 bool
34 CGridView::Create(
35 _In_ HWND hParent
36 )
37 {
38 WNDCLASSW wc = { 0 };
39 wc.style = CS_DBLCLKS;
40 wc.lpfnWndProc = MapWndProc;
41 wc.cbWndExtra = sizeof(CGridView *);
42 wc.hInstance = g_hInstance;
43 wc.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
44 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
45 wc.lpszClassName = m_szMapWndClass;
46
47 if (RegisterClassW(&wc))
48 {
49 m_hwnd = CreateWindowExW(0,
50 m_szMapWndClass,
51 NULL,
52 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL,
53 0,0,0,0,
54 hParent,
55 NULL,
56 g_hInstance,
57 this);
58
59 }
60
61 return !!(m_hwnd != NULL);
62 }
63
64 bool
65 CGridView::UpdateGridLayout(
66 )
67 {
68 // Go through all the cells and calculate
69 // their coordinates within the grid
70 for (int y = 0; y < m_yNumCells; y++)
71 for (int x = 0; x < m_xNumCells; x++)
72 {
73 RECT CellCoordinates;
74 CellCoordinates.left = x * m_CellSize.cx + 1;
75 CellCoordinates.top = y * m_CellSize.cy + 1;
76 CellCoordinates.right = (x + 1) * m_CellSize.cx + 2;
77 CellCoordinates.bottom = (y + 1) * m_CellSize.cy + 2;
78
79 m_Cells[y][x]->SetCellCoordinates(CellCoordinates);
80 }
81
82 return true;
83 }
84
85 LRESULT
86 CGridView::OnCreate(
87 _In_ HWND hwnd,
88 _In_ HWND hParent
89 )
90 {
91 m_hwnd = hwnd;
92 m_hParent = hParent;
93
94 // C++ doesn't allow : "CCells ***C = new CCell***[x * y]"
95 // so we have to build the 2d array up manually
96 m_Cells = new CCell**[m_yNumCells]; // rows
97 for (int i = 0; i < m_yNumCells; i++)
98 m_Cells[i] = new CCell*[m_xNumCells]; // columns
99
100 for (int y = 0; y < m_yNumCells; y++)
101 for (int x = 0; x < m_xNumCells; x++)
102 {
103 m_Cells[y][x] = new CCell(m_hwnd);
104 }
105
106 // Give the first cell focus
107 SetCellFocus(m_Cells[0][0]);
108
109 return 0;
110 }
111
112 LRESULT
113 CGridView::OnSize(
114 _In_ INT Width,
115 _In_ INT Height
116 )
117 {
118 // Get the client area of the main dialog
119 RECT ParentRect;
120 GetClientRect(m_hParent, &ParentRect);
121
122 // Calculate the grid size using the parent
123 m_ClientCoordinates.left = ParentRect.left + 25;
124 m_ClientCoordinates.top = ParentRect.top + 50;
125 m_ClientCoordinates.right = ParentRect.right - m_ClientCoordinates.left - 10;
126 m_ClientCoordinates.bottom = ParentRect.bottom - m_ClientCoordinates.top - 70;
127
128 SetWindowPos(m_hwnd,
129 NULL,
130 m_ClientCoordinates.left,
131 m_ClientCoordinates.top,
132 m_ClientCoordinates.right,
133 m_ClientCoordinates.bottom,
134 SWP_NOZORDER | SWP_SHOWWINDOW);
135
136 // Get the client area we can draw on. The position we set above
137 // includes a scrollbar. GetClientRect gives us the size without
138 // the scroll, and it more efficient than getting the scroll
139 // metrics and calculating the size
140 RECT ClientRect;
141 GetClientRect(m_hwnd, &ClientRect);
142 m_CellSize.cx = ClientRect.right / m_xNumCells;
143 m_CellSize.cy = ClientRect.bottom / m_yNumCells;
144
145 UpdateGridLayout();
146
147 return 0;
148 }
149
150 LRESULT
151 CGridView::OnPaint(
152 _In_opt_ HDC hdc
153 )
154 {
155 PAINTSTRUCT PaintStruct = { 0 };
156 HDC LocalHdc = NULL;
157 BOOL bSuccess = FALSE;
158
159 // Check if we were passed a DC
160 if (hdc == NULL)
161 {
162 // We weren't, let's get one
163 LocalHdc = BeginPaint(m_hwnd, &PaintStruct);
164 if (LocalHdc) bSuccess = TRUE;
165 }
166 else
167 {
168 // Use the existing DC and just get the region to paint
169 bSuccess = GetUpdateRect(m_hwnd,
170 &PaintStruct.rcPaint,
171 TRUE);
172 if (bSuccess)
173 {
174 // Update the struct with the DC we were passed
175 PaintStruct.hdc = (HDC)hdc;
176 }
177 }
178
179 if (bSuccess)
180 {
181 DrawGrid(&PaintStruct);
182
183 if (LocalHdc)
184 {
185 EndPaint(m_hwnd, &PaintStruct);
186 }
187 }
188
189 return 0;
190 }
191
192 LRESULT
193 CALLBACK
194 CGridView::MapWndProc(
195 HWND hwnd,
196 UINT uMsg,
197 WPARAM wParam,
198 LPARAM lParam
199 )
200 {
201 CGridView *This;
202 LRESULT RetCode = 0;
203
204 // Get the object pointer from window context
205 This = (CGridView *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
206 if (This == NULL)
207 {
208 // Check that this isn't a create message
209 if (uMsg != WM_CREATE)
210 {
211 // Don't handle null info pointer
212 goto HandleDefaultMessage;
213 }
214 }
215
216 switch (uMsg)
217 {
218 case WM_CREATE:
219 {
220 // Get the object pointer from the create param
221 This = (CGridView *)((LPCREATESTRUCT)lParam)->lpCreateParams;
222
223 // Store the pointer in the window's global user data
224 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)This);
225
226 This->OnCreate(hwnd, ((LPCREATESTRUCTW)lParam)->hwndParent);
227 break;
228 }
229
230 case WM_SIZE:
231 {
232 INT Width, Height;
233 Width = LOWORD(lParam);
234 Height = HIWORD(lParam);
235
236 This->OnSize(Width, Height);
237 break;
238 }
239
240 case WM_PAINT:
241 {
242 This->OnPaint((HDC)wParam);
243 break;
244 }
245
246 case WM_DESTROY:
247 {
248 This->DeleteCells();
249 break;
250 }
251
252 default:
253 {
254 HandleDefaultMessage:
255 RetCode = DefWindowProcW(hwnd, uMsg, wParam, lParam);
256 break;
257 }
258 }
259
260 return RetCode;
261 }
262
263
264 void
265 CGridView::DrawGrid(
266 _In_ LPPAINTSTRUCT PaintStruct
267 )
268 {
269 // Traverse all the cells and tell them to paint themselves
270 for (int y = 0; y < m_yNumCells; y++)
271 for (int x = 0; x < m_xNumCells; x++)
272 {
273 m_Cells[y][x]->OnPaint(*PaintStruct);
274 }
275 }
276
277 void
278 CGridView::DeleteCells()
279 {
280 if (m_Cells == nullptr)
281 return;
282
283 // Free cells withing the 2d array
284 for (int i = 0; i < m_yNumCells; i++)
285 delete[] m_Cells[i];
286 delete[] m_Cells;
287
288 m_Cells = nullptr;
289 }
290
291 void
292 CGridView::SetCellFocus(
293 _In_ CCell* NewActiveCell
294 )
295 {
296 if (m_ActiveCell)
297 {
298 // Remove focus from any existing cell
299 m_ActiveCell->SetFocus(false);
300 }
301
302 // Set the new active cell and give it focus
303 m_ActiveCell = NewActiveCell;
304 m_ActiveCell->SetFocus(true);
305 }