• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *******************************************************************************
3  *
4  *   © 2016 and later: Unicode, Inc. and others.
5  *   License & terms of use: http://www.unicode.org/copyright.html
6  *
7  *******************************************************************************
8  *******************************************************************************
9  *
10  *   Copyright (C) 1999-2007, International Business Machines
11  *   Corporation and others.  All Rights Reserved.
12  *
13  *******************************************************************************
14  *   file name:  Layout.cpp
15  *
16  *   created on: 08/03/2000
17  *   created by: Eric R. Mader
18  */
19 
20 #include <windows.h>
21 #include <stdio.h>
22 
23 #include "paragraph.h"
24 
25 #include "GDIGUISupport.h"
26 #include "GDIFontMap.h"
27 #include "UnicodeReader.h"
28 #include "ScriptCompositeFontInstance.h"
29 
30 #include "resource.h"
31 
32 #define ARRAY_LENGTH(array) (sizeof array / sizeof array[0])
33 
34 struct Context
35 {
36     le_int32 width;
37     le_int32 height;
38     Paragraph *paragraph;
39 };
40 
41 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
42 
43 #define APP_NAME "LayoutSample"
44 
45 TCHAR szAppName[] = TEXT(APP_NAME);
46 
PrettyTitle(HWND hwnd,char * fileName)47 void PrettyTitle(HWND hwnd, char *fileName)
48 {
49     char title[MAX_PATH + 64];
50 
51     sprintf(title, "%s - %s", APP_NAME, fileName);
52 
53     SetWindowTextA(hwnd, title);
54 }
55 
InitParagraph(HWND hwnd,Context * context)56 void InitParagraph(HWND hwnd, Context *context)
57 {
58     SCROLLINFO si;
59 
60     if (context->paragraph != nullptr) {
61         // FIXME: does it matter what we put in the ScrollInfo
62         // if the window's been minimized?
63         if (context->width > 0 && context->height > 0) {
64             context->paragraph->breakLines(context->width, context->height);
65         }
66 
67         si.cbSize = sizeof si;
68         si.fMask = SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL;
69         si.nMin = 0;
70         si.nMax = context->paragraph->getLineCount() - 1;
71         si.nPage = context->height / context->paragraph->getLineHeight();
72         SetScrollInfo(hwnd, SB_VERT, &si, true);
73     }
74 }
75 
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow)76 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
77 {
78     HWND hwnd;
79     HACCEL hAccel;
80     MSG msg;
81     WNDCLASS wndclass;
82     LEErrorCode status = LE_NO_ERROR;
83 
84     wndclass.style         = CS_HREDRAW | CS_VREDRAW;
85     wndclass.lpfnWndProc   = WndProc;
86     wndclass.cbClsExtra    = 0;
87     wndclass.cbWndExtra    = sizeof(LONG);
88     wndclass.hInstance     = hInstance;
89     wndclass.hIcon         = LoadIcon(nullptr, IDI_APPLICATION);
90     wndclass.hCursor       = LoadCursor(nullptr, IDC_ARROW);
91     wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
92     wndclass.lpszMenuName  = szAppName;
93     wndclass.lpszClassName = szAppName;
94 
95     if (!RegisterClass(&wndclass)) {
96         MessageBox(nullptr, TEXT("This demo only runs on Windows 2000!"), szAppName, MB_ICONERROR);
97 
98         return 0;
99     }
100 
101     hAccel = LoadAccelerators(hInstance, szAppName);
102 
103     hwnd = CreateWindow(szAppName, nullptr,
104                         WS_OVERLAPPEDWINDOW | WS_VSCROLL,
105                         CW_USEDEFAULT, CW_USEDEFAULT,
106                         600, 400,
107                         nullptr, nullptr, hInstance, nullptr);
108 
109     ShowWindow(hwnd, iCmdShow);
110     UpdateWindow(hwnd);
111 
112     while (GetMessage(&msg, nullptr, 0, 0)) {
113         if (!TranslateAccelerator(hwnd, hAccel, &msg)) {
114             TranslateMessage(&msg);
115             DispatchMessage(&msg);
116         }
117     }
118 
119     UnregisterClass(szAppName, hInstance);
120     return msg.wParam;
121 }
122 
WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)123 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
124 {
125     HDC hdc;
126     Context *context;
127     static le_int32 windowCount = 0;
128     static GDIFontMap *fontMap = nullptr;
129     static GDISurface *surface = nullptr;
130     static GDIGUISupport *guiSupport = new GDIGUISupport();
131     static ScriptCompositeFontInstance *font = nullptr;
132 
133     switch (message) {
134     case WM_CREATE:
135     {
136         LEErrorCode fontStatus = LE_NO_ERROR;
137 
138         hdc = GetDC(hwnd);
139         surface = new GDISurface(hdc);
140 
141         fontMap = new GDIFontMap(surface, "FontMap.GDI", 24, guiSupport, fontStatus);
142         font    = new ScriptCompositeFontInstance(fontMap);
143 
144         if (LE_FAILURE(fontStatus)) {
145             ReleaseDC(hwnd, hdc);
146             return -1;
147         }
148 
149         context = new Context();
150 
151         context->width  = 600;
152         context->height = 400;
153 
154         context->paragraph = Paragraph::paragraphFactory("Sample.txt", font, guiSupport);
155         SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) context);
156 
157         windowCount += 1;
158         ReleaseDC(hwnd, hdc);
159 
160         PrettyTitle(hwnd, "Sample.txt");
161         return 0;
162     }
163 
164     case WM_SIZE:
165     {
166         context = (Context *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
167         context->width  = LOWORD(lParam);
168         context->height = HIWORD(lParam);
169 
170         InitParagraph(hwnd, context);
171         return 0;
172     }
173 
174     case WM_VSCROLL:
175     {
176         SCROLLINFO si;
177         le_int32 vertPos;
178 
179         si.cbSize = sizeof si;
180         si.fMask = SIF_ALL;
181         GetScrollInfo(hwnd, SB_VERT, &si);
182 
183         vertPos = si.nPos;
184 
185         switch (LOWORD(wParam))
186         {
187         case SB_TOP:
188             si.nPos = si.nMin;
189             break;
190 
191         case SB_BOTTOM:
192             si.nPos = si.nMax;
193             break;
194 
195         case SB_LINEUP:
196             si.nPos -= 1;
197             break;
198 
199         case SB_LINEDOWN:
200             si.nPos += 1;
201             break;
202 
203         case SB_PAGEUP:
204             si.nPos -= si.nPage;
205             break;
206 
207         case SB_PAGEDOWN:
208             si.nPos += si.nPage;
209             break;
210 
211         case SB_THUMBTRACK:
212             si.nPos = si.nTrackPos;
213             break;
214 
215         default:
216             break;
217         }
218 
219         si.fMask = SIF_POS;
220         SetScrollInfo(hwnd, SB_VERT, &si, true);
221         GetScrollInfo(hwnd, SB_VERT, &si);
222 
223         context = (Context *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
224 
225         if (context->paragraph != nullptr && si.nPos != vertPos) {
226             ScrollWindow(hwnd, 0, context->paragraph->getLineHeight() * (vertPos - si.nPos), nullptr, nullptr);
227             UpdateWindow(hwnd);
228         }
229 
230         return 0;
231     }
232 
233     case WM_PAINT:
234     {
235         PAINTSTRUCT ps;
236         SCROLLINFO si;
237         le_int32 firstLine, lastLine;
238 
239         hdc = BeginPaint(hwnd, &ps);
240         SetBkMode(hdc, TRANSPARENT);
241 
242         si.cbSize = sizeof si;
243         si.fMask = SIF_ALL;
244         GetScrollInfo(hwnd, SB_VERT, &si);
245 
246         firstLine = si.nPos;
247 
248         context = (Context *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
249 
250         if (context->paragraph != nullptr) {
251             surface->setHDC(hdc);
252 
253             // NOTE: si.nPos + si.nPage may include a partial line at the bottom
254             // of the window. We need this because scrolling assumes that the
255             // partial line has been painted.
256             lastLine  = min (si.nPos + (le_int32) si.nPage, context->paragraph->getLineCount() - 1);
257 
258             context->paragraph->draw(surface, firstLine, lastLine);
259         }
260 
261         EndPaint(hwnd, &ps);
262         return 0;
263     }
264 
265     case WM_COMMAND:
266         switch (LOWORD(wParam)) {
267         case IDM_FILE_OPEN:
268         {
269             OPENFILENAMEA ofn;
270             char szFileName[MAX_PATH], szTitleName[MAX_PATH];
271             static char szFilter[] = "Text Files (.txt)\0*.txt\0"
272                                      "All Files (*.*)\0*.*\0\0";
273 
274             ofn.lStructSize       = sizeof (OPENFILENAMEA);
275             ofn.hwndOwner         = hwnd;
276             ofn.hInstance         = nullptr;
277             ofn.lpstrFilter       = szFilter;
278             ofn.lpstrCustomFilter = nullptr;
279             ofn.nMaxCustFilter    = 0;
280             ofn.nFilterIndex      = 0;
281             ofn.lpstrFile         = szFileName;
282             ofn.nMaxFile          = MAX_PATH;
283             ofn.lpstrFileTitle    = szTitleName;
284             ofn.nMaxFileTitle     = MAX_PATH;
285             ofn.lpstrInitialDir   = nullptr;
286             ofn.lpstrTitle        = nullptr;
287             ofn.Flags             = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
288             ofn.nFileOffset       = 0;
289             ofn.nFileExtension    = 0;
290             ofn.lpstrDefExt       = "txt";
291             ofn.lCustData         = 0L;
292             ofn.lpfnHook          = nullptr;
293             ofn.lpTemplateName    = nullptr;
294 
295             szFileName[0] = '\0';
296 
297             if (GetOpenFileNameA(&ofn)) {
298                 hdc = GetDC(hwnd);
299                 surface->setHDC(hdc);
300 
301                 Paragraph *newParagraph = Paragraph::paragraphFactory(szFileName, font, guiSupport);
302 
303                 if (newParagraph != nullptr) {
304                     context = (Context *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
305 
306                     if (context->paragraph != nullptr) {
307                         delete context->paragraph;
308                     }
309 
310                     context->paragraph = newParagraph;
311                     InitParagraph(hwnd, context);
312                     PrettyTitle(hwnd, szTitleName);
313                     InvalidateRect(hwnd, nullptr, true);
314 
315                 }
316             }
317 
318             //ReleaseDC(hwnd, hdc);
319 
320             return 0;
321         }
322 
323         case IDM_FILE_EXIT:
324         case IDM_FILE_CLOSE:
325             SendMessage(hwnd, WM_CLOSE, 0, 0);
326             return 0;
327 
328         case IDM_HELP_ABOUTLAYOUTSAMPLE:
329             MessageBox(hwnd, TEXT("Windows Layout Sample 0.1\n")
330                              TEXT("Copyright (C) 1998-2005 By International Business Machines Corporation and others.\n")
331                              TEXT("Author: Eric Mader"),
332                        szAppName, MB_ICONINFORMATION | MB_OK);
333             return 0;
334 
335         }
336         break;
337 
338 
339     case WM_DESTROY:
340     {
341         context = (Context *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
342 
343         if (context != nullptr && context->paragraph != nullptr) {
344             delete context->paragraph;
345         }
346 
347         delete context;
348 
349         if (--windowCount <= 0) {
350             delete font;
351             delete surface;
352 
353             PostQuitMessage(0);
354         }
355 
356         return 0;
357     }
358 
359     default:
360         return DefWindowProc(hwnd, message, wParam, lParam);
361     }
362 
363     return 0;
364 }
365