Something went wrong. Try again.
Reactos
Something went wrong. Try again.
13 kB · 522 lines
C++
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523/** PROJECT: ReactOS Character Map* LICENSE: GPL - See COPYING in the top level directory* FILE: base/applications/charmap/GridView.cpp* PURPOSE: Class for for the window which contains the font matrix* COPYRIGHT: Copyright 2015 Ged Murphy <gedmurphy@reactos.org>*/
#include "precomp.h"#include "GridView.h"#include "Cell.h"
/* DATA *****************************************************/
extern HINSTANCE g_hInstance;
/* PUBLIC METHODS **********************************************/
CGridView::CGridView() : m_xNumCells(20), m_yNumCells(10), m_ScrollPosition(0), m_NumRows(0){ m_szMapWndClass = L"CharGridWClass";}
CGridView::~CGridView(){}
boolCGridView::Create( _In_ HWND hParent ){ WNDCLASSW wc = { 0 }; wc.style = CS_DBLCLKS; wc.lpfnWndProc = MapWndProc; wc.cbWndExtra = sizeof(CGridView *); wc.hInstance = g_hInstance; wc.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszClassName = m_szMapWndClass;
if (RegisterClassW(&wc)) { m_hwnd = CreateWindowExW(0, m_szMapWndClass, NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL, 0,0,0,0, hParent, NULL, g_hInstance, this);
}
return !!(m_hwnd != NULL);}
boolCGridView::SetFont( _In_ CAtlString& FontName ){
// Create a temporary container for the new font CurrentFont NewFont = { 0 }; NewFont.FontName = FontName;
// Get the DC for the full grid window HDC hdc; hdc = GetDC(m_hwnd); if (hdc == NULL) return false;
// Setup the logfont structure NewFont.Font.lfHeight = 0; // This is set in WM_SIZE NewFont.Font.lfCharSet = DEFAULT_CHARSET; StringCchCopyW(NewFont.Font.lfFaceName, LF_FACESIZE, FontName);
// Get a handle to the new font NewFont.hFont = CreateFontIndirectW(&NewFont.Font); if (NewFont.hFont == NULL) { ReleaseDC(m_hwnd, hdc); return false; }
// Setup an array of all possible non-BMP indices WCHAR ch[MAX_GLYPHS]; for (int i = 0; i < MAX_GLYPHS; i++) ch[i] = (WCHAR)i;
HFONT hOldFont; hOldFont = (HFONT)SelectObject(hdc, NewFont.hFont);
// Translate all the indices into glyphs WORD out[MAX_GLYPHS]; DWORD Status; Status = GetGlyphIndicesW(hdc, ch, MAX_GLYPHS, out, GGI_MARK_NONEXISTING_GLYPHS); ReleaseDC(m_hwnd, hdc); if (Status == GDI_ERROR) { SelectObject(hdc, hOldFont); return false; }
// Loop all the glyphs looking for valid ones // and store those in our font data int j = 0; for (int i = 0; i < MAX_GLYPHS; i++) { if (out[i] != 0xffff) { NewFont.ValidGlyphs[j] = ch[i]; j++; } } NewFont.NumValidGlyphs = j;
// Calculate the number of rows required to hold all glyphs m_NumRows = NewFont.NumValidGlyphs / m_xNumCells; if (NewFont.NumValidGlyphs % m_xNumCells) m_NumRows += 1;
// Set the scrollbar in relation to the rows SetScrollRange(m_hwnd, SB_VERT, 0, m_NumRows - m_yNumCells, FALSE);
// We're done, update the current font m_CurrentFont = NewFont;
// We changed the font, we'll need to repaint the whole window InvalidateRect(m_hwnd, NULL, TRUE);
return true;}
/* PRIVATE METHODS **********************************************/
boolCGridView::UpdateCellCoordinates( ){ // Go through all the cells and calculate // their coordinates within the grid for (int y = 0; y < m_yNumCells; y++) for (int x = 0; x < m_xNumCells; x++) { RECT CellCoordinates; CellCoordinates.left = x * m_CellSize.cx; CellCoordinates.top = y * m_CellSize.cy; CellCoordinates.right = (x + 1) * m_CellSize.cx + 1; CellCoordinates.bottom = (y + 1) * m_CellSize.cy + 1;
m_Cells[y][x]->SetCellCoordinates(CellCoordinates); }
return true;}
LRESULTCGridView::OnCreate( _In_ HWND hwnd, _In_ HWND hParent ){ m_hwnd = hwnd; m_hParent = hParent;
// C++ doesn't allow : "CCells ***C = new CCell***[x * y]" // so we have to build the 2d array up manually m_Cells = new CCell**[m_yNumCells]; // rows for (int i = 0; i < m_yNumCells; i++) m_Cells[i] = new CCell*[m_xNumCells]; // columns
for (int y = 0; y < m_yNumCells; y++) for (int x = 0; x < m_xNumCells; x++) { m_Cells[y][x] = new CCell(m_hwnd); }
// Give the first cell focus SetCellFocus(m_Cells[0][0]);
return 0;}
LRESULTCGridView::OnSize( _In_ INT Width, _In_ INT Height ){ // Get the client area of the main dialog RECT ParentRect; GetClientRect(m_hParent, &ParentRect);
// Calculate the grid size using the parent m_ClientCoordinates.left = ParentRect.left + 25; m_ClientCoordinates.top = ParentRect.top + 50; m_ClientCoordinates.right = ParentRect.right - m_ClientCoordinates.left - 10; m_ClientCoordinates.bottom = ParentRect.bottom - m_ClientCoordinates.top - 70;
// Resize the grid window SetWindowPos(m_hwnd, NULL, m_ClientCoordinates.left, m_ClientCoordinates.top, m_ClientCoordinates.right, m_ClientCoordinates.bottom, SWP_NOZORDER | SWP_SHOWWINDOW);
// Get the client area we can draw on. The position we set above includes // a scrollbar which we obviously can't draw on. GetClientRect gives us // the size without the scroll, and it's more efficient than getting the // scroll metrics and calculating the size from that RECT ClientRect; GetClientRect(m_hwnd, &ClientRect); m_CellSize.cx = ClientRect.right / m_xNumCells; m_CellSize.cy = ClientRect.bottom / m_yNumCells;
// Let all the cells know about their new coords UpdateCellCoordinates();
// We scale the font size up or down depending on the cell size if (m_CurrentFont.hFont) { // Delete the existing font DeleteObject(m_CurrentFont.hFont);
HDC hdc; hdc = GetDC(m_hwnd); if (hdc) { // Update the font size with respect to the cell size m_CurrentFont.Font.lfHeight = (m_CellSize.cy - 5); m_CurrentFont.hFont = CreateFontIndirectW(&m_CurrentFont.Font); ReleaseDC(m_hwnd, hdc); } }
// Redraw the whole grid InvalidateRect(m_hwnd, &ClientRect, TRUE);
return 0;}
VOIDCGridView::OnVScroll(_In_ INT Value, _In_ INT Pos){ INT PrevScrollPosition = m_ScrollPosition;
switch (Value) { case SB_LINEUP: m_ScrollPosition -= 1; break;
case SB_LINEDOWN: m_ScrollPosition += 1; break;
case SB_PAGEUP: m_ScrollPosition -= m_yNumCells; break;
case SB_PAGEDOWN: m_ScrollPosition += m_yNumCells; break;
case SB_THUMBTRACK: m_ScrollPosition = Pos; break;
default: break; }
// Make sure we don't scroll past row 0 or max rows m_ScrollPosition = max(0, m_ScrollPosition); m_ScrollPosition = min(m_ScrollPosition, m_NumRows);
// Check if there's a difference from the previous position INT ScrollDiff; ScrollDiff = PrevScrollPosition - m_ScrollPosition; if (ScrollDiff) { // Set the new scrollbar position in the scroll box SetScrollPos(m_hwnd, SB_VERT, m_ScrollPosition, TRUE);
// Check if the scrollbar has moved more than the // number of visible rows (draged or paged) if (abs(ScrollDiff) < m_yNumCells) { RECT rect; GetClientRect(m_hwnd, &rect);
// Scroll the visible cells which remain within the grid // and invalidate any new ones which appear from the top / bottom ScrollWindowEx(m_hwnd, 0, ScrollDiff * m_CellSize.cy, &rect, &rect, NULL, NULL, SW_INVALIDATE); } else { // All the cells need to be redrawn InvalidateRect(m_hwnd, NULL, TRUE); } }}
LRESULTCGridView::OnPaint( _In_opt_ HDC hdc ){ PAINTSTRUCT PaintStruct = { 0 }; HDC LocalHdc = NULL; BOOL bSuccess = FALSE;
// Check if we were passed a DC if (hdc == NULL) { // We weren't, let's get one LocalHdc = BeginPaint(m_hwnd, &PaintStruct); if (LocalHdc) bSuccess = TRUE; } else { // Use the existing DC and just get the region to paint bSuccess = GetUpdateRect(m_hwnd, &PaintStruct.rcPaint, TRUE); if (bSuccess) { // Update the struct with the DC we were passed PaintStruct.hdc = (HDC)hdc; } }
// Make sure we have a valid DC if (bSuccess) { // Paint the grid and chars DrawGrid(&PaintStruct);
if (LocalHdc) { EndPaint(m_hwnd, &PaintStruct); } }
return 0;}
LRESULTCALLBACKCGridView::MapWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ){ CGridView *This; LRESULT RetCode = 0;
// Get the object pointer from window context This = (CGridView *)GetWindowLongPtr(hwnd, GWLP_USERDATA); if (This == NULL) { // Check that this isn't a create message if (uMsg != WM_CREATE) { // Don't handle null info pointer goto HandleDefaultMessage; } }
switch (uMsg) { case WM_CREATE: { // Get the object pointer from the create param This = (CGridView *)((LPCREATESTRUCT)lParam)->lpCreateParams;
// Store the pointer in the window's global user data SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)This);
This->OnCreate(hwnd, ((LPCREATESTRUCTW)lParam)->hwndParent); break; }
case WM_SIZE: { INT Width, Height; Width = LOWORD(lParam); Height = HIWORD(lParam);
This->OnSize(Width, Height); break; }
case WM_VSCROLL: { INT Value, Pos; Value = LOWORD(wParam); Pos = HIWORD(wParam);
This->OnVScroll(Value, Pos); break; }
case WM_PAINT: { This->OnPaint((HDC)wParam); break; }
case WM_DESTROY: { This->DeleteCells(); break; }
default: {HandleDefaultMessage: RetCode = DefWindowProcW(hwnd, uMsg, wParam, lParam); break; } }
return RetCode;}
voidCGridView::DrawGrid( _In_ LPPAINTSTRUCT PaintStruct ){ // Calculate which glyph to start at based on scroll position int i; i = m_xNumCells * m_ScrollPosition;
// Make sure we have the correct font on the DC HFONT hOldFont; hOldFont = (HFONT)SelectFont(PaintStruct->hdc, m_CurrentFont.hFont);
// Traverse all the cells for (int y = 0; y < m_yNumCells; y++) for (int x = 0; x < m_xNumCells; x++) { // Update the glyph for this cell WCHAR ch = (WCHAR)m_CurrentFont.ValidGlyphs[i]; m_Cells[y][x]->SetChar(ch);
// Tell it to paint itself m_Cells[y][x]->OnPaint(*PaintStruct); i++; }
SelectObject(PaintStruct->hdc, hOldFont);
}
voidCGridView::DeleteCells(){ if (m_Cells == nullptr) return;
// Free cells withing the 2d array for (int i = 0; i < m_yNumCells; i++) delete[] m_Cells[i]; delete[] m_Cells;
m_Cells = nullptr;}
voidCGridView::SetCellFocus( _In_ CCell* NewActiveCell ){ if (m_ActiveCell) { // Remove focus from any existing cell m_ActiveCell->SetFocus(false); InvalidateRect(m_hwnd, m_ActiveCell->GetCellCoordinates(), TRUE); }
// Set the new active cell and give it focus m_ActiveCell = NewActiveCell; m_ActiveCell->SetFocus(true);}