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