user32/tests: Fix some window test failures on various Windows platforms.
[wine] / programs / wordpad / wordpad.c
1 /*
2  * Wordpad implementation
3  *
4  * Copyright 2004 by Krzysztof Foltman
5  * Copyright 2007-2008 by Alexander N. Sørnes <alex@thehandofagony.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #define WIN32_LEAN_AND_MEAN
23 #define _WIN32_IE 0x0400
24
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <stdio.h>
29 #include <assert.h>
30
31 #include <windows.h>
32 #include <richedit.h>
33 #include <commctrl.h>
34 #include <commdlg.h>
35 #include <shellapi.h>
36 #include <math.h>
37 #include <errno.h>
38
39 #include "wine/unicode.h"
40 #include "wordpad.h"
41
42 #ifdef NONAMELESSUNION
43 # define U(x)  (x).u
44 # define U2(x) (x).u2
45 # define U3(x) (x).u3
46 #else
47 # define U(x)  (x)
48 # define U2(x) (x)
49 # define U3(x) (x)
50 #endif
51
52 /* use LoadString */
53 static const WCHAR wszAppTitle[] = {'W','i','n','e',' ','W','o','r','d','p','a','d',0};
54
55 static const WCHAR wszRichEditClass[] = {'R','I','C','H','E','D','I','T','2','0','W',0};
56 static const WCHAR wszMainWndClass[] = {'W','O','R','D','P','A','D','T','O','P',0};
57
58 static const WCHAR stringFormat[] = {'%','2','d','\0'};
59
60 static HWND hMainWnd;
61 static HWND hEditorWnd;
62 static HWND hFindWnd;
63 static HMENU hPopupMenu;
64
65 static UINT ID_FINDMSGSTRING;
66
67 static DWORD wordWrap[2];
68 static DWORD barState[2];
69 static WPARAM fileFormat = SF_RTF;
70
71 static WCHAR wszFileName[MAX_PATH];
72 static WCHAR wszFilter[MAX_STRING_LEN*4+6*3+5];
73 static WCHAR wszDefaultFileName[MAX_STRING_LEN];
74 static WCHAR wszSaveChanges[MAX_STRING_LEN];
75 static WCHAR units_cmW[MAX_STRING_LEN];
76
77 static char units_cmA[MAX_STRING_LEN];
78
79 static LRESULT OnSize( HWND hWnd, WPARAM wParam, LPARAM lParam );
80
81 /* Load string resources */
82 static void DoLoadStrings(void)
83 {
84     LPWSTR p = wszFilter;
85     static const WCHAR files_rtf[] = {'*','.','r','t','f','\0'};
86     static const WCHAR files_txt[] = {'*','.','t','x','t','\0'};
87     static const WCHAR files_all[] = {'*','.','*','\0'};
88
89     HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hMainWnd, GWLP_HINSTANCE);
90
91     LoadStringW(hInstance, STRING_RICHTEXT_FILES_RTF, p, MAX_STRING_LEN);
92     p += lstrlenW(p) + 1;
93     lstrcpyW(p, files_rtf);
94     p += lstrlenW(p) + 1;
95     LoadStringW(hInstance, STRING_TEXT_FILES_TXT, p, MAX_STRING_LEN);
96     p += lstrlenW(p) + 1;
97     lstrcpyW(p, files_txt);
98     p += lstrlenW(p) + 1;
99     LoadStringW(hInstance, STRING_TEXT_FILES_UNICODE_TXT, p, MAX_STRING_LEN);
100     p += lstrlenW(p) + 1;
101     lstrcpyW(p, files_txt);
102     p += lstrlenW(p) + 1;
103     LoadStringW(hInstance, STRING_ALL_FILES, p, MAX_STRING_LEN);
104     p += lstrlenW(p) + 1;
105     lstrcpyW(p, files_all);
106     p += lstrlenW(p) + 1;
107     *p = '\0';
108
109     p = wszDefaultFileName;
110     LoadStringW(hInstance, STRING_DEFAULT_FILENAME, p, MAX_STRING_LEN);
111
112     p = wszSaveChanges;
113     LoadStringW(hInstance, STRING_PROMPT_SAVE_CHANGES, p, MAX_STRING_LEN);
114
115     LoadStringA(hInstance, STRING_UNITS_CM, units_cmA, MAX_STRING_LEN);
116     LoadStringW(hInstance, STRING_UNITS_CM, units_cmW, MAX_STRING_LEN);
117 }
118
119 /* Show a message box with resource strings */
120 static int MessageBoxWithResStringW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
121 {
122     MSGBOXPARAMSW params;
123
124     params.cbSize             = sizeof(params);
125     params.hwndOwner          = hWnd;
126     params.hInstance          = GetModuleHandleW(0);
127     params.lpszText           = lpText;
128     params.lpszCaption        = lpCaption;
129     params.dwStyle            = uType;
130     params.lpszIcon           = NULL;
131     params.dwContextHelpId    = 0;
132     params.lpfnMsgBoxCallback = NULL;
133     params.dwLanguageId       = 0;
134     return MessageBoxIndirectW(&params);
135 }
136
137
138 static void AddButton(HWND hwndToolBar, int nImage, int nCommand)
139 {
140     TBBUTTON button;
141
142     ZeroMemory(&button, sizeof(button));
143     button.iBitmap = nImage;
144     button.idCommand = nCommand;
145     button.fsState = TBSTATE_ENABLED;
146     button.fsStyle = TBSTYLE_BUTTON;
147     button.dwData = 0;
148     button.iString = -1;
149     SendMessageW(hwndToolBar, TB_ADDBUTTONSW, 1, (LPARAM)&button);
150 }
151
152 static void AddSeparator(HWND hwndToolBar)
153 {
154     TBBUTTON button;
155
156     ZeroMemory(&button, sizeof(button));
157     button.iBitmap = -1;
158     button.idCommand = 0;
159     button.fsState = 0;
160     button.fsStyle = TBSTYLE_SEP;
161     button.dwData = 0;
162     button.iString = -1;
163     SendMessageW(hwndToolBar, TB_ADDBUTTONSW, 1, (LPARAM)&button);
164 }
165
166 static DWORD CALLBACK stream_in(DWORD_PTR cookie, LPBYTE buffer, LONG cb, LONG *pcb)
167 {
168     HANDLE hFile = (HANDLE)cookie;
169     DWORD read;
170
171     if(!ReadFile(hFile, buffer, cb, &read, 0))
172         return 1;
173
174     *pcb = read;
175
176     return 0;
177 }
178
179 static DWORD CALLBACK stream_out(DWORD_PTR cookie, LPBYTE buffer, LONG cb, LONG *pcb)
180 {
181     DWORD written;
182     int ret;
183     HANDLE hFile = (HANDLE)cookie;
184
185     ret = WriteFile(hFile, buffer, cb, &written, 0);
186
187     if(!ret || (cb != written))
188         return 1;
189
190     *pcb = cb;
191
192     return 0;
193 }
194
195 LPWSTR file_basename(LPWSTR path)
196 {
197     LPWSTR pos = path + lstrlenW(path);
198
199     while(pos > path)
200     {
201         if(*pos == '\\' || *pos == '/')
202         {
203             pos++;
204             break;
205         }
206         pos--;
207     }
208     return pos;
209 }
210
211 static void set_caption(LPCWSTR wszNewFileName)
212 {
213     static const WCHAR wszSeparator[] = {' ','-',' '};
214     WCHAR *wszCaption;
215     SIZE_T length = 0;
216
217     if(!wszNewFileName)
218         wszNewFileName = wszDefaultFileName;
219     else
220         wszNewFileName = file_basename((LPWSTR)wszNewFileName);
221
222     wszCaption = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
223                 lstrlenW(wszNewFileName)*sizeof(WCHAR)+sizeof(wszSeparator)+sizeof(wszAppTitle));
224
225     if(!wszCaption)
226         return;
227
228     memcpy(wszCaption, wszNewFileName, lstrlenW(wszNewFileName)*sizeof(WCHAR));
229     length += lstrlenW(wszNewFileName);
230     memcpy(wszCaption + length, wszSeparator, sizeof(wszSeparator));
231     length += sizeof(wszSeparator) / sizeof(WCHAR);
232     memcpy(wszCaption + length, wszAppTitle, sizeof(wszAppTitle));
233
234     SetWindowTextW(hMainWnd, wszCaption);
235
236     HeapFree(GetProcessHeap(), 0, wszCaption);
237 }
238
239 static BOOL validate_endptr(LPCSTR endptr, BOOL units)
240 {
241     if(!endptr)
242         return FALSE;
243     if(!*endptr)
244         return TRUE;
245
246     while(*endptr == ' ')
247         endptr++;
248
249     if(!units)
250         return *endptr == '\0';
251
252     /* FIXME: Allow other units and convert between them */
253     if(!lstrcmpA(endptr, units_cmA))
254         endptr += 2;
255
256     return *endptr == '\0';
257 }
258
259 static BOOL number_from_string(LPCWSTR string, float *num, BOOL units)
260 {
261     double ret;
262     char buffer[MAX_STRING_LEN];
263     char *endptr = buffer;
264
265     WideCharToMultiByte(CP_ACP, 0, string, -1, buffer, MAX_STRING_LEN, NULL, NULL);
266     *num = 0;
267     errno = 0;
268     ret = strtod(buffer, &endptr);
269
270     if((ret == 0 && errno != 0) || endptr == buffer || !validate_endptr(endptr, units))
271     {
272         return FALSE;
273     } else
274     {
275         *num = (float)ret;
276         return TRUE;
277     }
278 }
279
280 static void set_size(float size)
281 {
282     CHARFORMAT2W fmt;
283
284     ZeroMemory(&fmt, sizeof(fmt));
285     fmt.cbSize = sizeof(fmt);
286     fmt.dwMask = CFM_SIZE;
287     fmt.yHeight = (int)(size * 20.0);
288     SendMessageW(hEditorWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
289 }
290
291 static void on_sizelist_modified(HWND hwndSizeList, LPWSTR wszNewFontSize)
292 {
293     WCHAR sizeBuffer[MAX_STRING_LEN];
294     CHARFORMAT2W format;
295
296     ZeroMemory(&format, sizeof(format));
297     format.cbSize = sizeof(format);
298     SendMessageW(hEditorWnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&format);
299
300     wsprintfW(sizeBuffer, stringFormat, format.yHeight / 20);
301     if(lstrcmpW(sizeBuffer, wszNewFontSize))
302     {
303         float size = 0;
304         if(number_from_string(wszNewFontSize, &size, FALSE)
305            && size > 0)
306         {
307             set_size(size);
308         } else
309         {
310             SetWindowTextW(hwndSizeList, sizeBuffer);
311             MessageBoxWithResStringW(hMainWnd, MAKEINTRESOURCEW(STRING_INVALID_NUMBER),
312                         wszAppTitle, MB_OK | MB_ICONINFORMATION);
313         }
314     }
315 }
316
317 static void add_size(HWND hSizeListWnd, unsigned size)
318 {
319     WCHAR buffer[3];
320     COMBOBOXEXITEMW cbItem;
321     cbItem.mask = CBEIF_TEXT;
322     cbItem.iItem = -1;
323
324     wsprintfW(buffer, stringFormat, size);
325     cbItem.pszText = buffer;
326     SendMessageW(hSizeListWnd, CBEM_INSERTITEMW, 0, (LPARAM)&cbItem);
327 }
328
329 static void populate_size_list(HWND hSizeListWnd)
330 {
331     HWND hReBarWnd = GetDlgItem(hMainWnd, IDC_REBAR);
332     HWND hFontListWnd = GetDlgItem(hReBarWnd, IDC_FONTLIST);
333     COMBOBOXEXITEMW cbFontItem;
334     CHARFORMAT2W fmt;
335     HWND hListEditWnd = (HWND)SendMessageW(hSizeListWnd, CBEM_GETEDITCONTROL, 0, 0);
336     HDC hdc = GetDC(hMainWnd);
337     static const unsigned choices[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
338     WCHAR buffer[3];
339     size_t i;
340     DWORD fontStyle;
341
342     ZeroMemory(&fmt, sizeof(fmt));
343     fmt.cbSize = sizeof(fmt);
344     SendMessageW(hEditorWnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
345
346     cbFontItem.mask = CBEIF_LPARAM;
347     cbFontItem.iItem = SendMessageW(hFontListWnd, CB_FINDSTRINGEXACT, -1, (LPARAM)fmt.szFaceName);
348     SendMessageW(hFontListWnd, CBEM_GETITEMW, 0, (LPARAM)&cbFontItem);
349
350     fontStyle = (DWORD)LOWORD(cbFontItem.lParam);
351
352     SendMessageW(hSizeListWnd, CB_RESETCONTENT, 0, 0);
353
354     if((fontStyle & RASTER_FONTTYPE) && cbFontItem.iItem)
355     {
356         add_size(hSizeListWnd, (BYTE)MulDiv(HIWORD(cbFontItem.lParam), 72,
357                                GetDeviceCaps(hdc, LOGPIXELSY)));
358     } else
359     {
360         for(i = 0; i < sizeof(choices)/sizeof(choices[0]); i++)
361             add_size(hSizeListWnd, choices[i]);
362     }
363
364     wsprintfW(buffer, stringFormat, fmt.yHeight / 20);
365     SendMessageW(hListEditWnd, WM_SETTEXT, 0, (LPARAM)buffer);
366 }
367
368 static void update_size_list(void)
369 {
370     HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR);
371     HWND hwndSizeList = GetDlgItem(hReBar, IDC_SIZELIST);
372     HWND hwndSizeListEdit = (HWND)SendMessageW(hwndSizeList, CBEM_GETEDITCONTROL, 0, 0);
373     WCHAR fontSize[MAX_STRING_LEN], sizeBuffer[MAX_STRING_LEN];
374     CHARFORMAT2W fmt;
375
376     ZeroMemory(&fmt, sizeof(fmt));
377     fmt.cbSize = sizeof(fmt);
378
379     SendMessageW(hEditorWnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
380
381     SendMessageW(hwndSizeListEdit, WM_GETTEXT, MAX_PATH, (LPARAM)fontSize);
382     wsprintfW(sizeBuffer, stringFormat, fmt.yHeight / 20);
383
384     if(lstrcmpW(fontSize, sizeBuffer))
385         SendMessageW(hwndSizeListEdit, WM_SETTEXT, 0, (LPARAM)sizeBuffer);
386 }
387
388 static void update_font_list(void)
389 {
390     HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR);
391     HWND hFontList = GetDlgItem(hReBar, IDC_FONTLIST);
392     HWND hFontListEdit = (HWND)SendMessageW(hFontList, CBEM_GETEDITCONTROL, 0, 0);
393     WCHAR fontName[MAX_STRING_LEN];
394     CHARFORMAT2W fmt;
395
396     ZeroMemory(&fmt, sizeof(fmt));
397     fmt.cbSize = sizeof(fmt);
398
399     SendMessageW(hEditorWnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
400     if (!SendMessageW(hFontListEdit, WM_GETTEXT, MAX_PATH, (LPARAM)fontName)) return;
401
402     if(lstrcmpW(fontName, fmt.szFaceName))
403     {
404         SendMessageW(hFontListEdit, WM_SETTEXT, 0, (LPARAM)fmt.szFaceName);
405         populate_size_list(GetDlgItem(hReBar, IDC_SIZELIST));
406     } else
407     {
408         update_size_list();
409     }
410 }
411
412 static void clear_formatting(void)
413 {
414     PARAFORMAT2 pf;
415
416     pf.cbSize = sizeof(pf);
417     pf.dwMask = PFM_ALIGNMENT;
418     pf.wAlignment = PFA_LEFT;
419     SendMessageW(hEditorWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
420 }
421
422 static int fileformat_number(WPARAM format)
423 {
424     int number = 0;
425
426     if(format == SF_TEXT)
427     {
428         number = 1;
429     } else if (format == (SF_TEXT | SF_UNICODE))
430     {
431         number = 2;
432     }
433     return number;
434 }
435
436 static WPARAM fileformat_flags(int format)
437 {
438     WPARAM flags[] = { SF_RTF , SF_TEXT , SF_TEXT | SF_UNICODE };
439
440     return flags[format];
441 }
442
443 static void set_font(LPCWSTR wszFaceName)
444 {
445     HWND hReBarWnd = GetDlgItem(hMainWnd, IDC_REBAR);
446     HWND hSizeListWnd = GetDlgItem(hReBarWnd, IDC_SIZELIST);
447     HWND hFontListWnd = GetDlgItem(hReBarWnd, IDC_FONTLIST);
448     HWND hFontListEditWnd = (HWND)SendMessageW(hFontListWnd, CBEM_GETEDITCONTROL, 0, 0);
449     CHARFORMAT2W fmt;
450
451     ZeroMemory(&fmt, sizeof(fmt));
452
453     fmt.cbSize = sizeof(fmt);
454     fmt.dwMask = CFM_FACE;
455
456     lstrcpyW(fmt.szFaceName, wszFaceName);
457
458     SendMessageW(hEditorWnd, EM_SETCHARFORMAT,  SCF_SELECTION, (LPARAM)&fmt);
459
460     populate_size_list(hSizeListWnd);
461
462     SendMessageW(hFontListEditWnd, WM_SETTEXT, 0, (LPARAM)wszFaceName);
463 }
464
465 static void set_default_font(void)
466 {
467     static const WCHAR richTextFont[] = {'T','i','m','e','s',' ','N','e','w',' ',
468                                          'R','o','m','a','n',0};
469     static const WCHAR plainTextFont[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
470     CHARFORMAT2W fmt;
471     LPCWSTR font;
472
473     ZeroMemory(&fmt, sizeof(fmt));
474
475     fmt.cbSize = sizeof(fmt);
476     fmt.dwMask = CFM_FACE | CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE;
477     fmt.dwEffects = 0;
478
479     if(fileFormat & SF_RTF)
480         font = richTextFont;
481     else
482         font = plainTextFont;
483
484     lstrcpyW(fmt.szFaceName, font);
485
486     SendMessageW(hEditorWnd, EM_SETCHARFORMAT,  SCF_DEFAULT, (LPARAM)&fmt);
487 }
488
489 static void on_fontlist_modified(LPWSTR wszNewFaceName)
490 {
491     CHARFORMAT2W format;
492     ZeroMemory(&format, sizeof(format));
493     format.cbSize = sizeof(format);
494     SendMessageW(hEditorWnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&format);
495
496     if(lstrcmpW(format.szFaceName, wszNewFaceName))
497         set_font(wszNewFaceName);
498 }
499
500 static void add_font(LPCWSTR fontName, DWORD fontType, HWND hListWnd, const NEWTEXTMETRICEXW *ntmc)
501 {
502     COMBOBOXEXITEMW cbItem;
503     WCHAR buffer[MAX_PATH];
504     int fontHeight = 0;
505
506     cbItem.mask = CBEIF_TEXT;
507     cbItem.pszText = buffer;
508     cbItem.cchTextMax = MAX_STRING_LEN;
509     cbItem.iItem = 0;
510
511     while(SendMessageW(hListWnd, CBEM_GETITEMW, 0, (LPARAM)&cbItem))
512     {
513         if(lstrcmpiW(cbItem.pszText, fontName) <= 0)
514             cbItem.iItem++;
515         else
516             break;
517     }
518     cbItem.pszText = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(fontName) + 1)*sizeof(WCHAR) );
519     lstrcpyW( cbItem.pszText, fontName );
520
521     cbItem.mask |= CBEIF_LPARAM;
522     if(fontType & RASTER_FONTTYPE)
523         fontHeight = ntmc->ntmTm.tmHeight - ntmc->ntmTm.tmInternalLeading;
524
525     cbItem.lParam = MAKELONG(fontType,fontHeight);
526     SendMessageW(hListWnd, CBEM_INSERTITEMW, 0, (LPARAM)&cbItem);
527     HeapFree( GetProcessHeap(), 0, cbItem.pszText );
528 }
529
530 static void dialog_choose_font(void)
531 {
532     CHOOSEFONTW cf;
533     LOGFONTW lf;
534     CHARFORMAT2W fmt;
535     HDC hDC = GetDC(hMainWnd);
536
537     ZeroMemory(&cf, sizeof(cf));
538     cf.lStructSize = sizeof(cf);
539     cf.hwndOwner = hMainWnd;
540     cf.lpLogFont = &lf;
541     cf.Flags = CF_SCREENFONTS | CF_NOSCRIPTSEL | CF_INITTOLOGFONTSTRUCT | CF_EFFECTS;
542
543     ZeroMemory(&fmt, sizeof(fmt));
544     fmt.cbSize = sizeof(fmt);
545
546     SendMessageW(hEditorWnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
547     lstrcpyW(cf.lpLogFont->lfFaceName, fmt.szFaceName);
548     cf.lpLogFont->lfItalic = (fmt.dwEffects & CFE_ITALIC) ? TRUE : FALSE;
549     cf.lpLogFont->lfWeight = (fmt.dwEffects & CFE_BOLD) ? FW_BOLD : FW_NORMAL;
550     cf.lpLogFont->lfUnderline = (fmt.dwEffects & CFE_UNDERLINE) ? TRUE : FALSE;
551     cf.lpLogFont->lfStrikeOut = (fmt.dwEffects & CFE_STRIKEOUT) ? TRUE : FALSE;
552     cf.lpLogFont->lfHeight = -MulDiv(fmt.yHeight / 20, GetDeviceCaps(hDC, LOGPIXELSY), 72);
553     cf.rgbColors = fmt.crTextColor;
554
555     if(ChooseFontW(&cf))
556     {
557         ZeroMemory(&fmt, sizeof(fmt));
558         fmt.cbSize = sizeof(fmt);
559         fmt.dwMask = CFM_BOLD | CFM_ITALIC | CFM_SIZE | CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR;
560         fmt.yHeight = cf.iPointSize * 2;
561
562         if(cf.nFontType & BOLD_FONTTYPE)
563             fmt.dwEffects |= CFE_BOLD;
564         if(cf.nFontType & ITALIC_FONTTYPE)
565             fmt.dwEffects |= CFE_ITALIC;
566         if(cf.lpLogFont->lfUnderline == TRUE)
567             fmt.dwEffects |= CFE_UNDERLINE;
568         if(cf.lpLogFont->lfStrikeOut == TRUE)
569             fmt.dwEffects |= CFE_STRIKEOUT;
570
571         fmt.crTextColor = cf.rgbColors;
572
573         SendMessageW(hEditorWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
574         set_font(cf.lpLogFont->lfFaceName);
575     }
576 }
577
578
579 static int CALLBACK enum_font_proc(const LOGFONTW *lpelfe, const TEXTMETRICW *lpntme,
580                             DWORD FontType, LPARAM lParam)
581 {
582     HWND hListWnd = (HWND) lParam;
583
584     if(SendMessageW(hListWnd, CB_FINDSTRINGEXACT, -1, (LPARAM)lpelfe->lfFaceName) == CB_ERR)
585     {
586
587         add_font(lpelfe->lfFaceName, FontType, hListWnd, (const NEWTEXTMETRICEXW*)lpntme);
588     }
589
590     return 1;
591 }
592
593 static void populate_font_list(HWND hListWnd)
594 {
595     HDC hdc = GetDC(hMainWnd);
596     LOGFONTW fontinfo;
597     HWND hListEditWnd = (HWND)SendMessageW(hListWnd, CBEM_GETEDITCONTROL, 0, 0);
598     CHARFORMAT2W fmt;
599
600     fontinfo.lfCharSet = DEFAULT_CHARSET;
601     *fontinfo.lfFaceName = '\0';
602     fontinfo.lfPitchAndFamily = 0;
603
604     EnumFontFamiliesExW(hdc, &fontinfo, enum_font_proc,
605                         (LPARAM)hListWnd, 0);
606
607     ZeroMemory(&fmt, sizeof(fmt));
608     fmt.cbSize = sizeof(fmt);
609     SendMessageW(hEditorWnd, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&fmt);
610     SendMessageW(hListEditWnd, WM_SETTEXT, 0, (LPARAM)fmt.szFaceName);
611 }
612
613 static void update_window(void)
614 {
615     RECT rect;
616
617     GetClientRect(hMainWnd, &rect);
618
619     OnSize(hMainWnd, SIZE_RESTORED, MAKELPARAM(rect.right, rect.bottom));
620 }
621
622 static BOOL is_bar_visible(int bandId)
623 {
624     return barState[reg_formatindex(fileFormat)] & (1 << bandId);
625 }
626
627 static void store_bar_state(int bandId, BOOL show)
628 {
629     int formatIndex = reg_formatindex(fileFormat);
630
631     if(show)
632         barState[formatIndex] |= (1 << bandId);
633     else
634         barState[formatIndex] &= ~(1 << bandId);
635 }
636
637 static void set_toolbar_state(int bandId, BOOL show)
638 {
639     HWND hwndReBar = GetDlgItem(hMainWnd, IDC_REBAR);
640
641     SendMessageW(hwndReBar, RB_SHOWBAND, SendMessageW(hwndReBar, RB_IDTOINDEX, bandId, 0), show);
642
643     if(bandId == BANDID_TOOLBAR)
644     {
645         REBARBANDINFOW rbbinfo;
646         int index = SendMessageW(hwndReBar, RB_IDTOINDEX, BANDID_FONTLIST, 0);
647
648         rbbinfo.cbSize = sizeof(rbbinfo);
649         rbbinfo.fMask = RBBIM_STYLE;
650
651         SendMessageW(hwndReBar, RB_GETBANDINFO, index, (LPARAM)&rbbinfo);
652
653         if(!show)
654             rbbinfo.fStyle &= ~RBBS_BREAK;
655         else
656             rbbinfo.fStyle |= RBBS_BREAK;
657
658         SendMessageW(hwndReBar, RB_SETBANDINFO, index, (LPARAM)&rbbinfo);
659     }
660
661     if(bandId == BANDID_TOOLBAR || bandId == BANDID_FORMATBAR || bandId == BANDID_RULER)
662         store_bar_state(bandId, show);
663 }
664
665 static void set_statusbar_state(BOOL show)
666 {
667     HWND hStatusWnd = GetDlgItem(hMainWnd, IDC_STATUSBAR);
668
669     ShowWindow(hStatusWnd, show ? SW_SHOW : SW_HIDE);
670     store_bar_state(BANDID_STATUSBAR, show);
671 }
672
673 static void set_bar_states(void)
674 {
675     set_toolbar_state(BANDID_TOOLBAR, is_bar_visible(BANDID_TOOLBAR));
676     set_toolbar_state(BANDID_FONTLIST, is_bar_visible(BANDID_FORMATBAR));
677     set_toolbar_state(BANDID_SIZELIST, is_bar_visible(BANDID_FORMATBAR));
678     set_toolbar_state(BANDID_FORMATBAR, is_bar_visible(BANDID_FORMATBAR));
679     set_toolbar_state(BANDID_RULER, is_bar_visible(BANDID_RULER));
680     set_statusbar_state(is_bar_visible(BANDID_STATUSBAR));
681
682     update_window();
683 }
684
685 static void preview_exit(HWND hMainWnd)
686 {
687     HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hMainWnd, GWLP_HINSTANCE);
688     HMENU hMenu = LoadMenuW(hInstance, MAKEINTRESOURCEW(IDM_MAINMENU));
689     HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR);
690
691     set_bar_states();
692     ShowWindow(hEditorWnd, TRUE);
693
694     close_preview(hMainWnd);
695
696     SetMenu(hMainWnd, hMenu);
697     registry_read_filelist(hMainWnd);
698
699     update_window();
700 }
701
702 static void set_fileformat(WPARAM format)
703 {
704     HICON hIcon;
705     HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hMainWnd, GWLP_HINSTANCE);
706     fileFormat = format;
707
708     if(format & SF_TEXT)
709         hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_TXT));
710     else
711         hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_RTF));
712
713     SendMessageW(hMainWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
714
715     set_bar_states();
716     set_default_font();
717     target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
718 }
719
720 static void ShowOpenError(DWORD Code)
721 {
722     LPWSTR Message;
723
724     switch(Code)
725     {
726         case ERROR_ACCESS_DENIED:
727             Message = MAKEINTRESOURCEW(STRING_OPEN_ACCESS_DENIED);
728             break;
729
730         default:
731             Message = MAKEINTRESOURCEW(STRING_OPEN_FAILED);
732     }
733     MessageBoxW(hMainWnd, Message, wszAppTitle, MB_ICONEXCLAMATION | MB_OK);
734 }
735
736 static void DoOpenFile(LPCWSTR szOpenFileName)
737 {
738     HANDLE hFile;
739     EDITSTREAM es;
740     char fileStart[5];
741     DWORD readOut;
742     WPARAM format = SF_TEXT;
743
744     hFile = CreateFileW(szOpenFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
745                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
746     if (hFile == INVALID_HANDLE_VALUE)
747     {
748         ShowOpenError(GetLastError());
749         return;
750     }
751
752     ReadFile(hFile, fileStart, 5, &readOut, NULL);
753     SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
754
755     if(readOut >= 2 && (BYTE)fileStart[0] == 0xff && (BYTE)fileStart[1] == 0xfe)
756     {
757         format = SF_TEXT | SF_UNICODE;
758         SetFilePointer(hFile, 2, NULL, FILE_BEGIN);
759     } else if(readOut >= 5)
760     {
761         static const char header[] = "{\\rtf";
762         static const BYTE STG_magic[] = { 0xd0,0xcf,0x11,0xe0 };
763
764         if(!memcmp(header, fileStart, 5))
765             format = SF_RTF;
766         else if (!memcmp(STG_magic, fileStart, sizeof(STG_magic)))
767         {
768             CloseHandle(hFile);
769             MessageBoxWithResStringW(hMainWnd, MAKEINTRESOURCEW(STRING_OLE_STORAGE_NOT_SUPPORTED),
770                     wszAppTitle, MB_OK | MB_ICONEXCLAMATION);
771             return;
772         }
773     }
774
775     es.dwCookie = (DWORD_PTR)hFile;
776     es.pfnCallback = stream_in;
777
778     clear_formatting();
779     set_fileformat(format);
780     SendMessageW(hEditorWnd, EM_STREAMIN, format, (LPARAM)&es);
781
782     CloseHandle(hFile);
783
784     SetFocus(hEditorWnd);
785
786     set_caption(szOpenFileName);
787
788     lstrcpyW(wszFileName, szOpenFileName);
789     SendMessageW(hEditorWnd, EM_SETMODIFY, FALSE, 0);
790     registry_set_filelist(szOpenFileName, hMainWnd);
791     update_font_list();
792 }
793
794 static void ShowWriteError(DWORD Code)
795 {
796     LPWSTR Message;
797
798     switch(Code)
799     {
800         case ERROR_ACCESS_DENIED:
801             Message = MAKEINTRESOURCEW(STRING_WRITE_ACCESS_DENIED);
802             break;
803
804         default:
805             Message = MAKEINTRESOURCEW(STRING_WRITE_FAILED);
806     }
807     MessageBoxW(hMainWnd, Message, wszAppTitle, MB_ICONEXCLAMATION | MB_OK);
808 }
809
810 static void DoSaveFile(LPCWSTR wszSaveFileName, WPARAM format)
811 {
812     HANDLE hFile;
813     EDITSTREAM stream;
814     LRESULT ret;
815
816     hFile = CreateFileW(wszSaveFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
817         FILE_ATTRIBUTE_NORMAL, NULL);
818
819     if(hFile == INVALID_HANDLE_VALUE)
820     {
821         ShowWriteError(GetLastError());
822         return;
823     }
824
825     if(format == (SF_TEXT | SF_UNICODE))
826     {
827         static const BYTE unicode[] = {0xff,0xfe};
828         DWORD writeOut;
829         WriteFile(hFile, &unicode, sizeof(unicode), &writeOut, 0);
830
831         if(writeOut != sizeof(unicode))
832         {
833             CloseHandle(hFile);
834             return;
835         }
836     }
837
838     stream.dwCookie = (DWORD_PTR)hFile;
839     stream.pfnCallback = stream_out;
840
841     ret = SendMessageW(hEditorWnd, EM_STREAMOUT, format, (LPARAM)&stream);
842
843     CloseHandle(hFile);
844
845     SetFocus(hEditorWnd);
846
847     if(!ret)
848     {
849         GETTEXTLENGTHEX gt;
850         gt.flags = GTL_DEFAULT;
851         gt.codepage = 1200;
852
853         if(SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0))
854             return;
855     }
856
857     lstrcpyW(wszFileName, wszSaveFileName);
858     set_caption(wszFileName);
859     SendMessageW(hEditorWnd, EM_SETMODIFY, FALSE, 0);
860     set_fileformat(format);
861 }
862
863 static void DialogSaveFile(void)
864 {
865     OPENFILENAMEW sfn;
866
867     WCHAR wszFile[MAX_PATH] = {'\0'};
868     static const WCHAR wszDefExt[] = {'r','t','f','\0'};
869
870     ZeroMemory(&sfn, sizeof(sfn));
871
872     sfn.lStructSize = sizeof(sfn);
873     sfn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
874     sfn.hwndOwner = hMainWnd;
875     sfn.lpstrFilter = wszFilter;
876     sfn.lpstrFile = wszFile;
877     sfn.nMaxFile = MAX_PATH;
878     sfn.lpstrDefExt = wszDefExt;
879     sfn.nFilterIndex = fileformat_number(fileFormat)+1;
880
881     while(GetSaveFileNameW(&sfn))
882     {
883         if(fileformat_flags(sfn.nFilterIndex-1) != SF_RTF)
884         {
885             if(MessageBoxWithResStringW(hMainWnd, MAKEINTRESOURCEW(STRING_SAVE_LOSEFORMATTING),
886                            wszAppTitle, MB_YESNO | MB_ICONEXCLAMATION) != IDYES)
887             {
888                 continue;
889             } else
890             {
891                 DoSaveFile(sfn.lpstrFile, fileformat_flags(sfn.nFilterIndex-1));
892                 break;
893             }
894         } else
895         {
896             DoSaveFile(sfn.lpstrFile, fileformat_flags(sfn.nFilterIndex-1));
897             break;
898         }
899     }
900 }
901
902 static BOOL prompt_save_changes(void)
903 {
904     if(!wszFileName[0])
905     {
906         GETTEXTLENGTHEX gt;
907         gt.flags = GTL_NUMCHARS;
908         gt.codepage = 1200;
909         if(!SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0))
910             return TRUE;
911     }
912
913     if(!SendMessageW(hEditorWnd, EM_GETMODIFY, 0, 0))
914     {
915         return TRUE;
916     } else
917     {
918         LPWSTR displayFileName;
919         WCHAR *text;
920         int ret;
921
922         if(!wszFileName[0])
923             displayFileName = wszDefaultFileName;
924         else
925             displayFileName = file_basename(wszFileName);
926
927         text = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
928                          (lstrlenW(displayFileName)+lstrlenW(wszSaveChanges))*sizeof(WCHAR));
929
930         if(!text)
931             return FALSE;
932
933         wsprintfW(text, wszSaveChanges, displayFileName);
934
935         ret = MessageBoxW(hMainWnd, text, wszAppTitle, MB_YESNOCANCEL | MB_ICONEXCLAMATION);
936
937         HeapFree(GetProcessHeap(), 0, text);
938
939         switch(ret)
940         {
941             case IDNO:
942                 return TRUE;
943
944             case IDYES:
945                 if(wszFileName[0])
946                     DoSaveFile(wszFileName, fileFormat);
947                 else
948                     DialogSaveFile();
949                 return TRUE;
950
951             default:
952                 return FALSE;
953         }
954     }
955 }
956
957 static void DialogOpenFile(void)
958 {
959     OPENFILENAMEW ofn;
960
961     WCHAR wszFile[MAX_PATH] = {'\0'};
962     static const WCHAR wszDefExt[] = {'r','t','f','\0'};
963
964     ZeroMemory(&ofn, sizeof(ofn));
965
966     ofn.lStructSize = sizeof(ofn);
967     ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
968     ofn.hwndOwner = hMainWnd;
969     ofn.lpstrFilter = wszFilter;
970     ofn.lpstrFile = wszFile;
971     ofn.nMaxFile = MAX_PATH;
972     ofn.lpstrDefExt = wszDefExt;
973     ofn.nFilterIndex = fileformat_number(fileFormat)+1;
974
975     if(GetOpenFileNameW(&ofn))
976     {
977         if(prompt_save_changes())
978             DoOpenFile(ofn.lpstrFile);
979     }
980 }
981
982 static void dialog_about(void)
983 {
984     HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hMainWnd, GWLP_HINSTANCE);
985     HICON icon = LoadImageW(hInstance, MAKEINTRESOURCEW(IDI_WORDPAD), IMAGE_ICON, 48, 48, LR_SHARED);
986     ShellAboutW(hMainWnd, wszAppTitle, 0, icon);
987 }
988
989 static INT_PTR CALLBACK formatopts_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
990 {
991     switch(message)
992     {
993         case WM_INITDIALOG:
994             {
995                 LPPROPSHEETPAGEW ps = (LPPROPSHEETPAGEW)lParam;
996                 int wrap = -1;
997                 char id[4];
998                 HWND hIdWnd = GetDlgItem(hWnd, IDC_PAGEFMT_ID);
999
1000                 sprintf(id, "%d\n", (int)ps->lParam);
1001                 SetWindowTextA(hIdWnd, id);
1002                 if(wordWrap[ps->lParam] == ID_WORDWRAP_NONE)
1003                     wrap = IDC_PAGEFMT_WN;
1004                 else if(wordWrap[ps->lParam] == ID_WORDWRAP_WINDOW)
1005                     wrap = IDC_PAGEFMT_WW;
1006                 else if(wordWrap[ps->lParam] == ID_WORDWRAP_MARGIN)
1007                     wrap = IDC_PAGEFMT_WM;
1008
1009                 if(wrap != -1)
1010                     CheckRadioButton(hWnd, IDC_PAGEFMT_WN,
1011                                      IDC_PAGEFMT_WM, wrap);
1012
1013                 if(barState[ps->lParam] & (1 << BANDID_TOOLBAR))
1014                     CheckDlgButton(hWnd, IDC_PAGEFMT_TB, TRUE);
1015                 if(barState[ps->lParam] & (1 << BANDID_FORMATBAR))
1016                     CheckDlgButton(hWnd, IDC_PAGEFMT_FB, TRUE);
1017                 if(barState[ps->lParam] & (1 << BANDID_RULER))
1018                     CheckDlgButton(hWnd, IDC_PAGEFMT_RU, TRUE);
1019                 if(barState[ps->lParam] & (1 << BANDID_STATUSBAR))
1020                     CheckDlgButton(hWnd, IDC_PAGEFMT_SB, TRUE);
1021             }
1022             break;
1023
1024         case WM_COMMAND:
1025             switch(LOWORD(wParam))
1026             {
1027                 case IDC_PAGEFMT_WN:
1028                 case IDC_PAGEFMT_WW:
1029                 case IDC_PAGEFMT_WM:
1030                     CheckRadioButton(hWnd, IDC_PAGEFMT_WN, IDC_PAGEFMT_WM,
1031                                      LOWORD(wParam));
1032                     break;
1033
1034                 case IDC_PAGEFMT_TB:
1035                 case IDC_PAGEFMT_FB:
1036                 case IDC_PAGEFMT_RU:
1037                 case IDC_PAGEFMT_SB:
1038                     CheckDlgButton(hWnd, LOWORD(wParam),
1039                                    !IsDlgButtonChecked(hWnd, LOWORD(wParam)));
1040                     break;
1041             }
1042             break;
1043         case WM_NOTIFY:
1044             {
1045                 LPNMHDR header = (LPNMHDR)lParam;
1046                 if(header->code == PSN_APPLY)
1047                 {
1048                     HWND hIdWnd = GetDlgItem(hWnd, IDC_PAGEFMT_ID);
1049                     char sid[4];
1050                     int id;
1051
1052                     GetWindowTextA(hIdWnd, sid, 4);
1053                     id = atoi(sid);
1054                     if(IsDlgButtonChecked(hWnd, IDC_PAGEFMT_WN))
1055                         wordWrap[id] = ID_WORDWRAP_NONE;
1056                     else if(IsDlgButtonChecked(hWnd, IDC_PAGEFMT_WW))
1057                         wordWrap[id] = ID_WORDWRAP_WINDOW;
1058                     else if(IsDlgButtonChecked(hWnd, IDC_PAGEFMT_WM))
1059                         wordWrap[id] = ID_WORDWRAP_MARGIN;
1060
1061                     if(IsDlgButtonChecked(hWnd, IDC_PAGEFMT_TB))
1062                         barState[id] |= (1 << BANDID_TOOLBAR);
1063                     else
1064                         barState[id] &= ~(1 << BANDID_TOOLBAR);
1065
1066                     if(IsDlgButtonChecked(hWnd, IDC_PAGEFMT_FB))
1067                         barState[id] |= (1 << BANDID_FORMATBAR);
1068                     else
1069                         barState[id] &= ~(1 << BANDID_FORMATBAR);
1070
1071                     if(IsDlgButtonChecked(hWnd, IDC_PAGEFMT_RU))
1072                         barState[id] |= (1 << BANDID_RULER);
1073                     else
1074                         barState[id] &= ~(1 << BANDID_RULER);
1075
1076                     if(IsDlgButtonChecked(hWnd, IDC_PAGEFMT_SB))
1077                         barState[id] |= (1 << BANDID_STATUSBAR);
1078                     else
1079                         barState[id] &= ~(1 << BANDID_STATUSBAR);
1080                 }
1081             }
1082             break;
1083     }
1084     return FALSE;
1085 }
1086
1087 static void dialog_viewproperties(void)
1088 {
1089     PROPSHEETPAGEW psp[2];
1090     PROPSHEETHEADERW psh;
1091     size_t i;
1092     HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hMainWnd, GWLP_HINSTANCE);
1093     LPCPROPSHEETPAGEW ppsp = (LPCPROPSHEETPAGEW)&psp;
1094
1095     psp[0].dwSize = sizeof(PROPSHEETPAGEW);
1096     psp[0].dwFlags = PSP_USETITLE;
1097     U(psp[0]).pszTemplate = MAKEINTRESOURCEW(IDD_FORMATOPTS);
1098     psp[0].pfnDlgProc = formatopts_proc;
1099     psp[0].hInstance = hInstance;
1100     psp[0].lParam = reg_formatindex(SF_TEXT);
1101     psp[0].pfnCallback = NULL;
1102     psp[0].pszTitle = MAKEINTRESOURCEW(STRING_VIEWPROPS_TEXT);
1103     for(i = 1; i < sizeof(psp)/sizeof(psp[0]); i++)
1104     {
1105         psp[i].dwSize = psp[0].dwSize;
1106         psp[i].dwFlags = psp[0].dwFlags;
1107         U(psp[i]).pszTemplate = U(psp[0]).pszTemplate;
1108         psp[i].pfnDlgProc = psp[0].pfnDlgProc;
1109         psp[i].hInstance = psp[0].hInstance;
1110         psp[i].lParam = reg_formatindex(SF_RTF);
1111         psp[i].pfnCallback = psp[0].pfnCallback;
1112         psp[i].pszTitle = MAKEINTRESOURCEW(STRING_VIEWPROPS_RICHTEXT);
1113     }
1114
1115     psh.dwSize = sizeof(psh);
1116     psh.dwFlags = PSH_USEICONID | PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW;
1117     psh.hwndParent = hMainWnd;
1118     psh.hInstance = hInstance;
1119     psh.pszCaption = MAKEINTRESOURCEW(STRING_VIEWPROPS_TITLE);
1120     psh.nPages = sizeof(psp)/sizeof(psp[0]);
1121     U3(psh).ppsp = ppsp;
1122     U(psh).pszIcon = MAKEINTRESOURCEW(IDI_WORDPAD);
1123
1124     if(fileFormat & SF_RTF)
1125         U2(psh).nStartPage = 1;
1126     else
1127         U2(psh).nStartPage = 0;
1128     PropertySheetW(&psh);
1129     set_bar_states();
1130     target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
1131 }
1132
1133 static void HandleCommandLine(LPWSTR cmdline)
1134 {
1135     WCHAR delimiter;
1136     int opt_print = 0;
1137
1138     /* skip white space */
1139     while (*cmdline == ' ') cmdline++;
1140
1141     /* skip executable name */
1142     delimiter = (*cmdline == '"' ? '"' : ' ');
1143
1144     if (*cmdline == delimiter) cmdline++;
1145     while (*cmdline && *cmdline != delimiter) cmdline++;
1146     if (*cmdline == delimiter) cmdline++;
1147
1148     while (*cmdline)
1149     {
1150         while (isspace(*cmdline)) cmdline++;
1151
1152         if (*cmdline == '-' || *cmdline == '/')
1153         {
1154             if (!cmdline[2] || isspace(cmdline[2]))
1155             {
1156                 switch (cmdline[1])
1157                 {
1158                 case 'P':
1159                 case 'p':
1160                     opt_print = 1;
1161                     cmdline += 2;
1162                     continue;
1163                 }
1164             }
1165             /* a filename starting by / */
1166         }
1167         break;
1168     }
1169
1170     if (*cmdline)
1171     {
1172         /* file name is passed on the command line */
1173         if (cmdline[0] == '"')
1174         {
1175             cmdline++;
1176             cmdline[lstrlenW(cmdline) - 1] = 0;
1177         }
1178         DoOpenFile(cmdline);
1179         InvalidateRect(hMainWnd, NULL, FALSE);
1180     }
1181
1182     if (opt_print)
1183         MessageBoxWithResStringW(hMainWnd, MAKEINTRESOURCEW(STRING_PRINTING_NOT_IMPLEMENTED), wszAppTitle, MB_OK);
1184 }
1185
1186 static LRESULT handle_findmsg(LPFINDREPLACEW pFr)
1187 {
1188     if(pFr->Flags & FR_DIALOGTERM)
1189     {
1190         hFindWnd = 0;
1191         pFr->Flags = FR_FINDNEXT;
1192         return 0;
1193     }
1194
1195     if(pFr->Flags & FR_FINDNEXT || pFr->Flags & FR_REPLACE || pFr->Flags & FR_REPLACEALL)
1196     {
1197         DWORD flags = FR_DOWN;
1198         FINDTEXTW ft;
1199         static CHARRANGE cr;
1200         LRESULT end, ret;
1201         GETTEXTLENGTHEX gt;
1202         LRESULT length;
1203         int startPos;
1204         HMENU hMenu = GetMenu(hMainWnd);
1205         MENUITEMINFOW mi;
1206
1207         mi.cbSize = sizeof(mi);
1208         mi.fMask = MIIM_DATA;
1209         mi.dwItemData = 1;
1210         SetMenuItemInfoW(hMenu, ID_FIND_NEXT, FALSE, &mi);
1211
1212         gt.flags = GTL_NUMCHARS;
1213         gt.codepage = 1200;
1214
1215         length = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0);
1216
1217         if(pFr->lCustData == -1)
1218         {
1219             SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&startPos, (LPARAM)&end);
1220             cr.cpMin = startPos;
1221             pFr->lCustData = startPos;
1222             cr.cpMax = length;
1223             if(cr.cpMin == length)
1224                 cr.cpMin = 0;
1225         } else
1226         {
1227             startPos = pFr->lCustData;
1228         }
1229
1230         if(cr.cpMax > length)
1231         {
1232             startPos = 0;
1233             cr.cpMin = 0;
1234             cr.cpMax = length;
1235         }
1236
1237         ft.chrg = cr;
1238         ft.lpstrText = pFr->lpstrFindWhat;
1239
1240         if(pFr->Flags & FR_MATCHCASE)
1241             flags |= FR_MATCHCASE;
1242         if(pFr->Flags & FR_WHOLEWORD)
1243             flags |= FR_WHOLEWORD;
1244
1245         ret = SendMessageW(hEditorWnd, EM_FINDTEXTW, (WPARAM)flags, (LPARAM)&ft);
1246
1247         if(ret == -1)
1248         {
1249             if(cr.cpMax == length && cr.cpMax != startPos)
1250             {
1251                 ft.chrg.cpMin = cr.cpMin = 0;
1252                 ft.chrg.cpMax = cr.cpMax = startPos;
1253
1254                 ret = SendMessageW(hEditorWnd, EM_FINDTEXTW, (WPARAM)flags, (LPARAM)&ft);
1255             }
1256         }
1257
1258         if(ret == -1)
1259         {
1260             pFr->lCustData = -1;
1261             MessageBoxWithResStringW(hMainWnd, MAKEINTRESOURCEW(STRING_SEARCH_FINISHED), wszAppTitle,
1262                         MB_OK | MB_ICONASTERISK);
1263         } else
1264         {
1265             end = ret + lstrlenW(pFr->lpstrFindWhat);
1266             cr.cpMin = end;
1267             SendMessageW(hEditorWnd, EM_SETSEL, (WPARAM)ret, (LPARAM)end);
1268             SendMessageW(hEditorWnd, EM_SCROLLCARET, 0, 0);
1269
1270             if(pFr->Flags & FR_REPLACE || pFr->Flags & FR_REPLACEALL)
1271                 SendMessageW(hEditorWnd, EM_REPLACESEL, TRUE, (LPARAM)pFr->lpstrReplaceWith);
1272
1273             if(pFr->Flags & FR_REPLACEALL)
1274                 handle_findmsg(pFr);
1275         }
1276     }
1277
1278     return 0;
1279 }
1280
1281 static void dialog_find(LPFINDREPLACEW fr, BOOL replace)
1282 {
1283     static WCHAR findBuffer[MAX_STRING_LEN];
1284
1285     ZeroMemory(fr, sizeof(FINDREPLACEW));
1286     fr->lStructSize = sizeof(FINDREPLACEW);
1287     fr->hwndOwner = hMainWnd;
1288     fr->Flags = FR_HIDEUPDOWN;
1289     fr->lpstrFindWhat = findBuffer;
1290     fr->lCustData = -1;
1291     fr->wFindWhatLen = MAX_STRING_LEN*sizeof(WCHAR);
1292
1293     if(replace)
1294         hFindWnd = ReplaceTextW(fr);
1295     else
1296         hFindWnd = FindTextW(fr);
1297 }
1298
1299 static int current_units_to_twips(float number)
1300 {
1301     int twips = (int)(number * 1000.0 / (float)CENTMM_PER_INCH *  (float)TWIPS_PER_INCH);
1302     return twips;
1303 }
1304
1305 static void append_current_units(LPWSTR buffer)
1306 {
1307     static const WCHAR space[] = {' ', 0};
1308     lstrcatW(buffer, space);
1309     lstrcatW(buffer, units_cmW);
1310 }
1311
1312 static void number_with_units(LPWSTR buffer, int number)
1313 {
1314     static const WCHAR fmt[] = {'%','.','2','f',' ','%','s','\0'};
1315     float converted = (float)number / (float)TWIPS_PER_INCH *(float)CENTMM_PER_INCH / 1000.0;
1316
1317     sprintfW(buffer, fmt, converted, units_cmW);
1318 }
1319
1320 static BOOL get_comboexlist_selection(HWND hComboEx, LPWSTR wszBuffer, UINT bufferLength)
1321 {
1322     COMBOBOXEXITEMW cbItem;
1323     COMBOBOXINFO cbInfo;
1324     HWND hCombo, hList;
1325     int idx, result;
1326
1327     hCombo = (HWND)SendMessage(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0);
1328     if (!hCombo)
1329         return FALSE;
1330     cbInfo.cbSize = sizeof(COMBOBOXINFO);
1331     result = SendMessage(hCombo, CB_GETCOMBOBOXINFO, 0, (LPARAM)&cbInfo);
1332     if (!result)
1333         return FALSE;
1334     hList = cbInfo.hwndList;
1335     idx = SendMessage(hList, LB_GETCURSEL, 0, 0);
1336     if (idx < 0)
1337         return FALSE;
1338
1339     ZeroMemory(&cbItem, sizeof(cbItem));
1340     cbItem.mask = CBEIF_TEXT;
1341     cbItem.iItem = idx;
1342     cbItem.pszText = wszBuffer;
1343     cbItem.cchTextMax = bufferLength-1;
1344     result = SendMessageW(hComboEx, CBEM_GETITEMW, 0, (LPARAM)&cbItem);
1345
1346     return result != 0;
1347 }
1348
1349 static INT_PTR CALLBACK datetime_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1350 {
1351     switch(message)
1352     {
1353         case WM_INITDIALOG:
1354             {
1355                 WCHAR buffer[MAX_STRING_LEN];
1356                 SYSTEMTIME st;
1357                 HWND hListWnd = GetDlgItem(hWnd, IDC_DATETIME);
1358                 GetLocalTime(&st);
1359
1360                 GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, 0, (LPWSTR)&buffer,
1361                                MAX_STRING_LEN);
1362                 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1363                 GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, 0, (LPWSTR)&buffer,
1364                                MAX_STRING_LEN);
1365                 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1366                 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, 0, (LPWSTR)&buffer, MAX_STRING_LEN);
1367                 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1368
1369                 SendMessageW(hListWnd, LB_SETSEL, TRUE, 0);
1370             }
1371             break;
1372
1373         case WM_COMMAND:
1374             switch(LOWORD(wParam))
1375             {
1376                 case IDC_DATETIME:
1377                     if (HIWORD(wParam) != LBN_DBLCLK)
1378                         break;
1379                     /* Fall through */
1380
1381                 case IDOK:
1382                     {
1383                         LRESULT index;
1384                         HWND hListWnd = GetDlgItem(hWnd, IDC_DATETIME);
1385
1386                         index = SendMessageW(hListWnd, LB_GETCURSEL, 0, 0);
1387
1388                         if(index != LB_ERR)
1389                         {
1390                             WCHAR buffer[MAX_STRING_LEN];
1391                             SendMessageW(hListWnd, LB_GETTEXT, index, (LPARAM)&buffer);
1392                             SendMessageW(hEditorWnd, EM_REPLACESEL, TRUE, (LPARAM)&buffer);
1393                         }
1394                     }
1395                     /* Fall through */
1396
1397                 case IDCANCEL:
1398                     EndDialog(hWnd, wParam);
1399                     return TRUE;
1400             }
1401     }
1402     return FALSE;
1403 }
1404
1405 static INT_PTR CALLBACK newfile_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1406 {
1407     switch(message)
1408     {
1409         case WM_INITDIALOG:
1410             {
1411                 HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hMainWnd, GWLP_HINSTANCE);
1412                 WCHAR buffer[MAX_STRING_LEN];
1413                 HWND hListWnd = GetDlgItem(hWnd, IDC_NEWFILE);
1414
1415                 LoadStringW(hInstance, STRING_NEWFILE_RICHTEXT, buffer, MAX_STRING_LEN);
1416                 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1417                 LoadStringW(hInstance, STRING_NEWFILE_TXT, buffer, MAX_STRING_LEN);
1418                 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1419                 LoadStringW(hInstance, STRING_NEWFILE_TXT_UNICODE, buffer, MAX_STRING_LEN);
1420                 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1421
1422                 SendMessageW(hListWnd, LB_SETSEL, TRUE, 0);
1423             }
1424             break;
1425
1426         case WM_COMMAND:
1427             switch(LOWORD(wParam))
1428             {
1429                 case IDOK:
1430                     {
1431                         LRESULT index;
1432                         HWND hListWnd = GetDlgItem(hWnd, IDC_NEWFILE);
1433                         index = SendMessageW(hListWnd, LB_GETCURSEL, 0, 0);
1434
1435                         if(index != LB_ERR)
1436                             EndDialog(hWnd, MAKELONG(fileformat_flags(index),0));
1437                     }
1438                     return TRUE;
1439
1440                 case IDCANCEL:
1441                     EndDialog(hWnd, MAKELONG(ID_NEWFILE_ABORT,0));
1442                     return TRUE;
1443             }
1444     }
1445     return FALSE;
1446 }
1447
1448 static INT_PTR CALLBACK paraformat_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1449 {
1450     static const WORD ALIGNMENT_VALUES[] = {PFA_LEFT, PFA_RIGHT, PFA_CENTER};
1451
1452     switch(message)
1453     {
1454         case WM_INITDIALOG:
1455             {
1456                 HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hMainWnd,
1457                                                                   GWLP_HINSTANCE);
1458                 WCHAR buffer[MAX_STRING_LEN];
1459                 HWND hListWnd = GetDlgItem(hWnd, IDC_PARA_ALIGN);
1460                 HWND hLeftWnd = GetDlgItem(hWnd, IDC_PARA_LEFT);
1461                 HWND hRightWnd = GetDlgItem(hWnd, IDC_PARA_RIGHT);
1462                 HWND hFirstWnd = GetDlgItem(hWnd, IDC_PARA_FIRST);
1463                 PARAFORMAT2 pf;
1464                 int index = 0;
1465
1466                 LoadStringW(hInstance, STRING_ALIGN_LEFT, buffer,
1467                             MAX_STRING_LEN);
1468                 SendMessageW(hListWnd, CB_ADDSTRING, 0, (LPARAM)buffer);
1469                 LoadStringW(hInstance, STRING_ALIGN_RIGHT, buffer,
1470                             MAX_STRING_LEN);
1471                 SendMessageW(hListWnd, CB_ADDSTRING, 0, (LPARAM)buffer);
1472                 LoadStringW(hInstance, STRING_ALIGN_CENTER, buffer,
1473                             MAX_STRING_LEN);
1474                 SendMessageW(hListWnd, CB_ADDSTRING, 0, (LPARAM)buffer);
1475
1476                 pf.cbSize = sizeof(pf);
1477                 pf.dwMask = PFM_ALIGNMENT | PFM_OFFSET | PFM_RIGHTINDENT |
1478                             PFM_STARTINDENT;
1479                 SendMessageW(hEditorWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
1480
1481                 if(pf.wAlignment == PFA_RIGHT)
1482                     index ++;
1483                 else if(pf.wAlignment == PFA_CENTER)
1484                     index += 2;
1485
1486                 SendMessageW(hListWnd, CB_SETCURSEL, index, 0);
1487
1488                 number_with_units(buffer, pf.dxStartIndent + pf.dxOffset);
1489                 SetWindowTextW(hLeftWnd, buffer);
1490                 number_with_units(buffer, pf.dxRightIndent);
1491                 SetWindowTextW(hRightWnd, buffer);
1492                 number_with_units(buffer, -pf.dxOffset);
1493                 SetWindowTextW(hFirstWnd, buffer);
1494             }
1495             break;
1496
1497         case WM_COMMAND:
1498             switch(LOWORD(wParam))
1499             {
1500                 case IDOK:
1501                     {
1502                         HWND hListWnd = GetDlgItem(hWnd, IDC_PARA_ALIGN);
1503                         HWND hLeftWnd = GetDlgItem(hWnd, IDC_PARA_LEFT);
1504                         HWND hRightWnd = GetDlgItem(hWnd, IDC_PARA_RIGHT);
1505                         HWND hFirstWnd = GetDlgItem(hWnd, IDC_PARA_FIRST);
1506                         WCHAR buffer[MAX_STRING_LEN];
1507                         int index;
1508                         float num;
1509                         int ret = 0;
1510                         PARAFORMAT pf;
1511
1512                         index = SendMessageW(hListWnd, CB_GETCURSEL, 0, 0);
1513                         pf.wAlignment = ALIGNMENT_VALUES[index];
1514
1515                         GetWindowTextW(hLeftWnd, buffer, MAX_STRING_LEN);
1516                         if(number_from_string(buffer, &num, TRUE))
1517                             ret++;
1518                         pf.dxOffset = current_units_to_twips(num);
1519                         GetWindowTextW(hRightWnd, buffer, MAX_STRING_LEN);
1520                         if(number_from_string(buffer, &num, TRUE))
1521                             ret++;
1522                         pf.dxRightIndent = current_units_to_twips(num);
1523                         GetWindowTextW(hFirstWnd, buffer, MAX_STRING_LEN);
1524                         if(number_from_string(buffer, &num, TRUE))
1525                             ret++;
1526                         pf.dxStartIndent = current_units_to_twips(num);
1527
1528                         if(ret != 3)
1529                         {
1530                             MessageBoxWithResStringW(hMainWnd, MAKEINTRESOURCEW(STRING_INVALID_NUMBER),
1531                                         wszAppTitle, MB_OK | MB_ICONASTERISK);
1532                             return FALSE;
1533                         } else
1534                         {
1535                             if (pf.dxOffset + pf.dxStartIndent < 0
1536                                 && pf.dxStartIndent < 0)
1537                             {
1538                                 /* The first line is before the left edge, so
1539                                  * make sure it is at the left edge. */
1540                                 pf.dxOffset = -pf.dxStartIndent;
1541                             } else if (pf.dxOffset < 0) {
1542                                 /* The second and following lines are before
1543                                  * the left edge, so set it to be at the left
1544                                  * edge, and adjust the first line since it
1545                                  * is relative to it. */
1546                                 pf.dxStartIndent = max(pf.dxStartIndent + pf.dxOffset, 0);
1547                                 pf.dxOffset = 0;
1548                             }
1549                             /* Internally the dxStartIndent is the absolute
1550                              * offset for the first line and dxOffset is
1551                              * to it value as opposed how it is displayed with
1552                              * the first line being the relative value.
1553                              * These two lines make the adjustments. */
1554                             pf.dxStartIndent = pf.dxStartIndent + pf.dxOffset;
1555                             pf.dxOffset = pf.dxOffset - pf.dxStartIndent;
1556
1557                             pf.cbSize = sizeof(pf);
1558                             pf.dwMask = PFM_ALIGNMENT | PFM_OFFSET | PFM_RIGHTINDENT |
1559                                         PFM_STARTINDENT;
1560                             SendMessageW(hEditorWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
1561                         }
1562                     }
1563                     /* Fall through */
1564
1565                 case IDCANCEL:
1566                     EndDialog(hWnd, wParam);
1567                     return TRUE;
1568             }
1569     }
1570     return FALSE;
1571 }
1572
1573 static INT_PTR CALLBACK tabstops_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1574 {
1575     switch(message)
1576     {
1577         case WM_INITDIALOG:
1578             {
1579                 HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1580                 PARAFORMAT pf;
1581                 WCHAR buffer[MAX_STRING_LEN];
1582                 int i;
1583
1584                 pf.cbSize = sizeof(pf);
1585                 pf.dwMask = PFM_TABSTOPS;
1586                 SendMessageW(hEditorWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
1587                 SendMessageW(hTabWnd, CB_LIMITTEXT, MAX_STRING_LEN-1, 0);
1588
1589                 for(i = 0; i < pf.cTabCount; i++)
1590                 {
1591                     number_with_units(buffer, pf.rgxTabs[i]);
1592                     SendMessageW(hTabWnd, CB_ADDSTRING, 0, (LPARAM)&buffer);
1593                 }
1594                 SetFocus(hTabWnd);
1595             }
1596             break;
1597
1598         case WM_COMMAND:
1599             switch(LOWORD(wParam))
1600             {
1601                 case IDC_TABSTOPS:
1602                     {
1603                         HWND hTabWnd = (HWND)lParam;
1604                         HWND hAddWnd = GetDlgItem(hWnd, ID_TAB_ADD);
1605                         HWND hDelWnd = GetDlgItem(hWnd, ID_TAB_DEL);
1606                         HWND hEmptyWnd = GetDlgItem(hWnd, ID_TAB_EMPTY);
1607
1608                         if(GetWindowTextLengthW(hTabWnd))
1609                             EnableWindow(hAddWnd, TRUE);
1610                         else
1611                             EnableWindow(hAddWnd, FALSE);
1612
1613                         if(SendMessageW(hTabWnd, CB_GETCOUNT, 0, 0))
1614                         {
1615                             EnableWindow(hEmptyWnd, TRUE);
1616
1617                             if(SendMessageW(hTabWnd, CB_GETCURSEL, 0, 0) == CB_ERR)
1618                                 EnableWindow(hDelWnd, FALSE);
1619                             else
1620                                 EnableWindow(hDelWnd, TRUE);
1621                         } else
1622                         {
1623                             EnableWindow(hEmptyWnd, FALSE);
1624                         }
1625                     }
1626                     break;
1627
1628                 case ID_TAB_ADD:
1629                     {
1630                         HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1631                         WCHAR buffer[MAX_STRING_LEN];
1632
1633                         GetWindowTextW(hTabWnd, buffer, MAX_STRING_LEN);
1634                         append_current_units(buffer);
1635
1636                         if(SendMessageW(hTabWnd, CB_FINDSTRINGEXACT, -1, (LPARAM)&buffer) == CB_ERR)
1637                         {
1638                             float number = 0;
1639
1640                             if(!number_from_string(buffer, &number, TRUE))
1641                             {
1642                                 MessageBoxWithResStringW(hWnd, MAKEINTRESOURCEW(STRING_INVALID_NUMBER),
1643                                              wszAppTitle, MB_OK | MB_ICONINFORMATION);
1644                             } else
1645                             {
1646                                 SendMessageW(hTabWnd, CB_ADDSTRING, 0, (LPARAM)&buffer);
1647                                 SetWindowTextW(hTabWnd, 0);
1648                             }
1649                         }
1650                         SetFocus(hTabWnd);
1651                     }
1652                     break;
1653
1654                 case ID_TAB_DEL:
1655                     {
1656                         HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1657                         LRESULT ret;
1658                         ret = SendMessageW(hTabWnd, CB_GETCURSEL, 0, 0);
1659                         if(ret != CB_ERR)
1660                             SendMessageW(hTabWnd, CB_DELETESTRING, ret, 0);
1661                     }
1662                     break;
1663
1664                 case ID_TAB_EMPTY:
1665                     {
1666                         HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1667                         SendMessageW(hTabWnd, CB_RESETCONTENT, 0, 0);
1668                         SetFocus(hTabWnd);
1669                     }
1670                     break;
1671
1672                 case IDOK:
1673                     {
1674                         HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1675                         int i;
1676                         WCHAR buffer[MAX_STRING_LEN];
1677                         PARAFORMAT pf;
1678                         float number;
1679
1680                         pf.cbSize = sizeof(pf);
1681                         pf.dwMask = PFM_TABSTOPS;
1682
1683                         for(i = 0; SendMessageW(hTabWnd, CB_GETLBTEXT, i,
1684                                                 (LPARAM)&buffer) != CB_ERR &&
1685                                                         i < MAX_TAB_STOPS; i++)
1686                         {
1687                             number_from_string(buffer, &number, TRUE);
1688                             pf.rgxTabs[i] = current_units_to_twips(number);
1689                         }
1690                         pf.cTabCount = i;
1691                         SendMessageW(hEditorWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
1692                     }
1693                     /* Fall through */
1694                 case IDCANCEL:
1695                     EndDialog(hWnd, wParam);
1696                     return TRUE;
1697             }
1698     }
1699     return FALSE;
1700 }
1701
1702 static int context_menu(LPARAM lParam)
1703 {
1704     int x = (int)(short)LOWORD(lParam);
1705     int y = (int)(short)HIWORD(lParam);
1706     HMENU hPop = GetSubMenu(hPopupMenu, 0);
1707
1708     if(x == -1)
1709     {
1710         int from = 0, to = 0;
1711         POINTL pt;
1712         SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&from, (LPARAM)&to);
1713         SendMessageW(hEditorWnd, EM_POSFROMCHAR, (WPARAM)&pt, (LPARAM)to);
1714         ClientToScreen(hEditorWnd, (POINT*)&pt);
1715         x = pt.x;
1716         y = pt.y;
1717     }
1718
1719     TrackPopupMenu(hPop, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON,
1720                    x, y, 0, hMainWnd, 0);
1721
1722     return 0;
1723 }
1724
1725 static LRESULT OnCreate( HWND hWnd )
1726 {
1727     HWND hToolBarWnd, hFormatBarWnd,  hReBarWnd, hFontListWnd, hSizeListWnd, hRulerWnd;
1728     HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
1729     HANDLE hDLL;
1730     TBADDBITMAP ab;
1731     int nStdBitmaps = 0;
1732     REBARINFO rbi;
1733     REBARBANDINFOW rbb;
1734     static const WCHAR wszRichEditDll[] = {'R','I','C','H','E','D','2','0','.','D','L','L','\0'};
1735     static const WCHAR wszRichEditText[] = {'R','i','c','h','E','d','i','t',' ','t','e','x','t','\0'};
1736
1737     CreateStatusWindowW(CCS_NODIVIDER|WS_CHILD|WS_VISIBLE, wszRichEditText, hWnd, IDC_STATUSBAR);
1738
1739     hReBarWnd = CreateWindowExW(WS_EX_TOOLWINDOW, REBARCLASSNAMEW, NULL,
1740       CCS_NODIVIDER|WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|RBS_VARHEIGHT|CCS_TOP,
1741       CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hWnd, (HMENU)IDC_REBAR, hInstance, NULL);
1742
1743     rbi.cbSize = sizeof(rbi);
1744     rbi.fMask = 0;
1745     rbi.himl = NULL;
1746     if(!SendMessageW(hReBarWnd, RB_SETBARINFO, 0, (LPARAM)&rbi))
1747         return -1;
1748
1749     hToolBarWnd = CreateToolbarEx(hReBarWnd, CCS_NOPARENTALIGN|CCS_NOMOVEY|WS_VISIBLE|WS_CHILD|TBSTYLE_TOOLTIPS|TBSTYLE_BUTTON,
1750       IDC_TOOLBAR,
1751       1, hInstance, IDB_TOOLBAR,
1752       NULL, 0,
1753       24, 24, 16, 16, sizeof(TBBUTTON));
1754
1755     ab.hInst = HINST_COMMCTRL;
1756     ab.nID = IDB_STD_SMALL_COLOR;
1757     nStdBitmaps = SendMessageW(hToolBarWnd, TB_ADDBITMAP, 0, (LPARAM)&ab);
1758
1759     AddButton(hToolBarWnd, nStdBitmaps+STD_FILENEW, ID_FILE_NEW);
1760     AddButton(hToolBarWnd, nStdBitmaps+STD_FILEOPEN, ID_FILE_OPEN);
1761     AddButton(hToolBarWnd, nStdBitmaps+STD_FILESAVE, ID_FILE_SAVE);
1762     AddSeparator(hToolBarWnd);
1763     AddButton(hToolBarWnd, nStdBitmaps+STD_PRINT, ID_PRINT_QUICK);
1764     AddButton(hToolBarWnd, nStdBitmaps+STD_PRINTPRE, ID_PREVIEW);
1765     AddSeparator(hToolBarWnd);
1766     AddButton(hToolBarWnd, nStdBitmaps+STD_FIND, ID_FIND);
1767     AddSeparator(hToolBarWnd);
1768     AddButton(hToolBarWnd, nStdBitmaps+STD_CUT, ID_EDIT_CUT);
1769     AddButton(hToolBarWnd, nStdBitmaps+STD_COPY, ID_EDIT_COPY);
1770     AddButton(hToolBarWnd, nStdBitmaps+STD_PASTE, ID_EDIT_PASTE);
1771     AddButton(hToolBarWnd, nStdBitmaps+STD_UNDO, ID_EDIT_UNDO);
1772     AddButton(hToolBarWnd, nStdBitmaps+STD_REDOW, ID_EDIT_REDO);
1773     AddSeparator(hToolBarWnd);
1774     AddButton(hToolBarWnd, 0, ID_DATETIME);
1775
1776     SendMessageW(hToolBarWnd, TB_AUTOSIZE, 0, 0);
1777
1778     rbb.cbSize = sizeof(rbb);
1779     rbb.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD | RBBIM_STYLE | RBBIM_ID;
1780     rbb.fStyle = RBBS_CHILDEDGE | RBBS_BREAK | RBBS_NOGRIPPER;
1781     rbb.cx = 0;
1782     rbb.hwndChild = hToolBarWnd;
1783     rbb.cxMinChild = 0;
1784     rbb.cyChild = rbb.cyMinChild = HIWORD(SendMessageW(hToolBarWnd, TB_GETBUTTONSIZE, 0, 0));
1785     rbb.wID = BANDID_TOOLBAR;
1786
1787     SendMessageW(hReBarWnd, RB_INSERTBAND, -1, (LPARAM)&rbb);
1788
1789     hFontListWnd = CreateWindowExW(0, WC_COMBOBOXEXW, NULL,
1790                       WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN | CBS_SORT,
1791                       0, 0, 200, 150, hReBarWnd, (HMENU)IDC_FONTLIST, hInstance, NULL);
1792
1793     rbb.hwndChild = hFontListWnd;
1794     rbb.cx = 200;
1795     rbb.wID = BANDID_FONTLIST;
1796
1797     SendMessageW(hReBarWnd, RB_INSERTBAND, -1, (LPARAM)&rbb);
1798
1799     hSizeListWnd = CreateWindowExW(0, WC_COMBOBOXEXW, NULL,
1800                       WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN,
1801                       0, 0, 50, 150, hReBarWnd, (HMENU)IDC_SIZELIST, hInstance, NULL);
1802
1803     rbb.hwndChild = hSizeListWnd;
1804     rbb.cx = 50;
1805     rbb.fStyle ^= RBBS_BREAK;
1806     rbb.wID = BANDID_SIZELIST;
1807
1808     SendMessageW(hReBarWnd, RB_INSERTBAND, -1, (LPARAM)&rbb);
1809
1810     hFormatBarWnd = CreateToolbarEx(hReBarWnd,
1811          CCS_NOPARENTALIGN | CCS_NOMOVEY | WS_VISIBLE | TBSTYLE_TOOLTIPS | TBSTYLE_BUTTON,
1812          IDC_FORMATBAR, 7, hInstance, IDB_FORMATBAR, NULL, 0, 16, 16, 16, 16, sizeof(TBBUTTON));
1813
1814     AddButton(hFormatBarWnd, 0, ID_FORMAT_BOLD);
1815     AddButton(hFormatBarWnd, 1, ID_FORMAT_ITALIC);
1816     AddButton(hFormatBarWnd, 2, ID_FORMAT_UNDERLINE);
1817     AddSeparator(hFormatBarWnd);
1818     AddButton(hFormatBarWnd, 3, ID_ALIGN_LEFT);
1819     AddButton(hFormatBarWnd, 4, ID_ALIGN_CENTER);
1820     AddButton(hFormatBarWnd, 5, ID_ALIGN_RIGHT);
1821     AddSeparator(hFormatBarWnd);
1822     AddButton(hFormatBarWnd, 6, ID_BULLET);
1823
1824     SendMessageW(hFormatBarWnd, TB_AUTOSIZE, 0, 0);
1825
1826     rbb.hwndChild = hFormatBarWnd;
1827     rbb.wID = BANDID_FORMATBAR;
1828
1829     SendMessageW(hReBarWnd, RB_INSERTBAND, -1, (LPARAM)&rbb);
1830
1831     hRulerWnd = CreateWindowExW(0, WC_STATICW, NULL, WS_VISIBLE | WS_CHILD,
1832                                 0, 0, 200, 10, hReBarWnd,  (HMENU)IDC_RULER, hInstance, NULL);
1833
1834
1835     rbb.hwndChild = hRulerWnd;
1836     rbb.wID = BANDID_RULER;
1837     rbb.fStyle |= RBBS_BREAK;
1838
1839     SendMessageW(hReBarWnd, RB_INSERTBAND, -1, (LPARAM)&rbb);
1840
1841     hDLL = LoadLibraryW(wszRichEditDll);
1842     if(!hDLL)
1843     {
1844         MessageBoxWithResStringW(hWnd, MAKEINTRESOURCEW(STRING_LOAD_RICHED_FAILED), wszAppTitle,
1845                     MB_OK | MB_ICONEXCLAMATION);
1846         PostQuitMessage(1);
1847     }
1848
1849     hEditorWnd = CreateWindowExW(WS_EX_CLIENTEDGE, wszRichEditClass, NULL,
1850       WS_CHILD|WS_VISIBLE|ES_SELECTIONBAR|ES_MULTILINE|ES_AUTOVSCROLL
1851       |ES_WANTRETURN|WS_VSCROLL|ES_NOHIDESEL|WS_HSCROLL,
1852       0, 0, 1000, 100, hWnd, (HMENU)IDC_EDITOR, hInstance, NULL);
1853
1854     if (!hEditorWnd)
1855     {
1856         fprintf(stderr, "Error code %u\n", GetLastError());
1857         return -1;
1858     }
1859     assert(hEditorWnd);
1860
1861     SetFocus(hEditorWnd);
1862     SendMessageW(hEditorWnd, EM_SETEVENTMASK, 0, ENM_SELCHANGE);
1863
1864     set_default_font();
1865
1866     populate_font_list(hFontListWnd);
1867     populate_size_list(hSizeListWnd);
1868     DoLoadStrings();
1869     SendMessageW(hEditorWnd, EM_SETMODIFY, FALSE, 0);
1870
1871     ID_FINDMSGSTRING = RegisterWindowMessageW(FINDMSGSTRINGW);
1872
1873     registry_read_filelist(hWnd);
1874     registry_read_formatopts_all(barState, wordWrap);
1875     registry_read_options();
1876     DragAcceptFiles(hWnd, TRUE);
1877
1878     return 0;
1879 }
1880
1881 static LRESULT OnUser( HWND hWnd )
1882 {
1883     HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
1884     HWND hwndReBar = GetDlgItem(hWnd, IDC_REBAR);
1885     HWND hwndToolBar = GetDlgItem(hwndReBar, IDC_TOOLBAR);
1886     HWND hwndFormatBar = GetDlgItem(hwndReBar, IDC_FORMATBAR);
1887     int from, to;
1888     CHARFORMAT2W fmt;
1889     PARAFORMAT2 pf;
1890     GETTEXTLENGTHEX gt;
1891
1892     ZeroMemory(&fmt, sizeof(fmt));
1893     fmt.cbSize = sizeof(fmt);
1894
1895     ZeroMemory(&pf, sizeof(pf));
1896     pf.cbSize = sizeof(pf);
1897
1898     gt.flags = GTL_NUMCHARS;
1899     gt.codepage = 1200;
1900
1901     SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_FIND,
1902                  SendMessageW(hwndEditor, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0) ? 1 : 0);
1903
1904     SendMessageW(hwndEditor, EM_GETCHARFORMAT, TRUE, (LPARAM)&fmt);
1905
1906     SendMessageW(hwndEditor, EM_GETSEL, (WPARAM)&from, (LPARAM)&to);
1907     SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_EDIT_UNDO,
1908       SendMessageW(hwndEditor, EM_CANUNDO, 0, 0));
1909     SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_EDIT_REDO,
1910       SendMessageW(hwndEditor, EM_CANREDO, 0, 0));
1911     SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_EDIT_CUT, from == to ? 0 : 1);
1912     SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_EDIT_COPY, from == to ? 0 : 1);
1913
1914     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_FORMAT_BOLD, (fmt.dwMask & CFM_BOLD) &&
1915             (fmt.dwEffects & CFE_BOLD));
1916     SendMessageW(hwndFormatBar, TB_INDETERMINATE, ID_FORMAT_BOLD, !(fmt.dwMask & CFM_BOLD));
1917     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_FORMAT_ITALIC, (fmt.dwMask & CFM_ITALIC) &&
1918             (fmt.dwEffects & CFE_ITALIC));
1919     SendMessageW(hwndFormatBar, TB_INDETERMINATE, ID_FORMAT_ITALIC, !(fmt.dwMask & CFM_ITALIC));
1920     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_FORMAT_UNDERLINE, (fmt.dwMask & CFM_UNDERLINE) &&
1921             (fmt.dwEffects & CFE_UNDERLINE));
1922     SendMessageW(hwndFormatBar, TB_INDETERMINATE, ID_FORMAT_UNDERLINE, !(fmt.dwMask & CFM_UNDERLINE));
1923
1924     SendMessageW(hwndEditor, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
1925     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_ALIGN_LEFT, (pf.wAlignment == PFA_LEFT));
1926     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_ALIGN_CENTER, (pf.wAlignment == PFA_CENTER));
1927     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_ALIGN_RIGHT, (pf.wAlignment == PFA_RIGHT));
1928
1929     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_BULLET, (pf.wNumbering & PFN_BULLET));
1930     return 0;
1931 }
1932
1933 static LRESULT OnNotify( HWND hWnd, LPARAM lParam)
1934 {
1935     HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
1936     HWND hwndReBar = GetDlgItem(hWnd, IDC_REBAR);
1937     NMHDR *pHdr = (NMHDR *)lParam;
1938     HWND hwndFontList = GetDlgItem(hwndReBar, IDC_FONTLIST);
1939     HWND hwndSizeList = GetDlgItem(hwndReBar, IDC_SIZELIST);
1940
1941     if (pHdr->hwndFrom == hwndFontList || pHdr->hwndFrom == hwndSizeList)
1942     {
1943         if (pHdr->code == CBEN_ENDEDITW)
1944         {
1945             NMCBEENDEDIT *endEdit = (NMCBEENDEDIT *)lParam;
1946             if(pHdr->hwndFrom == hwndFontList)
1947             {
1948                 on_fontlist_modified((LPWSTR)endEdit->szText);
1949             } else if (pHdr->hwndFrom == hwndSizeList)
1950             {
1951                 on_sizelist_modified(hwndFontList,(LPWSTR)endEdit->szText);
1952             }
1953         }
1954         return 0;
1955     }
1956
1957     if (pHdr->hwndFrom != hwndEditor)
1958         return 0;
1959
1960     if (pHdr->code == EN_SELCHANGE)
1961     {
1962         SELCHANGE *pSC = (SELCHANGE *)lParam;
1963         char buf[128];
1964
1965         update_font_list();
1966
1967         sprintf( buf,"selection = %d..%d, line count=%ld",
1968                  pSC->chrg.cpMin, pSC->chrg.cpMax,
1969                 SendMessage(hwndEditor, EM_GETLINECOUNT, 0, 0));
1970         SetWindowTextA(GetDlgItem(hWnd, IDC_STATUSBAR), buf);
1971         SendMessage(hWnd, WM_USER, 0, 0);
1972         return 1;
1973     }
1974     return 0;
1975 }
1976
1977 static LRESULT OnCommand( HWND hWnd, WPARAM wParam, LPARAM lParam)
1978 {
1979     HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
1980     static FINDREPLACEW findreplace;
1981
1982     if ((HWND)lParam == hwndEditor)
1983         return 0;
1984
1985     switch(LOWORD(wParam))
1986     {
1987
1988     case ID_FILE_EXIT:
1989         PostMessageW(hWnd, WM_CLOSE, 0, 0);
1990         break;
1991
1992     case ID_FILE_NEW:
1993         {
1994             HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
1995             int ret = DialogBox(hInstance, MAKEINTRESOURCE(IDD_NEWFILE), hWnd,
1996                                 newfile_proc);
1997
1998             if(ret != ID_NEWFILE_ABORT)
1999             {
2000                 if(prompt_save_changes())
2001                 {
2002                     SETTEXTEX st;
2003
2004                     set_caption(NULL);
2005                     wszFileName[0] = '\0';
2006
2007                     clear_formatting();
2008
2009                     st.flags = ST_DEFAULT;
2010                     st.codepage = 1200;
2011                     SendMessageW(hEditorWnd, EM_SETTEXTEX, (WPARAM)&st, 0);
2012
2013                     SendMessageW(hEditorWnd, EM_SETMODIFY, FALSE, 0);
2014                     set_fileformat(ret);
2015                     update_font_list();
2016                 }
2017             }
2018         }
2019         break;
2020
2021     case ID_FILE_OPEN:
2022         DialogOpenFile();
2023         break;
2024
2025     case ID_FILE_SAVE:
2026         if(wszFileName[0])
2027         {
2028             DoSaveFile(wszFileName, fileFormat);
2029             break;
2030         }
2031         /* Fall through */
2032
2033     case ID_FILE_SAVEAS:
2034         DialogSaveFile();
2035         break;
2036
2037     case ID_FILE_RECENT1:
2038     case ID_FILE_RECENT2:
2039     case ID_FILE_RECENT3:
2040     case ID_FILE_RECENT4:
2041         {
2042             HMENU hMenu = GetMenu(hWnd);
2043             MENUITEMINFOW mi;
2044
2045             mi.cbSize = sizeof(MENUITEMINFOW);
2046             mi.fMask = MIIM_DATA;
2047             if(GetMenuItemInfoW(hMenu, LOWORD(wParam), FALSE, &mi))
2048                 DoOpenFile((LPWSTR)mi.dwItemData);
2049         }
2050         break;
2051
2052     case ID_FIND:
2053         dialog_find(&findreplace, FALSE);
2054         break;
2055
2056     case ID_FIND_NEXT:
2057         handle_findmsg(&findreplace);
2058         break;
2059
2060     case ID_REPLACE:
2061         dialog_find(&findreplace, TRUE);
2062         break;
2063
2064     case ID_FONTSETTINGS:
2065         dialog_choose_font();
2066         break;
2067
2068     case ID_PRINT:
2069         dialog_print(hWnd, wszFileName);
2070         target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
2071         break;
2072
2073     case ID_PRINT_QUICK:
2074         print_quick(wszFileName);
2075         target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
2076         break;
2077
2078     case ID_PREVIEW:
2079         {
2080             int index = reg_formatindex(fileFormat);
2081             DWORD tmp = barState[index];
2082             barState[index] = 0;
2083             set_bar_states();
2084             barState[index] = tmp;
2085             ShowWindow(hEditorWnd, FALSE);
2086
2087             init_preview(hWnd, wszFileName);
2088
2089             SetMenu(hWnd, NULL);
2090             InvalidateRect(0, 0, TRUE);
2091         }
2092         break;
2093
2094     case ID_PRINTSETUP:
2095         dialog_printsetup(hWnd);
2096         target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
2097         break;
2098
2099     case ID_FORMAT_BOLD:
2100     case ID_FORMAT_ITALIC:
2101     case ID_FORMAT_UNDERLINE:
2102         {
2103         CHARFORMAT2W fmt;
2104         int effects = CFE_BOLD;
2105
2106         ZeroMemory(&fmt, sizeof(fmt));
2107         fmt.cbSize = sizeof(fmt);
2108         SendMessageW(hwndEditor, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
2109
2110         fmt.dwMask = CFM_BOLD;
2111
2112         if (LOWORD(wParam) == ID_FORMAT_ITALIC)
2113         {
2114             effects = CFE_ITALIC;
2115             fmt.dwMask = CFM_ITALIC;
2116         } else if (LOWORD(wParam) == ID_FORMAT_UNDERLINE)
2117         {
2118             effects = CFE_UNDERLINE;
2119             fmt.dwMask = CFM_UNDERLINE;
2120         }
2121
2122         fmt.dwEffects ^= effects;
2123
2124         SendMessageW(hwndEditor, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
2125         break;
2126         }
2127
2128     case ID_EDIT_CUT:
2129         PostMessageW(hwndEditor, WM_CUT, 0, 0);
2130         break;
2131
2132     case ID_EDIT_COPY:
2133         PostMessageW(hwndEditor, WM_COPY, 0, 0);
2134         break;
2135
2136     case ID_EDIT_PASTE:
2137         PostMessageW(hwndEditor, WM_PASTE, 0, 0);
2138         break;
2139
2140     case ID_EDIT_CLEAR:
2141         PostMessageW(hwndEditor, WM_CLEAR, 0, 0);
2142         break;
2143
2144     case ID_EDIT_SELECTALL:
2145         {
2146         CHARRANGE range = {0, -1};
2147         SendMessageW(hwndEditor, EM_EXSETSEL, 0, (LPARAM)&range);
2148         /* SendMessage(hwndEditor, EM_SETSEL, 0, -1); */
2149         return 0;
2150         }
2151
2152     case ID_EDIT_GETTEXT:
2153         {
2154         int nLen = GetWindowTextLengthW(hwndEditor);
2155         LPWSTR data = HeapAlloc( GetProcessHeap(), 0, (nLen+1)*sizeof(WCHAR) );
2156         TEXTRANGEW tr;
2157
2158         GetWindowTextW(hwndEditor, data, nLen+1);
2159         MessageBoxW(NULL, data, wszAppTitle, MB_OK);
2160
2161         HeapFree( GetProcessHeap(), 0, data);
2162         data = HeapAlloc(GetProcessHeap(), 0, (nLen+1)*sizeof(WCHAR));
2163         tr.chrg.cpMin = 0;
2164         tr.chrg.cpMax = nLen;
2165         tr.lpstrText = data;
2166         SendMessage (hwndEditor, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
2167         MessageBoxW(NULL, data, wszAppTitle, MB_OK);
2168         HeapFree( GetProcessHeap(), 0, data );
2169
2170         /* SendMessage(hwndEditor, EM_SETSEL, 0, -1); */
2171         return 0;
2172         }
2173
2174     case ID_EDIT_CHARFORMAT:
2175     case ID_EDIT_DEFCHARFORMAT:
2176         {
2177         CHARFORMAT2W cf;
2178         LRESULT i;
2179         ZeroMemory(&cf, sizeof(cf));
2180         cf.cbSize = sizeof(cf);
2181         cf.dwMask = 0;
2182         i = SendMessageW(hwndEditor, EM_GETCHARFORMAT,
2183                         LOWORD(wParam) == ID_EDIT_CHARFORMAT, (LPARAM)&cf);
2184         return 0;
2185         }
2186
2187     case ID_EDIT_PARAFORMAT:
2188         {
2189         PARAFORMAT2 pf;
2190         ZeroMemory(&pf, sizeof(pf));
2191         pf.cbSize = sizeof(pf);
2192         SendMessageW(hwndEditor, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
2193         return 0;
2194         }
2195
2196     case ID_EDIT_SELECTIONINFO:
2197         {
2198         CHARRANGE range = {0, -1};
2199         char buf[128];
2200         WCHAR *data = NULL;
2201
2202         SendMessage(hwndEditor, EM_EXGETSEL, 0, (LPARAM)&range);
2203         data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data) * (range.cpMax-range.cpMin+1));
2204         SendMessage(hwndEditor, EM_GETSELTEXT, 0, (LPARAM)data);
2205         sprintf(buf, "Start = %d, End = %d", range.cpMin, range.cpMax);
2206         MessageBoxA(hWnd, buf, "Editor", MB_OK);
2207         MessageBoxW(hWnd, data, wszAppTitle, MB_OK);
2208         HeapFree( GetProcessHeap(), 0, data);
2209         /* SendMessage(hwndEditor, EM_SETSEL, 0, -1); */
2210         return 0;
2211         }
2212
2213     case ID_EDIT_READONLY:
2214         {
2215         long nStyle = GetWindowLong(hwndEditor, GWL_STYLE);
2216         if (nStyle & ES_READONLY)
2217             SendMessageW(hwndEditor, EM_SETREADONLY, 0, 0);
2218         else
2219             SendMessageW(hwndEditor, EM_SETREADONLY, 1, 0);
2220         return 0;
2221         }
2222
2223     case ID_EDIT_MODIFIED:
2224         if (SendMessageW(hwndEditor, EM_GETMODIFY, 0, 0))
2225             SendMessageW(hwndEditor, EM_SETMODIFY, 0, 0);
2226         else
2227             SendMessageW(hwndEditor, EM_SETMODIFY, 1, 0);
2228         return 0;
2229
2230     case ID_EDIT_UNDO:
2231         SendMessageW(hwndEditor, EM_UNDO, 0, 0);
2232         return 0;
2233
2234     case ID_EDIT_REDO:
2235         SendMessageW(hwndEditor, EM_REDO, 0, 0);
2236         return 0;
2237
2238     case ID_BULLET:
2239         {
2240             PARAFORMAT pf;
2241
2242             pf.cbSize = sizeof(pf);
2243             pf.dwMask = PFM_NUMBERING;
2244             SendMessageW(hwndEditor, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
2245
2246             pf.dwMask |=  PFM_OFFSET;
2247
2248             if(pf.wNumbering == PFN_BULLET)
2249             {
2250                 pf.wNumbering = 0;
2251                 pf.dxOffset = 0;
2252             } else
2253             {
2254                 pf.wNumbering = PFN_BULLET;
2255                 pf.dxOffset = 720;
2256             }
2257
2258             SendMessageW(hwndEditor, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
2259         }
2260         break;
2261
2262     case ID_ALIGN_LEFT:
2263     case ID_ALIGN_CENTER:
2264     case ID_ALIGN_RIGHT:
2265         {
2266         PARAFORMAT2 pf;
2267
2268         pf.cbSize = sizeof(pf);
2269         pf.dwMask = PFM_ALIGNMENT;
2270         switch(LOWORD(wParam)) {
2271         case ID_ALIGN_LEFT: pf.wAlignment = PFA_LEFT; break;
2272         case ID_ALIGN_CENTER: pf.wAlignment = PFA_CENTER; break;
2273         case ID_ALIGN_RIGHT: pf.wAlignment = PFA_RIGHT; break;
2274         }
2275         SendMessageW(hwndEditor, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
2276         break;
2277         }
2278
2279     case ID_BACK_1:
2280         SendMessageW(hwndEditor, EM_SETBKGNDCOLOR, 1, 0);
2281         break;
2282
2283     case ID_BACK_2:
2284         SendMessageW(hwndEditor, EM_SETBKGNDCOLOR, 0, RGB(255,255,192));
2285         break;
2286
2287     case ID_TOGGLE_TOOLBAR:
2288         set_toolbar_state(BANDID_TOOLBAR, !is_bar_visible(BANDID_TOOLBAR));
2289         update_window();
2290         break;
2291
2292     case ID_TOGGLE_FORMATBAR:
2293         set_toolbar_state(BANDID_FONTLIST, !is_bar_visible(BANDID_FORMATBAR));
2294         set_toolbar_state(BANDID_SIZELIST, !is_bar_visible(BANDID_FORMATBAR));
2295         set_toolbar_state(BANDID_FORMATBAR, !is_bar_visible(BANDID_FORMATBAR));
2296         update_window();
2297         break;
2298
2299     case ID_TOGGLE_STATUSBAR:
2300         set_statusbar_state(!is_bar_visible(BANDID_STATUSBAR));
2301         update_window();
2302         break;
2303
2304     case ID_TOGGLE_RULER:
2305         set_toolbar_state(BANDID_RULER, !is_bar_visible(BANDID_RULER));
2306         update_window();
2307         break;
2308
2309     case ID_DATETIME:
2310         {
2311         HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
2312         DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_DATETIME), hWnd, datetime_proc);
2313         break;
2314         }
2315
2316     case ID_PARAFORMAT:
2317         {
2318             HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
2319             DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_PARAFORMAT), hWnd,
2320                        paraformat_proc);
2321         }
2322         break;
2323
2324     case ID_TABSTOPS:
2325         {
2326             HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
2327             DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_TABSTOPS), hWnd, tabstops_proc);
2328         }
2329         break;
2330
2331     case ID_ABOUT:
2332         dialog_about();
2333         break;
2334
2335     case ID_VIEWPROPERTIES:
2336         dialog_viewproperties();
2337         break;
2338
2339     case IDC_FONTLIST:
2340         if (HIWORD(wParam) == CBN_SELENDOK)
2341         {
2342             WCHAR buffer[LF_FACESIZE];
2343             HWND hwndFontList = (HWND)lParam;
2344             get_comboexlist_selection(hwndFontList, buffer, LF_FACESIZE);
2345             on_fontlist_modified(buffer);
2346         }
2347         break;
2348
2349     case IDC_SIZELIST:
2350         if (HIWORD(wParam) == CBN_SELENDOK)
2351         {
2352             WCHAR buffer[MAX_STRING_LEN+1];
2353             HWND hwndSizeList = (HWND)lParam;
2354             get_comboexlist_selection(hwndSizeList, buffer, MAX_STRING_LEN+1);
2355             on_sizelist_modified(hwndSizeList, buffer);
2356         }
2357         break;
2358
2359     default:
2360         SendMessageW(hwndEditor, WM_COMMAND, wParam, lParam);
2361         break;
2362     }
2363     return 0;
2364 }
2365
2366 static LRESULT OnInitPopupMenu( HWND hWnd, WPARAM wParam )
2367 {
2368     HMENU hMenu = (HMENU)wParam;
2369     HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
2370     HWND hwndStatus = GetDlgItem(hWnd, IDC_STATUSBAR);
2371     PARAFORMAT pf;
2372     int nAlignment = -1;
2373     int selFrom, selTo;
2374     GETTEXTLENGTHEX gt;
2375     LRESULT textLength;
2376     MENUITEMINFOW mi;
2377
2378     SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&selFrom, (LPARAM)&selTo);
2379     EnableMenuItem(hMenu, ID_EDIT_COPY, MF_BYCOMMAND|(selFrom == selTo) ? MF_GRAYED : MF_ENABLED);
2380     EnableMenuItem(hMenu, ID_EDIT_CUT, MF_BYCOMMAND|(selFrom == selTo) ? MF_GRAYED : MF_ENABLED);
2381
2382     pf.cbSize = sizeof(PARAFORMAT);
2383     SendMessageW(hwndEditor, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
2384     CheckMenuItem(hMenu, ID_EDIT_READONLY,
2385       MF_BYCOMMAND|(GetWindowLong(hwndEditor, GWL_STYLE)&ES_READONLY ? MF_CHECKED : MF_UNCHECKED));
2386     CheckMenuItem(hMenu, ID_EDIT_MODIFIED,
2387       MF_BYCOMMAND|(SendMessage(hwndEditor, EM_GETMODIFY, 0, 0) ? MF_CHECKED : MF_UNCHECKED));
2388     if (pf.dwMask & PFM_ALIGNMENT)
2389         nAlignment = pf.wAlignment;
2390     CheckMenuItem(hMenu, ID_ALIGN_LEFT, MF_BYCOMMAND|(nAlignment == PFA_LEFT) ?
2391             MF_CHECKED : MF_UNCHECKED);
2392     CheckMenuItem(hMenu, ID_ALIGN_CENTER, MF_BYCOMMAND|(nAlignment == PFA_CENTER) ?
2393             MF_CHECKED : MF_UNCHECKED);
2394     CheckMenuItem(hMenu, ID_ALIGN_RIGHT, MF_BYCOMMAND|(nAlignment == PFA_RIGHT) ?
2395             MF_CHECKED : MF_UNCHECKED);
2396     CheckMenuItem(hMenu, ID_BULLET, MF_BYCOMMAND | ((pf.wNumbering == PFN_BULLET) ?
2397             MF_CHECKED : MF_UNCHECKED));
2398     EnableMenuItem(hMenu, ID_EDIT_UNDO, MF_BYCOMMAND|(SendMessageW(hwndEditor, EM_CANUNDO, 0, 0)) ?
2399             MF_ENABLED : MF_GRAYED);
2400     EnableMenuItem(hMenu, ID_EDIT_REDO, MF_BYCOMMAND|(SendMessageW(hwndEditor, EM_CANREDO, 0, 0)) ?
2401             MF_ENABLED : MF_GRAYED);
2402
2403     CheckMenuItem(hMenu, ID_TOGGLE_TOOLBAR, MF_BYCOMMAND|(is_bar_visible(BANDID_TOOLBAR)) ?
2404             MF_CHECKED : MF_UNCHECKED);
2405
2406     CheckMenuItem(hMenu, ID_TOGGLE_FORMATBAR, MF_BYCOMMAND|(is_bar_visible(BANDID_FORMATBAR)) ?
2407             MF_CHECKED : MF_UNCHECKED);
2408
2409     CheckMenuItem(hMenu, ID_TOGGLE_STATUSBAR, MF_BYCOMMAND|IsWindowVisible(hwndStatus) ?
2410             MF_CHECKED : MF_UNCHECKED);
2411
2412     CheckMenuItem(hMenu, ID_TOGGLE_RULER, MF_BYCOMMAND|(is_bar_visible(BANDID_RULER)) ? MF_CHECKED : MF_UNCHECKED);
2413
2414     gt.flags = GTL_NUMCHARS;
2415     gt.codepage = 1200;
2416     textLength = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0);
2417     EnableMenuItem(hMenu, ID_FIND, MF_BYCOMMAND|(textLength ? MF_ENABLED : MF_GRAYED));
2418
2419     mi.cbSize = sizeof(mi);
2420     mi.fMask = MIIM_DATA;
2421
2422     GetMenuItemInfoW(hMenu, ID_FIND_NEXT, FALSE, &mi);
2423
2424     EnableMenuItem(hMenu, ID_FIND_NEXT, MF_BYCOMMAND|((textLength && mi.dwItemData) ?
2425                    MF_ENABLED : MF_GRAYED));
2426
2427     EnableMenuItem(hMenu, ID_REPLACE, MF_BYCOMMAND|(textLength ? MF_ENABLED : MF_GRAYED));
2428
2429     return 0;
2430 }
2431
2432 static LRESULT OnSize( HWND hWnd, WPARAM wParam, LPARAM lParam )
2433 {
2434     int nStatusSize = 0;
2435     RECT rc;
2436     HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
2437     HWND hwndStatusBar = GetDlgItem(hWnd, IDC_STATUSBAR);
2438     HWND hwndReBar = GetDlgItem(hWnd, IDC_REBAR);
2439     HWND hRulerWnd = GetDlgItem(hWnd, IDC_RULER);
2440     int rebarHeight = 0;
2441
2442     if (hwndStatusBar)
2443     {
2444         SendMessageW(hwndStatusBar, WM_SIZE, 0, 0);
2445         if (IsWindowVisible(hwndStatusBar))
2446         {
2447             GetClientRect(hwndStatusBar, &rc);
2448             nStatusSize = rc.bottom - rc.top;
2449         } else
2450         {
2451             nStatusSize = 0;
2452         }
2453     }
2454     if (hwndReBar)
2455     {
2456         rebarHeight = SendMessageW(hwndReBar, RB_GETBARHEIGHT, 0, 0);
2457
2458         MoveWindow(hwndReBar, 0, 0, LOWORD(lParam), rebarHeight, TRUE);
2459     }
2460     if (hwndEditor)
2461     {
2462         GetClientRect(hWnd, &rc);
2463         MoveWindow(hwndEditor, 0, rebarHeight, rc.right, rc.bottom-nStatusSize-rebarHeight, TRUE);
2464     }
2465
2466     redraw_ruler(hRulerWnd);
2467
2468     return DefWindowProcW(hWnd, WM_SIZE, wParam, lParam);
2469 }
2470
2471 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
2472 {
2473     if(msg == ID_FINDMSGSTRING)
2474         return handle_findmsg((LPFINDREPLACEW)lParam);
2475
2476     switch(msg)
2477     {
2478     case WM_CREATE:
2479         return OnCreate( hWnd );
2480
2481     case WM_USER:
2482         return OnUser( hWnd );
2483
2484     case WM_NOTIFY:
2485         return OnNotify( hWnd, lParam );
2486
2487     case WM_COMMAND:
2488         if(preview_isactive())
2489         {
2490             return preview_command( hWnd, wParam );
2491         }
2492
2493         return OnCommand( hWnd, wParam, lParam );
2494
2495     case WM_DESTROY:
2496         PostQuitMessage(0);
2497         break;
2498
2499     case WM_CLOSE:
2500         if(preview_isactive())
2501         {
2502             preview_exit(hWnd);
2503         } else if(prompt_save_changes())
2504         {
2505             registry_set_options(hMainWnd);
2506             registry_set_formatopts_all(barState);
2507             PostQuitMessage(0);
2508         }
2509         break;
2510
2511     case WM_ACTIVATE:
2512         if (LOWORD(wParam))
2513             SetFocus(GetDlgItem(hWnd, IDC_EDITOR));
2514         return 0;
2515
2516     case WM_INITMENUPOPUP:
2517         return OnInitPopupMenu( hWnd, wParam );
2518
2519     case WM_SIZE:
2520         return OnSize( hWnd, wParam, lParam );
2521
2522     case WM_CONTEXTMENU:
2523         if((HWND)wParam == hEditorWnd)
2524             return context_menu(lParam);
2525         else
2526             return DefWindowProcW(hWnd, msg, wParam, lParam);
2527
2528     case WM_DROPFILES:
2529         {
2530             WCHAR file[MAX_PATH];
2531             DragQueryFileW((HDROP)wParam, 0, file, MAX_PATH);
2532             DragFinish((HDROP)wParam);
2533
2534             if(prompt_save_changes())
2535                 DoOpenFile(file);
2536         }
2537         break;
2538     case WM_PAINT:
2539         if(preview_isactive())
2540             return print_preview(hWnd);
2541         else
2542             return DefWindowProcW(hWnd, msg, wParam, lParam);
2543
2544     default:
2545         return DefWindowProcW(hWnd, msg, wParam, lParam);
2546     }
2547
2548     return 0;
2549 }
2550
2551 int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hOldInstance, LPSTR szCmdParagraph, int nCmdShow)
2552 {
2553     INITCOMMONCONTROLSEX classes = {8, ICC_BAR_CLASSES|ICC_COOL_CLASSES|ICC_USEREX_CLASSES};
2554     HACCEL hAccel;
2555     WNDCLASSW wc;
2556     MSG msg;
2557     RECT rc;
2558     UINT_PTR hPrevRulerProc;
2559     HWND hRulerWnd;
2560     POINTL EditPoint;
2561     DWORD bMaximized;
2562     static const WCHAR wszAccelTable[] = {'M','A','I','N','A','C','C','E','L',
2563                                           'T','A','B','L','E','\0'};
2564
2565     InitCommonControlsEx(&classes);
2566
2567     hAccel = LoadAcceleratorsW(hInstance, wszAccelTable);
2568
2569     wc.style = CS_HREDRAW | CS_VREDRAW;
2570     wc.lpfnWndProc = WndProc;
2571     wc.cbClsExtra = 0;
2572     wc.cbWndExtra = 4;
2573     wc.hInstance = hInstance;
2574     wc.hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_WORDPAD));
2575     wc.hCursor = LoadCursor(NULL, IDC_IBEAM);
2576     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
2577     wc.lpszMenuName = MAKEINTRESOURCEW(IDM_MAINMENU);
2578     wc.lpszClassName = wszMainWndClass;
2579     RegisterClassW(&wc);
2580
2581     registry_read_winrect(&rc);
2582     hMainWnd = CreateWindowExW(0, wszMainWndClass, wszAppTitle, WS_CLIPCHILDREN|WS_OVERLAPPEDWINDOW,
2583       rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, hInstance, NULL);
2584     registry_read_maximized(&bMaximized);
2585     if ((nCmdShow == SW_SHOWNORMAL || nCmdShow == SW_SHOWDEFAULT)
2586              && bMaximized)
2587         nCmdShow = SW_SHOWMAXIMIZED;
2588     ShowWindow(hMainWnd, nCmdShow);
2589
2590     set_caption(NULL);
2591     set_bar_states();
2592     set_fileformat(SF_RTF);
2593     hPopupMenu = LoadMenuW(hInstance, MAKEINTRESOURCEW(IDM_POPUP));
2594     get_default_printer_opts();
2595     target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
2596
2597     hRulerWnd = GetDlgItem(GetDlgItem(hMainWnd, IDC_REBAR), IDC_RULER);
2598     SendMessageW(GetDlgItem(hMainWnd, IDC_EDITOR), EM_POSFROMCHAR, (WPARAM)&EditPoint, 0);
2599     hPrevRulerProc = SetWindowLongPtrW(hRulerWnd, GWLP_WNDPROC, (UINT_PTR)ruler_proc);
2600     SendMessageW(hRulerWnd, WM_USER, (WPARAM)&EditPoint, hPrevRulerProc);
2601
2602     HandleCommandLine(GetCommandLineW());
2603
2604     while(GetMessageW(&msg,0,0,0))
2605     {
2606         if (IsDialogMessage(hFindWnd, &msg))
2607             continue;
2608
2609         if (TranslateAcceleratorW(hMainWnd, hAccel, &msg))
2610             continue;
2611         TranslateMessage(&msg);
2612         DispatchMessageW(&msg);
2613         if (!PeekMessageW(&msg, 0, 0, 0, PM_NOREMOVE))
2614             SendMessageW(hMainWnd, WM_USER, 0, 0);
2615     }
2616
2617     return 0;
2618 }