2 * PROJECT: ReactOS Character Map
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/charmap/map.c
5 * PURPOSE: class implementation for painting glyph region
6 * COPYRIGHT: Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
14 static const WCHAR szMapWndClass
[] = L
"FontMapWnd";
15 static const WCHAR szLrgCellWndClass
[] = L
"LrgCellWnd";
17 #define MAX_ROWS (0xFFFF / XCELLS) + 1 - YCELLS
26 for (y
= 0; y
< YCELLS
; y
++)
27 for (x
= 0; x
< XCELLS
; x
++)
29 infoPtr
->Cells
[y
][x
].CellExt
.left
= x
* infoPtr
->CellSize
.cx
+ 1;
30 infoPtr
->Cells
[y
][x
].CellExt
.top
= y
* infoPtr
->CellSize
.cy
+ 1;
31 infoPtr
->Cells
[y
][x
].CellExt
.right
= (x
+ 1) * infoPtr
->CellSize
.cx
+ 2;
32 infoPtr
->Cells
[y
][x
].CellExt
.bottom
= (y
+ 1) * infoPtr
->CellSize
.cy
+ 2;
34 CopyRect(&infoPtr
->Cells
[y
][x
].CellInt
,
35 &infoPtr
->Cells
[y
][x
].CellExt
);
37 InflateRect(&infoPtr
->Cells
[y
][x
].CellInt
,
45 DrawActiveCell(PMAP infoPtr
,
49 infoPtr
->pActiveCell
->CellInt
.left
,
50 infoPtr
->pActiveCell
->CellInt
.top
,
51 infoPtr
->pActiveCell
->CellInt
.right
,
52 infoPtr
->pActiveCell
->CellInt
.bottom
);
59 DrawGrid(PMAP infoPtr
,
66 for (y
= 0; y
< YCELLS
; y
++)
67 for (x
= 0; x
< XCELLS
; x
++)
69 Cell
= &infoPtr
->Cells
[y
][x
];
71 if (!IntersectRect(&rc
,
82 Cell
->CellExt
.bottom
);
84 if (infoPtr
->pActiveCell
== Cell
)
86 DrawActiveCell(infoPtr
, ps
->hdc
);
94 FillGrid(PMAP infoPtr
,
104 hOldFont
= SelectObject(ps
->hdc
,
107 i
= XCELLS
* infoPtr
->iYStart
;
111 for (y
= 0; y
< YCELLS
; y
++)
112 for (x
= 0; x
< XCELLS
; x
++)
114 ch
= (WCHAR
)infoPtr
->ValidGlyphs
[i
];
116 Cell
= &infoPtr
->Cells
[y
][x
];
118 if (IntersectRect(&rc
,
128 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
);
136 SelectObject(ps
->hdc
,
143 CreateLargeCell(PMAP infoPtr
)
148 &infoPtr
->pActiveCell
->CellExt
);
150 MapWindowPoints(infoPtr
->hMapWnd
,
159 infoPtr
->hLrgWnd
= CreateWindowExW(0,
162 WS_CHILDWINDOW
| WS_VISIBLE
,
165 rLarge
.right
- rLarge
.left
,
166 rLarge
.bottom
- rLarge
.top
,
171 if (!infoPtr
->hLrgWnd
)
180 MoveLargeCell(PMAP infoPtr
)
185 &infoPtr
->pActiveCell
->CellExt
);
187 MapWindowPoints(infoPtr
->hMapWnd
,
196 MoveWindow(infoPtr
->hLrgWnd
,
199 rLarge
.right
- rLarge
.left
,
200 rLarge
.bottom
- rLarge
.top
,
203 InvalidateRect(infoPtr
->hLrgWnd
,
211 SetFont(PMAP infoPtr
,
215 WCHAR ch
[MAX_GLYPHS
];
216 WORD out
[MAX_GLYPHS
];
219 /* Destroy Zoom window, since it was created with older font */
220 DestroyWindow(infoPtr
->hLrgWnd
);
221 infoPtr
->hLrgWnd
= NULL
;
224 DeleteObject(infoPtr
->hFont
);
226 ZeroMemory(&infoPtr
->CurrentFont
,
229 hdc
= GetDC(infoPtr
->hMapWnd
);
230 infoPtr
->CurrentFont
.lfHeight
= GetDeviceCaps(hdc
, LOGPIXELSY
) / 5;
232 infoPtr
->CurrentFont
.lfCharSet
= DEFAULT_CHARSET
;
233 wcsncpy(infoPtr
->CurrentFont
.lfFaceName
,
235 sizeof(infoPtr
->CurrentFont
.lfFaceName
) / sizeof(infoPtr
->CurrentFont
.lfFaceName
[0]));
237 infoPtr
->hFont
= CreateFontIndirectW(&infoPtr
->CurrentFont
);
239 InvalidateRect(infoPtr
->hMapWnd
,
243 infoPtr
->pActiveCell
= &infoPtr
->Cells
[0][0];
245 // Get all the valid glyphs in this font
247 SelectObject(hdc
, infoPtr
->hFont
);
249 for (i
= 0; i
< MAX_GLYPHS
; i
++)
252 if (GetGlyphIndicesW(hdc
,
256 GGI_MARK_NONEXISTING_GLYPHS
) != GDI_ERROR
)
259 for (i
= 0; i
< MAX_GLYPHS
; i
++)
261 if (out
[i
] != 0xffff)
263 infoPtr
->ValidGlyphs
[j
] = ch
[i
];
267 infoPtr
->NumValidGlyphs
= j
;
270 ReleaseDC(infoPtr
->hMapWnd
, hdc
);
272 infoPtr
->NumRows
= infoPtr
->NumValidGlyphs
/ XCELLS
;
273 if (infoPtr
->NumValidGlyphs
% XCELLS
)
274 infoPtr
->NumRows
+= 1;
275 infoPtr
->NumRows
= (infoPtr
->NumRows
> YCELLS
) ? infoPtr
->NumRows
- YCELLS
: 0;
277 SetScrollRange(infoPtr
->hMapWnd
, SB_VERT
, 0, infoPtr
->NumRows
, FALSE
);
278 SetScrollPos(infoPtr
->hMapWnd
, SB_VERT
, 0, TRUE
);
279 infoPtr
->iYStart
= 0;
285 NotifyParentOfSelection(PMAP infoPtr
,
291 if (infoPtr
->hParent
!= NULL
)
293 DWORD dwIdc
= GetWindowLongPtr(infoPtr
->hMapWnd
, GWLP_ID
);
295 * Push directly into the event queue instead of waiting
296 * the parent to be unlocked.
297 * High word of LPARAM is still available for future needs...
299 Ret
= PostMessage(infoPtr
->hParent
,
301 MAKELPARAM((WORD
)dwIdc
, (WORD
)code
),
311 OnClick(PMAP infoPtr
,
321 for (x
= 0; x
< XCELLS
; x
++)
322 for (y
= 0; y
< YCELLS
; y
++)
324 if (PtInRect(&infoPtr
->Cells
[y
][x
].CellInt
,
327 /* if the cell is not already active */
328 if (!infoPtr
->Cells
[y
][x
].bActive
)
330 /* set previous active cell to inactive */
331 if (infoPtr
->pActiveCell
)
333 /* invalidate normal cells, required when
334 * moving a small active cell via keyboard */
335 if (!infoPtr
->pActiveCell
->bLarge
)
337 InvalidateRect(infoPtr
->hMapWnd
,
338 &infoPtr
->pActiveCell
->CellInt
,
342 infoPtr
->pActiveCell
->bActive
= FALSE
;
343 infoPtr
->pActiveCell
->bLarge
= FALSE
;
346 /* set new cell to active */
347 infoPtr
->pActiveCell
= &infoPtr
->Cells
[y
][x
];
348 infoPtr
->pActiveCell
->bActive
= TRUE
;
349 infoPtr
->pActiveCell
->bLarge
= TRUE
;
350 if (infoPtr
->hLrgWnd
)
351 MoveLargeCell(infoPtr
);
353 CreateLargeCell(infoPtr
);
357 /* flick between large and small */
358 if (infoPtr
->pActiveCell
->bLarge
)
360 DestroyWindow(infoPtr
->hLrgWnd
);
361 infoPtr
->hLrgWnd
= NULL
;
365 CreateLargeCell(infoPtr
);
368 infoPtr
->pActiveCell
->bLarge
= (infoPtr
->pActiveCell
->bLarge
) ? FALSE
: TRUE
;
379 OnCreate(PMAP infoPtr
,
386 infoPtr
= HeapAlloc(GetProcessHeap(),
392 SetWindowLongPtrW(hwnd
,
395 if (GetLastError() == 0)
400 infoPtr
->hMapWnd
= hwnd
;
401 infoPtr
->hParent
= hParent
;
403 GetClientRect(hwnd
, &rc
);
404 infoPtr
->ClientSize
.cx
= rc
.right
;
405 infoPtr
->ClientSize
.cy
= rc
.bottom
;
406 infoPtr
->CellSize
.cx
= infoPtr
->ClientSize
.cx
/ XCELLS
;
407 infoPtr
->CellSize
.cy
= infoPtr
->ClientSize
.cy
/ YCELLS
;
409 infoPtr
->pActiveCell
= NULL
;
413 SetScrollPos(infoPtr
->hParent
, SB_VERT
, 0, TRUE
);
425 OnVScroll(PMAP infoPtr
,
429 INT iYDiff
, iOldYStart
= infoPtr
->iYStart
;
434 infoPtr
->iYStart
-= 1;
438 infoPtr
->iYStart
+= 1;
442 infoPtr
->iYStart
-= YCELLS
;
446 infoPtr
->iYStart
+= YCELLS
;
450 infoPtr
->iYStart
= Pos
;
457 infoPtr
->iYStart
= max(0, infoPtr
->iYStart
);
458 infoPtr
->iYStart
= min(infoPtr
->iYStart
, infoPtr
->NumRows
);
460 iYDiff
= iOldYStart
- infoPtr
->iYStart
;
463 if (infoPtr
->hLrgWnd
!= NULL
)
465 ShowWindow(infoPtr
->hLrgWnd
, SW_HIDE
);
468 SetScrollPos(infoPtr
->hMapWnd
,
473 if (abs(iYDiff
) < YCELLS
)
476 GetClientRect(infoPtr
->hMapWnd
, &rect
);
479 ScrollWindowEx(infoPtr
->hMapWnd
,
481 iYDiff
* infoPtr
->CellSize
.cy
,
490 InvalidateRect(infoPtr
->hMapWnd
,
495 if (infoPtr
->hLrgWnd
!= NULL
)
497 ShowWindow(infoPtr
->hLrgWnd
, SW_SHOW
);
505 OnPaint(PMAP infoPtr
,
514 if (!GetUpdateRect(infoPtr
->hMapWnd
,
520 ps
.hdc
= (HDC
)wParam
;
524 hdc
= BeginPaint(infoPtr
->hMapWnd
,
532 DrawGrid(infoPtr
, &ps
);
534 FillGrid(infoPtr
, &ps
);
538 EndPaint(infoPtr
->hMapWnd
,
546 MapWndProc(HWND hwnd
,
554 infoPtr
= (PMAP
)GetWindowLongPtrW(hwnd
,
561 if (!OnCreate(infoPtr
,
563 ((LPCREATESTRUCTW
)lParam
)->hwndParent
))
580 case WM_LBUTTONDBLCLK
:
582 NotifyParentOfSelection(infoPtr
,
584 infoPtr
->pActiveCell
->ch
);
600 SetFont(infoPtr
, (LPWSTR
)lParam
);
605 if (!infoPtr
->pActiveCell
) return 0;
606 return infoPtr
->pActiveCell
->ch
;
610 return (LRESULT
)infoPtr
->hFont
;
621 DeleteObject(infoPtr
->hFont
);
622 HeapFree(GetProcessHeap(),
625 SetWindowLongPtrW(hwnd
,
633 Ret
= DefWindowProcW(hwnd
,
646 RegisterMapClasses(HINSTANCE hInstance
)
650 wc
.style
= CS_DBLCLKS
;
651 wc
.lpfnWndProc
= MapWndProc
;
652 wc
.cbWndExtra
= sizeof(PMAP
);
653 wc
.hInstance
= hInstance
;
654 wc
.hCursor
= LoadCursorW(NULL
,
656 wc
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
657 wc
.lpszClassName
= szMapWndClass
;
659 if (RegisterClassW(&wc
))
661 wc
.lpfnWndProc
= LrgCellWndProc
;
663 wc
.lpszClassName
= szLrgCellWndClass
;
665 return RegisterClassW(&wc
) != 0;
672 UnregisterMapClasses(HINSTANCE hInstance
)
674 UnregisterClassW(szMapWndClass
,
677 UnregisterClassW(szLrgCellWndClass
,