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