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