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