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