1 /*
2  * PROJECT:     ReactOS VGA Font Editor
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Dialog for editing a glyph
5  * COPYRIGHT:   Copyright 2008 Colin Finck (colin@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 static VOID
11 AddToolboxButton(IN HWND hToolbar, IN INT iBitmap, IN INT idCommand, IN BYTE fsState)
12 {
13     TBBUTTON tbb = {0,};
14 
15     tbb.fsState = fsState;
16     tbb.fsStyle = BTNS_CHECKGROUP;
17     tbb.iBitmap = iBitmap;
18     tbb.idCommand = idCommand;
19 
20     SendMessageW( hToolbar, TB_ADDBUTTONSW, 1, (LPARAM)&tbb );
21 }
22 
23 static VOID
24 InitToolbox(IN PEDIT_GLYPH_INFO Info)
25 {
26     HWND hToolbar;
27     INT iBitmap;
28     TBADDBITMAP tbab;
29 
30     hToolbar = GetDlgItem(Info->hSelf, IDC_EDIT_GLYPH_TOOLBOX);
31 
32     // Identify the used Common Controls version
33     SendMessageW(hToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
34 
35     // Set the button size to 24x24
36     SendMessageW( hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(24, 24) );
37     SendMessageW( hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(24, 24) );
38 
39     // Add the Toolbox bitmaps
40     tbab.hInst = hInstance;
41     tbab.nID = IDB_EDIT_GLYPH_TOOLBOX;
42     iBitmap = (INT)SendMessageW(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
43 
44     AddToolboxButton(hToolbar, iBitmap + TOOLBOX_PEN, ID_TOOLBOX_PEN, TBSTATE_ENABLED | TBSTATE_CHECKED);
45 }
46 
47 static VOID
48 GetBitRect(IN PEDIT_GLYPH_INFO Info, IN UINT uRow, IN UINT uColumn, OUT LPRECT BitRect)
49 {
50     BitRect->left = uColumn * Info->lEditSpacing + 1;
51     BitRect->top = uRow * Info->lEditSpacing + 1;
52     BitRect->right = BitRect->left + Info->lEditSpacing - 1;
53     BitRect->bottom = BitRect->top + Info->lEditSpacing - 1;
54 }
55 
56 static VOID
57 SetPixelBit(IN PEDIT_GLYPH_INFO Info, IN UINT uRow, IN UINT uColumn, IN BOOL uBit)
58 {
59     // Set the bit in the bitfield
60     if(uBit)
61         Info->CharacterBits[uRow] |= 1 << (7 - uColumn);
62     else
63         Info->CharacterBits[uRow] &= ~( 1 << (7 - uColumn) );
64 
65     // Redraw everything
66     InvalidateRect(Info->hEdit, NULL, FALSE);
67     InvalidateRect(Info->hPreview, NULL, FALSE);
68 }
69 
70 static BOOL
71 EditGlyphCommand(IN INT idCommand, IN PEDIT_GLYPH_INFO Info)
72 {
73     switch(idCommand)
74     {
75         case IDOK:
76         {
77             RECT rect;
78             UINT uColumn;
79             UINT uRow;
80 
81             RtlCopyMemory( Info->FontWndInfo->Font->Bits + Info->uCharacter * 8, Info->CharacterBits, sizeof(Info->CharacterBits) );
82 
83             GetCharacterPosition(Info->uCharacter, &uRow, &uColumn);
84             GetCharacterRect(uRow, uColumn, &rect);
85             InvalidateRect(Info->FontWndInfo->hFontBoxesWnd, &rect, FALSE);
86 
87             Info->FontWndInfo->OpenInfo->bModified = TRUE;
88 
89             // Fall through
90         }
91 
92         // This is the equivalent of WM_DESTROY for dialogs
93         case IDCANCEL:
94             EndDialog(Info->hSelf, 0);
95 
96             // Remove the window from the linked list
97             if(Info->PrevEditGlyphWnd)
98                 Info->PrevEditGlyphWnd->NextEditGlyphWnd = Info->NextEditGlyphWnd;
99             else
100                 Info->FontWndInfo->FirstEditGlyphWnd = Info->NextEditGlyphWnd;
101 
102             if(Info->NextEditGlyphWnd)
103                 Info->NextEditGlyphWnd->PrevEditGlyphWnd = Info->PrevEditGlyphWnd;
104             else
105                 Info->FontWndInfo->LastEditGlyphWnd = Info->PrevEditGlyphWnd;
106 
107             SetWindowLongPtrW(Info->hSelf, GWLP_USERDATA, 0);
108             SetWindowLongPtrW(Info->hEdit, GWLP_USERDATA, 0);
109             SetWindowLongPtrW(Info->hPreview, GWLP_USERDATA, 0 );
110 
111             HeapFree(hProcessHeap, 0, Info);
112             return TRUE;
113     }
114 
115     return FALSE;
116 }
117 
118 INT_PTR CALLBACK
119 EditGlyphDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
120 {
121     PEDIT_GLYPH_INFO Info;
122 
123     Info = (PEDIT_GLYPH_INFO) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
124 
125     if(Info || uMsg == WM_INITDIALOG)
126     {
127         switch(uMsg)
128         {
129             case WM_COMMAND:
130                 return EditGlyphCommand( LOWORD(wParam), Info );
131 
132             case WM_INITDIALOG:
133                 Info = (PEDIT_GLYPH_INFO) lParam;
134                 Info->hSelf = hwnd;
135                 Info->hEdit = GetDlgItem(hwnd, IDC_EDIT_GLYPH_EDIT);
136                 Info->hPreview = GetDlgItem(hwnd, IDC_EDIT_GLYPH_PREVIEW);
137 
138                 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)Info);
139                 SetWindowLongPtrW(Info->hEdit, GWLP_USERDATA, (LONG_PTR)Info);
140                 SetWindowLongPtrW(Info->hPreview, GWLP_USERDATA, (LONG_PTR)Info);
141 
142                 InitToolbox(Info);
143 
144                 return TRUE;
145         }
146     }
147 
148     return FALSE;
149 }
150 
151 static LRESULT CALLBACK
152 EditGlyphEditWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
153 {
154     PEDIT_GLYPH_INFO Info;
155 
156     Info = (PEDIT_GLYPH_INFO) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
157 
158     if(Info)
159     {
160         switch(uMsg)
161         {
162             case WM_CREATE:
163                 return 0;
164 
165             case WM_LBUTTONDOWN:
166                 SetPixelBit(Info, GET_Y_LPARAM(lParam) / Info->lEditSpacing, GET_X_LPARAM(lParam) / Info->lEditSpacing, 1);
167                 return 0;
168 
169             case WM_RBUTTONDOWN:
170                 SetPixelBit(Info, GET_Y_LPARAM(lParam) / Info->lEditSpacing, GET_X_LPARAM(lParam) / Info->lEditSpacing, 0);
171                 return 0;
172 
173             case WM_PAINT:
174             {
175                 BOOL bBit;
176                 HPEN hOldPen;
177                 HPEN hPen;
178                 PAINTSTRUCT ps;
179                 RECT rect;
180                 UINT i;
181                 UINT j;
182 
183                 BeginPaint(hwnd, &ps);
184 
185                 // Draw the grid
186                 GetClientRect(hwnd, &rect);
187                 Info->lEditSpacing = rect.right / 8;
188 
189                 hPen = CreatePen( PS_SOLID, 1, RGB(128, 128, 128) );
190                 hOldPen = SelectObject(ps.hdc, hPen);
191 
192                 for(i = 1; i < 8; i++)
193                 {
194                     MoveToEx(ps.hdc, i * Info->lEditSpacing, 0, NULL);
195                     LineTo  (ps.hdc, i * Info->lEditSpacing, rect.right);
196 
197                     MoveToEx(ps.hdc, 0, i * Info->lEditSpacing, NULL);
198                     LineTo  (ps.hdc, rect.right, i * Info->lEditSpacing);
199                 }
200 
201                 SelectObject(ps.hdc, hOldPen);
202                 DeleteObject(hPen);
203 
204                 // Draw all bits
205                 for(i = 0; i < 8; i++)
206                 {
207                     for(j = 0; j < 8; j++)
208                     {
209                         bBit = (BOOL) (Info->CharacterBits[i] << j & 0x80);
210 
211                         GetBitRect(Info, i, j, &rect);
212                         FillRect( ps.hdc, &rect, (HBRUSH) GetStockObject(bBit ? BLACK_BRUSH : WHITE_BRUSH) );
213                     }
214                 }
215 
216                 // Draw the bounding rectangle
217                 SelectObject( ps.hdc, GetStockObject(NULL_BRUSH) );
218                 Rectangle(ps.hdc, 0, 0, rect.right, rect.right);
219 
220                 EndPaint(hwnd, &ps);
221                 return 0;
222             }
223         }
224     }
225 
226     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
227 }
228 
229 static LRESULT CALLBACK
230 EditGlyphPreviewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
231 {
232     PEDIT_GLYPH_INFO Info;
233 
234     Info = (PEDIT_GLYPH_INFO) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
235 
236     if(Info)
237     {
238         switch(uMsg)
239         {
240             case WM_CREATE:
241                 return 0;
242 
243             case WM_PAINT:
244             {
245                 BOOL bBit;
246                 INT iLeft;
247                 INT iTop;
248                 PAINTSTRUCT ps;
249                 RECT rect;
250                 UINT i;
251                 UINT j;
252 
253                 BeginPaint(hwnd, &ps);
254 
255                 // Draw the bounding rectangle
256                 GetClientRect(hwnd, &rect);
257                 Rectangle(ps.hdc, 0, 0, rect.right, rect.bottom);
258 
259                 // Draw all bits
260                 iLeft = rect.right / 2 - 8 / 2;
261                 iTop = rect.bottom / 2 - 8 / 2;
262 
263                 for(i = 0; i < 8; i++)
264                 {
265                     for(j = 0; j < 8; j++)
266                     {
267                         bBit = (BOOL) (Info->CharacterBits[i] << j & 0x80);
268                         SetPixel( ps.hdc, j + iLeft, i + iTop, (bBit ? 0 : 0xFFFFFF) );
269                     }
270                 }
271 
272                 EndPaint(hwnd, &ps);
273 
274                 return 0;
275             }
276         }
277     }
278 
279     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
280 }
281 
282 BOOL
283 InitEditGlyphWndClasses(VOID)
284 {
285     WNDCLASSW wc = {0,};
286 
287     wc.lpfnWndProc    = EditGlyphEditWndProc;
288     wc.hInstance      = hInstance;
289     wc.hCursor        = LoadCursor( NULL, IDC_ARROW );
290     wc.lpszClassName  = EDIT_GLYPH_EDIT_CLASSW;
291 
292     if( !RegisterClassW(&wc) )
293         return FALSE;
294 
295     wc.lpfnWndProc    = EditGlyphPreviewWndProc;
296     wc.lpszClassName  = EDIT_GLYPH_PREVIEW_CLASSW;
297 
298     return RegisterClassW(&wc) != 0;
299 }
300 
301 VOID
302 UnInitEditGlyphWndClasses(VOID)
303 {
304     UnregisterClassW(EDIT_GLYPH_EDIT_CLASSW, hInstance);
305     UnregisterClassW(EDIT_GLYPH_PREVIEW_CLASSW, hInstance);
306 }
307