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