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>
15 /* DATA *****************************************************/
17 extern HINSTANCE g_hInstance
;
20 /* PUBLIC METHODS **********************************************/
22 CGridView::CGridView() :
28 m_szMapWndClass
= L
"CharGridWClass";
31 CGridView::~CGridView()
41 wc
.style
= CS_DBLCLKS
;
42 wc
.lpfnWndProc
= MapWndProc
;
43 wc
.cbWndExtra
= sizeof(CGridView
*);
44 wc
.hInstance
= g_hInstance
;
45 wc
.hCursor
= LoadCursorW(NULL
, (LPWSTR
)IDC_ARROW
);
46 wc
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
47 wc
.lpszClassName
= m_szMapWndClass
;
49 if (RegisterClassW(&wc
))
51 m_hwnd
= CreateWindowExW(0,
54 WS_CHILD
| WS_VISIBLE
| WS_TABSTOP
| WS_VSCROLL
,
63 return !!(m_hwnd
!= NULL
);
68 _In_ CAtlString
& FontName
72 // Create a temporary container for the new font
73 CurrentFont NewFont
= { 0 };
74 NewFont
.FontName
= FontName
;
76 // Get the DC for the full grid window
79 if (hdc
== NULL
) return false;
81 // Setup the logfont structure
82 NewFont
.Font
.lfHeight
= 0; // This is set in WM_SIZE
83 NewFont
.Font
.lfCharSet
= DEFAULT_CHARSET
;
84 StringCchCopyW(NewFont
.Font
.lfFaceName
, LF_FACESIZE
, FontName
);
86 // Get a handle to the new font
87 NewFont
.hFont
= CreateFontIndirectW(&NewFont
.Font
);
88 if (NewFont
.hFont
== NULL
)
90 ReleaseDC(m_hwnd
, hdc
);
94 // Setup an array of all possible non-BMP indices
96 for (int i
= 0; i
< MAX_GLYPHS
; i
++)
100 hOldFont
= (HFONT
)SelectObject(hdc
, NewFont
.hFont
);
102 // Translate all the indices into glyphs
103 WORD out
[MAX_GLYPHS
];
105 Status
= GetGlyphIndicesW(hdc
,
109 GGI_MARK_NONEXISTING_GLYPHS
);
110 ReleaseDC(m_hwnd
, hdc
);
111 if (Status
== GDI_ERROR
)
113 SelectObject(hdc
, hOldFont
);
117 // Loop all the glyphs looking for valid ones
118 // and store those in our font data
120 for (int i
= 0; i
< MAX_GLYPHS
; i
++)
122 if (out
[i
] != 0xffff)
124 NewFont
.ValidGlyphs
[j
] = ch
[i
];
128 NewFont
.NumValidGlyphs
= j
;
130 // Calculate the number of rows required to hold all glyphs
131 m_NumRows
= NewFont
.NumValidGlyphs
/ m_xNumCells
;
132 if (NewFont
.NumValidGlyphs
% m_xNumCells
)
135 // Set the scrollbar in relation to the rows
136 SetScrollRange(m_hwnd
, SB_VERT
, 0, m_NumRows
- m_yNumCells
, FALSE
);
138 // We're done, update the current font
139 m_CurrentFont
= NewFont
;
141 // We changed the font, we'll need to repaint the whole window
142 InvalidateRect(m_hwnd
,
151 /* PRIVATE METHODS **********************************************/
154 CGridView::UpdateCellCoordinates(
157 // Go through all the cells and calculate
158 // their coordinates within the grid
159 for (int y
= 0; y
< m_yNumCells
; y
++)
160 for (int x
= 0; x
< m_xNumCells
; x
++)
162 RECT CellCoordinates
;
163 CellCoordinates
.left
= x
* m_CellSize
.cx
;
164 CellCoordinates
.top
= y
* m_CellSize
.cy
;
165 CellCoordinates
.right
= (x
+ 1) * m_CellSize
.cx
+ 1;
166 CellCoordinates
.bottom
= (y
+ 1) * m_CellSize
.cy
+ 1;
168 m_Cells
[y
][x
]->SetCellCoordinates(CellCoordinates
);
183 // C++ doesn't allow : "CCells ***C = new CCell***[x * y]"
184 // so we have to build the 2d array up manually
185 m_Cells
= new CCell
**[m_yNumCells
]; // rows
186 for (int i
= 0; i
< m_yNumCells
; i
++)
187 m_Cells
[i
] = new CCell
*[m_xNumCells
]; // columns
189 for (int y
= 0; y
< m_yNumCells
; y
++)
190 for (int x
= 0; x
< m_xNumCells
; x
++)
192 m_Cells
[y
][x
] = new CCell(m_hwnd
);
195 // Give the first cell focus
196 SetCellFocus(m_Cells
[0][0]);
207 // Get the client area of the main dialog
209 GetClientRect(m_hParent
, &ParentRect
);
211 // Calculate the grid size using the parent
212 m_ClientCoordinates
.left
= ParentRect
.left
+ 25;
213 m_ClientCoordinates
.top
= ParentRect
.top
+ 50;
214 m_ClientCoordinates
.right
= ParentRect
.right
- m_ClientCoordinates
.left
- 10;
215 m_ClientCoordinates
.bottom
= ParentRect
.bottom
- m_ClientCoordinates
.top
- 70;
217 // Resize the grid window
220 m_ClientCoordinates
.left
,
221 m_ClientCoordinates
.top
,
222 m_ClientCoordinates
.right
,
223 m_ClientCoordinates
.bottom
,
224 SWP_NOZORDER
| SWP_SHOWWINDOW
);
226 // Get the client area we can draw on. The position we set above includes
227 // a scrollbar which we obviously can't draw on. GetClientRect gives us
228 // the size without the scroll, and it's more efficient than getting the
229 // scroll metrics and calculating the size from that
231 GetClientRect(m_hwnd
, &ClientRect
);
232 m_CellSize
.cx
= ClientRect
.right
/ m_xNumCells
;
233 m_CellSize
.cy
= ClientRect
.bottom
/ m_yNumCells
;
235 // Let all the cells know about their new coords
236 UpdateCellCoordinates();
238 // We scale the font size up or down depending on the cell size
239 if (m_CurrentFont
.hFont
)
241 // Delete the existing font
242 DeleteObject(m_CurrentFont
.hFont
);
248 // Update the font size with respect to the cell size
249 m_CurrentFont
.Font
.lfHeight
= (m_CellSize
.cy
- 5);
250 m_CurrentFont
.hFont
= CreateFontIndirectW(&m_CurrentFont
.Font
);
251 ReleaseDC(m_hwnd
, hdc
);
255 // Redraw the whole grid
256 InvalidateRect(m_hwnd
, &ClientRect
, TRUE
);
262 CGridView::OnVScroll(_In_ INT Value
,
266 INT PrevScrollPosition
= m_ScrollPosition
;
271 m_ScrollPosition
-= 1;
275 m_ScrollPosition
+= 1;
279 m_ScrollPosition
-= m_yNumCells
;
283 m_ScrollPosition
+= m_yNumCells
;
287 m_ScrollPosition
= Pos
;
294 // Make sure we don't scroll past row 0 or max rows
295 m_ScrollPosition
= max(0, m_ScrollPosition
);
296 m_ScrollPosition
= min(m_ScrollPosition
, m_NumRows
);
298 // Check if there's a difference from the previous position
300 ScrollDiff
= PrevScrollPosition
- m_ScrollPosition
;
303 // Set the new scrollbar position in the scroll box
309 // Check if the scrollbar has moved more than the
310 // number of visible rows (draged or paged)
311 if (abs(ScrollDiff
) < m_yNumCells
)
314 GetClientRect(m_hwnd
, &rect
);
316 // Scroll the visible cells which remain within the grid
317 // and invalidate any new ones which appear from the top / bottom
318 ScrollWindowEx(m_hwnd
,
320 ScrollDiff
* m_CellSize
.cy
,
329 // All the cells need to be redrawn
330 InvalidateRect(m_hwnd
,
342 PAINTSTRUCT PaintStruct
= { 0 };
344 BOOL bSuccess
= FALSE
;
346 // Check if we were passed a DC
349 // We weren't, let's get one
350 LocalHdc
= BeginPaint(m_hwnd
, &PaintStruct
);
351 if (LocalHdc
) bSuccess
= TRUE
;
355 // Use the existing DC and just get the region to paint
356 bSuccess
= GetUpdateRect(m_hwnd
,
357 &PaintStruct
.rcPaint
,
361 // Update the struct with the DC we were passed
362 PaintStruct
.hdc
= (HDC
)hdc
;
366 // Make sure we have a valid DC
369 // Paint the grid and chars
370 DrawGrid(&PaintStruct
);
374 EndPaint(m_hwnd
, &PaintStruct
);
383 CGridView::MapWndProc(
393 // Get the object pointer from window context
394 This
= (CGridView
*)GetWindowLongPtr(hwnd
, GWLP_USERDATA
);
397 // Check that this isn't a create message
398 if (uMsg
!= WM_CREATE
)
400 // Don't handle null info pointer
401 goto HandleDefaultMessage
;
409 // Get the object pointer from the create param
410 This
= (CGridView
*)((LPCREATESTRUCT
)lParam
)->lpCreateParams
;
412 // Store the pointer in the window's global user data
413 SetWindowLongPtr(hwnd
, GWLP_USERDATA
, (LONG_PTR
)This
);
415 This
->OnCreate(hwnd
, ((LPCREATESTRUCTW
)lParam
)->hwndParent
);
422 Width
= LOWORD(lParam
);
423 Height
= HIWORD(lParam
);
425 This
->OnSize(Width
, Height
);
432 Value
= LOWORD(wParam
);
433 Pos
= HIWORD(wParam
);
435 This
->OnVScroll(Value
, Pos
);
441 This
->OnPaint((HDC
)wParam
);
453 HandleDefaultMessage
:
454 RetCode
= DefWindowProcW(hwnd
, uMsg
, wParam
, lParam
);
465 _In_ LPPAINTSTRUCT PaintStruct
468 // Calculate which glyph to start at based on scroll position
470 i
= m_xNumCells
* m_ScrollPosition
;
472 // Make sure we have the correct font on the DC
474 hOldFont
= (HFONT
)SelectFont(PaintStruct
->hdc
,
475 m_CurrentFont
.hFont
);
477 // Traverse all the cells
478 for (int y
= 0; y
< m_yNumCells
; y
++)
479 for (int x
= 0; x
< m_xNumCells
; x
++)
481 // Update the glyph for this cell
482 WCHAR ch
= (WCHAR
)m_CurrentFont
.ValidGlyphs
[i
];
483 m_Cells
[y
][x
]->SetChar(ch
);
485 // Tell it to paint itself
486 m_Cells
[y
][x
]->OnPaint(*PaintStruct
);
490 SelectObject(PaintStruct
->hdc
, hOldFont
);
495 CGridView::DeleteCells()
497 if (m_Cells
== nullptr)
500 // Free cells withing the 2d array
501 for (int i
= 0; i
< m_yNumCells
; i
++)
509 CGridView::SetCellFocus(
510 _In_ CCell
* NewActiveCell
515 // Remove focus from any existing cell
516 m_ActiveCell
->SetFocus(false);
517 InvalidateRect(m_hwnd
, m_ActiveCell
->GetCellCoordinates(), TRUE
);
520 // Set the new active cell and give it focus
521 m_ActiveCell
= NewActiveCell
;
522 m_ActiveCell
->SetFocus(true);