wordpad: Do not pass resource ids to MessageBox.
[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((LPCWSTR) 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 = (LPWSTR)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((LPCWSTR) 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     wsprintfW(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_GETITEM, 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 IDOK:
1377                     {
1378                         LRESULT index;
1379                         HWND hListWnd = GetDlgItem(hWnd, IDC_DATETIME);
1380
1381                         index = SendMessageW(hListWnd, LB_GETCURSEL, 0, 0);
1382
1383                         if(index != LB_ERR)
1384                         {
1385                             WCHAR buffer[MAX_STRING_LEN];
1386                             SendMessageW(hListWnd, LB_GETTEXT, index, (LPARAM)&buffer);
1387                             SendMessageW(hEditorWnd, EM_REPLACESEL, TRUE, (LPARAM)&buffer);
1388                         }
1389                     }
1390                     /* Fall through */
1391
1392                 case IDCANCEL:
1393                     EndDialog(hWnd, wParam);
1394                     return TRUE;
1395             }
1396     }
1397     return FALSE;
1398 }
1399
1400 static INT_PTR CALLBACK newfile_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1401 {
1402     switch(message)
1403     {
1404         case WM_INITDIALOG:
1405             {
1406                 HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hMainWnd, GWLP_HINSTANCE);
1407                 WCHAR buffer[MAX_STRING_LEN];
1408                 HWND hListWnd = GetDlgItem(hWnd, IDC_NEWFILE);
1409
1410                 LoadStringW(hInstance, STRING_NEWFILE_RICHTEXT, (LPWSTR)buffer, MAX_STRING_LEN);
1411                 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1412                 LoadStringW(hInstance, STRING_NEWFILE_TXT, (LPWSTR)buffer, MAX_STRING_LEN);
1413                 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1414                 LoadStringW(hInstance, STRING_NEWFILE_TXT_UNICODE, (LPWSTR)buffer, MAX_STRING_LEN);
1415                 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1416
1417                 SendMessageW(hListWnd, LB_SETSEL, TRUE, 0);
1418             }
1419             break;
1420
1421         case WM_COMMAND:
1422             switch(LOWORD(wParam))
1423             {
1424                 case IDOK:
1425                     {
1426                         LRESULT index;
1427                         HWND hListWnd = GetDlgItem(hWnd, IDC_NEWFILE);
1428                         index = SendMessageW(hListWnd, LB_GETCURSEL, 0, 0);
1429
1430                         if(index != LB_ERR)
1431                             EndDialog(hWnd, MAKELONG(fileformat_flags(index),0));
1432                     }
1433                     return TRUE;
1434
1435                 case IDCANCEL:
1436                     EndDialog(hWnd, MAKELONG(ID_NEWFILE_ABORT,0));
1437                     return TRUE;
1438             }
1439     }
1440     return FALSE;
1441 }
1442
1443 static INT_PTR CALLBACK paraformat_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1444 {
1445     static const WORD ALIGNMENT_VALUES[] = {PFA_LEFT, PFA_RIGHT, PFA_CENTER};
1446
1447     switch(message)
1448     {
1449         case WM_INITDIALOG:
1450             {
1451                 HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hMainWnd,
1452                                                                   GWLP_HINSTANCE);
1453                 WCHAR buffer[MAX_STRING_LEN];
1454                 HWND hListWnd = GetDlgItem(hWnd, IDC_PARA_ALIGN);
1455                 HWND hLeftWnd = GetDlgItem(hWnd, IDC_PARA_LEFT);
1456                 HWND hRightWnd = GetDlgItem(hWnd, IDC_PARA_RIGHT);
1457                 HWND hFirstWnd = GetDlgItem(hWnd, IDC_PARA_FIRST);
1458                 PARAFORMAT2 pf;
1459                 int index = 0;
1460
1461                 LoadStringW(hInstance, STRING_ALIGN_LEFT, buffer,
1462                             MAX_STRING_LEN);
1463                 SendMessageW(hListWnd, CB_ADDSTRING, 0, (LPARAM)buffer);
1464                 LoadStringW(hInstance, STRING_ALIGN_RIGHT, buffer,
1465                             MAX_STRING_LEN);
1466                 SendMessageW(hListWnd, CB_ADDSTRING, 0, (LPARAM)buffer);
1467                 LoadStringW(hInstance, STRING_ALIGN_CENTER, buffer,
1468                             MAX_STRING_LEN);
1469                 SendMessageW(hListWnd, CB_ADDSTRING, 0, (LPARAM)buffer);
1470
1471                 pf.cbSize = sizeof(pf);
1472                 pf.dwMask = PFM_ALIGNMENT | PFM_OFFSET | PFM_RIGHTINDENT |
1473                             PFM_STARTINDENT;
1474                 SendMessageW(hEditorWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
1475
1476                 if(pf.wAlignment == PFA_RIGHT)
1477                     index ++;
1478                 else if(pf.wAlignment == PFA_CENTER)
1479                     index += 2;
1480
1481                 SendMessageW(hListWnd, CB_SETCURSEL, index, 0);
1482
1483                 number_with_units(buffer, pf.dxStartIndent + pf.dxOffset);
1484                 SetWindowTextW(hLeftWnd, buffer);
1485                 number_with_units(buffer, pf.dxRightIndent);
1486                 SetWindowTextW(hRightWnd, buffer);
1487                 number_with_units(buffer, -pf.dxOffset);
1488                 SetWindowTextW(hFirstWnd, buffer);
1489             }
1490             break;
1491
1492         case WM_COMMAND:
1493             switch(LOWORD(wParam))
1494             {
1495                 case IDOK:
1496                     {
1497                         HWND hListWnd = GetDlgItem(hWnd, IDC_PARA_ALIGN);
1498                         HWND hLeftWnd = GetDlgItem(hWnd, IDC_PARA_LEFT);
1499                         HWND hRightWnd = GetDlgItem(hWnd, IDC_PARA_RIGHT);
1500                         HWND hFirstWnd = GetDlgItem(hWnd, IDC_PARA_FIRST);
1501                         WCHAR buffer[MAX_STRING_LEN];
1502                         int index;
1503                         float num;
1504                         int ret = 0;
1505                         PARAFORMAT pf;
1506
1507                         index = SendMessageW(hListWnd, CB_GETCURSEL, 0, 0);
1508                         pf.wAlignment = ALIGNMENT_VALUES[index];
1509
1510                         GetWindowTextW(hLeftWnd, buffer, MAX_STRING_LEN);
1511                         if(number_from_string(buffer, &num, TRUE))
1512                             ret++;
1513                         pf.dxOffset = current_units_to_twips(num);
1514                         GetWindowTextW(hRightWnd, buffer, MAX_STRING_LEN);
1515                         if(number_from_string(buffer, &num, TRUE))
1516                             ret++;
1517                         pf.dxRightIndent = current_units_to_twips(num);
1518                         GetWindowTextW(hFirstWnd, buffer, MAX_STRING_LEN);
1519                         if(number_from_string(buffer, &num, TRUE))
1520                             ret++;
1521                         pf.dxStartIndent = current_units_to_twips(num);
1522
1523                         if(ret != 3)
1524                         {
1525                             MessageBoxWithResStringW(hMainWnd, MAKEINTRESOURCEW(STRING_INVALID_NUMBER),
1526                                         wszAppTitle, MB_OK | MB_ICONASTERISK);
1527                             return FALSE;
1528                         } else
1529                         {
1530                             if (pf.dxOffset + pf.dxStartIndent < 0
1531                                 && pf.dxStartIndent < 0)
1532                             {
1533                                 /* The first line is before the left edge, so
1534                                  * make sure it is at the left edge. */
1535                                 pf.dxOffset = -pf.dxStartIndent;
1536                             } else if (pf.dxOffset < 0) {
1537                                 /* The second and following lines are before
1538                                  * the left edge, so set it to be at the left
1539                                  * edge, and adjust the first line since it
1540                                  * is relative to it. */
1541                                 pf.dxStartIndent = max(pf.dxStartIndent + pf.dxOffset, 0);
1542                                 pf.dxOffset = 0;
1543                             }
1544                             /* Internally the dxStartIndent is the absolute
1545                              * offset for the first line and dxOffset is
1546                              * to it value as opposed how it is displayed with
1547                              * the first line being the relative value.
1548                              * These two lines make the adjustments. */
1549                             pf.dxStartIndent = pf.dxStartIndent + pf.dxOffset;
1550                             pf.dxOffset = pf.dxOffset - pf.dxStartIndent;
1551
1552                             pf.cbSize = sizeof(pf);
1553                             pf.dwMask = PFM_ALIGNMENT | PFM_OFFSET | PFM_RIGHTINDENT |
1554                                         PFM_STARTINDENT;
1555                             SendMessageW(hEditorWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
1556                         }
1557                     }
1558                     /* Fall through */
1559
1560                 case IDCANCEL:
1561                     EndDialog(hWnd, wParam);
1562                     return TRUE;
1563             }
1564     }
1565     return FALSE;
1566 }
1567
1568 static INT_PTR CALLBACK tabstops_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1569 {
1570     switch(message)
1571     {
1572         case WM_INITDIALOG:
1573             {
1574                 HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1575                 PARAFORMAT pf;
1576                 WCHAR buffer[MAX_STRING_LEN];
1577                 int i;
1578
1579                 pf.cbSize = sizeof(pf);
1580                 pf.dwMask = PFM_TABSTOPS;
1581                 SendMessageW(hEditorWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
1582                 SendMessageW(hTabWnd, CB_LIMITTEXT, MAX_STRING_LEN-1, 0);
1583
1584                 for(i = 0; i < pf.cTabCount; i++)
1585                 {
1586                     number_with_units(buffer, pf.rgxTabs[i]);
1587                     SendMessageW(hTabWnd, CB_ADDSTRING, 0, (LPARAM)&buffer);
1588                 }
1589                 SetFocus(hTabWnd);
1590             }
1591             break;
1592
1593         case WM_COMMAND:
1594             switch(LOWORD(wParam))
1595             {
1596                 case IDC_TABSTOPS:
1597                     {
1598                         HWND hTabWnd = (HWND)lParam;
1599                         HWND hAddWnd = GetDlgItem(hWnd, ID_TAB_ADD);
1600                         HWND hDelWnd = GetDlgItem(hWnd, ID_TAB_DEL);
1601                         HWND hEmptyWnd = GetDlgItem(hWnd, ID_TAB_EMPTY);
1602
1603                         if(GetWindowTextLengthW(hTabWnd))
1604                             EnableWindow(hAddWnd, TRUE);
1605                         else
1606                             EnableWindow(hAddWnd, FALSE);
1607
1608                         if(SendMessageW(hTabWnd, CB_GETCOUNT, 0, 0))
1609                         {
1610                             EnableWindow(hEmptyWnd, TRUE);
1611
1612                             if(SendMessageW(hTabWnd, CB_GETCURSEL, 0, 0) == CB_ERR)
1613                                 EnableWindow(hDelWnd, FALSE);
1614                             else
1615                                 EnableWindow(hDelWnd, TRUE);
1616                         } else
1617                         {
1618                             EnableWindow(hEmptyWnd, FALSE);
1619                         }
1620                     }
1621                     break;
1622
1623                 case ID_TAB_ADD:
1624                     {
1625                         HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1626                         WCHAR buffer[MAX_STRING_LEN];
1627
1628                         GetWindowTextW(hTabWnd, buffer, MAX_STRING_LEN);
1629                         append_current_units(buffer);
1630
1631                         if(SendMessageW(hTabWnd, CB_FINDSTRINGEXACT, -1, (LPARAM)&buffer) == CB_ERR)
1632                         {
1633                             float number = 0;
1634
1635                             if(!number_from_string(buffer, &number, TRUE))
1636                             {
1637                                 MessageBoxWithResStringW(hWnd, MAKEINTRESOURCEW(STRING_INVALID_NUMBER),
1638                                              wszAppTitle, MB_OK | MB_ICONINFORMATION);
1639                             } else
1640                             {
1641                                 SendMessageW(hTabWnd, CB_ADDSTRING, 0, (LPARAM)&buffer);
1642                                 SetWindowTextW(hTabWnd, 0);
1643                             }
1644                         }
1645                         SetFocus(hTabWnd);
1646                     }
1647                     break;
1648
1649                 case ID_TAB_DEL:
1650                     {
1651                         HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1652                         LRESULT ret;
1653                         ret = SendMessageW(hTabWnd, CB_GETCURSEL, 0, 0);
1654                         if(ret != CB_ERR)
1655                             SendMessageW(hTabWnd, CB_DELETESTRING, ret, 0);
1656                     }
1657                     break;
1658
1659                 case ID_TAB_EMPTY:
1660                     {
1661                         HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1662                         SendMessageW(hTabWnd, CB_RESETCONTENT, 0, 0);
1663                         SetFocus(hTabWnd);
1664                     }
1665                     break;
1666
1667                 case IDOK:
1668                     {
1669                         HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1670                         int i;
1671                         WCHAR buffer[MAX_STRING_LEN];
1672                         PARAFORMAT pf;
1673                         float number;
1674
1675                         pf.cbSize = sizeof(pf);
1676                         pf.dwMask = PFM_TABSTOPS;
1677
1678                         for(i = 0; SendMessageW(hTabWnd, CB_GETLBTEXT, i,
1679                                                 (LPARAM)&buffer) != CB_ERR &&
1680                                                         i < MAX_TAB_STOPS; i++)
1681                         {
1682                             number_from_string(buffer, &number, TRUE);
1683                             pf.rgxTabs[i] = current_units_to_twips(number);
1684                         }
1685                         pf.cTabCount = i;
1686                         SendMessageW(hEditorWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
1687                     }
1688                     /* Fall through */
1689                 case IDCANCEL:
1690                     EndDialog(hWnd, wParam);
1691                     return TRUE;
1692             }
1693     }
1694     return FALSE;
1695 }
1696
1697 static int context_menu(LPARAM lParam)
1698 {
1699     int x = (int)(short)LOWORD(lParam);
1700     int y = (int)(short)HIWORD(lParam);
1701     HMENU hPop = GetSubMenu(hPopupMenu, 0);
1702
1703     if(x == -1)
1704     {
1705         int from = 0, to = 0;
1706         POINTL pt;
1707         SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&from, (LPARAM)&to);
1708         SendMessageW(hEditorWnd, EM_POSFROMCHAR, (WPARAM)&pt, (LPARAM)to);
1709         ClientToScreen(hEditorWnd, (POINT*)&pt);
1710         x = pt.x;
1711         y = pt.y;
1712     }
1713
1714     TrackPopupMenu(hPop, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON,
1715                    x, y, 0, hMainWnd, 0);
1716
1717     return 0;
1718 }
1719
1720 static LRESULT OnCreate( HWND hWnd )
1721 {
1722     HWND hToolBarWnd, hFormatBarWnd,  hReBarWnd, hFontListWnd, hSizeListWnd, hRulerWnd;
1723     HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
1724     HANDLE hDLL;
1725     TBADDBITMAP ab;
1726     int nStdBitmaps = 0;
1727     REBARINFO rbi;
1728     REBARBANDINFOW rbb;
1729     static const WCHAR wszRichEditDll[] = {'R','I','C','H','E','D','2','0','.','D','L','L','\0'};
1730     static const WCHAR wszRichEditText[] = {'R','i','c','h','E','d','i','t',' ','t','e','x','t','\0'};
1731
1732     CreateStatusWindowW(CCS_NODIVIDER|WS_CHILD|WS_VISIBLE, wszRichEditText, hWnd, IDC_STATUSBAR);
1733
1734     hReBarWnd = CreateWindowExW(WS_EX_TOOLWINDOW, REBARCLASSNAMEW, NULL,
1735       CCS_NODIVIDER|WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|RBS_VARHEIGHT|CCS_TOP,
1736       CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hWnd, (HMENU)IDC_REBAR, hInstance, NULL);
1737
1738     rbi.cbSize = sizeof(rbi);
1739     rbi.fMask = 0;
1740     rbi.himl = NULL;
1741     if(!SendMessageW(hReBarWnd, RB_SETBARINFO, 0, (LPARAM)&rbi))
1742         return -1;
1743
1744     hToolBarWnd = CreateToolbarEx(hReBarWnd, CCS_NOPARENTALIGN|CCS_NOMOVEY|WS_VISIBLE|WS_CHILD|TBSTYLE_TOOLTIPS|TBSTYLE_BUTTON,
1745       IDC_TOOLBAR,
1746       1, hInstance, IDB_TOOLBAR,
1747       NULL, 0,
1748       24, 24, 16, 16, sizeof(TBBUTTON));
1749
1750     ab.hInst = HINST_COMMCTRL;
1751     ab.nID = IDB_STD_SMALL_COLOR;
1752     nStdBitmaps = SendMessageW(hToolBarWnd, TB_ADDBITMAP, 0, (LPARAM)&ab);
1753
1754     AddButton(hToolBarWnd, nStdBitmaps+STD_FILENEW, ID_FILE_NEW);
1755     AddButton(hToolBarWnd, nStdBitmaps+STD_FILEOPEN, ID_FILE_OPEN);
1756     AddButton(hToolBarWnd, nStdBitmaps+STD_FILESAVE, ID_FILE_SAVE);
1757     AddSeparator(hToolBarWnd);
1758     AddButton(hToolBarWnd, nStdBitmaps+STD_PRINT, ID_PRINT_QUICK);
1759     AddButton(hToolBarWnd, nStdBitmaps+STD_PRINTPRE, ID_PREVIEW);
1760     AddSeparator(hToolBarWnd);
1761     AddButton(hToolBarWnd, nStdBitmaps+STD_FIND, ID_FIND);
1762     AddSeparator(hToolBarWnd);
1763     AddButton(hToolBarWnd, nStdBitmaps+STD_CUT, ID_EDIT_CUT);
1764     AddButton(hToolBarWnd, nStdBitmaps+STD_COPY, ID_EDIT_COPY);
1765     AddButton(hToolBarWnd, nStdBitmaps+STD_PASTE, ID_EDIT_PASTE);
1766     AddButton(hToolBarWnd, nStdBitmaps+STD_UNDO, ID_EDIT_UNDO);
1767     AddButton(hToolBarWnd, nStdBitmaps+STD_REDOW, ID_EDIT_REDO);
1768     AddSeparator(hToolBarWnd);
1769     AddButton(hToolBarWnd, 0, ID_DATETIME);
1770
1771     SendMessageW(hToolBarWnd, TB_AUTOSIZE, 0, 0);
1772
1773     rbb.cbSize = sizeof(rbb);
1774     rbb.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD | RBBIM_STYLE | RBBIM_ID;
1775     rbb.fStyle = RBBS_CHILDEDGE | RBBS_BREAK | RBBS_NOGRIPPER;
1776     rbb.cx = 0;
1777     rbb.hwndChild = hToolBarWnd;
1778     rbb.cxMinChild = 0;
1779     rbb.cyChild = rbb.cyMinChild = HIWORD(SendMessageW(hToolBarWnd, TB_GETBUTTONSIZE, 0, 0));
1780     rbb.wID = BANDID_TOOLBAR;
1781
1782     SendMessageW(hReBarWnd, RB_INSERTBAND, -1, (LPARAM)&rbb);
1783
1784     hFontListWnd = CreateWindowExW(0, WC_COMBOBOXEXW, NULL,
1785                       WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN | CBS_SORT,
1786                       0, 0, 200, 150, hReBarWnd, (HMENU)IDC_FONTLIST, hInstance, NULL);
1787
1788     rbb.hwndChild = hFontListWnd;
1789     rbb.cx = 200;
1790     rbb.wID = BANDID_FONTLIST;
1791
1792     SendMessageW(hReBarWnd, RB_INSERTBAND, -1, (LPARAM)&rbb);
1793
1794     hSizeListWnd = CreateWindowExW(0, WC_COMBOBOXEXW, NULL,
1795                       WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN,
1796                       0, 0, 50, 150, hReBarWnd, (HMENU)IDC_SIZELIST, hInstance, NULL);
1797
1798     rbb.hwndChild = hSizeListWnd;
1799     rbb.cx = 50;
1800     rbb.fStyle ^= RBBS_BREAK;
1801     rbb.wID = BANDID_SIZELIST;
1802
1803     SendMessageW(hReBarWnd, RB_INSERTBAND, -1, (LPARAM)&rbb);
1804
1805     hFormatBarWnd = CreateToolbarEx(hReBarWnd,
1806          CCS_NOPARENTALIGN | CCS_NOMOVEY | WS_VISIBLE | TBSTYLE_TOOLTIPS | TBSTYLE_BUTTON,
1807          IDC_FORMATBAR, 7, hInstance, IDB_FORMATBAR, NULL, 0, 16, 16, 16, 16, sizeof(TBBUTTON));
1808
1809     AddButton(hFormatBarWnd, 0, ID_FORMAT_BOLD);
1810     AddButton(hFormatBarWnd, 1, ID_FORMAT_ITALIC);
1811     AddButton(hFormatBarWnd, 2, ID_FORMAT_UNDERLINE);
1812     AddSeparator(hFormatBarWnd);
1813     AddButton(hFormatBarWnd, 3, ID_ALIGN_LEFT);
1814     AddButton(hFormatBarWnd, 4, ID_ALIGN_CENTER);
1815     AddButton(hFormatBarWnd, 5, ID_ALIGN_RIGHT);
1816     AddSeparator(hFormatBarWnd);
1817     AddButton(hFormatBarWnd, 6, ID_BULLET);
1818
1819     SendMessageW(hFormatBarWnd, TB_AUTOSIZE, 0, 0);
1820
1821     rbb.hwndChild = hFormatBarWnd;
1822     rbb.wID = BANDID_FORMATBAR;
1823
1824     SendMessageW(hReBarWnd, RB_INSERTBAND, -1, (LPARAM)&rbb);
1825
1826     hRulerWnd = CreateWindowExW(0, WC_STATICW, NULL, WS_VISIBLE | WS_CHILD,
1827                                 0, 0, 200, 10, hReBarWnd,  (HMENU)IDC_RULER, hInstance, NULL);
1828
1829
1830     rbb.hwndChild = hRulerWnd;
1831     rbb.wID = BANDID_RULER;
1832     rbb.fStyle |= RBBS_BREAK;
1833
1834     SendMessageW(hReBarWnd, RB_INSERTBAND, -1, (LPARAM)&rbb);
1835
1836     hDLL = LoadLibraryW(wszRichEditDll);
1837     if(!hDLL)
1838     {
1839         MessageBoxWithResStringW(hWnd, MAKEINTRESOURCEW(STRING_LOAD_RICHED_FAILED), wszAppTitle,
1840                     MB_OK | MB_ICONEXCLAMATION);
1841         PostQuitMessage(1);
1842     }
1843
1844     hEditorWnd = CreateWindowExW(WS_EX_CLIENTEDGE, wszRichEditClass, NULL,
1845       WS_CHILD|WS_VISIBLE|ES_SELECTIONBAR|ES_MULTILINE|ES_AUTOVSCROLL
1846       |ES_WANTRETURN|WS_VSCROLL|ES_NOHIDESEL|WS_HSCROLL,
1847       0, 0, 1000, 100, hWnd, (HMENU)IDC_EDITOR, hInstance, NULL);
1848
1849     if (!hEditorWnd)
1850     {
1851         fprintf(stderr, "Error code %u\n", GetLastError());
1852         return -1;
1853     }
1854     assert(hEditorWnd);
1855
1856     SetFocus(hEditorWnd);
1857     SendMessageW(hEditorWnd, EM_SETEVENTMASK, 0, ENM_SELCHANGE);
1858
1859     set_default_font();
1860
1861     populate_font_list(hFontListWnd);
1862     populate_size_list(hSizeListWnd);
1863     DoLoadStrings();
1864     SendMessageW(hEditorWnd, EM_SETMODIFY, FALSE, 0);
1865
1866     ID_FINDMSGSTRING = RegisterWindowMessageW(FINDMSGSTRINGW);
1867
1868     registry_read_filelist(hWnd);
1869     registry_read_formatopts_all(barState, wordWrap);
1870     registry_read_options();
1871     DragAcceptFiles(hWnd, TRUE);
1872
1873     return 0;
1874 }
1875
1876 static LRESULT OnUser( HWND hWnd )
1877 {
1878     HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
1879     HWND hwndReBar = GetDlgItem(hWnd, IDC_REBAR);
1880     HWND hwndToolBar = GetDlgItem(hwndReBar, IDC_TOOLBAR);
1881     HWND hwndFormatBar = GetDlgItem(hwndReBar, IDC_FORMATBAR);
1882     int from, to;
1883     CHARFORMAT2W fmt;
1884     PARAFORMAT2 pf;
1885     GETTEXTLENGTHEX gt;
1886
1887     ZeroMemory(&fmt, sizeof(fmt));
1888     fmt.cbSize = sizeof(fmt);
1889
1890     ZeroMemory(&pf, sizeof(pf));
1891     pf.cbSize = sizeof(pf);
1892
1893     gt.flags = GTL_NUMCHARS;
1894     gt.codepage = 1200;
1895
1896     SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_FIND,
1897                  SendMessageW(hwndEditor, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0) ? 1 : 0);
1898
1899     SendMessageW(hwndEditor, EM_GETCHARFORMAT, TRUE, (LPARAM)&fmt);
1900
1901     SendMessageW(hwndEditor, EM_GETSEL, (WPARAM)&from, (LPARAM)&to);
1902     SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_EDIT_UNDO,
1903       SendMessageW(hwndEditor, EM_CANUNDO, 0, 0));
1904     SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_EDIT_REDO,
1905       SendMessageW(hwndEditor, EM_CANREDO, 0, 0));
1906     SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_EDIT_CUT, from == to ? 0 : 1);
1907     SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_EDIT_COPY, from == to ? 0 : 1);
1908
1909     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_FORMAT_BOLD, (fmt.dwMask & CFM_BOLD) &&
1910             (fmt.dwEffects & CFE_BOLD));
1911     SendMessageW(hwndFormatBar, TB_INDETERMINATE, ID_FORMAT_BOLD, !(fmt.dwMask & CFM_BOLD));
1912     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_FORMAT_ITALIC, (fmt.dwMask & CFM_ITALIC) &&
1913             (fmt.dwEffects & CFE_ITALIC));
1914     SendMessageW(hwndFormatBar, TB_INDETERMINATE, ID_FORMAT_ITALIC, !(fmt.dwMask & CFM_ITALIC));
1915     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_FORMAT_UNDERLINE, (fmt.dwMask & CFM_UNDERLINE) &&
1916             (fmt.dwEffects & CFE_UNDERLINE));
1917     SendMessageW(hwndFormatBar, TB_INDETERMINATE, ID_FORMAT_UNDERLINE, !(fmt.dwMask & CFM_UNDERLINE));
1918
1919     SendMessageW(hwndEditor, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
1920     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_ALIGN_LEFT, (pf.wAlignment == PFA_LEFT));
1921     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_ALIGN_CENTER, (pf.wAlignment == PFA_CENTER));
1922     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_ALIGN_RIGHT, (pf.wAlignment == PFA_RIGHT));
1923
1924     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_BULLET, (pf.wNumbering & PFN_BULLET));
1925     return 0;
1926 }
1927
1928 static LRESULT OnNotify( HWND hWnd, LPARAM lParam)
1929 {
1930     HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
1931     HWND hwndReBar = GetDlgItem(hWnd, IDC_REBAR);
1932     NMHDR *pHdr = (NMHDR *)lParam;
1933     HWND hwndFontList = GetDlgItem(hwndReBar, IDC_FONTLIST);
1934     HWND hwndSizeList = GetDlgItem(hwndReBar, IDC_SIZELIST);
1935
1936     if (pHdr->hwndFrom == hwndFontList || pHdr->hwndFrom == hwndSizeList)
1937     {
1938         if (pHdr->code == CBEN_ENDEDITW)
1939         {
1940             NMCBEENDEDIT *endEdit = (NMCBEENDEDIT *)lParam;
1941             if(pHdr->hwndFrom == hwndFontList)
1942             {
1943                 on_fontlist_modified((LPWSTR)endEdit->szText);
1944             } else if (pHdr->hwndFrom == hwndSizeList)
1945             {
1946                 on_sizelist_modified(hwndFontList,(LPWSTR)endEdit->szText);
1947             }
1948         }
1949         return 0;
1950     }
1951
1952     if (pHdr->hwndFrom != hwndEditor)
1953         return 0;
1954
1955     if (pHdr->code == EN_SELCHANGE)
1956     {
1957         SELCHANGE *pSC = (SELCHANGE *)lParam;
1958         char buf[128];
1959
1960         update_font_list();
1961
1962         sprintf( buf,"selection = %d..%d, line count=%ld",
1963                  pSC->chrg.cpMin, pSC->chrg.cpMax,
1964                 SendMessage(hwndEditor, EM_GETLINECOUNT, 0, 0));
1965         SetWindowTextA(GetDlgItem(hWnd, IDC_STATUSBAR), buf);
1966         SendMessage(hWnd, WM_USER, 0, 0);
1967         return 1;
1968     }
1969     return 0;
1970 }
1971
1972 static LRESULT OnCommand( HWND hWnd, WPARAM wParam, LPARAM lParam)
1973 {
1974     HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
1975     static FINDREPLACEW findreplace;
1976
1977     if ((HWND)lParam == hwndEditor)
1978         return 0;
1979
1980     switch(LOWORD(wParam))
1981     {
1982
1983     case ID_FILE_EXIT:
1984         PostMessageW(hWnd, WM_CLOSE, 0, 0);
1985         break;
1986
1987     case ID_FILE_NEW:
1988         {
1989             HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
1990             int ret = DialogBox(hInstance, MAKEINTRESOURCE(IDD_NEWFILE), hWnd,
1991                                 newfile_proc);
1992
1993             if(ret != ID_NEWFILE_ABORT)
1994             {
1995                 if(prompt_save_changes())
1996                 {
1997                     SETTEXTEX st;
1998
1999                     set_caption(NULL);
2000                     wszFileName[0] = '\0';
2001
2002                     clear_formatting();
2003
2004                     st.flags = ST_DEFAULT;
2005                     st.codepage = 1200;
2006                     SendMessageW(hEditorWnd, EM_SETTEXTEX, (WPARAM)&st, 0);
2007
2008                     SendMessageW(hEditorWnd, EM_SETMODIFY, FALSE, 0);
2009                     set_fileformat(ret);
2010                     update_font_list();
2011                 }
2012             }
2013         }
2014         break;
2015
2016     case ID_FILE_OPEN:
2017         DialogOpenFile();
2018         break;
2019
2020     case ID_FILE_SAVE:
2021         if(wszFileName[0])
2022         {
2023             DoSaveFile(wszFileName, fileFormat);
2024             break;
2025         }
2026         /* Fall through */
2027
2028     case ID_FILE_SAVEAS:
2029         DialogSaveFile();
2030         break;
2031
2032     case ID_FILE_RECENT1:
2033     case ID_FILE_RECENT2:
2034     case ID_FILE_RECENT3:
2035     case ID_FILE_RECENT4:
2036         {
2037             HMENU hMenu = GetMenu(hWnd);
2038             MENUITEMINFOW mi;
2039
2040             mi.cbSize = sizeof(MENUITEMINFOW);
2041             mi.fMask = MIIM_DATA;
2042             if(GetMenuItemInfoW(hMenu, LOWORD(wParam), FALSE, &mi))
2043                 DoOpenFile((LPWSTR)mi.dwItemData);
2044         }
2045         break;
2046
2047     case ID_FIND:
2048         dialog_find(&findreplace, FALSE);
2049         break;
2050
2051     case ID_FIND_NEXT:
2052         handle_findmsg(&findreplace);
2053         break;
2054
2055     case ID_REPLACE:
2056         dialog_find(&findreplace, TRUE);
2057         break;
2058
2059     case ID_FONTSETTINGS:
2060         dialog_choose_font();
2061         break;
2062
2063     case ID_PRINT:
2064         dialog_print(hWnd, wszFileName);
2065         target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
2066         break;
2067
2068     case ID_PRINT_QUICK:
2069         print_quick(wszFileName);
2070         target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
2071         break;
2072
2073     case ID_PREVIEW:
2074         {
2075             int index = reg_formatindex(fileFormat);
2076             DWORD tmp = barState[index];
2077             barState[index] = 0;
2078             set_bar_states();
2079             barState[index] = tmp;
2080             ShowWindow(hEditorWnd, FALSE);
2081
2082             init_preview(hWnd, wszFileName);
2083
2084             SetMenu(hWnd, NULL);
2085             InvalidateRect(0, 0, TRUE);
2086         }
2087         break;
2088
2089     case ID_PRINTSETUP:
2090         dialog_printsetup(hWnd);
2091         target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
2092         break;
2093
2094     case ID_FORMAT_BOLD:
2095     case ID_FORMAT_ITALIC:
2096     case ID_FORMAT_UNDERLINE:
2097         {
2098         CHARFORMAT2W fmt;
2099         int effects = CFE_BOLD;
2100
2101         ZeroMemory(&fmt, sizeof(fmt));
2102         fmt.cbSize = sizeof(fmt);
2103         SendMessageW(hwndEditor, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
2104
2105         fmt.dwMask = CFM_BOLD;
2106
2107         if (LOWORD(wParam) == ID_FORMAT_ITALIC)
2108         {
2109             effects = CFE_ITALIC;
2110             fmt.dwMask = CFM_ITALIC;
2111         } else if (LOWORD(wParam) == ID_FORMAT_UNDERLINE)
2112         {
2113             effects = CFE_UNDERLINE;
2114             fmt.dwMask = CFM_UNDERLINE;
2115         }
2116
2117         fmt.dwEffects ^= effects;
2118
2119         SendMessageW(hwndEditor, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
2120         break;
2121         }
2122
2123     case ID_EDIT_CUT:
2124         PostMessageW(hwndEditor, WM_CUT, 0, 0);
2125         break;
2126
2127     case ID_EDIT_COPY:
2128         PostMessageW(hwndEditor, WM_COPY, 0, 0);
2129         break;
2130
2131     case ID_EDIT_PASTE:
2132         PostMessageW(hwndEditor, WM_PASTE, 0, 0);
2133         break;
2134
2135     case ID_EDIT_CLEAR:
2136         PostMessageW(hwndEditor, WM_CLEAR, 0, 0);
2137         break;
2138
2139     case ID_EDIT_SELECTALL:
2140         {
2141         CHARRANGE range = {0, -1};
2142         SendMessageW(hwndEditor, EM_EXSETSEL, 0, (LPARAM)&range);
2143         /* SendMessage(hwndEditor, EM_SETSEL, 0, -1); */
2144         return 0;
2145         }
2146
2147     case ID_EDIT_GETTEXT:
2148         {
2149         int nLen = GetWindowTextLengthW(hwndEditor);
2150         LPWSTR data = HeapAlloc( GetProcessHeap(), 0, (nLen+1)*sizeof(WCHAR) );
2151         TEXTRANGEW tr;
2152
2153         GetWindowTextW(hwndEditor, data, nLen+1);
2154         MessageBoxW(NULL, data, wszAppTitle, MB_OK);
2155
2156         HeapFree( GetProcessHeap(), 0, data);
2157         data = HeapAlloc(GetProcessHeap(), 0, (nLen+1)*sizeof(WCHAR));
2158         tr.chrg.cpMin = 0;
2159         tr.chrg.cpMax = nLen;
2160         tr.lpstrText = data;
2161         SendMessage (hwndEditor, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
2162         MessageBoxW(NULL, data, wszAppTitle, MB_OK);
2163         HeapFree( GetProcessHeap(), 0, data );
2164
2165         /* SendMessage(hwndEditor, EM_SETSEL, 0, -1); */
2166         return 0;
2167         }
2168
2169     case ID_EDIT_CHARFORMAT:
2170     case ID_EDIT_DEFCHARFORMAT:
2171         {
2172         CHARFORMAT2W cf;
2173         LRESULT i;
2174         ZeroMemory(&cf, sizeof(cf));
2175         cf.cbSize = sizeof(cf);
2176         cf.dwMask = 0;
2177         i = SendMessageW(hwndEditor, EM_GETCHARFORMAT,
2178                         LOWORD(wParam) == ID_EDIT_CHARFORMAT, (LPARAM)&cf);
2179         return 0;
2180         }
2181
2182     case ID_EDIT_PARAFORMAT:
2183         {
2184         PARAFORMAT2 pf;
2185         ZeroMemory(&pf, sizeof(pf));
2186         pf.cbSize = sizeof(pf);
2187         SendMessageW(hwndEditor, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
2188         return 0;
2189         }
2190
2191     case ID_EDIT_SELECTIONINFO:
2192         {
2193         CHARRANGE range = {0, -1};
2194         char buf[128];
2195         WCHAR *data = NULL;
2196
2197         SendMessage(hwndEditor, EM_EXGETSEL, 0, (LPARAM)&range);
2198         data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data) * (range.cpMax-range.cpMin+1));
2199         SendMessage(hwndEditor, EM_GETSELTEXT, 0, (LPARAM)data);
2200         sprintf(buf, "Start = %d, End = %d", range.cpMin, range.cpMax);
2201         MessageBoxA(hWnd, buf, "Editor", MB_OK);
2202         MessageBoxW(hWnd, data, wszAppTitle, MB_OK);
2203         HeapFree( GetProcessHeap(), 0, data);
2204         /* SendMessage(hwndEditor, EM_SETSEL, 0, -1); */
2205         return 0;
2206         }
2207
2208     case ID_EDIT_READONLY:
2209         {
2210         long nStyle = GetWindowLong(hwndEditor, GWL_STYLE);
2211         if (nStyle & ES_READONLY)
2212             SendMessageW(hwndEditor, EM_SETREADONLY, 0, 0);
2213         else
2214             SendMessageW(hwndEditor, EM_SETREADONLY, 1, 0);
2215         return 0;
2216         }
2217
2218     case ID_EDIT_MODIFIED:
2219         if (SendMessageW(hwndEditor, EM_GETMODIFY, 0, 0))
2220             SendMessageW(hwndEditor, EM_SETMODIFY, 0, 0);
2221         else
2222             SendMessageW(hwndEditor, EM_SETMODIFY, 1, 0);
2223         return 0;
2224
2225     case ID_EDIT_UNDO:
2226         SendMessageW(hwndEditor, EM_UNDO, 0, 0);
2227         return 0;
2228
2229     case ID_EDIT_REDO:
2230         SendMessageW(hwndEditor, EM_REDO, 0, 0);
2231         return 0;
2232
2233     case ID_BULLET:
2234         {
2235             PARAFORMAT pf;
2236
2237             pf.cbSize = sizeof(pf);
2238             pf.dwMask = PFM_NUMBERING;
2239             SendMessageW(hwndEditor, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
2240
2241             pf.dwMask |=  PFM_OFFSET;
2242
2243             if(pf.wNumbering == PFN_BULLET)
2244             {
2245                 pf.wNumbering = 0;
2246                 pf.dxOffset = 0;
2247             } else
2248             {
2249                 pf.wNumbering = PFN_BULLET;
2250                 pf.dxOffset = 720;
2251             }
2252
2253             SendMessageW(hwndEditor, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
2254         }
2255         break;
2256
2257     case ID_ALIGN_LEFT:
2258     case ID_ALIGN_CENTER:
2259     case ID_ALIGN_RIGHT:
2260         {
2261         PARAFORMAT2 pf;
2262
2263         pf.cbSize = sizeof(pf);
2264         pf.dwMask = PFM_ALIGNMENT;
2265         switch(LOWORD(wParam)) {
2266         case ID_ALIGN_LEFT: pf.wAlignment = PFA_LEFT; break;
2267         case ID_ALIGN_CENTER: pf.wAlignment = PFA_CENTER; break;
2268         case ID_ALIGN_RIGHT: pf.wAlignment = PFA_RIGHT; break;
2269         }
2270         SendMessageW(hwndEditor, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
2271         break;
2272         }
2273
2274     case ID_BACK_1:
2275         SendMessageW(hwndEditor, EM_SETBKGNDCOLOR, 1, 0);
2276         break;
2277
2278     case ID_BACK_2:
2279         SendMessageW(hwndEditor, EM_SETBKGNDCOLOR, 0, RGB(255,255,192));
2280         break;
2281
2282     case ID_TOGGLE_TOOLBAR:
2283         set_toolbar_state(BANDID_TOOLBAR, !is_bar_visible(BANDID_TOOLBAR));
2284         update_window();
2285         break;
2286
2287     case ID_TOGGLE_FORMATBAR:
2288         set_toolbar_state(BANDID_FONTLIST, !is_bar_visible(BANDID_FORMATBAR));
2289         set_toolbar_state(BANDID_SIZELIST, !is_bar_visible(BANDID_FORMATBAR));
2290         set_toolbar_state(BANDID_FORMATBAR, !is_bar_visible(BANDID_FORMATBAR));
2291         update_window();
2292         break;
2293
2294     case ID_TOGGLE_STATUSBAR:
2295         set_statusbar_state(!is_bar_visible(BANDID_STATUSBAR));
2296         update_window();
2297         break;
2298
2299     case ID_TOGGLE_RULER:
2300         set_toolbar_state(BANDID_RULER, !is_bar_visible(BANDID_RULER));
2301         update_window();
2302         break;
2303
2304     case ID_DATETIME:
2305         {
2306         HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
2307         DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_DATETIME), hWnd, datetime_proc);
2308         break;
2309         }
2310
2311     case ID_PARAFORMAT:
2312         {
2313             HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
2314             DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_PARAFORMAT), hWnd,
2315                        paraformat_proc);
2316         }
2317         break;
2318
2319     case ID_TABSTOPS:
2320         {
2321             HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
2322             DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_TABSTOPS), hWnd, tabstops_proc);
2323         }
2324         break;
2325
2326     case ID_ABOUT:
2327         dialog_about();
2328         break;
2329
2330     case ID_VIEWPROPERTIES:
2331         dialog_viewproperties();
2332         break;
2333
2334     case IDC_FONTLIST:
2335         if (HIWORD(wParam) == CBN_SELENDOK)
2336         {
2337             WCHAR buffer[LF_FACESIZE];
2338             HWND hwndFontList = (HWND)lParam;
2339             get_comboexlist_selection(hwndFontList, buffer, LF_FACESIZE);
2340             on_fontlist_modified(buffer);
2341         }
2342         break;
2343
2344     case IDC_SIZELIST:
2345         if (HIWORD(wParam) == CBN_SELENDOK)
2346         {
2347             WCHAR buffer[MAX_STRING_LEN+1];
2348             HWND hwndSizeList = (HWND)lParam;
2349             get_comboexlist_selection(hwndSizeList, buffer, MAX_STRING_LEN+1);
2350             on_sizelist_modified(hwndSizeList, buffer);
2351         }
2352         break;
2353
2354     default:
2355         SendMessageW(hwndEditor, WM_COMMAND, wParam, lParam);
2356         break;
2357     }
2358     return 0;
2359 }
2360
2361 static LRESULT OnInitPopupMenu( HWND hWnd, WPARAM wParam )
2362 {
2363     HMENU hMenu = (HMENU)wParam;
2364     HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
2365     HWND hwndStatus = GetDlgItem(hWnd, IDC_STATUSBAR);
2366     PARAFORMAT pf;
2367     int nAlignment = -1;
2368     int selFrom, selTo;
2369     GETTEXTLENGTHEX gt;
2370     LRESULT textLength;
2371     MENUITEMINFOW mi;
2372
2373     SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&selFrom, (LPARAM)&selTo);
2374     EnableMenuItem(hMenu, ID_EDIT_COPY, MF_BYCOMMAND|(selFrom == selTo) ? MF_GRAYED : MF_ENABLED);
2375     EnableMenuItem(hMenu, ID_EDIT_CUT, MF_BYCOMMAND|(selFrom == selTo) ? MF_GRAYED : MF_ENABLED);
2376
2377     pf.cbSize = sizeof(PARAFORMAT);
2378     SendMessageW(hwndEditor, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
2379     CheckMenuItem(hMenu, ID_EDIT_READONLY,
2380       MF_BYCOMMAND|(GetWindowLong(hwndEditor, GWL_STYLE)&ES_READONLY ? MF_CHECKED : MF_UNCHECKED));
2381     CheckMenuItem(hMenu, ID_EDIT_MODIFIED,
2382       MF_BYCOMMAND|(SendMessage(hwndEditor, EM_GETMODIFY, 0, 0) ? MF_CHECKED : MF_UNCHECKED));
2383     if (pf.dwMask & PFM_ALIGNMENT)
2384         nAlignment = pf.wAlignment;
2385     CheckMenuItem(hMenu, ID_ALIGN_LEFT, MF_BYCOMMAND|(nAlignment == PFA_LEFT) ?
2386             MF_CHECKED : MF_UNCHECKED);
2387     CheckMenuItem(hMenu, ID_ALIGN_CENTER, MF_BYCOMMAND|(nAlignment == PFA_CENTER) ?
2388             MF_CHECKED : MF_UNCHECKED);
2389     CheckMenuItem(hMenu, ID_ALIGN_RIGHT, MF_BYCOMMAND|(nAlignment == PFA_RIGHT) ?
2390             MF_CHECKED : MF_UNCHECKED);
2391     CheckMenuItem(hMenu, ID_BULLET, MF_BYCOMMAND | ((pf.wNumbering == PFN_BULLET) ?
2392             MF_CHECKED : MF_UNCHECKED));
2393     EnableMenuItem(hMenu, ID_EDIT_UNDO, MF_BYCOMMAND|(SendMessageW(hwndEditor, EM_CANUNDO, 0, 0)) ?
2394             MF_ENABLED : MF_GRAYED);
2395     EnableMenuItem(hMenu, ID_EDIT_REDO, MF_BYCOMMAND|(SendMessageW(hwndEditor, EM_CANREDO, 0, 0)) ?
2396             MF_ENABLED : MF_GRAYED);
2397
2398     CheckMenuItem(hMenu, ID_TOGGLE_TOOLBAR, MF_BYCOMMAND|(is_bar_visible(BANDID_TOOLBAR)) ?
2399             MF_CHECKED : MF_UNCHECKED);
2400
2401     CheckMenuItem(hMenu, ID_TOGGLE_FORMATBAR, MF_BYCOMMAND|(is_bar_visible(BANDID_FORMATBAR)) ?
2402             MF_CHECKED : MF_UNCHECKED);
2403
2404     CheckMenuItem(hMenu, ID_TOGGLE_STATUSBAR, MF_BYCOMMAND|IsWindowVisible(hwndStatus) ?
2405             MF_CHECKED : MF_UNCHECKED);
2406
2407     CheckMenuItem(hMenu, ID_TOGGLE_RULER, MF_BYCOMMAND|(is_bar_visible(BANDID_RULER)) ? MF_CHECKED : MF_UNCHECKED);
2408
2409     gt.flags = GTL_NUMCHARS;
2410     gt.codepage = 1200;
2411     textLength = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0);
2412     EnableMenuItem(hMenu, ID_FIND, MF_BYCOMMAND|(textLength ? MF_ENABLED : MF_GRAYED));
2413
2414     mi.cbSize = sizeof(mi);
2415     mi.fMask = MIIM_DATA;
2416
2417     GetMenuItemInfoW(hMenu, ID_FIND_NEXT, FALSE, &mi);
2418
2419     EnableMenuItem(hMenu, ID_FIND_NEXT, MF_BYCOMMAND|((textLength && mi.dwItemData) ?
2420                    MF_ENABLED : MF_GRAYED));
2421
2422     EnableMenuItem(hMenu, ID_REPLACE, MF_BYCOMMAND|(textLength ? MF_ENABLED : MF_GRAYED));
2423
2424     return 0;
2425 }
2426
2427 static LRESULT OnSize( HWND hWnd, WPARAM wParam, LPARAM lParam )
2428 {
2429     int nStatusSize = 0;
2430     RECT rc;
2431     HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
2432     HWND hwndStatusBar = GetDlgItem(hWnd, IDC_STATUSBAR);
2433     HWND hwndReBar = GetDlgItem(hWnd, IDC_REBAR);
2434     HWND hRulerWnd = GetDlgItem(hWnd, IDC_RULER);
2435     int rebarHeight = 0;
2436
2437     if (hwndStatusBar)
2438     {
2439         SendMessageW(hwndStatusBar, WM_SIZE, 0, 0);
2440         if (IsWindowVisible(hwndStatusBar))
2441         {
2442             GetClientRect(hwndStatusBar, &rc);
2443             nStatusSize = rc.bottom - rc.top;
2444         } else
2445         {
2446             nStatusSize = 0;
2447         }
2448     }
2449     if (hwndReBar)
2450     {
2451         rebarHeight = SendMessageW(hwndReBar, RB_GETBARHEIGHT, 0, 0);
2452
2453         MoveWindow(hwndReBar, 0, 0, LOWORD(lParam), rebarHeight, TRUE);
2454     }
2455     if (hwndEditor)
2456     {
2457         GetClientRect(hWnd, &rc);
2458         MoveWindow(hwndEditor, 0, rebarHeight, rc.right, rc.bottom-nStatusSize-rebarHeight, TRUE);
2459     }
2460
2461     redraw_ruler(hRulerWnd);
2462
2463     return DefWindowProcW(hWnd, WM_SIZE, wParam, lParam);
2464 }
2465
2466 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
2467 {
2468     if(msg == ID_FINDMSGSTRING)
2469         return handle_findmsg((LPFINDREPLACEW)lParam);
2470
2471     switch(msg)
2472     {
2473     case WM_CREATE:
2474         return OnCreate( hWnd );
2475
2476     case WM_USER:
2477         return OnUser( hWnd );
2478
2479     case WM_NOTIFY:
2480         return OnNotify( hWnd, lParam );
2481
2482     case WM_COMMAND:
2483         if(preview_isactive())
2484         {
2485             return preview_command( hWnd, wParam );
2486         }
2487
2488         return OnCommand( hWnd, wParam, lParam );
2489
2490     case WM_DESTROY:
2491         PostQuitMessage(0);
2492         break;
2493
2494     case WM_CLOSE:
2495         if(preview_isactive())
2496         {
2497             preview_exit(hWnd);
2498         } else if(prompt_save_changes())
2499         {
2500             registry_set_options(hMainWnd);
2501             registry_set_formatopts_all(barState);
2502             PostQuitMessage(0);
2503         }
2504         break;
2505
2506     case WM_ACTIVATE:
2507         if (LOWORD(wParam))
2508             SetFocus(GetDlgItem(hWnd, IDC_EDITOR));
2509         return 0;
2510
2511     case WM_INITMENUPOPUP:
2512         return OnInitPopupMenu( hWnd, wParam );
2513
2514     case WM_SIZE:
2515         return OnSize( hWnd, wParam, lParam );
2516
2517     case WM_CONTEXTMENU:
2518         if((HWND)wParam == hEditorWnd)
2519             return context_menu(lParam);
2520         else
2521             return DefWindowProcW(hWnd, msg, wParam, lParam);
2522
2523     case WM_DROPFILES:
2524         {
2525             WCHAR file[MAX_PATH];
2526             DragQueryFileW((HDROP)wParam, 0, file, MAX_PATH);
2527             DragFinish((HDROP)wParam);
2528
2529             if(prompt_save_changes())
2530                 DoOpenFile(file);
2531         }
2532         break;
2533     case WM_PAINT:
2534         if(preview_isactive())
2535             return print_preview(hWnd);
2536         else
2537             return DefWindowProcW(hWnd, msg, wParam, lParam);
2538
2539     default:
2540         return DefWindowProcW(hWnd, msg, wParam, lParam);
2541     }
2542
2543     return 0;
2544 }
2545
2546 int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hOldInstance, LPSTR szCmdParagraph, int nCmdShow)
2547 {
2548     INITCOMMONCONTROLSEX classes = {8, ICC_BAR_CLASSES|ICC_COOL_CLASSES|ICC_USEREX_CLASSES};
2549     HACCEL hAccel;
2550     WNDCLASSW wc;
2551     MSG msg;
2552     RECT rc;
2553     UINT_PTR hPrevRulerProc;
2554     HWND hRulerWnd;
2555     POINTL EditPoint;
2556     DWORD bMaximized;
2557     static const WCHAR wszAccelTable[] = {'M','A','I','N','A','C','C','E','L',
2558                                           'T','A','B','L','E','\0'};
2559
2560     InitCommonControlsEx(&classes);
2561
2562     hAccel = LoadAcceleratorsW(hInstance, wszAccelTable);
2563
2564     wc.style = CS_HREDRAW | CS_VREDRAW;
2565     wc.lpfnWndProc = WndProc;
2566     wc.cbClsExtra = 0;
2567     wc.cbWndExtra = 4;
2568     wc.hInstance = hInstance;
2569     wc.hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_WORDPAD));
2570     wc.hCursor = LoadCursor(NULL, IDC_IBEAM);
2571     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
2572     wc.lpszMenuName = MAKEINTRESOURCEW(IDM_MAINMENU);
2573     wc.lpszClassName = wszMainWndClass;
2574     RegisterClassW(&wc);
2575
2576     registry_read_winrect(&rc);
2577     hMainWnd = CreateWindowExW(0, wszMainWndClass, wszAppTitle, WS_CLIPCHILDREN|WS_OVERLAPPEDWINDOW,
2578       rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, hInstance, NULL);
2579     registry_read_maximized(&bMaximized);
2580     if ((nCmdShow == SW_SHOWNORMAL || nCmdShow == SW_SHOWDEFAULT)
2581              && bMaximized)
2582         nCmdShow = SW_SHOWMAXIMIZED;
2583     ShowWindow(hMainWnd, nCmdShow);
2584
2585     set_caption(NULL);
2586     set_bar_states();
2587     set_fileformat(SF_RTF);
2588     hPopupMenu = LoadMenuW(hInstance, MAKEINTRESOURCEW(IDM_POPUP));
2589     get_default_printer_opts();
2590     target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
2591
2592     hRulerWnd = GetDlgItem(GetDlgItem(hMainWnd, IDC_REBAR), IDC_RULER);
2593     SendMessageW(GetDlgItem(hMainWnd, IDC_EDITOR), EM_POSFROMCHAR, (WPARAM)&EditPoint, 0);
2594     hPrevRulerProc = SetWindowLongPtrW(hRulerWnd, GWLP_WNDPROC, (UINT_PTR)ruler_proc);
2595     SendMessageW(hRulerWnd, WM_USER, (WPARAM)&EditPoint, hPrevRulerProc);
2596
2597     HandleCommandLine(GetCommandLineW());
2598
2599     while(GetMessageW(&msg,0,0,0))
2600     {
2601         if (IsDialogMessage(hFindWnd, &msg))
2602             continue;
2603
2604         if (TranslateAcceleratorW(hMainWnd, hAccel, &msg))
2605             continue;
2606         TranslateMessage(&msg);
2607         DispatchMessageW(&msg);
2608         if (!PeekMessageW(&msg, 0, 0, 0, PM_NOREMOVE))
2609             SendMessageW(hMainWnd, WM_USER, 0, 0);
2610     }
2611
2612     return 0;
2613 }