notepad: Add Hebrew translation.
[wine] / programs / notepad / dialog.c
1 /*
2  *  Notepad (dialog.c)
3  *
4  *  Copyright 1998,99 Marcel Baur <mbaur@g26.ethz.ch>
5  *  Copyright 2002 Sylvain Petreolle <spetreolle@yahoo.fr>
6  *  Copyright 2002 Andriy Palamarchuk
7  *  Copyright 2007 Rolf Kalbermatter
8  *  Copyright 2010 Vitaly Perov
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24
25 #include <assert.h>
26 #include <stdio.h>
27 #include <windows.h>
28 #include <commdlg.h>
29 #include <shlwapi.h>
30 #include <winternl.h>
31
32 #include "main.h"
33 #include "dialog.h"
34
35 #define SPACES_IN_TAB 8
36 #define PRINT_LEN_MAX 500
37
38 static const WCHAR helpfileW[] = { 'n','o','t','e','p','a','d','.','h','l','p',0 };
39
40 static INT_PTR WINAPI DIALOG_PAGESETUP_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
41
42 /* Swap bytes of WCHAR buffer (big-endian <-> little-endian). */
43 static inline void byteswap_wide_string(LPWSTR str, UINT num)
44 {
45     UINT i;
46     for (i = 0; i < num; i++) str[i] = RtlUshortByteSwap(str[i]);
47 }
48
49 static void load_encoding_name(ENCODING enc, WCHAR* buffer, int length)
50 {
51     switch (enc)
52     {
53         case ENCODING_UTF16LE:
54             LoadStringW(Globals.hInstance, STRING_UNICODE_LE, buffer, length);
55             break;
56
57         case ENCODING_UTF16BE:
58             LoadStringW(Globals.hInstance, STRING_UNICODE_BE, buffer, length);
59             break;
60
61         default:
62         {
63             CPINFOEXW cpi;
64             GetCPInfoExW((enc==ENCODING_UTF8) ? CP_UTF8 : CP_ACP, 0, &cpi);
65             lstrcpynW(buffer, cpi.CodePageName, length);
66             break;
67         }
68     }
69 }
70
71 VOID ShowLastError(void)
72 {
73     DWORD error = GetLastError();
74     if (error != NO_ERROR)
75     {
76         LPWSTR lpMsgBuf;
77         WCHAR szTitle[MAX_STRING_LEN];
78
79         LoadStringW(Globals.hInstance, STRING_ERROR, szTitle, ARRAY_SIZE(szTitle));
80         FormatMessageW(
81             FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
82             NULL, error, 0, (LPWSTR)&lpMsgBuf, 0, NULL);
83         MessageBoxW(NULL, lpMsgBuf, szTitle, MB_OK | MB_ICONERROR);
84         LocalFree(lpMsgBuf);
85     }
86 }
87
88 /**
89  * Sets the caption of the main window according to Globals.szFileTitle:
90  *    Untitled - Notepad        if no file is open
91  *    filename - Notepad        if a file is given
92  */
93 void UpdateWindowCaption(void)
94 {
95   WCHAR szCaption[MAX_STRING_LEN];
96   WCHAR szNotepad[MAX_STRING_LEN];
97   static const WCHAR hyphenW[] = { ' ','-',' ',0 };
98
99   if (Globals.szFileTitle[0] != '\0')
100       lstrcpyW(szCaption, Globals.szFileTitle);
101   else
102       LoadStringW(Globals.hInstance, STRING_UNTITLED, szCaption, ARRAY_SIZE(szCaption));
103
104   LoadStringW(Globals.hInstance, STRING_NOTEPAD, szNotepad, ARRAY_SIZE(szNotepad));
105   lstrcatW(szCaption, hyphenW);
106   lstrcatW(szCaption, szNotepad);
107
108   SetWindowTextW(Globals.hMainWnd, szCaption);
109 }
110
111 int DIALOG_StringMsgBox(HWND hParent, int formatId, LPCWSTR szString, DWORD dwFlags)
112 {
113    WCHAR szMessage[MAX_STRING_LEN];
114    WCHAR szResource[MAX_STRING_LEN];
115
116    /* Load and format szMessage */
117    LoadStringW(Globals.hInstance, formatId, szResource, ARRAY_SIZE(szResource));
118    wnsprintfW(szMessage, ARRAY_SIZE(szMessage), szResource, szString);
119
120    /* Load szCaption */
121    if ((dwFlags & MB_ICONMASK) == MB_ICONEXCLAMATION)
122      LoadStringW(Globals.hInstance, STRING_ERROR,  szResource, ARRAY_SIZE(szResource));
123    else
124      LoadStringW(Globals.hInstance, STRING_NOTEPAD,  szResource, ARRAY_SIZE(szResource));
125
126    /* Display Modal Dialog */
127    if (hParent == NULL)
128      hParent = Globals.hMainWnd;
129    return MessageBoxW(hParent, szMessage, szResource, dwFlags);
130 }
131
132 static void AlertFileNotFound(LPCWSTR szFileName)
133 {
134    DIALOG_StringMsgBox(NULL, STRING_NOTFOUND, szFileName, MB_ICONEXCLAMATION|MB_OK);
135 }
136
137 static int AlertFileNotSaved(LPCWSTR szFileName)
138 {
139    WCHAR szUntitled[MAX_STRING_LEN];
140
141    LoadStringW(Globals.hInstance, STRING_UNTITLED, szUntitled, ARRAY_SIZE(szUntitled));
142    return DIALOG_StringMsgBox(NULL, STRING_NOTSAVED, szFileName[0] ? szFileName : szUntitled,
143      MB_ICONQUESTION|MB_YESNOCANCEL);
144 }
145
146 static int AlertUnicodeCharactersLost(LPCWSTR szFileName)
147 {
148     WCHAR szMsgFormat[MAX_STRING_LEN];
149     WCHAR szEnc[MAX_STRING_LEN];
150     WCHAR szMsg[ARRAY_SIZE(szMsgFormat) + MAX_PATH + ARRAY_SIZE(szEnc)];
151     WCHAR szCaption[MAX_STRING_LEN];
152
153     LoadStringW(Globals.hInstance, STRING_LOSS_OF_UNICODE_CHARACTERS,
154                 szMsgFormat, ARRAY_SIZE(szMsgFormat));
155     load_encoding_name(ENCODING_ANSI, szEnc, ARRAY_SIZE(szEnc));
156     wnsprintfW(szMsg, ARRAY_SIZE(szMsg), szMsgFormat, szFileName, szEnc);
157     LoadStringW(Globals.hInstance, STRING_NOTEPAD, szCaption,
158                 ARRAY_SIZE(szCaption));
159     return MessageBoxW(Globals.hMainWnd, szMsg, szCaption,
160                        MB_OKCANCEL|MB_ICONEXCLAMATION);
161 }
162
163 /**
164  * Returns:
165  *   TRUE  - if file exists
166  *   FALSE - if file does not exist
167  */
168 BOOL FileExists(LPCWSTR szFilename)
169 {
170    WIN32_FIND_DATAW entry;
171    HANDLE hFile;
172
173    hFile = FindFirstFileW(szFilename, &entry);
174    FindClose(hFile);
175
176    return (hFile != INVALID_HANDLE_VALUE);
177 }
178
179 static inline BOOL is_conversion_to_ansi_lossy(LPCWSTR textW, int lenW)
180 {
181     BOOL ret = FALSE;
182     WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, textW, lenW, NULL, 0,
183                         NULL, &ret);
184     return ret;
185 }
186
187 typedef enum
188 {
189     SAVED_OK,
190     SAVE_FAILED,
191     SHOW_SAVEAS_DIALOG
192 } SAVE_STATUS;
193
194 /* szFileName is the filename to save under; enc is the encoding to use.
195  *
196  * If the function succeeds, it returns SAVED_OK.
197  * If the function fails, it returns SAVE_FAILED.
198  * If Unicode data could be lost due to conversion to a non-Unicode character
199  * set, a warning is displayed. The user can continue (and the function carries
200  * on), or cancel (and the function returns SHOW_SAVEAS_DIALOG).
201  */
202 static SAVE_STATUS DoSaveFile(LPCWSTR szFileName, ENCODING enc)
203 {
204     int lenW;
205     WCHAR* textW;
206     HANDLE hFile;
207     DWORD dwNumWrite;
208     PVOID pBytes;
209     DWORD size;
210
211     /* lenW includes the byte-order mark, but not the \0. */
212     lenW = GetWindowTextLengthW(Globals.hEdit) + 1;
213     textW = HeapAlloc(GetProcessHeap(), 0, (lenW+1) * sizeof(WCHAR));
214     if (!textW)
215     {
216         ShowLastError();
217         return SAVE_FAILED;
218     }
219     textW[0] = (WCHAR) 0xfeff;
220     lenW = GetWindowTextW(Globals.hEdit, textW+1, lenW) + 1;
221
222     switch (enc)
223     {
224     case ENCODING_UTF16BE:
225         byteswap_wide_string(textW, lenW);
226         /* fall through */
227
228     case ENCODING_UTF16LE:
229         size = lenW * sizeof(WCHAR);
230         pBytes = textW;
231         break;
232
233     case ENCODING_UTF8:
234         size = WideCharToMultiByte(CP_UTF8, 0, textW, lenW, NULL, 0, NULL, NULL);
235         pBytes = HeapAlloc(GetProcessHeap(), 0, size);
236         if (!pBytes)
237         {
238             ShowLastError();
239             HeapFree(GetProcessHeap(), 0, textW);
240             return SAVE_FAILED;
241         }
242         WideCharToMultiByte(CP_UTF8, 0, textW, lenW, pBytes, size, NULL, NULL);
243         HeapFree(GetProcessHeap(), 0, textW);
244         break;
245
246     default:
247         if (is_conversion_to_ansi_lossy(textW+1, lenW-1)
248             && AlertUnicodeCharactersLost(szFileName) == IDCANCEL)
249         {
250             HeapFree(GetProcessHeap(), 0, textW);
251             return SHOW_SAVEAS_DIALOG;
252         }
253
254         size = WideCharToMultiByte(CP_ACP, 0, textW+1, lenW-1, NULL, 0, NULL, NULL);
255         pBytes = HeapAlloc(GetProcessHeap(), 0, size);
256         if (!pBytes)
257         {
258             ShowLastError();
259             HeapFree(GetProcessHeap(), 0, textW);
260             return SAVE_FAILED;
261         }
262         WideCharToMultiByte(CP_ACP, 0, textW+1, lenW-1, pBytes, size, NULL, NULL);
263         HeapFree(GetProcessHeap(), 0, textW);
264         break;
265     }
266
267     hFile = CreateFileW(szFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
268                        NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
269     if(hFile == INVALID_HANDLE_VALUE)
270     {
271         ShowLastError();
272         HeapFree(GetProcessHeap(), 0, pBytes);
273         return SAVE_FAILED;
274     }
275     if (!WriteFile(hFile, pBytes, size, &dwNumWrite, NULL))
276     {
277         ShowLastError();
278         CloseHandle(hFile);
279         HeapFree(GetProcessHeap(), 0, pBytes);
280         return SAVE_FAILED;
281     }
282     SetEndOfFile(hFile);
283     CloseHandle(hFile);
284     HeapFree(GetProcessHeap(), 0, pBytes);
285
286     SendMessageW(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
287     return SAVED_OK;
288 }
289
290 /**
291  * Returns:
292  *   TRUE  - User agreed to close (both save/don't save)
293  *   FALSE - User cancelled close by selecting "Cancel"
294  */
295 BOOL DoCloseFile(void)
296 {
297     int nResult;
298     static const WCHAR empty_strW[] = { 0 };
299
300     nResult=GetWindowTextLengthW(Globals.hEdit);
301     if (SendMessageW(Globals.hEdit, EM_GETMODIFY, 0, 0) &&
302         (nResult || Globals.szFileName[0]))
303     {
304         /* prompt user to save changes */
305         nResult = AlertFileNotSaved(Globals.szFileName);
306         switch (nResult) {
307             case IDYES:     return DIALOG_FileSave();
308
309             case IDNO:      break;
310
311             case IDCANCEL:  return(FALSE);
312
313             default:        return(FALSE);
314         } /* switch */
315     } /* if */
316
317     SetFileNameAndEncoding(empty_strW, ENCODING_ANSI);
318
319     UpdateWindowCaption();
320     return(TRUE);
321 }
322
323 static inline ENCODING detect_encoding_of_buffer(const void* buffer, int size)
324 {
325     static const char bom_utf8[] = { 0xef, 0xbb, 0xbf };
326     if (size >= sizeof(bom_utf8) && !memcmp(buffer, bom_utf8, sizeof(bom_utf8)))
327         return ENCODING_UTF8;
328     else
329     {
330         int flags = IS_TEXT_UNICODE_SIGNATURE |
331                     IS_TEXT_UNICODE_REVERSE_SIGNATURE |
332                     IS_TEXT_UNICODE_ODD_LENGTH;
333         IsTextUnicode(buffer, size, &flags);
334         if (flags & IS_TEXT_UNICODE_SIGNATURE)
335             return ENCODING_UTF16LE;
336         else if (flags & IS_TEXT_UNICODE_REVERSE_SIGNATURE)
337             return ENCODING_UTF16BE;
338         else
339             return ENCODING_ANSI;
340     }
341 }
342
343 void DoOpenFile(LPCWSTR szFileName, ENCODING enc)
344 {
345     static const WCHAR dotlog[] = { '.','L','O','G',0 };
346     HANDLE hFile;
347     LPSTR pTemp;
348     DWORD size;
349     DWORD dwNumRead;
350     int lenW;
351     WCHAR* textW;
352     int i;
353     WCHAR log[5];
354
355     /* Close any files and prompt to save changes */
356     if (!DoCloseFile())
357         return;
358
359     hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
360                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
361     if(hFile == INVALID_HANDLE_VALUE)
362     {
363         AlertFileNotFound(szFileName);
364         return;
365     }
366
367     size = GetFileSize(hFile, NULL);
368     if (size == INVALID_FILE_SIZE)
369     {
370         CloseHandle(hFile);
371         ShowLastError();
372         return;
373     }
374
375     /* Extra memory for (WCHAR)'\0'-termination. */
376     pTemp = HeapAlloc(GetProcessHeap(), 0, size+2);
377     if (!pTemp)
378     {
379         CloseHandle(hFile);
380         ShowLastError();
381         return;
382     }
383
384     if (!ReadFile(hFile, pTemp, size, &dwNumRead, NULL))
385     {
386         CloseHandle(hFile);
387         HeapFree(GetProcessHeap(), 0, pTemp);
388         ShowLastError();
389         return;
390     }
391
392     CloseHandle(hFile);
393
394     size = dwNumRead;
395
396     if (enc == ENCODING_AUTO)
397         enc = detect_encoding_of_buffer(pTemp, size);
398     else if (size >= 2 && (enc==ENCODING_UTF16LE || enc==ENCODING_UTF16BE))
399     {
400         /* If UTF-16 (BE or LE) is selected, and there is a UTF-16 BOM,
401          * override the selection (like native Notepad).
402          */
403         if ((BYTE)pTemp[0] == 0xff && (BYTE)pTemp[1] == 0xfe)
404             enc = ENCODING_UTF16LE;
405         else if ((BYTE)pTemp[0] == 0xfe && (BYTE)pTemp[1] == 0xff)
406             enc = ENCODING_UTF16BE;
407     }
408
409     switch (enc)
410     {
411     case ENCODING_UTF16BE:
412         byteswap_wide_string((WCHAR*) pTemp, size/sizeof(WCHAR));
413         /* Forget whether the file is BE or LE, like native Notepad. */
414         enc = ENCODING_UTF16LE;
415
416         /* fall through */
417
418     case ENCODING_UTF16LE:
419         textW = (LPWSTR)pTemp;
420         lenW  = size/sizeof(WCHAR);
421         break;
422
423     default:
424         {
425             int cp = (enc==ENCODING_UTF8) ? CP_UTF8 : CP_ACP;
426             lenW = MultiByteToWideChar(cp, 0, pTemp, size, NULL, 0);
427             textW = HeapAlloc(GetProcessHeap(), 0, (lenW+1) * sizeof(WCHAR));
428             if (!textW)
429             {
430                 ShowLastError();
431                 HeapFree(GetProcessHeap(), 0, pTemp);
432                 return;
433             }
434             MultiByteToWideChar(cp, 0, pTemp, size, textW, lenW);
435             HeapFree(GetProcessHeap(), 0, pTemp);
436             break;
437         }
438     }
439
440     /* Replace '\0's with spaces. Other than creating a custom control that
441      * can deal with '\0' characters, it's the best that can be done.
442      */
443     for (i = 0; i < lenW; i++)
444         if (textW[i] == '\0')
445             textW[i] = ' ';
446     textW[lenW] = '\0';
447
448     if (lenW >= 1 && textW[0] == 0xfeff)
449         SetWindowTextW(Globals.hEdit, textW+1);
450     else
451         SetWindowTextW(Globals.hEdit, textW);
452
453     HeapFree(GetProcessHeap(), 0, textW);
454
455     SendMessageW(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
456     SendMessageW(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
457     SetFocus(Globals.hEdit);
458     
459     /*  If the file starts with .LOG, add a time/date at the end and set cursor after */
460     if (GetWindowTextW(Globals.hEdit, log, ARRAY_SIZE(log)) && !lstrcmpW(log, dotlog))
461     {
462         static const WCHAR lfW[] = { '\r','\n',0 };
463         SendMessageW(Globals.hEdit, EM_SETSEL, GetWindowTextLengthW(Globals.hEdit), -1);
464         SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lfW);
465         DIALOG_EditTimeDate();
466         SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lfW);
467     }
468
469     SetFileNameAndEncoding(szFileName, enc);
470     UpdateWindowCaption();
471 }
472
473 VOID DIALOG_FileNew(VOID)
474 {
475     static const WCHAR empty_strW[] = { 0 };
476
477     /* Close any files and prompt to save changes */
478     if (DoCloseFile()) {
479         SetWindowTextW(Globals.hEdit, empty_strW);
480         SendMessageW(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
481         SetFocus(Globals.hEdit);
482     }
483 }
484
485 /* Used to detect encoding of files selected in Open dialog.
486  * Returns ENCODING_AUTO if file can't be read, etc.
487  */
488 static ENCODING detect_encoding_of_file(LPCWSTR szFileName)
489 {
490     DWORD size;
491     HANDLE hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
492                                OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
493     if (hFile == INVALID_HANDLE_VALUE)
494         return ENCODING_AUTO;
495     size = GetFileSize(hFile, NULL);
496     if (size == INVALID_FILE_SIZE)
497     {
498         CloseHandle(hFile);
499         return ENCODING_AUTO;
500     }
501     else
502     {
503         DWORD dwNumRead;
504         BYTE buffer[MAX_STRING_LEN];
505         if (!ReadFile(hFile, buffer, min(size, sizeof(buffer)), &dwNumRead, NULL))
506         {
507             CloseHandle(hFile);
508             return ENCODING_AUTO;
509         }
510         CloseHandle(hFile);
511         return detect_encoding_of_buffer(buffer, dwNumRead);
512     }
513 }
514
515 static LPWSTR dialog_print_to_file(HWND hMainWnd)
516 {
517     OPENFILENAMEW ofn;
518     static WCHAR file[MAX_PATH] = {'o','u','t','p','u','t','.','p','r','n',0};
519     static const WCHAR defExt[] = {'p','r','n',0};
520
521     ZeroMemory(&ofn, sizeof(ofn));
522
523     ofn.lStructSize = sizeof(ofn);
524     ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
525     ofn.hwndOwner = hMainWnd;
526     ofn.lpstrFile = file;
527     ofn.nMaxFile = MAX_PATH;
528     ofn.lpstrDefExt = defExt;
529
530     if(GetSaveFileNameW(&ofn))
531         return file;
532     else
533         return FALSE;
534 }
535 static UINT_PTR CALLBACK OfnHookProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
536 {
537     static HWND hEncCombo;
538
539     switch (uMsg)
540     {
541     case WM_INITDIALOG:
542         {
543             ENCODING enc;
544             hEncCombo = GetDlgItem(hdlg, IDC_OFN_ENCCOMBO);
545             for (enc = MIN_ENCODING; enc <= MAX_ENCODING; enc++)
546             {
547                 WCHAR szEnc[MAX_STRING_LEN];
548                 load_encoding_name(enc, szEnc, ARRAY_SIZE(szEnc));
549                 SendMessageW(hEncCombo, CB_ADDSTRING, 0, (LPARAM)szEnc);
550             }
551             SendMessageW(hEncCombo, CB_SETCURSEL, (WPARAM)Globals.encOfnCombo, 0);
552         }
553         break;
554
555     case WM_COMMAND:
556         if (LOWORD(wParam) == IDC_OFN_ENCCOMBO &&
557             HIWORD(wParam) == CBN_SELCHANGE)
558         {
559             int index = SendMessageW(hEncCombo, CB_GETCURSEL, 0, 0);
560             Globals.encOfnCombo = index==CB_ERR ? ENCODING_ANSI : (ENCODING)index;
561         }
562
563         break;
564
565     case WM_NOTIFY:
566         switch (((OFNOTIFYW*)lParam)->hdr.code)
567         {
568             case CDN_SELCHANGE:
569                 if (Globals.bOfnIsOpenDialog)
570                 {
571                     /* Check the start of the selected file for a BOM. */
572                     ENCODING enc;
573                     WCHAR szFileName[MAX_PATH];
574                     SendMessageW(GetParent(hdlg), CDM_GETFILEPATH,
575                                  ARRAY_SIZE(szFileName), (LPARAM)szFileName);
576                     enc = detect_encoding_of_file(szFileName);
577                     if (enc != ENCODING_AUTO)
578                     {
579                         Globals.encOfnCombo = enc;
580                         SendMessageW(hEncCombo, CB_SETCURSEL, (WPARAM)enc, 0);
581                     }
582                 }
583                 break;
584
585             default:
586                 break;
587         }
588         break;
589
590     default:
591         break;
592     }
593     return 0;
594 }
595
596 VOID DIALOG_FileOpen(VOID)
597 {
598     OPENFILENAMEW openfilename;
599     WCHAR szPath[MAX_PATH];
600     WCHAR szDir[MAX_PATH];
601     static const WCHAR szDefaultExt[] = { 't','x','t',0 };
602     static const WCHAR txt_files[] = { '*','.','t','x','t',0 };
603
604     ZeroMemory(&openfilename, sizeof(openfilename));
605
606     GetCurrentDirectoryW(ARRAY_SIZE(szDir), szDir);
607     lstrcpyW(szPath, txt_files);
608
609     openfilename.lStructSize       = sizeof(openfilename);
610     openfilename.hwndOwner         = Globals.hMainWnd;
611     openfilename.hInstance         = Globals.hInstance;
612     openfilename.lpstrFilter       = Globals.szFilter;
613     openfilename.lpstrFile         = szPath;
614     openfilename.nMaxFile          = ARRAY_SIZE(szPath);
615     openfilename.lpstrInitialDir   = szDir;
616     openfilename.Flags = OFN_ENABLETEMPLATE | OFN_ENABLEHOOK | OFN_EXPLORER |
617                          OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST |
618                          OFN_HIDEREADONLY | OFN_ENABLESIZING;
619     openfilename.lpfnHook          = OfnHookProc;
620     openfilename.lpTemplateName    = MAKEINTRESOURCEW(IDD_OFN_TEMPLATE);
621     openfilename.lpstrDefExt       = szDefaultExt;
622
623     Globals.encOfnCombo = ENCODING_ANSI;
624     Globals.bOfnIsOpenDialog = TRUE;
625
626     if (GetOpenFileNameW(&openfilename))
627         DoOpenFile(openfilename.lpstrFile, Globals.encOfnCombo);
628 }
629
630 /* Return FALSE to cancel close */
631 BOOL DIALOG_FileSave(VOID)
632 {
633     if (Globals.szFileName[0] == '\0')
634         return DIALOG_FileSaveAs();
635     else
636     {
637         switch (DoSaveFile(Globals.szFileName, Globals.encFile))
638         {
639             case SAVED_OK:           return TRUE;
640             case SHOW_SAVEAS_DIALOG: return DIALOG_FileSaveAs();
641             default:                 return FALSE;
642         }
643     }
644 }
645
646 BOOL DIALOG_FileSaveAs(VOID)
647 {
648     OPENFILENAMEW saveas;
649     WCHAR szPath[MAX_PATH];
650     WCHAR szDir[MAX_PATH];
651     static const WCHAR szDefaultExt[] = { 't','x','t',0 };
652     static const WCHAR txt_files[] = { '*','.','t','x','t',0 };
653
654     ZeroMemory(&saveas, sizeof(saveas));
655
656     GetCurrentDirectoryW(ARRAY_SIZE(szDir), szDir);
657     lstrcpyW(szPath, txt_files);
658
659     saveas.lStructSize       = sizeof(OPENFILENAMEW);
660     saveas.hwndOwner         = Globals.hMainWnd;
661     saveas.hInstance         = Globals.hInstance;
662     saveas.lpstrFilter       = Globals.szFilter;
663     saveas.lpstrFile         = szPath;
664     saveas.nMaxFile          = ARRAY_SIZE(szPath);
665     saveas.lpstrInitialDir   = szDir;
666     saveas.Flags          = OFN_ENABLETEMPLATE | OFN_ENABLEHOOK | OFN_EXPLORER |
667                             OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT |
668                             OFN_HIDEREADONLY | OFN_ENABLESIZING;
669     saveas.lpfnHook          = OfnHookProc;
670     saveas.lpTemplateName    = MAKEINTRESOURCEW(IDD_OFN_TEMPLATE);
671     saveas.lpstrDefExt       = szDefaultExt;
672
673     /* Preset encoding to what file was opened/saved last with. */
674     Globals.encOfnCombo = Globals.encFile;
675     Globals.bOfnIsOpenDialog = FALSE;
676
677 retry:
678     if (!GetSaveFileNameW(&saveas))
679         return FALSE;
680
681     switch (DoSaveFile(szPath, Globals.encOfnCombo))
682     {
683         case SAVED_OK:
684             SetFileNameAndEncoding(szPath, Globals.encOfnCombo);
685             UpdateWindowCaption();
686             return TRUE;
687
688         case SHOW_SAVEAS_DIALOG:
689             goto retry;
690
691         default:
692             return FALSE;
693     }
694 }
695
696 typedef struct {
697     LPWSTR mptr;
698     LPWSTR mend;
699     LPWSTR lptr;
700     DWORD len;
701 } TEXTINFO, *LPTEXTINFO;
702
703 static int notepad_print_header(HDC hdc, RECT *rc, BOOL dopage, BOOL header, int page, LPWSTR text)
704 {
705     SIZE szMetric;
706
707     if (*text)
708     {
709         /* Write the header or footer */
710         GetTextExtentPoint32W(hdc, text, lstrlenW(text), &szMetric);
711         if (dopage)
712             ExtTextOutW(hdc, (rc->left + rc->right - szMetric.cx) / 2,
713                         header ? rc->top : rc->bottom - szMetric.cy,
714                         ETO_CLIPPED, rc, text, lstrlenW(text), NULL);
715         return 1;
716     }
717     return 0;
718 }
719
720 static BOOL notepad_print_page(HDC hdc, RECT *rc, BOOL dopage, int page, LPTEXTINFO tInfo)
721 {
722     int b, y;
723     TEXTMETRICW tm;
724     SIZE szMetrics;
725
726     if (dopage)
727     {
728         if (StartPage(hdc) <= 0)
729         {
730             static const WCHAR failedW[] = { 'S','t','a','r','t','P','a','g','e',' ','f','a','i','l','e','d',0 };
731             static const WCHAR errorW[] = { 'P','r','i','n','t',' ','E','r','r','o','r',0 };
732             MessageBoxW(Globals.hMainWnd, failedW, errorW, MB_ICONEXCLAMATION);
733             return FALSE;
734         }
735     }
736
737     GetTextMetricsW(hdc, &tm);
738     y = rc->top + notepad_print_header(hdc, rc, dopage, TRUE, page, Globals.szFileName) * tm.tmHeight;
739     b = rc->bottom - 2 * notepad_print_header(hdc, rc, FALSE, FALSE, page, Globals.szFooter) * tm.tmHeight;
740
741     do {
742         INT m, n;
743
744         if (!tInfo->len)
745         {
746             /* find the end of the line */
747             while (tInfo->mptr < tInfo->mend && *tInfo->mptr != '\n' && *tInfo->mptr != '\r')
748             {
749                 if (*tInfo->mptr == '\t')
750                 {
751                     /* replace tabs with spaces */
752                     for (m = 0; m < SPACES_IN_TAB; m++)
753                     {
754                         if (tInfo->len < PRINT_LEN_MAX)
755                             tInfo->lptr[tInfo->len++] = ' ';
756                         else if (Globals.bWrapLongLines)
757                             break;
758                     }
759                 }
760                 else if (tInfo->len < PRINT_LEN_MAX)
761                     tInfo->lptr[tInfo->len++] = *tInfo->mptr;
762
763                 if (tInfo->len >= PRINT_LEN_MAX && Globals.bWrapLongLines)
764                      break;
765
766                 tInfo->mptr++;
767             }
768         }
769
770         /* Find out how much we should print if line wrapping is enabled */
771         if (Globals.bWrapLongLines)
772         {
773             GetTextExtentExPointW(hdc, tInfo->lptr, tInfo->len, rc->right - rc->left, &n, NULL, &szMetrics);
774             if (n < tInfo->len && tInfo->lptr[n] != ' ')
775             {
776                 m = n;
777                 /* Don't wrap words unless it's a single word over the entire line */
778                 while (m  && tInfo->lptr[m] != ' ') m--;
779                 if (m > 0) n = m + 1;
780             }
781         }
782         else
783             n = tInfo->len;
784
785         if (dopage)
786             ExtTextOutW(hdc, rc->left, y, ETO_CLIPPED, rc, tInfo->lptr, n, NULL);
787
788         tInfo->len -= n;
789
790         if (tInfo->len)
791         {
792             memcpy(tInfo->lptr, tInfo->lptr + n, tInfo->len * sizeof(WCHAR));
793             y += tm.tmHeight + tm.tmExternalLeading;
794         }
795         else
796         {
797             /* find the next line */
798             while (tInfo->mptr < tInfo->mend && y < b && (*tInfo->mptr == '\n' || *tInfo->mptr == '\r'))
799             {
800                 if (*tInfo->mptr == '\n')
801                     y += tm.tmHeight + tm.tmExternalLeading;
802                 tInfo->mptr++;
803             }
804         }
805     } while (tInfo->mptr < tInfo->mend && y < b);
806
807     notepad_print_header(hdc, rc, dopage, FALSE, page, Globals.szFooter);
808     if (dopage)
809     {
810         EndPage(hdc);
811     }
812     return TRUE;
813 }
814
815 VOID DIALOG_FilePrint(VOID)
816 {
817     DOCINFOW di;
818     PRINTDLGW printer;
819     int page, dopage, copy;
820     LOGFONTW lfFont;
821     HFONT hTextFont, old_font = 0;
822     DWORD size;
823     BOOL ret = FALSE;
824     RECT rc;
825     LPWSTR pTemp;
826     TEXTINFO tInfo;
827     WCHAR cTemp[PRINT_LEN_MAX];
828
829     /* Get Current Settings */
830     ZeroMemory(&printer, sizeof(printer));
831     printer.lStructSize           = sizeof(printer);
832     printer.hwndOwner             = Globals.hMainWnd;
833     printer.hDevMode              = Globals.hDevMode;
834     printer.hDevNames             = Globals.hDevNames;
835     printer.hInstance             = Globals.hInstance;
836
837     /* Set some default flags */
838     printer.Flags                 = PD_RETURNDC | PD_NOSELECTION;
839     printer.nFromPage             = 0;
840     printer.nMinPage              = 1;
841     /* we really need to calculate number of pages to set nMaxPage and nToPage */
842     printer.nToPage               = 0;
843     printer.nMaxPage              = -1;
844     /* Let commdlg manage copy settings */
845     printer.nCopies               = (WORD)PD_USEDEVMODECOPIES;
846
847     if (!PrintDlgW(&printer)) return;
848
849     Globals.hDevMode = printer.hDevMode;
850     Globals.hDevNames = printer.hDevNames;
851
852     SetMapMode(printer.hDC, MM_TEXT);
853
854     /* initialize DOCINFO */
855     di.cbSize = sizeof(DOCINFOW);
856     di.lpszDocName = Globals.szFileTitle;
857     di.lpszOutput = NULL;
858     di.lpszDatatype = NULL;
859     di.fwType = 0; 
860
861     if(printer.Flags & PD_PRINTTOFILE)
862     {
863         di.lpszOutput = dialog_print_to_file(printer.hwndOwner);
864         if(!di.lpszOutput)
865             return;
866     }
867
868     /* Get the file text */
869     size = GetWindowTextLengthW(Globals.hEdit) + 1;
870     pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
871     if (!pTemp)
872     {
873        DeleteDC(printer.hDC);
874        ShowLastError();
875        return;
876     }
877     size = GetWindowTextW(Globals.hEdit, pTemp, size);
878
879     if (StartDocW(printer.hDC, &di) > 0)
880     {
881         /* Get the page margins in pixels. */
882         rc.top =    MulDiv(Globals.iMarginTop, GetDeviceCaps(printer.hDC, LOGPIXELSY), 2540) -
883                     GetDeviceCaps(printer.hDC, PHYSICALOFFSETY);
884         rc.bottom = GetDeviceCaps(printer.hDC, PHYSICALHEIGHT) -
885                     MulDiv(Globals.iMarginBottom, GetDeviceCaps(printer.hDC, LOGPIXELSY), 2540);
886         rc.left =   MulDiv(Globals.iMarginLeft, GetDeviceCaps(printer.hDC, LOGPIXELSX), 2540) -
887                     GetDeviceCaps(printer.hDC, PHYSICALOFFSETX);
888         rc.right =  GetDeviceCaps(printer.hDC, PHYSICALWIDTH) -
889                     MulDiv(Globals.iMarginRight, GetDeviceCaps(printer.hDC, LOGPIXELSX), 2540);
890
891         /* Create a font for the printer resolution */
892         lfFont = Globals.lfFont;
893         lfFont.lfHeight = MulDiv(lfFont.lfHeight, GetDeviceCaps(printer.hDC, LOGPIXELSY), get_dpi());
894         /* Make the font a bit lighter */
895         lfFont.lfWeight -= 100;
896         hTextFont = CreateFontIndirectW(&lfFont);
897         old_font = SelectObject(printer.hDC, hTextFont);
898
899         for (copy = 1; copy <= printer.nCopies; copy++)
900         {
901             page = 1;
902
903             tInfo.mptr = pTemp;
904             tInfo.mend = pTemp + size;
905             tInfo.lptr = cTemp;
906             tInfo.len = 0;
907
908             do {
909                 if (printer.Flags & PD_PAGENUMS)
910                 {
911                     /* a specific range of pages is selected, so
912                      * skip pages that are not to be printed
913                      */
914                     if (page > printer.nToPage)
915                         break;
916                     else if (page >= printer.nFromPage)
917                         dopage = 1;
918                     else
919                         dopage = 0;
920                 }
921                 else
922                     dopage = 1;
923
924                 ret = notepad_print_page(printer.hDC, &rc, dopage, page, &tInfo);
925                 page++;
926             } while (ret && tInfo.mptr < tInfo.mend);
927
928             if (!ret) break;
929         }
930         EndDoc(printer.hDC);
931         SelectObject(printer.hDC, old_font);
932         DeleteObject(hTextFont);
933     }
934     DeleteDC(printer.hDC);
935     HeapFree(GetProcessHeap(), 0, pTemp);
936 }
937
938 VOID DIALOG_FilePrinterSetup(VOID)
939 {
940     PRINTDLGW printer;
941
942     ZeroMemory(&printer, sizeof(printer));
943     printer.lStructSize         = sizeof(printer);
944     printer.hwndOwner           = Globals.hMainWnd;
945     printer.hDevMode            = Globals.hDevMode;
946     printer.hDevNames           = Globals.hDevNames;
947     printer.hInstance           = Globals.hInstance;
948     printer.Flags               = PD_PRINTSETUP;
949     printer.nCopies             = 1;
950
951     PrintDlgW(&printer);
952
953     Globals.hDevMode = printer.hDevMode;
954     Globals.hDevNames = printer.hDevNames;
955 }
956
957 VOID DIALOG_FileExit(VOID)
958 {
959     PostMessageW(Globals.hMainWnd, WM_CLOSE, 0, 0l);
960 }
961
962 VOID DIALOG_EditUndo(VOID)
963 {
964     SendMessageW(Globals.hEdit, EM_UNDO, 0, 0);
965 }
966
967 VOID DIALOG_EditCut(VOID)
968 {
969     SendMessageW(Globals.hEdit, WM_CUT, 0, 0);
970 }
971
972 VOID DIALOG_EditCopy(VOID)
973 {
974     SendMessageW(Globals.hEdit, WM_COPY, 0, 0);
975 }
976
977 VOID DIALOG_EditPaste(VOID)
978 {
979     SendMessageW(Globals.hEdit, WM_PASTE, 0, 0);
980 }
981
982 VOID DIALOG_EditDelete(VOID)
983 {
984     SendMessageW(Globals.hEdit, WM_CLEAR, 0, 0);
985 }
986
987 VOID DIALOG_EditSelectAll(VOID)
988 {
989     SendMessageW(Globals.hEdit, EM_SETSEL, 0, -1);
990 }
991
992 VOID DIALOG_EditTimeDate(VOID)
993 {
994     SYSTEMTIME   st;
995     WCHAR        szDate[MAX_STRING_LEN];
996     static const WCHAR spaceW[] = { ' ',0 };
997
998     GetLocalTime(&st);
999
1000     GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, szDate, MAX_STRING_LEN);
1001     SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)szDate);
1002
1003     SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)spaceW);
1004
1005     GetDateFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, szDate, MAX_STRING_LEN);
1006     SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)szDate);
1007 }
1008
1009 VOID DIALOG_EditWrap(VOID)
1010 {
1011     BOOL modify = FALSE;
1012     static const WCHAR editW[] = { 'e','d','i','t',0 };
1013     DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL |
1014                     ES_AUTOVSCROLL | ES_MULTILINE;
1015     RECT rc;
1016     DWORD size;
1017     LPWSTR pTemp;
1018
1019     size = GetWindowTextLengthW(Globals.hEdit) + 1;
1020     pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
1021     if (!pTemp)
1022     {
1023         ShowLastError();
1024         return;
1025     }
1026     GetWindowTextW(Globals.hEdit, pTemp, size);
1027     modify = SendMessageW(Globals.hEdit, EM_GETMODIFY, 0, 0);
1028     DestroyWindow(Globals.hEdit);
1029     GetClientRect(Globals.hMainWnd, &rc);
1030     if( Globals.bWrapLongLines ) dwStyle |= WS_HSCROLL | ES_AUTOHSCROLL;
1031     Globals.hEdit = CreateWindowExW(WS_EX_CLIENTEDGE, editW, NULL, dwStyle,
1032                          0, 0, rc.right, rc.bottom, Globals.hMainWnd,
1033                          NULL, Globals.hInstance, NULL);
1034     SendMessageW(Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, FALSE);
1035     SetWindowTextW(Globals.hEdit, pTemp);
1036     SendMessageW(Globals.hEdit, EM_SETMODIFY, modify, 0);
1037     SetFocus(Globals.hEdit);
1038     HeapFree(GetProcessHeap(), 0, pTemp);
1039     
1040     Globals.bWrapLongLines = !Globals.bWrapLongLines;
1041     CheckMenuItem(GetMenu(Globals.hMainWnd), CMD_WRAP,
1042         MF_BYCOMMAND | (Globals.bWrapLongLines ? MF_CHECKED : MF_UNCHECKED));
1043 }
1044
1045 VOID DIALOG_SelectFont(VOID)
1046 {
1047     CHOOSEFONTW cf;
1048     LOGFONTW lf=Globals.lfFont;
1049
1050     ZeroMemory( &cf, sizeof(cf) );
1051     cf.lStructSize=sizeof(cf);
1052     cf.hwndOwner=Globals.hMainWnd;
1053     cf.lpLogFont=&lf;
1054     cf.Flags=CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT;
1055
1056     if( ChooseFontW(&cf) )
1057     {
1058         HFONT currfont=Globals.hFont;
1059
1060         Globals.hFont=CreateFontIndirectW( &lf );
1061         Globals.lfFont=lf;
1062         SendMessageW( Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, TRUE );
1063         if( currfont!=NULL )
1064             DeleteObject( currfont );
1065     }
1066 }
1067
1068 VOID DIALOG_Search(VOID)
1069 {
1070         /* Allow only one search/replace dialog to open */
1071         if(Globals.hFindReplaceDlg != NULL)
1072         {
1073             SetActiveWindow(Globals.hFindReplaceDlg);
1074             return;
1075         }
1076
1077         ZeroMemory(&Globals.find, sizeof(Globals.find));
1078         Globals.find.lStructSize      = sizeof(Globals.find);
1079         Globals.find.hwndOwner        = Globals.hMainWnd;
1080         Globals.find.hInstance        = Globals.hInstance;
1081         Globals.find.lpstrFindWhat    = Globals.szFindText;
1082         Globals.find.wFindWhatLen     = ARRAY_SIZE(Globals.szFindText);
1083         Globals.find.Flags            = FR_DOWN|FR_HIDEWHOLEWORD;
1084
1085         /* We only need to create the modal FindReplace dialog which will */
1086         /* notify us of incoming events using hMainWnd Window Messages    */
1087
1088         Globals.hFindReplaceDlg = FindTextW(&Globals.find);
1089         assert(Globals.hFindReplaceDlg !=0);
1090 }
1091
1092 VOID DIALOG_SearchNext(VOID)
1093 {
1094     if (Globals.lastFind.lpstrFindWhat == NULL)
1095         DIALOG_Search();
1096     else                /* use the last find data */
1097         NOTEPAD_DoFind(&Globals.lastFind);
1098 }
1099
1100 VOID DIALOG_Replace(VOID)
1101 {
1102         /* Allow only one search/replace dialog to open */
1103         if(Globals.hFindReplaceDlg != NULL)
1104         {
1105             SetActiveWindow(Globals.hFindReplaceDlg);
1106             return;
1107         }
1108
1109         ZeroMemory(&Globals.find, sizeof(Globals.find));
1110         Globals.find.lStructSize      = sizeof(Globals.find);
1111         Globals.find.hwndOwner        = Globals.hMainWnd;
1112         Globals.find.hInstance        = Globals.hInstance;
1113         Globals.find.lpstrFindWhat    = Globals.szFindText;
1114         Globals.find.wFindWhatLen     = ARRAY_SIZE(Globals.szFindText);
1115         Globals.find.lpstrReplaceWith = Globals.szReplaceText;
1116         Globals.find.wReplaceWithLen  = ARRAY_SIZE(Globals.szReplaceText);
1117         Globals.find.Flags            = FR_DOWN|FR_HIDEWHOLEWORD;
1118
1119         /* We only need to create the modal FindReplace dialog which will */
1120         /* notify us of incoming events using hMainWnd Window Messages    */
1121
1122         Globals.hFindReplaceDlg = ReplaceTextW(&Globals.find);
1123         assert(Globals.hFindReplaceDlg !=0);
1124 }
1125
1126 VOID DIALOG_HelpContents(VOID)
1127 {
1128     WinHelpW(Globals.hMainWnd, helpfileW, HELP_INDEX, 0);
1129 }
1130
1131 VOID DIALOG_HelpSearch(VOID)
1132 {
1133         /* Search Help */
1134 }
1135
1136 VOID DIALOG_HelpHelp(VOID)
1137 {
1138     WinHelpW(Globals.hMainWnd, helpfileW, HELP_HELPONHELP, 0);
1139 }
1140
1141 VOID DIALOG_HelpAboutNotepad(VOID)
1142 {
1143     static const WCHAR notepadW[] = { 'W','i','n','e',' ','N','o','t','e','p','a','d',0 };
1144     WCHAR szNotepad[MAX_STRING_LEN];
1145     HICON icon = LoadImageW(Globals.hInstance, MAKEINTRESOURCEW(IDI_NOTEPAD),
1146                             IMAGE_ICON, 48, 48, LR_SHARED);
1147
1148     LoadStringW(Globals.hInstance, STRING_NOTEPAD, szNotepad, ARRAY_SIZE(szNotepad));
1149     ShellAboutW(Globals.hMainWnd, szNotepad, notepadW, icon);
1150 }
1151
1152
1153 /***********************************************************************
1154  *
1155  *           DIALOG_FilePageSetup
1156  */
1157 VOID DIALOG_FilePageSetup(void)
1158 {
1159     DialogBoxW(Globals.hInstance, MAKEINTRESOURCEW(DIALOG_PAGESETUP),
1160                Globals.hMainWnd, DIALOG_PAGESETUP_DlgProc);
1161 }
1162
1163
1164 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1165  *
1166  *           DIALOG_PAGESETUP_DlgProc
1167  */
1168
1169 static INT_PTR WINAPI DIALOG_PAGESETUP_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
1170 {
1171
1172    switch (msg)
1173     {
1174     case WM_COMMAND:
1175       switch (wParam)
1176         {
1177         case IDOK:
1178           /* save user input and close dialog */
1179           GetDlgItemTextW(hDlg, IDC_PAGESETUP_HEADERVALUE, Globals.szHeader, ARRAY_SIZE(Globals.szHeader));
1180           GetDlgItemTextW(hDlg, IDC_PAGESETUP_FOOTERVALUE, Globals.szFooter, ARRAY_SIZE(Globals.szFooter));
1181
1182           Globals.iMarginTop = GetDlgItemInt(hDlg, IDC_PAGESETUP_TOPVALUE, NULL, FALSE) * 100;
1183           Globals.iMarginBottom = GetDlgItemInt(hDlg, IDC_PAGESETUP_BOTTOMVALUE, NULL, FALSE) * 100;
1184           Globals.iMarginLeft = GetDlgItemInt(hDlg, IDC_PAGESETUP_LEFTVALUE, NULL, FALSE) * 100;
1185           Globals.iMarginRight = GetDlgItemInt(hDlg, IDC_PAGESETUP_RIGHTVALUE, NULL, FALSE) * 100;
1186           EndDialog(hDlg, IDOK);
1187           return TRUE;
1188
1189         case IDCANCEL:
1190           /* discard user input and close dialog */
1191           EndDialog(hDlg, IDCANCEL);
1192           return TRUE;
1193
1194         case IDHELP:
1195         {
1196           /* FIXME: Bring this to work */
1197           static const WCHAR sorryW[] = { 'S','o','r','r','y',',',' ','n','o',' ','h','e','l','p',' ','a','v','a','i','l','a','b','l','e',0 };
1198           static const WCHAR helpW[] = { 'H','e','l','p',0 };
1199           MessageBoxW(Globals.hMainWnd, sorryW, helpW, MB_ICONEXCLAMATION);
1200           return TRUE;
1201         }
1202
1203         default:
1204             break;
1205         }
1206       break;
1207
1208     case WM_INITDIALOG:
1209        /* fetch last user input prior to display dialog */
1210        SetDlgItemTextW(hDlg, IDC_PAGESETUP_HEADERVALUE, Globals.szHeader);
1211        SetDlgItemTextW(hDlg, IDC_PAGESETUP_FOOTERVALUE, Globals.szFooter);
1212        SetDlgItemInt(hDlg, IDC_PAGESETUP_TOPVALUE, Globals.iMarginTop / 100, FALSE);
1213        SetDlgItemInt(hDlg, IDC_PAGESETUP_BOTTOMVALUE, Globals.iMarginBottom / 100, FALSE);
1214        SetDlgItemInt(hDlg, IDC_PAGESETUP_LEFTVALUE, Globals.iMarginLeft / 100, FALSE);
1215        SetDlgItemInt(hDlg, IDC_PAGESETUP_RIGHTVALUE, Globals.iMarginRight / 100, FALSE);
1216        break;
1217     }
1218
1219   return FALSE;
1220 }