quartz: Make dwSamplesProcessed a longlong.
[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     if (!SendMessageW(hFontListEdit, WM_GETTEXT, MAX_PATH, (LPARAM)fontName)) return;
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 = LoadImageW(hInstance, MAKEINTRESOURCEW(IDI_WORDPAD), IMAGE_ICON, 48, 48, LR_SHARED);
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)
1045     {
1046         while (isspace(*cmdline)) cmdline++;
1047
1048         if (*cmdline == '-' || *cmdline == '/')
1049         {
1050             if (!cmdline[2] || isspace(cmdline[2]))
1051             {
1052                 switch (cmdline[1])
1053                 {
1054                 case 'P':
1055                 case 'p':
1056                     opt_print = 1;
1057                     cmdline += 2;
1058                     continue;
1059                 }
1060             }
1061             /* a filename starting by / */
1062         }
1063         break;
1064     }
1065
1066     if (*cmdline)
1067     {
1068         /* file name is passed on the command line */
1069         if (cmdline[0] == '"')
1070         {
1071             cmdline++;
1072             cmdline[lstrlenW(cmdline) - 1] = 0;
1073         }
1074         DoOpenFile(cmdline);
1075         InvalidateRect(hMainWnd, NULL, FALSE);
1076     }
1077
1078     if (opt_print)
1079         MessageBox(hMainWnd, "Printing not implemented", "WordPad", MB_OK);
1080 }
1081
1082 static LRESULT handle_findmsg(LPFINDREPLACEW pFr)
1083 {
1084     if(pFr->Flags & FR_DIALOGTERM)
1085     {
1086         hFindWnd = 0;
1087         pFr->Flags = FR_FINDNEXT;
1088         return 0;
1089     }
1090
1091     if(pFr->Flags & FR_FINDNEXT || pFr->Flags & FR_REPLACE || pFr->Flags & FR_REPLACEALL)
1092     {
1093         DWORD flags = FR_DOWN;
1094         FINDTEXTW ft;
1095         static CHARRANGE cr;
1096         LRESULT end, ret;
1097         GETTEXTLENGTHEX gt;
1098         LRESULT length;
1099         int startPos;
1100         HMENU hMenu = GetMenu(hMainWnd);
1101         MENUITEMINFOW mi;
1102
1103         mi.cbSize = sizeof(mi);
1104         mi.fMask = MIIM_DATA;
1105         mi.dwItemData = 1;
1106         SetMenuItemInfoW(hMenu, ID_FIND_NEXT, FALSE, &mi);
1107
1108         gt.flags = GTL_NUMCHARS;
1109         gt.codepage = 1200;
1110
1111         length = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0);
1112
1113         if(pFr->lCustData == -1)
1114         {
1115             SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&startPos, (LPARAM)&end);
1116             cr.cpMin = startPos;
1117             pFr->lCustData = startPos;
1118             cr.cpMax = length;
1119             if(cr.cpMin == length)
1120                 cr.cpMin = 0;
1121         } else
1122         {
1123             startPos = pFr->lCustData;
1124         }
1125
1126         if(cr.cpMax > length)
1127         {
1128             startPos = 0;
1129             cr.cpMin = 0;
1130             cr.cpMax = length;
1131         }
1132
1133         ft.chrg = cr;
1134         ft.lpstrText = pFr->lpstrFindWhat;
1135
1136         if(pFr->Flags & FR_MATCHCASE)
1137             flags |= FR_MATCHCASE;
1138         if(pFr->Flags & FR_WHOLEWORD)
1139             flags |= FR_WHOLEWORD;
1140
1141         ret = SendMessageW(hEditorWnd, EM_FINDTEXTW, (WPARAM)flags, (LPARAM)&ft);
1142
1143         if(ret == -1)
1144         {
1145             if(cr.cpMax == length && cr.cpMax != startPos)
1146             {
1147                 ft.chrg.cpMin = cr.cpMin = 0;
1148                 ft.chrg.cpMax = cr.cpMax = startPos;
1149
1150                 ret = SendMessageW(hEditorWnd, EM_FINDTEXTW, (WPARAM)flags, (LPARAM)&ft);
1151             }
1152         }
1153
1154         if(ret == -1)
1155         {
1156             pFr->lCustData = -1;
1157             MessageBoxW(hMainWnd, MAKEINTRESOURCEW(STRING_SEARCH_FINISHED), wszAppTitle,
1158                         MB_OK | MB_ICONASTERISK);
1159         } else
1160         {
1161             end = ret + lstrlenW(pFr->lpstrFindWhat);
1162             cr.cpMin = end;
1163             SendMessageW(hEditorWnd, EM_SETSEL, (WPARAM)ret, (LPARAM)end);
1164             SendMessageW(hEditorWnd, EM_SCROLLCARET, 0, 0);
1165
1166             if(pFr->Flags & FR_REPLACE || pFr->Flags & FR_REPLACEALL)
1167                 SendMessageW(hEditorWnd, EM_REPLACESEL, TRUE, (LPARAM)pFr->lpstrReplaceWith);
1168
1169             if(pFr->Flags & FR_REPLACEALL)
1170                 handle_findmsg(pFr);
1171         }
1172     }
1173
1174     return 0;
1175 }
1176
1177 static void dialog_find(LPFINDREPLACEW fr, BOOL replace)
1178 {
1179     static WCHAR findBuffer[MAX_STRING_LEN];
1180
1181     ZeroMemory(fr, sizeof(FINDREPLACEW));
1182     fr->lStructSize = sizeof(FINDREPLACEW);
1183     fr->hwndOwner = hMainWnd;
1184     fr->Flags = FR_HIDEUPDOWN;
1185     fr->lpstrFindWhat = findBuffer;
1186     fr->lCustData = -1;
1187     fr->wFindWhatLen = MAX_STRING_LEN*sizeof(WCHAR);
1188
1189     if(replace)
1190         hFindWnd = ReplaceTextW(fr);
1191     else
1192         hFindWnd = FindTextW(fr);
1193 }
1194
1195 static int current_units_to_twips(float number)
1196 {
1197     int twips = (int)(number * TWIPS_PER_CM);
1198     return twips;
1199 }
1200
1201 static void append_current_units(LPWSTR buffer)
1202 {
1203     static const WCHAR space[] = {' '};
1204     lstrcatW(buffer, space);
1205     lstrcatW(buffer, units_cmW);
1206 }
1207
1208 static void number_with_units(LPWSTR buffer, int number)
1209 {
1210     float converted = (float)number / TWIPS_PER_CM;
1211     char string[MAX_STRING_LEN];
1212
1213     sprintf(string, "%.2f ", converted);
1214     lstrcatA(string, units_cmA);
1215     MultiByteToWideChar(CP_ACP, 0, string, -1, buffer, MAX_STRING_LEN);
1216 }
1217
1218 static INT_PTR CALLBACK datetime_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1219 {
1220     switch(message)
1221     {
1222         case WM_INITDIALOG:
1223             {
1224                 WCHAR buffer[MAX_STRING_LEN];
1225                 SYSTEMTIME st;
1226                 HWND hListWnd = GetDlgItem(hWnd, IDC_DATETIME);
1227                 GetLocalTime(&st);
1228
1229                 GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, 0, (LPWSTR)&buffer,
1230                                MAX_STRING_LEN);
1231                 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1232                 GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, 0, (LPWSTR)&buffer,
1233                                MAX_STRING_LEN);
1234                 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1235                 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, 0, (LPWSTR)&buffer, MAX_STRING_LEN);
1236                 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1237
1238                 SendMessageW(hListWnd, LB_SETSEL, TRUE, 0);
1239             }
1240             break;
1241
1242         case WM_COMMAND:
1243             switch(LOWORD(wParam))
1244             {
1245                 case IDOK:
1246                     {
1247                         LRESULT index;
1248                         HWND hListWnd = GetDlgItem(hWnd, IDC_DATETIME);
1249
1250                         index = SendMessageW(hListWnd, LB_GETCURSEL, 0, 0);
1251
1252                         if(index != LB_ERR)
1253                         {
1254                             WCHAR buffer[MAX_STRING_LEN];
1255                             SendMessageW(hListWnd, LB_GETTEXT, index, (LPARAM)&buffer);
1256                             SendMessageW(hEditorWnd, EM_REPLACESEL, TRUE, (LPARAM)&buffer);
1257                         }
1258                     }
1259                     /* Fall through */
1260
1261                 case IDCANCEL:
1262                     EndDialog(hWnd, wParam);
1263                     return TRUE;
1264             }
1265     }
1266     return FALSE;
1267 }
1268
1269 static INT_PTR CALLBACK newfile_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1270 {
1271     switch(message)
1272     {
1273         case WM_INITDIALOG:
1274             {
1275                 HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hMainWnd, GWLP_HINSTANCE);
1276                 WCHAR buffer[MAX_STRING_LEN];
1277                 HWND hListWnd = GetDlgItem(hWnd, IDC_NEWFILE);
1278
1279                 LoadStringW(hInstance, STRING_NEWFILE_RICHTEXT, (LPWSTR)buffer, MAX_STRING_LEN);
1280                 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1281                 LoadStringW(hInstance, STRING_NEWFILE_TXT, (LPWSTR)buffer, MAX_STRING_LEN);
1282                 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1283                 LoadStringW(hInstance, STRING_NEWFILE_TXT_UNICODE, (LPWSTR)buffer, MAX_STRING_LEN);
1284                 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1285
1286                 SendMessageW(hListWnd, LB_SETSEL, TRUE, 0);
1287             }
1288             break;
1289
1290         case WM_COMMAND:
1291             switch(LOWORD(wParam))
1292             {
1293                 case IDOK:
1294                     {
1295                         LRESULT index;
1296                         HWND hListWnd = GetDlgItem(hWnd, IDC_NEWFILE);
1297                         index = SendMessageW(hListWnd, LB_GETCURSEL, 0, 0);
1298
1299                         if(index != LB_ERR)
1300                             EndDialog(hWnd, MAKELONG(fileformat_flags(index),0));
1301                     }
1302                     return TRUE;
1303
1304                 case IDCANCEL:
1305                     EndDialog(hWnd, MAKELONG(ID_NEWFILE_ABORT,0));
1306                     return TRUE;
1307             }
1308     }
1309     return FALSE;
1310 }
1311
1312 static INT_PTR CALLBACK paraformat_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1313 {
1314     switch(message)
1315     {
1316         case WM_INITDIALOG:
1317             {
1318                 HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hMainWnd,
1319                                                                   GWLP_HINSTANCE);
1320                 WCHAR buffer[MAX_STRING_LEN];
1321                 HWND hListWnd = GetDlgItem(hWnd, IDC_PARA_ALIGN);
1322                 HWND hLeftWnd = GetDlgItem(hWnd, IDC_PARA_LEFT);
1323                 HWND hRightWnd = GetDlgItem(hWnd, IDC_PARA_RIGHT);
1324                 HWND hFirstWnd = GetDlgItem(hWnd, IDC_PARA_FIRST);
1325                 PARAFORMAT2 pf;
1326                 int index = 0;
1327
1328                 LoadStringW(hInstance, STRING_ALIGN_LEFT, buffer,
1329                             MAX_STRING_LEN);
1330                 SendMessageW(hListWnd, CB_ADDSTRING, 0, (LPARAM)buffer);
1331                 LoadStringW(hInstance, STRING_ALIGN_RIGHT, buffer,
1332                             MAX_STRING_LEN);
1333                 SendMessageW(hListWnd, CB_ADDSTRING, 0, (LPARAM)buffer);
1334                 LoadStringW(hInstance, STRING_ALIGN_CENTER, buffer,
1335                             MAX_STRING_LEN);
1336                 SendMessageW(hListWnd, CB_ADDSTRING, 0, (LPARAM)buffer);
1337
1338                 pf.cbSize = sizeof(pf);
1339                 pf.dwMask = PFM_ALIGNMENT | PFM_OFFSET | PFM_RIGHTINDENT |
1340                             PFM_OFFSETINDENT;
1341                 SendMessageW(hEditorWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
1342
1343                 if(pf.wAlignment == PFA_RIGHT)
1344                     index ++;
1345                 else if(pf.wAlignment == PFA_CENTER)
1346                     index += 2;
1347
1348                 SendMessageW(hListWnd, CB_SETCURSEL, index, 0);
1349
1350                 number_with_units(buffer, pf.dxOffset);
1351                 SetWindowTextW(hLeftWnd, buffer);
1352                 number_with_units(buffer, pf.dxRightIndent);
1353                 SetWindowTextW(hRightWnd, buffer);
1354                 number_with_units(buffer, pf.dxStartIndent - pf.dxOffset);
1355                 SetWindowTextW(hFirstWnd, buffer);
1356             }
1357             break;
1358
1359         case WM_COMMAND:
1360             switch(LOWORD(wParam))
1361             {
1362                 case IDOK:
1363                     {
1364                         HWND hLeftWnd = GetDlgItem(hWnd, IDC_PARA_LEFT);
1365                         HWND hRightWnd = GetDlgItem(hWnd, IDC_PARA_RIGHT);
1366                         HWND hFirstWnd = GetDlgItem(hWnd, IDC_PARA_FIRST);
1367                         WCHAR buffer[MAX_STRING_LEN];
1368                         float num;
1369                         int ret = 0;
1370                         PARAFORMAT pf;
1371
1372                         GetWindowTextW(hLeftWnd, buffer, MAX_STRING_LEN);
1373                         if(number_from_string(buffer, &num, TRUE))
1374                             ret++;
1375                         pf.dxOffset = current_units_to_twips(num);
1376                         GetWindowTextW(hRightWnd, buffer, MAX_STRING_LEN);
1377                         if(number_from_string(buffer, &num, TRUE))
1378                             ret++;
1379                         pf.dxRightIndent = current_units_to_twips(num);
1380                         GetWindowTextW(hFirstWnd, buffer, MAX_STRING_LEN);
1381                         if(number_from_string(buffer, &num, TRUE))
1382                             ret++;
1383                         pf.dxStartIndent = current_units_to_twips(num);
1384
1385                         if(ret != 3)
1386                         {
1387                             MessageBoxW(hMainWnd, MAKEINTRESOURCEW(STRING_INVALID_NUMBER),
1388                                         wszAppTitle, MB_OK | MB_ICONASTERISK);
1389                             return FALSE;
1390                         } else
1391                         {
1392                             pf.dxStartIndent = pf.dxStartIndent + pf.dxOffset;
1393                             pf.cbSize = sizeof(pf);
1394                             pf.dwMask = PFM_OFFSET | PFM_OFFSETINDENT | PFM_RIGHTINDENT;
1395                             SendMessageW(hEditorWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
1396                         }
1397                     }
1398                     /* Fall through */
1399
1400                 case IDCANCEL:
1401                     EndDialog(hWnd, wParam);
1402                     return TRUE;
1403             }
1404     }
1405     return FALSE;
1406 }
1407
1408 static INT_PTR CALLBACK tabstops_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1409 {
1410     switch(message)
1411     {
1412         case WM_INITDIALOG:
1413             {
1414                 HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1415                 PARAFORMAT pf;
1416                 WCHAR buffer[MAX_STRING_LEN];
1417                 int i;
1418
1419                 pf.cbSize = sizeof(pf);
1420                 pf.dwMask = PFM_TABSTOPS;
1421                 SendMessageW(hEditorWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
1422                 SendMessageW(hTabWnd, CB_LIMITTEXT, MAX_STRING_LEN-1, 0);
1423
1424                 for(i = 0; i < pf.cTabCount; i++)
1425                 {
1426                     number_with_units(buffer, pf.rgxTabs[i]);
1427                     SendMessageW(hTabWnd, CB_ADDSTRING, 0, (LPARAM)&buffer);
1428                 }
1429                 SetFocus(hTabWnd);
1430             }
1431             break;
1432
1433         case WM_COMMAND:
1434             switch(LOWORD(wParam))
1435             {
1436                 case IDC_TABSTOPS:
1437                     {
1438                         HWND hTabWnd = (HWND)lParam;
1439                         HWND hAddWnd = GetDlgItem(hWnd, ID_TAB_ADD);
1440                         HWND hDelWnd = GetDlgItem(hWnd, ID_TAB_DEL);
1441                         HWND hEmptyWnd = GetDlgItem(hWnd, ID_TAB_EMPTY);
1442
1443                         if(GetWindowTextLengthW(hTabWnd))
1444                             EnableWindow(hAddWnd, TRUE);
1445                         else
1446                             EnableWindow(hAddWnd, FALSE);
1447
1448                         if(SendMessageW(hTabWnd, CB_GETCOUNT, 0, 0))
1449                         {
1450                             EnableWindow(hEmptyWnd, TRUE);
1451
1452                             if(SendMessageW(hTabWnd, CB_GETCURSEL, 0, 0) == CB_ERR)
1453                                 EnableWindow(hDelWnd, FALSE);
1454                             else
1455                                 EnableWindow(hDelWnd, TRUE);
1456                         } else
1457                         {
1458                             EnableWindow(hEmptyWnd, FALSE);
1459                         }
1460                     }
1461                     break;
1462
1463                 case ID_TAB_ADD:
1464                     {
1465                         HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1466                         WCHAR buffer[MAX_STRING_LEN];
1467
1468                         GetWindowTextW(hTabWnd, buffer, MAX_STRING_LEN);
1469                         append_current_units(buffer);
1470
1471                         if(SendMessageW(hTabWnd, CB_FINDSTRINGEXACT, -1, (LPARAM)&buffer) == CB_ERR)
1472                         {
1473                             float number = 0;
1474
1475                             if(!number_from_string(buffer, &number, TRUE))
1476                             {
1477                                 MessageBoxW(hWnd, MAKEINTRESOURCEW(STRING_INVALID_NUMBER),
1478                                              wszAppTitle, MB_OK | MB_ICONINFORMATION);
1479                             } else
1480                             {
1481                                 SendMessageW(hTabWnd, CB_ADDSTRING, 0, (LPARAM)&buffer);
1482                                 SetWindowTextW(hTabWnd, 0);
1483                             }
1484                         }
1485                         SetFocus(hTabWnd);
1486                     }
1487                     break;
1488
1489                 case ID_TAB_DEL:
1490                     {
1491                         HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1492                         LRESULT ret;
1493                         ret = SendMessageW(hTabWnd, CB_GETCURSEL, 0, 0);
1494                         if(ret != CB_ERR)
1495                             SendMessageW(hTabWnd, CB_DELETESTRING, ret, 0);
1496                     }
1497                     break;
1498
1499                 case ID_TAB_EMPTY:
1500                     {
1501                         HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1502                         SendMessageW(hTabWnd, CB_RESETCONTENT, 0, 0);
1503                         SetFocus(hTabWnd);
1504                     }
1505                     break;
1506
1507                 case IDOK:
1508                     {
1509                         HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1510                         int i;
1511                         WCHAR buffer[MAX_STRING_LEN];
1512                         PARAFORMAT pf;
1513                         float number;
1514
1515                         pf.cbSize = sizeof(pf);
1516                         pf.dwMask = PFM_TABSTOPS;
1517
1518                         for(i = 0; SendMessageW(hTabWnd, CB_GETLBTEXT, i,
1519                                                 (LPARAM)&buffer) != CB_ERR &&
1520                                                         i < MAX_TAB_STOPS; i++)
1521                         {
1522                             number_from_string(buffer, &number, TRUE);
1523                             pf.rgxTabs[i] = current_units_to_twips(number);
1524                         }
1525                         pf.cTabCount = i;
1526                         SendMessageW(hEditorWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
1527                     }
1528                     /* Fall through */
1529                 case IDCANCEL:
1530                     EndDialog(hWnd, wParam);
1531                     return TRUE;
1532             }
1533     }
1534     return FALSE;
1535 }
1536
1537 static int context_menu(LPARAM lParam)
1538 {
1539     int x = (int)(short)LOWORD(lParam);
1540     int y = (int)(short)HIWORD(lParam);
1541     HMENU hPop = GetSubMenu(hPopupMenu, 0);
1542
1543     if(x == -1)
1544     {
1545         int from = 0, to = 0;
1546         POINTL pt;
1547         SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&from, (LPARAM)&to);
1548         SendMessageW(hEditorWnd, EM_POSFROMCHAR, (WPARAM)&pt, (LPARAM)to);
1549         ClientToScreen(hEditorWnd, (POINT*)&pt);
1550         x = pt.x;
1551         y = pt.y;
1552     }
1553
1554     TrackPopupMenu(hPop, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON,
1555                    x, y, 0, hMainWnd, 0);
1556
1557     return 0;
1558 }
1559
1560 static LRESULT OnCreate( HWND hWnd, WPARAM wParam, LPARAM lParam)
1561 {
1562     HWND hToolBarWnd, hFormatBarWnd,  hReBarWnd, hFontListWnd, hSizeListWnd, hRulerWnd;
1563     HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
1564     HANDLE hDLL;
1565     TBADDBITMAP ab;
1566     int nStdBitmaps = 0;
1567     REBARINFO rbi;
1568     REBARBANDINFOW rbb;
1569     static const WCHAR wszRichEditDll[] = {'R','I','C','H','E','D','2','0','.','D','L','L','\0'};
1570     static const WCHAR wszRichEditText[] = {'R','i','c','h','E','d','i','t',' ','t','e','x','t','\0'};
1571
1572     CreateStatusWindowW(CCS_NODIVIDER|WS_CHILD|WS_VISIBLE, wszRichEditText, hWnd, IDC_STATUSBAR);
1573
1574     hReBarWnd = CreateWindowExW(WS_EX_TOOLWINDOW, REBARCLASSNAMEW, NULL,
1575       CCS_NODIVIDER|WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|RBS_VARHEIGHT|CCS_TOP,
1576       CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hWnd, (HMENU)IDC_REBAR, hInstance, NULL);
1577
1578     rbi.cbSize = sizeof(rbi);
1579     rbi.fMask = 0;
1580     rbi.himl = NULL;
1581     if(!SendMessageW(hReBarWnd, RB_SETBARINFO, 0, (LPARAM)&rbi))
1582         return -1;
1583
1584     hToolBarWnd = CreateToolbarEx(hReBarWnd, CCS_NOPARENTALIGN|CCS_NOMOVEY|WS_VISIBLE|WS_CHILD|TBSTYLE_TOOLTIPS|TBSTYLE_BUTTON,
1585       IDC_TOOLBAR,
1586       1, hInstance, IDB_TOOLBAR,
1587       NULL, 0,
1588       24, 24, 16, 16, sizeof(TBBUTTON));
1589
1590     ab.hInst = HINST_COMMCTRL;
1591     ab.nID = IDB_STD_SMALL_COLOR;
1592     nStdBitmaps = SendMessageW(hToolBarWnd, TB_ADDBITMAP, 0, (LPARAM)&ab);
1593
1594     AddButton(hToolBarWnd, nStdBitmaps+STD_FILENEW, ID_FILE_NEW);
1595     AddButton(hToolBarWnd, nStdBitmaps+STD_FILEOPEN, ID_FILE_OPEN);
1596     AddButton(hToolBarWnd, nStdBitmaps+STD_FILESAVE, ID_FILE_SAVE);
1597     AddSeparator(hToolBarWnd);
1598     AddButton(hToolBarWnd, nStdBitmaps+STD_PRINT, ID_PRINT_QUICK);
1599     AddButton(hToolBarWnd, nStdBitmaps+STD_PRINTPRE, ID_PREVIEW);
1600     AddSeparator(hToolBarWnd);
1601     AddButton(hToolBarWnd, nStdBitmaps+STD_FIND, ID_FIND);
1602     AddSeparator(hToolBarWnd);
1603     AddButton(hToolBarWnd, nStdBitmaps+STD_CUT, ID_EDIT_CUT);
1604     AddButton(hToolBarWnd, nStdBitmaps+STD_COPY, ID_EDIT_COPY);
1605     AddButton(hToolBarWnd, nStdBitmaps+STD_PASTE, ID_EDIT_PASTE);
1606     AddButton(hToolBarWnd, nStdBitmaps+STD_UNDO, ID_EDIT_UNDO);
1607     AddButton(hToolBarWnd, nStdBitmaps+STD_REDOW, ID_EDIT_REDO);
1608     AddSeparator(hToolBarWnd);
1609     AddButton(hToolBarWnd, 0, ID_DATETIME);
1610
1611     SendMessageW(hToolBarWnd, TB_AUTOSIZE, 0, 0);
1612
1613     rbb.cbSize = sizeof(rbb);
1614     rbb.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD | RBBIM_STYLE | RBBIM_ID;
1615     rbb.fStyle = RBBS_CHILDEDGE | RBBS_BREAK | RBBS_NOGRIPPER;
1616     rbb.cx = 0;
1617     rbb.hwndChild = hToolBarWnd;
1618     rbb.cxMinChild = 0;
1619     rbb.cyChild = rbb.cyMinChild = HIWORD(SendMessageW(hToolBarWnd, TB_GETBUTTONSIZE, 0, 0));
1620     rbb.wID = BANDID_TOOLBAR;
1621
1622     SendMessageW(hReBarWnd, RB_INSERTBAND, -1, (LPARAM)&rbb);
1623
1624     hFontListWnd = CreateWindowExW(0, WC_COMBOBOXEXW, NULL,
1625                       WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN | CBS_SORT,
1626                       0, 0, 200, 150, hReBarWnd, (HMENU)IDC_FONTLIST, hInstance, NULL);
1627
1628     rbb.hwndChild = hFontListWnd;
1629     rbb.cx = 200;
1630     rbb.wID = BANDID_FONTLIST;
1631
1632     SendMessageW(hReBarWnd, RB_INSERTBAND, -1, (LPARAM)&rbb);
1633
1634     hSizeListWnd = CreateWindowExW(0, WC_COMBOBOXEXW, NULL,
1635                       WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN,
1636                       0, 0, 50, 150, hReBarWnd, (HMENU)IDC_SIZELIST, hInstance, NULL);
1637
1638     rbb.hwndChild = hSizeListWnd;
1639     rbb.cx = 50;
1640     rbb.fStyle ^= RBBS_BREAK;
1641     rbb.wID = BANDID_SIZELIST;
1642
1643     SendMessageW(hReBarWnd, RB_INSERTBAND, -1, (LPARAM)&rbb);
1644
1645     hFormatBarWnd = CreateToolbarEx(hReBarWnd,
1646          CCS_NOPARENTALIGN | CCS_NOMOVEY | WS_VISIBLE | TBSTYLE_TOOLTIPS | TBSTYLE_BUTTON,
1647          IDC_FORMATBAR, 7, hInstance, IDB_FORMATBAR, NULL, 0, 16, 16, 16, 16, sizeof(TBBUTTON));
1648
1649     AddButton(hFormatBarWnd, 0, ID_FORMAT_BOLD);
1650     AddButton(hFormatBarWnd, 1, ID_FORMAT_ITALIC);
1651     AddButton(hFormatBarWnd, 2, ID_FORMAT_UNDERLINE);
1652     AddSeparator(hFormatBarWnd);
1653     AddButton(hFormatBarWnd, 3, ID_ALIGN_LEFT);
1654     AddButton(hFormatBarWnd, 4, ID_ALIGN_CENTER);
1655     AddButton(hFormatBarWnd, 5, ID_ALIGN_RIGHT);
1656     AddSeparator(hFormatBarWnd);
1657     AddButton(hFormatBarWnd, 6, ID_BULLET);
1658
1659     SendMessageW(hFormatBarWnd, TB_AUTOSIZE, 0, 0);
1660
1661     rbb.hwndChild = hFormatBarWnd;
1662     rbb.wID = BANDID_FORMATBAR;
1663
1664     SendMessageW(hReBarWnd, RB_INSERTBAND, -1, (LPARAM)&rbb);
1665
1666     hRulerWnd = CreateWindowExW(0, WC_STATICW, NULL, WS_VISIBLE | WS_CHILD,
1667                                 0, 0, 200, 10, hReBarWnd,  (HMENU)IDC_RULER, hInstance, NULL);
1668
1669
1670     rbb.hwndChild = hRulerWnd;
1671     rbb.wID = BANDID_RULER;
1672     rbb.fStyle |= RBBS_BREAK;
1673
1674     SendMessageW(hReBarWnd, RB_INSERTBAND, -1, (LPARAM)&rbb);
1675
1676     hDLL = LoadLibraryW(wszRichEditDll);
1677     if(!hDLL)
1678     {
1679         MessageBoxW(hWnd, MAKEINTRESOURCEW(STRING_LOAD_RICHED_FAILED), wszAppTitle,
1680                     MB_OK | MB_ICONEXCLAMATION);
1681         PostQuitMessage(1);
1682     }
1683
1684     hEditorWnd = CreateWindowExW(WS_EX_CLIENTEDGE, wszRichEditClass, NULL,
1685       WS_CHILD|WS_VISIBLE|ECO_SELECTIONBAR|ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN|WS_VSCROLL,
1686       0, 0, 1000, 100, hWnd, (HMENU)IDC_EDITOR, hInstance, NULL);
1687
1688     if (!hEditorWnd)
1689     {
1690         fprintf(stderr, "Error code %u\n", GetLastError());
1691         return -1;
1692     }
1693     assert(hEditorWnd);
1694
1695     SetFocus(hEditorWnd);
1696     SendMessageW(hEditorWnd, EM_SETEVENTMASK, 0, ENM_SELCHANGE);
1697
1698     set_default_font();
1699
1700     populate_font_list(hFontListWnd);
1701     populate_size_list(hSizeListWnd);
1702     DoLoadStrings();
1703     SendMessageW(hEditorWnd, EM_SETMODIFY, FALSE, 0);
1704
1705     ID_FINDMSGSTRING = RegisterWindowMessageW(FINDMSGSTRINGW);
1706
1707     registry_read_filelist(hWnd);
1708     registry_read_formatopts_all(barState, wordWrap);
1709     registry_read_options();
1710     DragAcceptFiles(hWnd, TRUE);
1711
1712     return 0;
1713 }
1714
1715 static LRESULT OnUser( HWND hWnd, WPARAM wParam, LPARAM lParam)
1716 {
1717     HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
1718     HWND hwndReBar = GetDlgItem(hWnd, IDC_REBAR);
1719     HWND hwndToolBar = GetDlgItem(hwndReBar, IDC_TOOLBAR);
1720     HWND hwndFormatBar = GetDlgItem(hwndReBar, IDC_FORMATBAR);
1721     int from, to;
1722     CHARFORMAT2W fmt;
1723     PARAFORMAT2 pf;
1724     GETTEXTLENGTHEX gt;
1725
1726     ZeroMemory(&fmt, sizeof(fmt));
1727     fmt.cbSize = sizeof(fmt);
1728
1729     ZeroMemory(&pf, sizeof(pf));
1730     pf.cbSize = sizeof(pf);
1731
1732     gt.flags = GTL_NUMCHARS;
1733     gt.codepage = 1200;
1734
1735     SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_FIND,
1736                  SendMessageW(hwndEditor, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0) ? 1 : 0);
1737
1738     SendMessageW(hwndEditor, EM_GETCHARFORMAT, TRUE, (LPARAM)&fmt);
1739
1740     SendMessageW(hwndEditor, EM_GETSEL, (WPARAM)&from, (LPARAM)&to);
1741     SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_EDIT_UNDO,
1742       SendMessageW(hwndEditor, EM_CANUNDO, 0, 0));
1743     SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_EDIT_REDO,
1744       SendMessageW(hwndEditor, EM_CANREDO, 0, 0));
1745     SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_EDIT_CUT, from == to ? 0 : 1);
1746     SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_EDIT_COPY, from == to ? 0 : 1);
1747
1748     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_FORMAT_BOLD, (fmt.dwMask & CFM_BOLD) &&
1749             (fmt.dwEffects & CFE_BOLD));
1750     SendMessageW(hwndFormatBar, TB_INDETERMINATE, ID_FORMAT_BOLD, !(fmt.dwMask & CFM_BOLD));
1751     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_FORMAT_ITALIC, (fmt.dwMask & CFM_ITALIC) &&
1752             (fmt.dwEffects & CFE_ITALIC));
1753     SendMessageW(hwndFormatBar, TB_INDETERMINATE, ID_FORMAT_ITALIC, !(fmt.dwMask & CFM_ITALIC));
1754     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_FORMAT_UNDERLINE, (fmt.dwMask & CFM_UNDERLINE) &&
1755             (fmt.dwEffects & CFE_UNDERLINE));
1756     SendMessageW(hwndFormatBar, TB_INDETERMINATE, ID_FORMAT_UNDERLINE, !(fmt.dwMask & CFM_UNDERLINE));
1757
1758     SendMessageW(hwndEditor, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
1759     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_ALIGN_LEFT, (pf.wAlignment == PFA_LEFT));
1760     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_ALIGN_CENTER, (pf.wAlignment == PFA_CENTER));
1761     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_ALIGN_RIGHT, (pf.wAlignment == PFA_RIGHT));
1762
1763     SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_BULLET, (pf.wNumbering & PFN_BULLET));
1764     return 0;
1765 }
1766
1767 static LRESULT OnNotify( HWND hWnd, WPARAM wParam, LPARAM lParam)
1768 {
1769     HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
1770     HWND hwndReBar = GetDlgItem(hWnd, IDC_REBAR);
1771     NMHDR *pHdr = (NMHDR *)lParam;
1772     HWND hwndFontList = GetDlgItem(hwndReBar, IDC_FONTLIST);
1773     HWND hwndSizeList = GetDlgItem(hwndReBar, IDC_SIZELIST);
1774     WCHAR sizeBuffer[MAX_PATH];
1775
1776     if (pHdr->hwndFrom == hwndFontList || pHdr->hwndFrom == hwndSizeList)
1777     {
1778         if (pHdr->code == CBEN_ENDEDITW)
1779         {
1780             CHARFORMAT2W format;
1781             NMCBEENDEDIT *endEdit = (NMCBEENDEDIT *)lParam;
1782
1783             ZeroMemory(&format, sizeof(format));
1784             format.cbSize = sizeof(format);
1785             SendMessageW(hwndEditor, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&format);
1786
1787             if(pHdr->hwndFrom == hwndFontList)
1788             {
1789                 if(lstrcmpW(format.szFaceName, (LPWSTR)endEdit->szText))
1790                     set_font((LPCWSTR) endEdit->szText);
1791             } else if (pHdr->hwndFrom == hwndSizeList)
1792             {
1793                 wsprintfW(sizeBuffer, stringFormat, format.yHeight / 20);
1794                 if(lstrcmpW(sizeBuffer, (LPWSTR)endEdit->szText))
1795                 {
1796                     float size = 0;
1797                     if(number_from_string((LPWSTR)endEdit->szText, &size, FALSE))
1798                     {
1799                         set_size(size);
1800                     } else
1801                     {
1802                         SetWindowTextW(hwndSizeList, sizeBuffer);
1803                         MessageBoxW(hMainWnd, MAKEINTRESOURCEW(STRING_INVALID_NUMBER), wszAppTitle, MB_OK | MB_ICONINFORMATION);
1804                     }
1805                 }
1806             }
1807         }
1808         return 0;
1809     }
1810
1811     if (pHdr->hwndFrom != hwndEditor)
1812         return 0;
1813
1814     if (pHdr->code == EN_SELCHANGE)
1815     {
1816         SELCHANGE *pSC = (SELCHANGE *)lParam;
1817         char buf[128];
1818
1819         update_font_list();
1820
1821         sprintf( buf,"selection = %d..%d, line count=%ld",
1822                  pSC->chrg.cpMin, pSC->chrg.cpMax,
1823         SendMessage(hwndEditor, EM_GETLINECOUNT, 0, 0));
1824         SetWindowText(GetDlgItem(hWnd, IDC_STATUSBAR), buf);
1825         SendMessage(hWnd, WM_USER, 0, 0);
1826         return 1;
1827     }
1828     return 0;
1829 }
1830
1831 static LRESULT OnCommand( HWND hWnd, WPARAM wParam, LPARAM lParam)
1832 {
1833     HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
1834     static FINDREPLACEW findreplace;
1835
1836     if ((HWND)lParam == hwndEditor)
1837         return 0;
1838
1839     switch(LOWORD(wParam))
1840     {
1841
1842     case ID_FILE_EXIT:
1843         PostMessageW(hWnd, WM_CLOSE, 0, 0);
1844         break;
1845
1846     case ID_FILE_NEW:
1847         {
1848             HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
1849             int ret = DialogBox(hInstance, MAKEINTRESOURCE(IDD_NEWFILE), hWnd,
1850                                 newfile_proc);
1851
1852             if(ret != ID_NEWFILE_ABORT)
1853             {
1854                 if(prompt_save_changes())
1855                 {
1856                     SETTEXTEX st;
1857
1858                     set_caption(NULL);
1859                     wszFileName[0] = '\0';
1860
1861                     clear_formatting();
1862
1863                     st.flags = ST_DEFAULT;
1864                     st.codepage = 1200;
1865                     SendMessageW(hEditorWnd, EM_SETTEXTEX, (WPARAM)&st, 0);
1866
1867                     SendMessageW(hEditorWnd, EM_SETMODIFY, FALSE, 0);
1868                     set_fileformat(ret);
1869                     update_font_list();
1870                 }
1871             }
1872         }
1873         break;
1874
1875     case ID_FILE_OPEN:
1876         DialogOpenFile();
1877         break;
1878
1879     case ID_FILE_SAVE:
1880         if(wszFileName[0])
1881         {
1882             DoSaveFile(wszFileName, fileFormat);
1883             break;
1884         }
1885         /* Fall through */
1886
1887     case ID_FILE_SAVEAS:
1888         DialogSaveFile();
1889         break;
1890
1891     case ID_FILE_RECENT1:
1892     case ID_FILE_RECENT2:
1893     case ID_FILE_RECENT3:
1894     case ID_FILE_RECENT4:
1895         {
1896             HMENU hMenu = GetMenu(hWnd);
1897             MENUITEMINFOW mi;
1898
1899             mi.cbSize = sizeof(MENUITEMINFOW);
1900             mi.fMask = MIIM_DATA;
1901             if(GetMenuItemInfoW(hMenu, LOWORD(wParam), FALSE, &mi))
1902                 DoOpenFile((LPWSTR)mi.dwItemData);
1903         }
1904         break;
1905
1906     case ID_FIND:
1907         dialog_find(&findreplace, FALSE);
1908         break;
1909
1910     case ID_FIND_NEXT:
1911         handle_findmsg(&findreplace);
1912         break;
1913
1914     case ID_REPLACE:
1915         dialog_find(&findreplace, TRUE);
1916         break;
1917
1918     case ID_FONTSETTINGS:
1919         dialog_choose_font();
1920         break;
1921
1922     case ID_PRINT:
1923         dialog_print(hWnd, wszFileName);
1924         target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
1925         break;
1926
1927     case ID_PRINT_QUICK:
1928         print_quick(wszFileName);
1929         target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
1930         break;
1931
1932     case ID_PREVIEW:
1933         {
1934             int index = reg_formatindex(fileFormat);
1935             DWORD tmp = barState[index];
1936             barState[index] = 0;
1937             set_bar_states();
1938             barState[index] = tmp;
1939             ShowWindow(hEditorWnd, FALSE);
1940
1941             init_preview(hWnd, wszFileName);
1942
1943             SetMenu(hWnd, NULL);
1944             InvalidateRect(0, 0, TRUE);
1945         }
1946         break;
1947
1948     case ID_PRINTSETUP:
1949         dialog_printsetup(hWnd);
1950         target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
1951         break;
1952
1953     case ID_FORMAT_BOLD:
1954     case ID_FORMAT_ITALIC:
1955     case ID_FORMAT_UNDERLINE:
1956         {
1957         CHARFORMAT2W fmt;
1958         int effects = CFE_BOLD;
1959
1960         ZeroMemory(&fmt, sizeof(fmt));
1961         fmt.cbSize = sizeof(fmt);
1962         SendMessageW(hwndEditor, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
1963
1964         fmt.dwMask = CFM_BOLD;
1965
1966         if (LOWORD(wParam) == ID_FORMAT_ITALIC)
1967         {
1968             effects = CFE_ITALIC;
1969             fmt.dwMask = CFM_ITALIC;
1970         } else if (LOWORD(wParam) == ID_FORMAT_UNDERLINE)
1971         {
1972             effects = CFE_UNDERLINE;
1973             fmt.dwMask = CFM_UNDERLINE;
1974         }
1975
1976         fmt.dwEffects ^= effects;
1977
1978         SendMessageW(hwndEditor, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
1979         break;
1980         }
1981
1982     case ID_EDIT_CUT:
1983         PostMessageW(hwndEditor, WM_CUT, 0, 0);
1984         break;
1985
1986     case ID_EDIT_COPY:
1987         PostMessageW(hwndEditor, WM_COPY, 0, 0);
1988         break;
1989
1990     case ID_EDIT_PASTE:
1991         PostMessageW(hwndEditor, WM_PASTE, 0, 0);
1992         break;
1993
1994     case ID_EDIT_CLEAR:
1995         PostMessageW(hwndEditor, WM_CLEAR, 0, 0);
1996         break;
1997
1998     case ID_EDIT_SELECTALL:
1999         {
2000         CHARRANGE range = {0, -1};
2001         SendMessageW(hwndEditor, EM_EXSETSEL, 0, (LPARAM)&range);
2002         /* SendMessage(hwndEditor, EM_SETSEL, 0, -1); */
2003         return 0;
2004         }
2005
2006     case ID_EDIT_GETTEXT:
2007         {
2008         int nLen = GetWindowTextLengthW(hwndEditor);
2009         LPWSTR data = HeapAlloc( GetProcessHeap(), 0, (nLen+1)*sizeof(WCHAR) );
2010         TEXTRANGEW tr;
2011
2012         GetWindowTextW(hwndEditor, data, nLen+1);
2013         MessageBoxW(NULL, data, xszAppTitle, MB_OK);
2014
2015         HeapFree( GetProcessHeap(), 0, data);
2016         data = HeapAlloc(GetProcessHeap(), 0, (nLen+1)*sizeof(WCHAR));
2017         tr.chrg.cpMin = 0;
2018         tr.chrg.cpMax = nLen;
2019         tr.lpstrText = data;
2020         SendMessage (hwndEditor, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
2021         MessageBoxW(NULL, data, xszAppTitle, MB_OK);
2022         HeapFree( GetProcessHeap(), 0, data );
2023
2024         /* SendMessage(hwndEditor, EM_SETSEL, 0, -1); */
2025         return 0;
2026         }
2027
2028     case ID_EDIT_CHARFORMAT:
2029     case ID_EDIT_DEFCHARFORMAT:
2030         {
2031         CHARFORMAT2W cf;
2032         LRESULT i;
2033         ZeroMemory(&cf, sizeof(cf));
2034         cf.cbSize = sizeof(cf);
2035         cf.dwMask = 0;
2036         i = SendMessageW(hwndEditor, EM_GETCHARFORMAT,
2037                         LOWORD(wParam) == ID_EDIT_CHARFORMAT, (LPARAM)&cf);
2038         return 0;
2039         }
2040
2041     case ID_EDIT_PARAFORMAT:
2042         {
2043         PARAFORMAT2 pf;
2044         ZeroMemory(&pf, sizeof(pf));
2045         pf.cbSize = sizeof(pf);
2046         SendMessageW(hwndEditor, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
2047         return 0;
2048         }
2049
2050     case ID_EDIT_SELECTIONINFO:
2051         {
2052         CHARRANGE range = {0, -1};
2053         char buf[128];
2054         WCHAR *data = NULL;
2055
2056         SendMessage(hwndEditor, EM_EXGETSEL, 0, (LPARAM)&range);
2057         data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data) * (range.cpMax-range.cpMin+1));
2058         SendMessage(hwndEditor, EM_GETSELTEXT, 0, (LPARAM)data);
2059         sprintf(buf, "Start = %d, End = %d", range.cpMin, range.cpMax);
2060         MessageBoxA(hWnd, buf, "Editor", MB_OK);
2061         MessageBoxW(hWnd, data, xszAppTitle, MB_OK);
2062         HeapFree( GetProcessHeap(), 0, data);
2063         /* SendMessage(hwndEditor, EM_SETSEL, 0, -1); */
2064         return 0;
2065         }
2066
2067     case ID_EDIT_READONLY:
2068         {
2069         long nStyle = GetWindowLong(hwndEditor, GWL_STYLE);
2070         if (nStyle & ES_READONLY)
2071             SendMessageW(hwndEditor, EM_SETREADONLY, 0, 0);
2072         else
2073             SendMessageW(hwndEditor, EM_SETREADONLY, 1, 0);
2074         return 0;
2075         }
2076
2077     case ID_EDIT_MODIFIED:
2078         if (SendMessageW(hwndEditor, EM_GETMODIFY, 0, 0))
2079             SendMessageW(hwndEditor, EM_SETMODIFY, 0, 0);
2080         else
2081             SendMessageW(hwndEditor, EM_SETMODIFY, 1, 0);
2082         return 0;
2083
2084     case ID_EDIT_UNDO:
2085         SendMessageW(hwndEditor, EM_UNDO, 0, 0);
2086         return 0;
2087
2088     case ID_EDIT_REDO:
2089         SendMessageW(hwndEditor, EM_REDO, 0, 0);
2090         return 0;
2091
2092     case ID_BULLET:
2093         {
2094             PARAFORMAT pf;
2095
2096             pf.cbSize = sizeof(pf);
2097             pf.dwMask = PFM_NUMBERING;
2098             SendMessageW(hwndEditor, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
2099
2100             pf.dwMask |=  PFM_OFFSET;
2101
2102             if(pf.wNumbering == PFN_BULLET)
2103             {
2104                 pf.wNumbering = 0;
2105                 pf.dxOffset = 0;
2106             } else
2107             {
2108                 pf.wNumbering = PFN_BULLET;
2109                 pf.dxOffset = 720;
2110             }
2111
2112             SendMessageW(hwndEditor, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
2113         }
2114         break;
2115
2116     case ID_ALIGN_LEFT:
2117     case ID_ALIGN_CENTER:
2118     case ID_ALIGN_RIGHT:
2119         {
2120         PARAFORMAT2 pf;
2121
2122         pf.cbSize = sizeof(pf);
2123         pf.dwMask = PFM_ALIGNMENT;
2124         switch(LOWORD(wParam)) {
2125         case ID_ALIGN_LEFT: pf.wAlignment = PFA_LEFT; break;
2126         case ID_ALIGN_CENTER: pf.wAlignment = PFA_CENTER; break;
2127         case ID_ALIGN_RIGHT: pf.wAlignment = PFA_RIGHT; break;
2128         }
2129         SendMessageW(hwndEditor, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
2130         break;
2131         }
2132
2133     case ID_BACK_1:
2134         SendMessageW(hwndEditor, EM_SETBKGNDCOLOR, 1, 0);
2135         break;
2136
2137     case ID_BACK_2:
2138         SendMessageW(hwndEditor, EM_SETBKGNDCOLOR, 0, RGB(255,255,192));
2139         break;
2140
2141     case ID_TOGGLE_TOOLBAR:
2142         set_toolbar_state(BANDID_TOOLBAR, !is_bar_visible(BANDID_TOOLBAR));
2143         update_window();
2144         break;
2145
2146     case ID_TOGGLE_FORMATBAR:
2147         set_toolbar_state(BANDID_FONTLIST, !is_bar_visible(BANDID_FORMATBAR));
2148         set_toolbar_state(BANDID_SIZELIST, !is_bar_visible(BANDID_FORMATBAR));
2149         set_toolbar_state(BANDID_FORMATBAR, !is_bar_visible(BANDID_FORMATBAR));
2150         update_window();
2151         break;
2152
2153     case ID_TOGGLE_STATUSBAR:
2154         set_statusbar_state(!is_bar_visible(BANDID_STATUSBAR));
2155         update_window();
2156         break;
2157
2158     case ID_TOGGLE_RULER:
2159         set_toolbar_state(BANDID_RULER, !is_bar_visible(BANDID_RULER));
2160         update_window();
2161         break;
2162
2163     case ID_DATETIME:
2164         {
2165         HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
2166         DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_DATETIME), hWnd, datetime_proc);
2167         break;
2168         }
2169
2170     case ID_PARAFORMAT:
2171         {
2172             HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
2173             DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_PARAFORMAT), hWnd,
2174                        paraformat_proc);
2175         }
2176         break;
2177
2178     case ID_TABSTOPS:
2179         {
2180             HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
2181             DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_TABSTOPS), hWnd, tabstops_proc);
2182         }
2183         break;
2184
2185     case ID_ABOUT:
2186         dialog_about();
2187         break;
2188
2189     case ID_VIEWPROPERTIES:
2190         dialog_viewproperties();
2191         break;
2192
2193     default:
2194         SendMessageW(hwndEditor, WM_COMMAND, wParam, lParam);
2195         break;
2196     }
2197     return 0;
2198 }
2199
2200 static LRESULT OnInitPopupMenu( HWND hWnd, WPARAM wParam, LPARAM lParam )
2201 {
2202     HMENU hMenu = (HMENU)wParam;
2203     HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
2204     HWND hwndStatus = GetDlgItem(hWnd, IDC_STATUSBAR);
2205     PARAFORMAT pf;
2206     int nAlignment = -1;
2207     int selFrom, selTo;
2208     GETTEXTLENGTHEX gt;
2209     LRESULT textLength;
2210     MENUITEMINFOW mi;
2211
2212     SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&selFrom, (LPARAM)&selTo);
2213     EnableMenuItem(hMenu, ID_EDIT_COPY, MF_BYCOMMAND|(selFrom == selTo) ? MF_GRAYED : MF_ENABLED);
2214     EnableMenuItem(hMenu, ID_EDIT_CUT, MF_BYCOMMAND|(selFrom == selTo) ? MF_GRAYED : MF_ENABLED);
2215
2216     pf.cbSize = sizeof(PARAFORMAT);
2217     SendMessageW(hwndEditor, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
2218     CheckMenuItem(hMenu, ID_EDIT_READONLY,
2219       MF_BYCOMMAND|(GetWindowLong(hwndEditor, GWL_STYLE)&ES_READONLY ? MF_CHECKED : MF_UNCHECKED));
2220     CheckMenuItem(hMenu, ID_EDIT_MODIFIED,
2221       MF_BYCOMMAND|(SendMessage(hwndEditor, EM_GETMODIFY, 0, 0) ? MF_CHECKED : MF_UNCHECKED));
2222     if (pf.dwMask & PFM_ALIGNMENT)
2223         nAlignment = pf.wAlignment;
2224     CheckMenuItem(hMenu, ID_ALIGN_LEFT, MF_BYCOMMAND|(nAlignment == PFA_LEFT) ?
2225             MF_CHECKED : MF_UNCHECKED);
2226     CheckMenuItem(hMenu, ID_ALIGN_CENTER, MF_BYCOMMAND|(nAlignment == PFA_CENTER) ?
2227             MF_CHECKED : MF_UNCHECKED);
2228     CheckMenuItem(hMenu, ID_ALIGN_RIGHT, MF_BYCOMMAND|(nAlignment == PFA_RIGHT) ?
2229             MF_CHECKED : MF_UNCHECKED);
2230     CheckMenuItem(hMenu, ID_BULLET, MF_BYCOMMAND | ((pf.wNumbering == PFN_BULLET) ?
2231             MF_CHECKED : MF_UNCHECKED));
2232     EnableMenuItem(hMenu, ID_EDIT_UNDO, MF_BYCOMMAND|(SendMessageW(hwndEditor, EM_CANUNDO, 0, 0)) ?
2233             MF_ENABLED : MF_GRAYED);
2234     EnableMenuItem(hMenu, ID_EDIT_REDO, MF_BYCOMMAND|(SendMessageW(hwndEditor, EM_CANREDO, 0, 0)) ?
2235             MF_ENABLED : MF_GRAYED);
2236
2237     CheckMenuItem(hMenu, ID_TOGGLE_TOOLBAR, MF_BYCOMMAND|(is_bar_visible(BANDID_TOOLBAR)) ?
2238             MF_CHECKED : MF_UNCHECKED);
2239
2240     CheckMenuItem(hMenu, ID_TOGGLE_FORMATBAR, MF_BYCOMMAND|(is_bar_visible(BANDID_FORMATBAR)) ?
2241             MF_CHECKED : MF_UNCHECKED);
2242
2243     CheckMenuItem(hMenu, ID_TOGGLE_STATUSBAR, MF_BYCOMMAND|IsWindowVisible(hwndStatus) ?
2244             MF_CHECKED : MF_UNCHECKED);
2245
2246     CheckMenuItem(hMenu, ID_TOGGLE_RULER, MF_BYCOMMAND|(is_bar_visible(BANDID_RULER)) ? MF_CHECKED : MF_UNCHECKED);
2247
2248     gt.flags = GTL_NUMCHARS;
2249     gt.codepage = 1200;
2250     textLength = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0);
2251     EnableMenuItem(hMenu, ID_FIND, MF_BYCOMMAND|(textLength ? MF_ENABLED : MF_GRAYED));
2252
2253     mi.cbSize = sizeof(mi);
2254     mi.fMask = MIIM_DATA;
2255
2256     GetMenuItemInfoW(hMenu, ID_FIND_NEXT, FALSE, &mi);
2257
2258     EnableMenuItem(hMenu, ID_FIND_NEXT, MF_BYCOMMAND|((textLength && mi.dwItemData) ?
2259                    MF_ENABLED : MF_GRAYED));
2260
2261     EnableMenuItem(hMenu, ID_REPLACE, MF_BYCOMMAND|(textLength ? MF_ENABLED : MF_GRAYED));
2262
2263     return 0;
2264 }
2265
2266 static LRESULT OnSize( HWND hWnd, WPARAM wParam, LPARAM lParam )
2267 {
2268     int nStatusSize = 0;
2269     RECT rc;
2270     HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
2271     HWND hwndStatusBar = GetDlgItem(hWnd, IDC_STATUSBAR);
2272     HWND hwndReBar = GetDlgItem(hWnd, IDC_REBAR);
2273     HWND hRulerWnd = GetDlgItem(hWnd, IDC_RULER);
2274     int rebarHeight = 0;
2275
2276     if (hwndStatusBar)
2277     {
2278         SendMessageW(hwndStatusBar, WM_SIZE, 0, 0);
2279         if (IsWindowVisible(hwndStatusBar))
2280         {
2281             GetClientRect(hwndStatusBar, &rc);
2282             nStatusSize = rc.bottom - rc.top;
2283         } else
2284         {
2285             nStatusSize = 0;
2286         }
2287     }
2288     if (hwndReBar)
2289     {
2290         rebarHeight = SendMessageW(hwndReBar, RB_GETBARHEIGHT, 0, 0);
2291
2292         MoveWindow(hwndReBar, 0, 0, LOWORD(lParam), rebarHeight, TRUE);
2293     }
2294     if (hwndEditor)
2295     {
2296         GetClientRect(hWnd, &rc);
2297         MoveWindow(hwndEditor, 0, rebarHeight, rc.right, rc.bottom-nStatusSize-rebarHeight, TRUE);
2298     }
2299
2300     redraw_ruler(hRulerWnd);
2301
2302     return DefWindowProcW(hWnd, WM_SIZE, wParam, lParam);
2303 }
2304
2305 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
2306 {
2307     if(msg == ID_FINDMSGSTRING)
2308         return handle_findmsg((LPFINDREPLACEW)lParam);
2309
2310     switch(msg)
2311     {
2312     case WM_CREATE:
2313         return OnCreate( hWnd, wParam, lParam );
2314
2315     case WM_USER:
2316         return OnUser( hWnd, wParam, lParam );
2317
2318     case WM_NOTIFY:
2319         return OnNotify( hWnd, wParam, lParam );
2320
2321     case WM_COMMAND:
2322         if(preview_isactive())
2323         {
2324             return preview_command( hWnd, wParam, lParam );
2325         }
2326
2327         return OnCommand( hWnd, wParam, lParam );
2328
2329     case WM_DESTROY:
2330         PostQuitMessage(0);
2331         break;
2332
2333     case WM_CLOSE:
2334         if(preview_isactive())
2335         {
2336             preview_exit(hWnd);
2337         } else if(prompt_save_changes())
2338         {
2339             registry_set_options(hMainWnd);
2340             registry_set_formatopts_all(barState);
2341             PostQuitMessage(0);
2342         }
2343         break;
2344
2345     case WM_ACTIVATE:
2346         if (LOWORD(wParam))
2347             SetFocus(GetDlgItem(hWnd, IDC_EDITOR));
2348         return 0;
2349
2350     case WM_INITMENUPOPUP:
2351         return OnInitPopupMenu( hWnd, wParam, lParam );
2352
2353     case WM_SIZE:
2354         return OnSize( hWnd, wParam, lParam );
2355
2356     case WM_CONTEXTMENU:
2357         if((HWND)wParam == hEditorWnd)
2358             return context_menu(lParam);
2359         else
2360             return DefWindowProcW(hWnd, msg, wParam, lParam);
2361
2362     case WM_DROPFILES:
2363         {
2364             WCHAR file[MAX_PATH];
2365             DragQueryFileW((HDROP)wParam, 0, file, MAX_PATH);
2366             DragFinish((HDROP)wParam);
2367
2368             if(prompt_save_changes())
2369                 DoOpenFile(file);
2370         }
2371         break;
2372     case WM_PAINT:
2373         if(preview_isactive())
2374             return print_preview(hWnd);
2375         else
2376             return DefWindowProcW(hWnd, msg, wParam, lParam);
2377
2378     default:
2379         return DefWindowProcW(hWnd, msg, wParam, lParam);
2380     }
2381
2382     return 0;
2383 }
2384
2385 int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hOldInstance, LPSTR szCmdParagraph, int res)
2386 {
2387     INITCOMMONCONTROLSEX classes = {8, ICC_BAR_CLASSES|ICC_COOL_CLASSES|ICC_USEREX_CLASSES};
2388     HACCEL hAccel;
2389     WNDCLASSW wc;
2390     MSG msg;
2391     RECT rc;
2392     UINT_PTR hPrevRulerProc;
2393     HWND hRulerWnd;
2394     POINTL EditPoint;
2395     static const WCHAR wszAccelTable[] = {'M','A','I','N','A','C','C','E','L',
2396                                           'T','A','B','L','E','\0'};
2397
2398     InitCommonControlsEx(&classes);
2399
2400     hAccel = LoadAcceleratorsW(hInstance, wszAccelTable);
2401
2402     wc.style = CS_HREDRAW | CS_VREDRAW;
2403     wc.lpfnWndProc = WndProc;
2404     wc.cbClsExtra = 0;
2405     wc.cbWndExtra = 4;
2406     wc.hInstance = hInstance;
2407     wc.hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_WORDPAD));
2408     wc.hCursor = LoadCursor(NULL, IDC_IBEAM);
2409     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
2410     wc.lpszMenuName = MAKEINTRESOURCEW(IDM_MAINMENU);
2411     wc.lpszClassName = wszMainWndClass;
2412     RegisterClassW(&wc);
2413
2414     registry_read_winrect(&rc);
2415     hMainWnd = CreateWindowExW(0, wszMainWndClass, wszAppTitle, WS_CLIPCHILDREN|WS_OVERLAPPEDWINDOW,
2416       rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, hInstance, NULL);
2417     ShowWindow(hMainWnd, SW_SHOWDEFAULT);
2418
2419     set_caption(NULL);
2420     set_bar_states();
2421     set_fileformat(SF_RTF);
2422     hPopupMenu = LoadMenuW(hInstance, MAKEINTRESOURCEW(IDM_POPUP));
2423     get_default_printer_opts();
2424     target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
2425
2426     hRulerWnd = GetDlgItem(GetDlgItem(hMainWnd, IDC_REBAR), IDC_RULER);
2427     SendMessageW(GetDlgItem(hMainWnd, IDC_EDITOR), EM_POSFROMCHAR, (WPARAM)&EditPoint, 0);
2428     hPrevRulerProc = SetWindowLongPtrW(hRulerWnd, GWLP_WNDPROC, (UINT_PTR)ruler_proc);
2429     SendMessageW(hRulerWnd, WM_USER, (WPARAM)&EditPoint, hPrevRulerProc);
2430
2431     HandleCommandLine(GetCommandLineW());
2432
2433     while(GetMessageW(&msg,0,0,0))
2434     {
2435         if (IsDialogMessage(hFindWnd, &msg))
2436             continue;
2437
2438         if (TranslateAcceleratorW(hMainWnd, hAccel, &msg))
2439             continue;
2440         TranslateMessage(&msg);
2441         DispatchMessageW(&msg);
2442         if (!PeekMessageW(&msg, 0, 0, 0, PM_NOREMOVE))
2443             SendMessageW(hMainWnd, WM_USER, 0, 0);
2444     }
2445
2446     return 0;
2447 }