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