gdi32/uniscribe: Ensure the cache is initialised.
[wine.git] / programs / wordpad / wordpad.c
blobb357ef7d6b8e5ea414346ccbdf676b2b7eef338a
1 /*
2 * Wordpad implementation
4 * Copyright 2004 by Krzysztof Foltman
5 * Copyright 2007-2008 by Alexander N. Sørnes <alex@thehandofagony.com>
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.
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.
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
22 #define WIN32_LEAN_AND_MEAN
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <ctype.h>
27 #include <stdio.h>
28 #include <assert.h>
30 #include <windows.h>
31 #include <richedit.h>
32 #include <commctrl.h>
33 #include <commdlg.h>
34 #include <shellapi.h>
35 #include <math.h>
36 #include <errno.h>
38 #include "wordpad.h"
40 /* use LoadString */
41 static const WCHAR wszAppTitle[] = {'W','i','n','e',' ','W','o','r','d','p','a','d',0};
43 static const WCHAR wszMainWndClass[] = {'W','O','R','D','P','A','D','T','O','P',0};
45 static const WCHAR stringFormat[] = {'%','2','d','\0'};
47 const WCHAR wszPreviewWndClass[] = {'P','r','t','P','r','e','v','i','e','w',0};
48 LRESULT CALLBACK preview_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
50 static HWND hMainWnd;
51 static HWND hEditorWnd;
52 static HWND hFindWnd;
53 static HMENU hColorPopupMenu;
55 static UINT ID_FINDMSGSTRING;
57 static DWORD wordWrap[2];
58 static DWORD barState[2];
59 static WPARAM fileFormat = SF_RTF;
61 static WCHAR wszFileName[MAX_PATH];
62 static WCHAR wszFilter[MAX_STRING_LEN*4+6*3+5];
63 static WCHAR wszDefaultFileName[MAX_STRING_LEN];
64 static WCHAR wszSaveChanges[MAX_STRING_LEN];
65 static WCHAR units_cmW[MAX_STRING_LEN];
66 static WCHAR units_inW[MAX_STRING_LEN];
67 static WCHAR units_inchW[MAX_STRING_LEN];
68 static WCHAR units_ptW[MAX_STRING_LEN];
70 static int last_bullet = PFN_BULLET;
72 static LRESULT OnSize( HWND hWnd, WPARAM wParam, LPARAM lParam );
74 typedef enum
76 UNIT_CM,
77 UNIT_INCH,
78 UNIT_PT
79 } UNIT;
81 typedef struct
83 int endPos;
84 BOOL wrapped;
85 WCHAR findBuffer[128];
86 } FINDREPLACE_custom;
88 /* Load string resources */
89 static void DoLoadStrings(void)
91 LPWSTR p = wszFilter;
92 static const WCHAR files_rtf[] = {'*','.','r','t','f','\0'};
93 static const WCHAR files_txt[] = {'*','.','t','x','t','\0'};
94 static const WCHAR files_all[] = {'*','.','*','\0'};
96 HINSTANCE hInstance = GetModuleHandleW(0);
98 p += 1 + LoadStringW(hInstance, STRING_RICHTEXT_FILES_RTF, p, MAX_STRING_LEN);
99 lstrcpyW(p, files_rtf);
100 p += lstrlenW(p) + 1;
101 p += 1 + LoadStringW(hInstance, STRING_TEXT_FILES_TXT, p, MAX_STRING_LEN);
102 lstrcpyW(p, files_txt);
103 p += lstrlenW(p) + 1;
104 p += 1 + LoadStringW(hInstance, STRING_TEXT_FILES_UNICODE_TXT, p, MAX_STRING_LEN);
105 lstrcpyW(p, files_txt);
106 p += lstrlenW(p) + 1;
107 p += 1 + LoadStringW(hInstance, STRING_ALL_FILES, p, MAX_STRING_LEN);
108 lstrcpyW(p, files_all);
109 p += lstrlenW(p) + 1;
110 *p = '\0';
112 p = wszDefaultFileName;
113 LoadStringW(hInstance, STRING_DEFAULT_FILENAME, p, MAX_STRING_LEN);
115 p = wszSaveChanges;
116 LoadStringW(hInstance, STRING_PROMPT_SAVE_CHANGES, p, MAX_STRING_LEN);
118 LoadStringW(hInstance, STRING_UNITS_CM, units_cmW, MAX_STRING_LEN);
119 LoadStringW(hInstance, STRING_UNITS_IN, units_inW, MAX_STRING_LEN);
120 LoadStringW(hInstance, STRING_UNITS_INCH, units_inchW, MAX_STRING_LEN);
121 LoadStringW(hInstance, STRING_UNITS_PT, units_ptW, MAX_STRING_LEN);
124 /* Show a message box with resource strings */
125 static int MessageBoxWithResStringW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
127 MSGBOXPARAMSW params;
129 params.cbSize = sizeof(params);
130 params.hwndOwner = hWnd;
131 params.hInstance = GetModuleHandleW(0);
132 params.lpszText = lpText;
133 params.lpszCaption = lpCaption;
134 params.dwStyle = uType;
135 params.lpszIcon = NULL;
136 params.dwContextHelpId = 0;
137 params.lpfnMsgBoxCallback = NULL;
138 params.dwLanguageId = 0;
139 return MessageBoxIndirectW(&params);
143 static void AddButtonStyle(HWND hwndToolBar, int nImage, int nCommand, BYTE style)
145 TBBUTTON button;
147 ZeroMemory(&button, sizeof(button));
148 button.iBitmap = nImage;
149 button.idCommand = nCommand;
150 button.fsState = TBSTATE_ENABLED;
151 button.fsStyle = style;
152 button.dwData = 0;
153 button.iString = -1;
154 SendMessageW(hwndToolBar, TB_ADDBUTTONSW, 1, (LPARAM)&button);
157 static void AddButton(HWND hwndToolBar, int nImage, int nCommand)
159 AddButtonStyle(hwndToolBar, nImage, nCommand, BTNS_BUTTON);
162 static void AddSeparator(HWND hwndToolBar)
164 TBBUTTON button;
166 ZeroMemory(&button, sizeof(button));
167 button.iBitmap = -1;
168 button.idCommand = 0;
169 button.fsState = 0;
170 button.fsStyle = BTNS_SEP;
171 button.dwData = 0;
172 button.iString = -1;
173 SendMessageW(hwndToolBar, TB_ADDBUTTONSW, 1, (LPARAM)&button);
176 static DWORD CALLBACK stream_in(DWORD_PTR cookie, LPBYTE buffer, LONG cb, LONG *pcb)
178 HANDLE hFile = (HANDLE)cookie;
179 DWORD read;
181 if(!ReadFile(hFile, buffer, cb, &read, 0))
182 return 1;
184 *pcb = read;
186 return 0;
189 static DWORD CALLBACK stream_out(DWORD_PTR cookie, LPBYTE buffer, LONG cb, LONG *pcb)
191 DWORD written;
192 int ret;
193 HANDLE hFile = (HANDLE)cookie;
195 ret = WriteFile(hFile, buffer, cb, &written, 0);
197 if(!ret || (cb != written))
198 return 1;
200 *pcb = cb;
202 return 0;
205 LPWSTR file_basename(LPWSTR path)
207 LPWSTR pos = path + lstrlenW(path);
209 while(pos > path)
211 if(*pos == '\\' || *pos == '/')
213 pos++;
214 break;
216 pos--;
218 return pos;
221 static void set_caption(LPCWSTR wszNewFileName)
223 static const WCHAR wszSeparator[] = {' ','-',' '};
224 WCHAR *wszCaption;
225 SIZE_T length = 0;
227 if(!wszNewFileName)
228 wszNewFileName = wszDefaultFileName;
229 else
230 wszNewFileName = file_basename((LPWSTR)wszNewFileName);
232 wszCaption = calloc(1, lstrlenW(wszNewFileName)*sizeof(WCHAR)+sizeof(wszSeparator)+sizeof(wszAppTitle));
234 if(!wszCaption)
235 return;
237 memcpy(wszCaption, wszNewFileName, lstrlenW(wszNewFileName)*sizeof(WCHAR));
238 length += lstrlenW(wszNewFileName);
239 memcpy(wszCaption + length, wszSeparator, sizeof(wszSeparator));
240 length += ARRAY_SIZE(wszSeparator);
241 memcpy(wszCaption + length, wszAppTitle, sizeof(wszAppTitle));
243 SetWindowTextW(hMainWnd, wszCaption);
245 free(wszCaption);
248 static BOOL validate_endptr(LPCWSTR endptr, UNIT *punit)
250 if(punit != NULL)
251 *punit = UNIT_CM;
252 if(!endptr)
253 return FALSE;
254 if(!*endptr)
255 return TRUE;
257 while(*endptr == ' ')
258 endptr++;
260 if(punit == NULL)
261 return *endptr == '\0';
263 if(!lstrcmpW(endptr, units_cmW))
265 *punit = UNIT_CM;
266 endptr += lstrlenW(units_cmW);
268 else if (!lstrcmpW(endptr, units_inW))
270 *punit = UNIT_INCH;
271 endptr += lstrlenW(units_inW);
273 else if (!lstrcmpW(endptr, units_inchW))
275 *punit = UNIT_INCH;
276 endptr += lstrlenW(units_inchW);
278 else if (!lstrcmpW(endptr, units_ptW))
280 *punit = UNIT_PT;
281 endptr += lstrlenW(units_ptW);
284 return *endptr == '\0';
287 static BOOL number_from_string(LPCWSTR string, float *num, UNIT *punit)
289 double ret;
290 WCHAR *endptr;
292 *num = 0;
293 errno = 0;
294 ret = wcstod(string, &endptr);
296 if (punit != NULL)
297 *punit = UNIT_CM;
298 if((ret == 0 && errno != 0) || endptr == string || !validate_endptr(endptr, punit))
300 return FALSE;
301 } else
303 *num = (float)ret;
304 return TRUE;
308 static void set_size(float size)
310 CHARFORMAT2W fmt;
312 ZeroMemory(&fmt, sizeof(fmt));
313 fmt.cbSize = sizeof(fmt);
314 fmt.dwMask = CFM_SIZE;
315 fmt.yHeight = (int)(size * 20.0);
316 SendMessageW(hEditorWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
319 static void on_sizelist_modified(HWND hwndSizeList, LPWSTR wszNewFontSize)
321 WCHAR sizeBuffer[MAX_STRING_LEN];
322 CHARFORMAT2W format;
324 ZeroMemory(&format, sizeof(format));
325 format.cbSize = sizeof(format);
326 SendMessageW(hEditorWnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&format);
328 wsprintfW(sizeBuffer, stringFormat, format.yHeight / 20);
329 if(lstrcmpW(sizeBuffer, wszNewFontSize))
331 float size = 0;
332 if(number_from_string(wszNewFontSize, &size, NULL)
333 && size > 0)
335 set_size(size);
336 } else
338 SetWindowTextW(hwndSizeList, sizeBuffer);
339 MessageBoxWithResStringW(hMainWnd, MAKEINTRESOURCEW(STRING_INVALID_NUMBER),
340 wszAppTitle, MB_OK | MB_ICONINFORMATION);
345 static void add_size(HWND hSizeListWnd, unsigned size)
347 WCHAR buffer[3];
348 COMBOBOXEXITEMW cbItem;
349 cbItem.mask = CBEIF_TEXT;
350 cbItem.iItem = -1;
352 wsprintfW(buffer, stringFormat, size);
353 cbItem.pszText = buffer;
354 SendMessageW(hSizeListWnd, CBEM_INSERTITEMW, 0, (LPARAM)&cbItem);
357 static void populate_size_list(HWND hSizeListWnd)
359 HWND hReBarWnd = GetDlgItem(hMainWnd, IDC_REBAR);
360 HWND hFontListWnd = GetDlgItem(hReBarWnd, IDC_FONTLIST);
361 COMBOBOXEXITEMW cbFontItem;
362 CHARFORMAT2W fmt;
363 HWND hListEditWnd = (HWND)SendMessageW(hSizeListWnd, CBEM_GETEDITCONTROL, 0, 0);
364 HDC hdc = GetDC(hMainWnd);
365 static const unsigned choices[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
366 WCHAR buffer[3];
367 size_t i;
368 DWORD fontStyle;
370 ZeroMemory(&fmt, sizeof(fmt));
371 fmt.cbSize = sizeof(fmt);
372 SendMessageW(hEditorWnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
374 cbFontItem.mask = CBEIF_LPARAM;
375 cbFontItem.iItem = SendMessageW(hFontListWnd, CB_FINDSTRINGEXACT, -1, (LPARAM)fmt.szFaceName);
376 SendMessageW(hFontListWnd, CBEM_GETITEMW, 0, (LPARAM)&cbFontItem);
378 fontStyle = (DWORD)LOWORD(cbFontItem.lParam);
380 SendMessageW(hSizeListWnd, CB_RESETCONTENT, 0, 0);
382 if((fontStyle & RASTER_FONTTYPE) && cbFontItem.iItem)
384 add_size(hSizeListWnd, (BYTE)MulDiv(HIWORD(cbFontItem.lParam), 72,
385 GetDeviceCaps(hdc, LOGPIXELSY)));
386 } else
388 for(i = 0; i < ARRAY_SIZE(choices); i++)
389 add_size(hSizeListWnd, choices[i]);
392 wsprintfW(buffer, stringFormat, fmt.yHeight / 20);
393 SendMessageW(hListEditWnd, WM_SETTEXT, 0, (LPARAM)buffer);
396 static void update_size_list(void)
398 HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR);
399 HWND hwndSizeList = GetDlgItem(hReBar, IDC_SIZELIST);
400 HWND hwndSizeListEdit = (HWND)SendMessageW(hwndSizeList, CBEM_GETEDITCONTROL, 0, 0);
401 WCHAR fontSize[MAX_STRING_LEN], sizeBuffer[MAX_STRING_LEN];
402 CHARFORMAT2W fmt;
404 ZeroMemory(&fmt, sizeof(fmt));
405 fmt.cbSize = sizeof(fmt);
407 SendMessageW(hEditorWnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
409 SendMessageW(hwndSizeListEdit, WM_GETTEXT, MAX_PATH, (LPARAM)fontSize);
410 wsprintfW(sizeBuffer, stringFormat, fmt.yHeight / 20);
412 if(lstrcmpW(fontSize, sizeBuffer))
413 SendMessageW(hwndSizeListEdit, WM_SETTEXT, 0, (LPARAM)sizeBuffer);
416 static void update_font_list(void)
418 HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR);
419 HWND hFontList = GetDlgItem(hReBar, IDC_FONTLIST);
420 HWND hFontListEdit = (HWND)SendMessageW(hFontList, CBEM_GETEDITCONTROL, 0, 0);
421 WCHAR fontName[MAX_STRING_LEN];
422 CHARFORMAT2W fmt;
424 ZeroMemory(&fmt, sizeof(fmt));
425 fmt.cbSize = sizeof(fmt);
427 SendMessageW(hEditorWnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
428 if (!SendMessageW(hFontListEdit, WM_GETTEXT, MAX_PATH, (LPARAM)fontName)) return;
430 if(lstrcmpW(fontName, fmt.szFaceName))
432 SendMessageW(hFontListEdit, WM_SETTEXT, 0, (LPARAM)fmt.szFaceName);
433 populate_size_list(GetDlgItem(hReBar, IDC_SIZELIST));
434 } else
436 update_size_list();
440 static void clear_formatting(void)
442 PARAFORMAT2 pf;
444 pf.cbSize = sizeof(pf);
445 pf.dwMask = PFM_ALIGNMENT;
446 pf.wAlignment = PFA_LEFT;
447 SendMessageW(hEditorWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
450 static int fileformat_number(WPARAM format)
452 int number = 0;
454 if(format == SF_TEXT)
456 number = 1;
457 } else if (format == (SF_TEXT | SF_UNICODE))
459 number = 2;
461 return number;
464 static WPARAM fileformat_flags(int format)
466 WPARAM flags[] = { SF_RTF , SF_TEXT , SF_TEXT | SF_UNICODE };
468 return flags[format];
471 static void set_font(LPCWSTR wszFaceName)
473 HWND hReBarWnd = GetDlgItem(hMainWnd, IDC_REBAR);
474 HWND hSizeListWnd = GetDlgItem(hReBarWnd, IDC_SIZELIST);
475 HWND hFontListWnd = GetDlgItem(hReBarWnd, IDC_FONTLIST);
476 HWND hFontListEditWnd = (HWND)SendMessageW(hFontListWnd, CBEM_GETEDITCONTROL, 0, 0);
477 CHARFORMAT2W fmt;
479 ZeroMemory(&fmt, sizeof(fmt));
481 fmt.cbSize = sizeof(fmt);
482 fmt.dwMask = CFM_FACE;
484 lstrcpyW(fmt.szFaceName, wszFaceName);
486 SendMessageW(hEditorWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
488 populate_size_list(hSizeListWnd);
490 SendMessageW(hFontListEditWnd, WM_SETTEXT, 0, (LPARAM)wszFaceName);
493 static void set_default_font(void)
495 static const WCHAR richTextFont[] = {'T','i','m','e','s',' ','N','e','w',' ',
496 'R','o','m','a','n',0};
497 static const WCHAR plainTextFont[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
498 CHARFORMAT2W fmt;
499 LPCWSTR font;
501 ZeroMemory(&fmt, sizeof(fmt));
503 fmt.cbSize = sizeof(fmt);
504 fmt.dwMask = CFM_FACE | CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE;
505 fmt.dwEffects = 0;
507 if(fileFormat & SF_RTF)
508 font = richTextFont;
509 else
510 font = plainTextFont;
512 lstrcpyW(fmt.szFaceName, font);
514 SendMessageW(hEditorWnd, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&fmt);
517 static void on_fontlist_modified(LPWSTR wszNewFaceName)
519 CHARFORMAT2W format;
520 ZeroMemory(&format, sizeof(format));
521 format.cbSize = sizeof(format);
522 SendMessageW(hEditorWnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&format);
524 if(lstrcmpW(format.szFaceName, wszNewFaceName))
525 set_font(wszNewFaceName);
528 static void dialog_choose_font(void)
530 CHOOSEFONTW cf;
531 LOGFONTW lf;
532 CHARFORMAT2W fmt;
533 HDC hDC = GetDC(hMainWnd);
535 ZeroMemory(&cf, sizeof(cf));
536 cf.lStructSize = sizeof(cf);
537 cf.hwndOwner = hMainWnd;
538 cf.lpLogFont = &lf;
539 cf.Flags = CF_SCREENFONTS | CF_NOSCRIPTSEL | CF_INITTOLOGFONTSTRUCT | CF_EFFECTS | CF_NOVERTFONTS;
541 ZeroMemory(&fmt, sizeof(fmt));
542 fmt.cbSize = sizeof(fmt);
544 SendMessageW(hEditorWnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
545 lstrcpyW(cf.lpLogFont->lfFaceName, fmt.szFaceName);
546 cf.lpLogFont->lfItalic = (fmt.dwEffects & CFE_ITALIC) != 0;
547 cf.lpLogFont->lfWeight = (fmt.dwEffects & CFE_BOLD) ? FW_BOLD : FW_NORMAL;
548 cf.lpLogFont->lfUnderline = (fmt.dwEffects & CFE_UNDERLINE) != 0;
549 cf.lpLogFont->lfStrikeOut = (fmt.dwEffects & CFE_STRIKEOUT) != 0;
550 cf.lpLogFont->lfHeight = -MulDiv(fmt.yHeight / 20, GetDeviceCaps(hDC, LOGPIXELSY), 72);
551 cf.rgbColors = fmt.crTextColor;
553 if(ChooseFontW(&cf))
555 ZeroMemory(&fmt, sizeof(fmt));
556 fmt.cbSize = sizeof(fmt);
557 fmt.dwMask = CFM_BOLD | CFM_ITALIC | CFM_SIZE | CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR;
558 fmt.yHeight = cf.iPointSize * 2;
560 if(cf.nFontType & BOLD_FONTTYPE)
561 fmt.dwEffects |= CFE_BOLD;
562 if(cf.nFontType & ITALIC_FONTTYPE)
563 fmt.dwEffects |= CFE_ITALIC;
564 if(cf.lpLogFont->lfUnderline)
565 fmt.dwEffects |= CFE_UNDERLINE;
566 if(cf.lpLogFont->lfStrikeOut)
567 fmt.dwEffects |= CFE_STRIKEOUT;
569 fmt.crTextColor = cf.rgbColors;
571 SendMessageW(hEditorWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
572 set_font(cf.lpLogFont->lfFaceName);
576 struct font_desc
578 WCHAR *name;
579 LPARAM lParam;
582 struct font_array
584 struct font_desc *fonts;
585 size_t count;
586 size_t capacity;
589 static BOOL array_reserve(void **elements, size_t *capacity, size_t count, size_t size)
591 size_t new_capacity, max_capacity;
592 void *new_elements;
594 if (count <= *capacity)
595 return TRUE;
597 max_capacity = ~(SIZE_T)0 / size;
598 if (count > max_capacity)
599 return FALSE;
601 new_capacity = max(4, *capacity);
602 while (new_capacity < count && new_capacity <= max_capacity / 2)
603 new_capacity *= 2;
604 if (new_capacity < count)
605 new_capacity = max_capacity;
607 new_elements = *elements ? realloc(*elements, new_capacity * size) :
608 malloc(new_capacity * size);
609 if (!new_elements)
610 return FALSE;
612 *elements = new_elements;
613 *capacity = new_capacity;
615 return TRUE;
618 static void add_font(struct font_array *fonts, LPCWSTR fontName, DWORD fontType, const NEWTEXTMETRICEXW *ntmc)
620 int fontHeight = 0;
621 size_t idx;
623 if (!array_reserve((void **)&fonts->fonts, &fonts->capacity, fonts->count + 1, sizeof(*fonts->fonts)))
624 return;
626 if (fontType & RASTER_FONTTYPE)
627 fontHeight = ntmc->ntmTm.tmHeight - ntmc->ntmTm.tmInternalLeading;
629 idx = fonts->count;
630 fonts->fonts[idx].name = wcsdup(fontName);
631 fonts->fonts[idx].lParam = MAKELONG(fontType, fontHeight);
633 fonts->count++;
636 static int CALLBACK enum_font_proc(const LOGFONTW *lpelfe, const TEXTMETRICW *lpntme,
637 DWORD FontType, LPARAM lParam)
639 struct font_array *fonts = (void *)lParam;
641 if (lpelfe->lfFaceName[0] == '@') return 1; /* ignore vertical fonts */
643 add_font(fonts, lpelfe->lfFaceName, FontType, (const NEWTEXTMETRICEXW *)lpntme);
645 return 1;
648 static int __cdecl fonts_desc_compare(const void *a, const void *b)
650 const struct font_desc *left = a, *right = b;
651 return lstrcmpiW(left->name, right->name);
654 static void populate_font_list(HWND hListWnd)
656 struct font_array font_array = { 0 };
657 HDC hdc = GetDC(hMainWnd);
658 LOGFONTW fontinfo;
659 HWND hListEditWnd = (HWND)SendMessageW(hListWnd, CBEM_GETEDITCONTROL, 0, 0);
660 CHARFORMAT2W fmt;
661 size_t i, j;
663 fontinfo.lfCharSet = DEFAULT_CHARSET;
664 *fontinfo.lfFaceName = '\0';
665 fontinfo.lfPitchAndFamily = 0;
667 /* Collect font names, sort, remove duplicates. */
668 EnumFontFamiliesExW(hdc, &fontinfo, enum_font_proc, (LPARAM)&font_array, 0);
670 qsort(font_array.fonts, font_array.count, sizeof(*font_array.fonts), fonts_desc_compare);
672 for (i = 1, j = 0; i < font_array.count; ++i)
674 if (!lstrcmpiW(font_array.fonts[i].name, font_array.fonts[j].name))
676 free(font_array.fonts[i].name);
677 font_array.fonts[i].name = NULL;
679 else if (++j != i)
681 font_array.fonts[j] = font_array.fonts[i];
682 font_array.fonts[i].name = NULL;
685 font_array.count = j + 1;
687 for (i = 0; i < font_array.count; ++i)
689 COMBOBOXEXITEMW cbitem = { 0 };
691 cbitem.mask = CBEIF_TEXT | CBEIF_LPARAM;
692 cbitem.pszText = font_array.fonts[i].name;
693 cbitem.iItem = -1;
694 cbitem.lParam = font_array.fonts[i].lParam;
696 SendMessageW(hListWnd, CBEM_INSERTITEMW, 0, (LPARAM)&cbitem);
698 free(font_array.fonts[i].name);
700 free(font_array.fonts);
702 ZeroMemory(&fmt, sizeof(fmt));
703 fmt.cbSize = sizeof(fmt);
704 SendMessageW(hEditorWnd, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&fmt);
705 SendMessageW(hListEditWnd, WM_SETTEXT, 0, (LPARAM)fmt.szFaceName);
708 static void update_window(void)
710 RECT rect;
712 GetClientRect(hMainWnd, &rect);
714 OnSize(hMainWnd, SIZE_RESTORED, MAKELPARAM(rect.right, rect.bottom));
717 static BOOL is_bar_visible(int bandId)
719 return barState[reg_formatindex(fileFormat)] & (1 << bandId);
722 static void store_bar_state(int bandId, BOOL show)
724 int formatIndex = reg_formatindex(fileFormat);
726 if(show)
727 barState[formatIndex] |= (1 << bandId);
728 else
729 barState[formatIndex] &= ~(1 << bandId);
732 static void set_toolbar_state(int bandId, BOOL show)
734 HWND hwndReBar = GetDlgItem(hMainWnd, IDC_REBAR);
736 SendMessageW(hwndReBar, RB_SHOWBAND, SendMessageW(hwndReBar, RB_IDTOINDEX, bandId, 0), show);
738 if(bandId == BANDID_TOOLBAR)
740 REBARBANDINFOW rbbinfo;
741 int index = SendMessageW(hwndReBar, RB_IDTOINDEX, BANDID_FONTLIST, 0);
743 rbbinfo.cbSize = REBARBANDINFOW_V6_SIZE;
744 rbbinfo.fMask = RBBIM_STYLE;
746 SendMessageW(hwndReBar, RB_GETBANDINFOW, index, (LPARAM)&rbbinfo);
748 if(!show)
749 rbbinfo.fStyle &= ~RBBS_BREAK;
750 else
751 rbbinfo.fStyle |= RBBS_BREAK;
753 SendMessageW(hwndReBar, RB_SETBANDINFOW, index, (LPARAM)&rbbinfo);
756 if(bandId == BANDID_TOOLBAR || bandId == BANDID_FORMATBAR || bandId == BANDID_RULER)
757 store_bar_state(bandId, show);
760 static void set_statusbar_state(BOOL show)
762 HWND hStatusWnd = GetDlgItem(hMainWnd, IDC_STATUSBAR);
764 ShowWindow(hStatusWnd, show ? SW_SHOW : SW_HIDE);
765 store_bar_state(BANDID_STATUSBAR, show);
768 static void set_bar_states(void)
770 set_toolbar_state(BANDID_TOOLBAR, is_bar_visible(BANDID_TOOLBAR));
771 set_toolbar_state(BANDID_FONTLIST, is_bar_visible(BANDID_FORMATBAR));
772 set_toolbar_state(BANDID_SIZELIST, is_bar_visible(BANDID_FORMATBAR));
773 set_toolbar_state(BANDID_FORMATBAR, is_bar_visible(BANDID_FORMATBAR));
774 set_toolbar_state(BANDID_RULER, is_bar_visible(BANDID_RULER));
775 set_statusbar_state(is_bar_visible(BANDID_STATUSBAR));
777 update_window();
780 static void preview_exit(HWND hMainWnd)
782 HMENU hMenu = LoadMenuW(GetModuleHandleW(0), MAKEINTRESOURCEW(IDM_MAINMENU));
783 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR);
785 set_bar_states();
786 ShowWindow(hEditorWnd, TRUE);
788 close_preview(hMainWnd);
790 SetMenu(hMainWnd, hMenu);
791 registry_read_filelist(hMainWnd);
793 update_window();
796 static void set_fileformat(WPARAM format)
798 fileFormat = format;
800 set_bar_states();
801 set_default_font();
802 target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
805 static void ShowOpenError(DWORD Code)
807 LPWSTR Message;
809 switch(Code)
811 case ERROR_ACCESS_DENIED:
812 Message = MAKEINTRESOURCEW(STRING_OPEN_ACCESS_DENIED);
813 break;
815 default:
816 Message = MAKEINTRESOURCEW(STRING_OPEN_FAILED);
818 MessageBoxW(hMainWnd, Message, wszAppTitle, MB_ICONEXCLAMATION | MB_OK);
821 static void DoOpenFile(LPCWSTR szOpenFileName)
823 HANDLE hFile;
824 EDITSTREAM es;
825 char fileStart[5];
826 DWORD readOut;
827 WPARAM format = SF_TEXT;
829 hFile = CreateFileW(szOpenFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
830 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
831 if (hFile == INVALID_HANDLE_VALUE)
833 ShowOpenError(GetLastError());
834 return;
837 ReadFile(hFile, fileStart, 5, &readOut, NULL);
838 SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
840 if(readOut >= 2 && (BYTE)fileStart[0] == 0xff && (BYTE)fileStart[1] == 0xfe)
842 format = SF_TEXT | SF_UNICODE;
843 SetFilePointer(hFile, 2, NULL, FILE_BEGIN);
844 } else if(readOut >= 5)
846 static const char header[] = "{\\rtf";
847 static const BYTE STG_magic[] = { 0xd0,0xcf,0x11,0xe0 };
849 if(!memcmp(header, fileStart, 5))
850 format = SF_RTF;
851 else if (!memcmp(STG_magic, fileStart, sizeof(STG_magic)))
853 CloseHandle(hFile);
854 MessageBoxWithResStringW(hMainWnd, MAKEINTRESOURCEW(STRING_OLE_STORAGE_NOT_SUPPORTED),
855 wszAppTitle, MB_OK | MB_ICONEXCLAMATION);
856 return;
860 es.dwCookie = (DWORD_PTR)hFile;
861 es.pfnCallback = stream_in;
863 clear_formatting();
864 set_fileformat(format);
865 SendMessageW(hEditorWnd, EM_STREAMIN, format, (LPARAM)&es);
867 CloseHandle(hFile);
869 SetFocus(hEditorWnd);
871 set_caption(szOpenFileName);
873 lstrcpyW(wszFileName, szOpenFileName);
874 SendMessageW(hEditorWnd, EM_SETMODIFY, FALSE, 0);
875 registry_set_filelist(szOpenFileName, hMainWnd);
876 update_font_list();
879 static void ShowWriteError(DWORD Code)
881 LPWSTR Message;
883 switch(Code)
885 case ERROR_ACCESS_DENIED:
886 Message = MAKEINTRESOURCEW(STRING_WRITE_ACCESS_DENIED);
887 break;
889 default:
890 Message = MAKEINTRESOURCEW(STRING_WRITE_FAILED);
892 MessageBoxW(hMainWnd, Message, wszAppTitle, MB_ICONEXCLAMATION | MB_OK);
895 static BOOL DoSaveFile(LPCWSTR wszSaveFileName, WPARAM format)
897 HANDLE hFile;
898 EDITSTREAM stream;
899 LRESULT ret;
901 hFile = CreateFileW(wszSaveFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
902 FILE_ATTRIBUTE_NORMAL, NULL);
904 if(hFile == INVALID_HANDLE_VALUE)
906 ShowWriteError(GetLastError());
907 return FALSE;
910 if(format == (SF_TEXT | SF_UNICODE))
912 static const BYTE unicode[] = {0xff,0xfe};
913 DWORD writeOut;
914 WriteFile(hFile, &unicode, sizeof(unicode), &writeOut, 0);
916 if(writeOut != sizeof(unicode))
918 CloseHandle(hFile);
919 return FALSE;
923 stream.dwCookie = (DWORD_PTR)hFile;
924 stream.pfnCallback = stream_out;
926 ret = SendMessageW(hEditorWnd, EM_STREAMOUT, format, (LPARAM)&stream);
928 CloseHandle(hFile);
930 SetFocus(hEditorWnd);
932 if(!ret)
934 GETTEXTLENGTHEX gt;
935 gt.flags = GTL_DEFAULT;
936 gt.codepage = 1200;
938 if(SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0))
939 return FALSE;
942 lstrcpyW(wszFileName, wszSaveFileName);
943 set_caption(wszFileName);
944 SendMessageW(hEditorWnd, EM_SETMODIFY, FALSE, 0);
945 set_fileformat(format);
947 return TRUE;
950 static BOOL DialogSaveFile(void)
952 OPENFILENAMEW sfn;
954 WCHAR wszFile[MAX_PATH] = {'\0'};
955 static const WCHAR wszDefExt[] = {'r','t','f','\0'};
957 ZeroMemory(&sfn, sizeof(sfn));
959 sfn.lStructSize = sizeof(sfn);
960 sfn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_ENABLESIZING;
961 sfn.hwndOwner = hMainWnd;
962 sfn.lpstrFilter = wszFilter;
963 sfn.lpstrFile = wszFile;
964 sfn.nMaxFile = MAX_PATH;
965 sfn.lpstrDefExt = wszDefExt;
966 sfn.nFilterIndex = fileformat_number(fileFormat)+1;
968 while(GetSaveFileNameW(&sfn))
970 if(fileformat_flags(sfn.nFilterIndex-1) != SF_RTF)
972 if(MessageBoxWithResStringW(hMainWnd, MAKEINTRESOURCEW(STRING_SAVE_LOSEFORMATTING),
973 wszAppTitle, MB_YESNO | MB_ICONEXCLAMATION) != IDYES)
974 continue;
976 return DoSaveFile(sfn.lpstrFile, fileformat_flags(sfn.nFilterIndex-1));
978 return FALSE;
981 static BOOL prompt_save_changes(void)
983 if(!wszFileName[0])
985 GETTEXTLENGTHEX gt;
986 gt.flags = GTL_NUMCHARS;
987 gt.codepage = 1200;
988 if(!SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0))
989 return TRUE;
992 if(!SendMessageW(hEditorWnd, EM_GETMODIFY, 0, 0))
994 return TRUE;
995 } else
997 LPWSTR displayFileName;
998 WCHAR *text;
999 int ret;
1001 if(!wszFileName[0])
1002 displayFileName = wszDefaultFileName;
1003 else
1004 displayFileName = file_basename(wszFileName);
1006 text = calloc(lstrlenW(displayFileName)+lstrlenW(wszSaveChanges), sizeof(WCHAR));
1008 if(!text)
1009 return FALSE;
1011 wsprintfW(text, wszSaveChanges, displayFileName);
1013 ret = MessageBoxW(hMainWnd, text, wszAppTitle, MB_YESNOCANCEL | MB_ICONEXCLAMATION);
1015 free(text);
1017 switch(ret)
1019 case IDNO:
1020 return TRUE;
1022 case IDYES:
1023 if(wszFileName[0])
1024 return DoSaveFile(wszFileName, fileFormat);
1025 return DialogSaveFile();
1027 default:
1028 return FALSE;
1033 static void DialogOpenFile(void)
1035 OPENFILENAMEW ofn;
1037 WCHAR wszFile[MAX_PATH] = {'\0'};
1038 static const WCHAR wszDefExt[] = {'r','t','f','\0'};
1040 ZeroMemory(&ofn, sizeof(ofn));
1042 ofn.lStructSize = sizeof(ofn);
1043 ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_ENABLESIZING;
1044 ofn.hwndOwner = hMainWnd;
1045 ofn.lpstrFilter = wszFilter;
1046 ofn.lpstrFile = wszFile;
1047 ofn.nMaxFile = MAX_PATH;
1048 ofn.lpstrDefExt = wszDefExt;
1049 ofn.nFilterIndex = fileformat_number(fileFormat)+1;
1051 if(GetOpenFileNameW(&ofn))
1053 if(prompt_save_changes())
1054 DoOpenFile(ofn.lpstrFile);
1058 static void dialog_about(void)
1060 HICON icon = LoadImageW(GetModuleHandleW(0), MAKEINTRESOURCEW(IDI_WORDPAD), IMAGE_ICON, 48, 48, LR_SHARED);
1061 ShellAboutW(hMainWnd, wszAppTitle, 0, icon);
1064 static INT_PTR CALLBACK formatopts_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1066 switch(message)
1068 case WM_INITDIALOG:
1070 LPPROPSHEETPAGEW ps = (LPPROPSHEETPAGEW)lParam;
1071 int wrap = -1;
1072 char id[4];
1073 HWND hIdWnd = GetDlgItem(hWnd, IDC_PAGEFMT_ID);
1075 sprintf(id, "%d\n", (int)ps->lParam);
1076 SetWindowTextA(hIdWnd, id);
1077 if(wordWrap[ps->lParam] == ID_WORDWRAP_NONE)
1078 wrap = IDC_PAGEFMT_WN;
1079 else if(wordWrap[ps->lParam] == ID_WORDWRAP_WINDOW)
1080 wrap = IDC_PAGEFMT_WW;
1081 else if(wordWrap[ps->lParam] == ID_WORDWRAP_MARGIN)
1082 wrap = IDC_PAGEFMT_WM;
1084 if(wrap != -1)
1085 CheckRadioButton(hWnd, IDC_PAGEFMT_WN,
1086 IDC_PAGEFMT_WM, wrap);
1088 if(barState[ps->lParam] & (1 << BANDID_TOOLBAR))
1089 CheckDlgButton(hWnd, IDC_PAGEFMT_TB, TRUE);
1090 if(barState[ps->lParam] & (1 << BANDID_FORMATBAR))
1091 CheckDlgButton(hWnd, IDC_PAGEFMT_FB, TRUE);
1092 if(barState[ps->lParam] & (1 << BANDID_RULER))
1093 CheckDlgButton(hWnd, IDC_PAGEFMT_RU, TRUE);
1094 if(barState[ps->lParam] & (1 << BANDID_STATUSBAR))
1095 CheckDlgButton(hWnd, IDC_PAGEFMT_SB, TRUE);
1097 break;
1099 case WM_COMMAND:
1100 switch(LOWORD(wParam))
1102 case IDC_PAGEFMT_WN:
1103 case IDC_PAGEFMT_WW:
1104 case IDC_PAGEFMT_WM:
1105 CheckRadioButton(hWnd, IDC_PAGEFMT_WN, IDC_PAGEFMT_WM,
1106 LOWORD(wParam));
1107 break;
1109 case IDC_PAGEFMT_TB:
1110 case IDC_PAGEFMT_FB:
1111 case IDC_PAGEFMT_RU:
1112 case IDC_PAGEFMT_SB:
1113 CheckDlgButton(hWnd, LOWORD(wParam),
1114 !IsDlgButtonChecked(hWnd, LOWORD(wParam)));
1115 break;
1117 break;
1118 case WM_NOTIFY:
1120 LPNMHDR header = (LPNMHDR)lParam;
1121 if(header->code == PSN_APPLY)
1123 HWND hIdWnd = GetDlgItem(hWnd, IDC_PAGEFMT_ID);
1124 char sid[4];
1125 int id;
1127 GetWindowTextA(hIdWnd, sid, 4);
1128 id = atoi(sid);
1129 if(IsDlgButtonChecked(hWnd, IDC_PAGEFMT_WN))
1130 wordWrap[id] = ID_WORDWRAP_NONE;
1131 else if(IsDlgButtonChecked(hWnd, IDC_PAGEFMT_WW))
1132 wordWrap[id] = ID_WORDWRAP_WINDOW;
1133 else if(IsDlgButtonChecked(hWnd, IDC_PAGEFMT_WM))
1134 wordWrap[id] = ID_WORDWRAP_MARGIN;
1136 if(IsDlgButtonChecked(hWnd, IDC_PAGEFMT_TB))
1137 barState[id] |= (1 << BANDID_TOOLBAR);
1138 else
1139 barState[id] &= ~(1 << BANDID_TOOLBAR);
1141 if(IsDlgButtonChecked(hWnd, IDC_PAGEFMT_FB))
1142 barState[id] |= (1 << BANDID_FORMATBAR);
1143 else
1144 barState[id] &= ~(1 << BANDID_FORMATBAR);
1146 if(IsDlgButtonChecked(hWnd, IDC_PAGEFMT_RU))
1147 barState[id] |= (1 << BANDID_RULER);
1148 else
1149 barState[id] &= ~(1 << BANDID_RULER);
1151 if(IsDlgButtonChecked(hWnd, IDC_PAGEFMT_SB))
1152 barState[id] |= (1 << BANDID_STATUSBAR);
1153 else
1154 barState[id] &= ~(1 << BANDID_STATUSBAR);
1157 break;
1159 return FALSE;
1162 static void dialog_viewproperties(void)
1164 PROPSHEETPAGEW psp[2];
1165 PROPSHEETHEADERW psh;
1166 size_t i;
1167 HINSTANCE hInstance = GetModuleHandleW(0);
1168 LPCPROPSHEETPAGEW ppsp = (LPCPROPSHEETPAGEW)&psp;
1170 psp[0].dwSize = sizeof(PROPSHEETPAGEW);
1171 psp[0].dwFlags = PSP_USETITLE;
1172 psp[0].pszTemplate = MAKEINTRESOURCEW(IDD_FORMATOPTS);
1173 psp[0].pfnDlgProc = formatopts_proc;
1174 psp[0].hInstance = hInstance;
1175 psp[0].lParam = reg_formatindex(SF_TEXT);
1176 psp[0].pfnCallback = NULL;
1177 psp[0].pszTitle = MAKEINTRESOURCEW(STRING_VIEWPROPS_TEXT);
1178 for(i = 1; i < ARRAY_SIZE(psp); i++)
1180 psp[i].dwSize = psp[0].dwSize;
1181 psp[i].dwFlags = psp[0].dwFlags;
1182 psp[i].pszTemplate = psp[0].pszTemplate;
1183 psp[i].pfnDlgProc = psp[0].pfnDlgProc;
1184 psp[i].hInstance = psp[0].hInstance;
1185 psp[i].lParam = reg_formatindex(SF_RTF);
1186 psp[i].pfnCallback = psp[0].pfnCallback;
1187 psp[i].pszTitle = MAKEINTRESOURCEW(STRING_VIEWPROPS_RICHTEXT);
1190 psh.dwSize = sizeof(psh);
1191 psh.dwFlags = PSH_USEICONID | PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW;
1192 psh.hwndParent = hMainWnd;
1193 psh.hInstance = hInstance;
1194 psh.pszCaption = MAKEINTRESOURCEW(STRING_VIEWPROPS_TITLE);
1195 psh.nPages = ARRAY_SIZE(psp);
1196 psh.ppsp = ppsp;
1197 psh.pszIcon = MAKEINTRESOURCEW(IDI_WORDPAD);
1199 if(fileFormat & SF_RTF)
1200 psh.nStartPage = 1;
1201 else
1202 psh.nStartPage = 0;
1203 PropertySheetW(&psh);
1204 set_bar_states();
1205 target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
1208 static void HandleCommandLine(LPWSTR cmdline)
1210 WCHAR delimiter;
1211 BOOL opt_print = FALSE;
1213 /* skip white space */
1214 while (*cmdline == ' ') cmdline++;
1216 /* skip executable name */
1217 delimiter = (*cmdline == '"' ? '"' : ' ');
1219 if (*cmdline == delimiter) cmdline++;
1220 while (*cmdline && *cmdline != delimiter) cmdline++;
1221 if (*cmdline == delimiter) cmdline++;
1223 while (*cmdline)
1225 while (*cmdline == ' ' || *cmdline == '\t') cmdline++;
1227 if (*cmdline == '-' || *cmdline == '/')
1229 if (!cmdline[2] || isspace(cmdline[2]))
1231 switch (cmdline[1])
1233 case 'P':
1234 case 'p':
1235 opt_print = TRUE;
1236 cmdline += 2;
1237 continue;
1240 /* a filename starting by / */
1242 break;
1245 if (*cmdline)
1247 /* file name is passed on the command line */
1248 if (cmdline[0] == '"')
1250 cmdline++;
1251 cmdline[lstrlenW(cmdline) - 1] = 0;
1253 DoOpenFile(cmdline);
1254 InvalidateRect(hMainWnd, NULL, FALSE);
1257 if (opt_print)
1258 MessageBoxWithResStringW(hMainWnd, MAKEINTRESOURCEW(STRING_PRINTING_NOT_IMPLEMENTED), wszAppTitle, MB_OK);
1261 static LRESULT handle_findmsg(LPFINDREPLACEW pFr)
1263 if(pFr->Flags & FR_DIALOGTERM)
1265 hFindWnd = 0;
1266 pFr->Flags = FR_FINDNEXT;
1267 return 0;
1270 if(pFr->Flags & FR_FINDNEXT || pFr->Flags & FR_REPLACE || pFr->Flags & FR_REPLACEALL)
1272 FINDREPLACE_custom *custom_data = (FINDREPLACE_custom*)pFr->lCustData;
1273 DWORD flags;
1274 FINDTEXTEXW ft;
1275 CHARRANGE sel;
1276 LRESULT ret = -1;
1277 HMENU hMenu = GetMenu(hMainWnd);
1278 MENUITEMINFOW mi;
1280 mi.cbSize = sizeof(mi);
1281 mi.fMask = MIIM_DATA;
1282 mi.dwItemData = 1;
1283 SetMenuItemInfoW(hMenu, ID_FIND_NEXT, FALSE, &mi);
1285 /* Make sure find field is saved. */
1286 if (pFr->lpstrFindWhat != custom_data->findBuffer)
1288 lstrcpynW(custom_data->findBuffer, pFr->lpstrFindWhat,
1289 ARRAY_SIZE(custom_data->findBuffer));
1290 pFr->lpstrFindWhat = custom_data->findBuffer;
1293 SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&sel.cpMin, (LPARAM)&sel.cpMax);
1294 if(custom_data->endPos == -1) {
1295 custom_data->endPos = sel.cpMin;
1296 custom_data->wrapped = FALSE;
1299 flags = FR_DOWN | (pFr->Flags & (FR_MATCHCASE | FR_WHOLEWORD));
1300 ft.lpstrText = pFr->lpstrFindWhat;
1302 /* Only replace the existing selection if it is an exact match. */
1303 if (sel.cpMin != sel.cpMax &&
1304 (pFr->Flags & FR_REPLACE || pFr->Flags & FR_REPLACEALL))
1306 ft.chrg = sel;
1307 SendMessageW(hEditorWnd, EM_FINDTEXTEXW, flags, (LPARAM)&ft);
1308 if (ft.chrgText.cpMin == sel.cpMin && ft.chrgText.cpMax == sel.cpMax) {
1309 SendMessageW(hEditorWnd, EM_REPLACESEL, TRUE, (LPARAM)pFr->lpstrReplaceWith);
1310 SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&sel.cpMin, (LPARAM)&sel.cpMax);
1314 /* Search from the start of the selection, but exclude the first character
1315 * from search if there is a selection. */
1316 ft.chrg.cpMin = sel.cpMin;
1317 if (sel.cpMin != sel.cpMax)
1318 ft.chrg.cpMin++;
1320 /* Search to the end, then wrap around and search from the start. */
1321 if (!custom_data->wrapped) {
1322 ft.chrg.cpMax = -1;
1323 ret = SendMessageW(hEditorWnd, EM_FINDTEXTEXW, flags, (LPARAM)&ft);
1324 if (ret == -1) {
1325 custom_data->wrapped = TRUE;
1326 ft.chrg.cpMin = 0;
1330 if (ret == -1) {
1331 ft.chrg.cpMax = custom_data->endPos + lstrlenW(pFr->lpstrFindWhat) - 1;
1332 if (ft.chrg.cpMax > ft.chrg.cpMin)
1333 ret = SendMessageW(hEditorWnd, EM_FINDTEXTEXW, flags, (LPARAM)&ft);
1336 if (ret == -1) {
1337 custom_data->endPos = -1;
1338 EnableWindow(hMainWnd, FALSE);
1339 MessageBoxWithResStringW(hFindWnd, MAKEINTRESOURCEW(STRING_SEARCH_FINISHED),
1340 wszAppTitle, MB_OK | MB_ICONASTERISK | MB_TASKMODAL);
1341 EnableWindow(hMainWnd, TRUE);
1342 } else {
1343 SendMessageW(hEditorWnd, EM_SETSEL, ft.chrgText.cpMin, ft.chrgText.cpMax);
1344 SendMessageW(hEditorWnd, EM_SCROLLCARET, 0, 0);
1346 if (pFr->Flags & FR_REPLACEALL)
1347 return handle_findmsg(pFr);
1351 return 0;
1354 static void dialog_find(LPFINDREPLACEW fr, BOOL replace)
1356 static WCHAR selBuffer[128];
1357 static WCHAR replaceBuffer[128];
1358 static FINDREPLACE_custom custom_data;
1359 static const WCHAR endl = '\r';
1360 FINDTEXTW ft;
1362 /* Allow only one search/replace dialog to open */
1363 if(hFindWnd != NULL)
1365 SetActiveWindow(hFindWnd);
1366 return;
1369 ZeroMemory(fr, sizeof(FINDREPLACEW));
1370 fr->lStructSize = sizeof(FINDREPLACEW);
1371 fr->hwndOwner = hMainWnd;
1372 fr->Flags = FR_HIDEUPDOWN;
1373 /* Find field is filled with the selected text if it is non-empty
1374 * and stays within the same paragraph, otherwise the previous
1375 * find field is used. */
1376 SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&ft.chrg.cpMin,
1377 (LPARAM)&ft.chrg.cpMax);
1378 ft.lpstrText = &endl;
1379 if (ft.chrg.cpMin != ft.chrg.cpMax &&
1380 SendMessageW(hEditorWnd, EM_FINDTEXTW, FR_DOWN, (LPARAM)&ft) == -1)
1382 /* Use a temporary buffer for the selected text so that the saved
1383 * find field is only overwritten when a find/replace is clicked. */
1384 GETTEXTEX gt = {sizeof(selBuffer), GT_SELECTION, 1200, NULL, NULL};
1385 SendMessageW(hEditorWnd, EM_GETTEXTEX, (WPARAM)&gt, (LPARAM)selBuffer);
1386 fr->lpstrFindWhat = selBuffer;
1387 } else {
1388 fr->lpstrFindWhat = custom_data.findBuffer;
1390 fr->lpstrReplaceWith = replaceBuffer;
1391 custom_data.endPos = -1;
1392 custom_data.wrapped = FALSE;
1393 fr->lCustData = (LPARAM)&custom_data;
1394 fr->wFindWhatLen = sizeof(custom_data.findBuffer);
1395 fr->wReplaceWithLen = sizeof(replaceBuffer);
1397 if(replace)
1398 hFindWnd = ReplaceTextW(fr);
1399 else
1400 hFindWnd = FindTextW(fr);
1403 static int units_to_twips(UNIT unit, float number)
1405 int twips = 0;
1407 switch(unit)
1409 case UNIT_CM:
1410 twips = (int)(number * 1000.0 / (float)CENTMM_PER_INCH * (float)TWIPS_PER_INCH);
1411 break;
1413 case UNIT_INCH:
1414 twips = (int)(number * (float)TWIPS_PER_INCH);
1415 break;
1417 case UNIT_PT:
1418 twips = (int)(number * (0.0138 * (float)TWIPS_PER_INCH));
1419 break;
1422 return twips;
1425 static void append_current_units(LPWSTR buffer)
1427 static const WCHAR space[] = {' ', 0};
1428 lstrcatW(buffer, space);
1429 lstrcatW(buffer, units_cmW);
1432 static void number_with_units(LPWSTR buffer, int number)
1434 static const WCHAR fmt[] = {'%','.','2','f',' ','%','s','\0'};
1435 float converted = (float)number / (float)TWIPS_PER_INCH *(float)CENTMM_PER_INCH / 1000.0;
1437 swprintf(buffer, MAX_STRING_LEN, fmt, converted, units_cmW);
1440 static BOOL get_comboexlist_selection(HWND hComboEx, LPWSTR wszBuffer, UINT bufferLength)
1442 COMBOBOXEXITEMW cbItem;
1443 COMBOBOXINFO cbInfo;
1444 HWND hCombo, hList;
1445 int idx, result;
1447 hCombo = (HWND)SendMessageW(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0);
1448 if (!hCombo)
1449 return FALSE;
1450 cbInfo.cbSize = sizeof(COMBOBOXINFO);
1451 result = SendMessageW(hCombo, CB_GETCOMBOBOXINFO, 0, (LPARAM)&cbInfo);
1452 if (!result)
1453 return FALSE;
1454 hList = cbInfo.hwndList;
1455 idx = SendMessageW(hList, LB_GETCURSEL, 0, 0);
1456 if (idx < 0)
1457 return FALSE;
1459 ZeroMemory(&cbItem, sizeof(cbItem));
1460 cbItem.mask = CBEIF_TEXT;
1461 cbItem.iItem = idx;
1462 cbItem.pszText = wszBuffer;
1463 cbItem.cchTextMax = bufferLength-1;
1464 result = SendMessageW(hComboEx, CBEM_GETITEMW, 0, (LPARAM)&cbItem);
1466 return result != 0;
1469 static INT_PTR CALLBACK datetime_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1471 switch(message)
1473 case WM_INITDIALOG:
1475 WCHAR buffer[MAX_STRING_LEN];
1476 SYSTEMTIME st;
1477 HWND hListWnd = GetDlgItem(hWnd, IDC_DATETIME);
1478 GetLocalTime(&st);
1480 GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, 0, (LPWSTR)&buffer,
1481 MAX_STRING_LEN);
1482 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1483 GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, 0, (LPWSTR)&buffer,
1484 MAX_STRING_LEN);
1485 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1486 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, 0, (LPWSTR)&buffer, MAX_STRING_LEN);
1487 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1489 SendMessageW(hListWnd, LB_SETSEL, TRUE, 0);
1491 break;
1493 case WM_COMMAND:
1494 switch(LOWORD(wParam))
1496 case IDC_DATETIME:
1497 if (HIWORD(wParam) != LBN_DBLCLK)
1498 break;
1499 /* Fall through */
1501 case IDOK:
1503 LRESULT index;
1504 HWND hListWnd = GetDlgItem(hWnd, IDC_DATETIME);
1506 index = SendMessageW(hListWnd, LB_GETCURSEL, 0, 0);
1508 if(index != LB_ERR)
1510 WCHAR buffer[MAX_STRING_LEN];
1511 SendMessageW(hListWnd, LB_GETTEXT, index, (LPARAM)&buffer);
1512 SendMessageW(hEditorWnd, EM_REPLACESEL, TRUE, (LPARAM)&buffer);
1515 /* Fall through */
1517 case IDCANCEL:
1518 EndDialog(hWnd, wParam);
1519 return TRUE;
1522 return FALSE;
1525 static INT_PTR CALLBACK newfile_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1527 switch(message)
1529 case WM_INITDIALOG:
1531 HINSTANCE hInstance = GetModuleHandleW(0);
1532 WCHAR buffer[MAX_STRING_LEN];
1533 HWND hListWnd = GetDlgItem(hWnd, IDC_NEWFILE);
1535 LoadStringW(hInstance, STRING_NEWFILE_RICHTEXT, buffer, MAX_STRING_LEN);
1536 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1537 LoadStringW(hInstance, STRING_NEWFILE_TXT, buffer, MAX_STRING_LEN);
1538 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1539 LoadStringW(hInstance, STRING_NEWFILE_TXT_UNICODE, buffer, MAX_STRING_LEN);
1540 SendMessageW(hListWnd, LB_ADDSTRING, 0, (LPARAM)&buffer);
1542 SendMessageW(hListWnd, LB_SETSEL, TRUE, 0);
1544 break;
1546 case WM_COMMAND:
1547 switch(LOWORD(wParam))
1549 case IDOK:
1551 LRESULT index;
1552 HWND hListWnd = GetDlgItem(hWnd, IDC_NEWFILE);
1553 index = SendMessageW(hListWnd, LB_GETCURSEL, 0, 0);
1555 if(index != LB_ERR)
1556 EndDialog(hWnd, MAKELONG(fileformat_flags(index),0));
1558 return TRUE;
1560 case IDCANCEL:
1561 EndDialog(hWnd, MAKELONG(ID_NEWFILE_ABORT,0));
1562 return TRUE;
1565 return FALSE;
1568 static INT_PTR CALLBACK paraformat_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1570 static const WORD ALIGNMENT_VALUES[] = {PFA_LEFT, PFA_RIGHT, PFA_CENTER};
1572 switch(message)
1574 case WM_INITDIALOG:
1576 HINSTANCE hInstance = GetModuleHandleW(0);
1577 WCHAR buffer[MAX_STRING_LEN];
1578 HWND hListWnd = GetDlgItem(hWnd, IDC_PARA_ALIGN);
1579 HWND hLeftWnd = GetDlgItem(hWnd, IDC_PARA_LEFT);
1580 HWND hRightWnd = GetDlgItem(hWnd, IDC_PARA_RIGHT);
1581 HWND hFirstWnd = GetDlgItem(hWnd, IDC_PARA_FIRST);
1582 PARAFORMAT2 pf;
1583 int index = 0;
1585 LoadStringW(hInstance, STRING_ALIGN_LEFT, buffer,
1586 MAX_STRING_LEN);
1587 SendMessageW(hListWnd, CB_ADDSTRING, 0, (LPARAM)buffer);
1588 LoadStringW(hInstance, STRING_ALIGN_RIGHT, buffer,
1589 MAX_STRING_LEN);
1590 SendMessageW(hListWnd, CB_ADDSTRING, 0, (LPARAM)buffer);
1591 LoadStringW(hInstance, STRING_ALIGN_CENTER, buffer,
1592 MAX_STRING_LEN);
1593 SendMessageW(hListWnd, CB_ADDSTRING, 0, (LPARAM)buffer);
1595 pf.cbSize = sizeof(pf);
1596 pf.dwMask = PFM_ALIGNMENT | PFM_OFFSET | PFM_RIGHTINDENT |
1597 PFM_STARTINDENT;
1598 SendMessageW(hEditorWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
1600 if(pf.wAlignment == PFA_RIGHT)
1601 index ++;
1602 else if(pf.wAlignment == PFA_CENTER)
1603 index += 2;
1605 SendMessageW(hListWnd, CB_SETCURSEL, index, 0);
1607 number_with_units(buffer, pf.dxStartIndent + pf.dxOffset);
1608 SetWindowTextW(hLeftWnd, buffer);
1609 number_with_units(buffer, pf.dxRightIndent);
1610 SetWindowTextW(hRightWnd, buffer);
1611 number_with_units(buffer, -pf.dxOffset);
1612 SetWindowTextW(hFirstWnd, buffer);
1614 break;
1616 case WM_COMMAND:
1617 switch(LOWORD(wParam))
1619 case IDOK:
1621 HWND hListWnd = GetDlgItem(hWnd, IDC_PARA_ALIGN);
1622 HWND hLeftWnd = GetDlgItem(hWnd, IDC_PARA_LEFT);
1623 HWND hRightWnd = GetDlgItem(hWnd, IDC_PARA_RIGHT);
1624 HWND hFirstWnd = GetDlgItem(hWnd, IDC_PARA_FIRST);
1625 WCHAR buffer[MAX_STRING_LEN];
1626 int index;
1627 float num;
1628 int ret = 0;
1629 PARAFORMAT2 pf;
1630 UNIT unit;
1631 BOOL in_list = FALSE;
1633 pf.cbSize = sizeof(pf);
1634 pf.dwMask = PFM_NUMBERING;
1635 SendMessageW(hEditorWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
1636 if ((pf.dwMask & PFM_NUMBERING) && pf.wNumbering)
1637 in_list = TRUE;
1639 index = SendMessageW(hListWnd, CB_GETCURSEL, 0, 0);
1640 pf.wAlignment = ALIGNMENT_VALUES[index];
1642 GetWindowTextW(hLeftWnd, buffer, MAX_STRING_LEN);
1643 if(number_from_string(buffer, &num, &unit))
1644 ret++;
1645 pf.dxOffset = units_to_twips(unit, num);
1646 GetWindowTextW(hRightWnd, buffer, MAX_STRING_LEN);
1647 if(number_from_string(buffer, &num, &unit))
1648 ret++;
1649 pf.dxRightIndent = units_to_twips(unit, num);
1650 GetWindowTextW(hFirstWnd, buffer, MAX_STRING_LEN);
1651 if(number_from_string(buffer, &num, &unit))
1652 ret++;
1653 pf.dxStartIndent = units_to_twips(unit, num);
1655 if(ret != 3)
1657 MessageBoxWithResStringW(hMainWnd, MAKEINTRESOURCEW(STRING_INVALID_NUMBER),
1658 wszAppTitle, MB_OK | MB_ICONASTERISK);
1659 return FALSE;
1660 } else
1662 if (pf.dxOffset + pf.dxStartIndent < 0
1663 && pf.dxStartIndent < 0)
1665 /* The first line is before the left edge, so
1666 * make sure it is at the left edge. */
1667 pf.dxOffset = -pf.dxStartIndent;
1668 } else if (pf.dxOffset < 0) {
1669 /* The second and following lines are before
1670 * the left edge, so set it to be at the left
1671 * edge, and adjust the first line since it
1672 * is relative to it. */
1673 pf.dxStartIndent = max(pf.dxStartIndent + pf.dxOffset, 0);
1674 pf.dxOffset = 0;
1676 /* Internally the dxStartIndent is the absolute
1677 * offset for the first line and dxOffset is
1678 * to it value as opposed how it is displayed with
1679 * the first line being the relative value.
1680 * These two lines make the adjustments. */
1681 pf.dxStartIndent = pf.dxStartIndent + pf.dxOffset;
1682 pf.dxOffset = pf.dxOffset - pf.dxStartIndent;
1684 pf.cbSize = sizeof(pf);
1685 pf.dwMask = PFM_ALIGNMENT | PFM_OFFSET | PFM_RIGHTINDENT |
1686 PFM_STARTINDENT;
1687 if (in_list)
1689 pf.wNumberingTab = max(pf.dxOffset, 0);
1690 pf.dwMask |= PFM_NUMBERINGTAB;
1693 SendMessageW(hEditorWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
1696 /* Fall through */
1698 case IDCANCEL:
1699 EndDialog(hWnd, wParam);
1700 return TRUE;
1703 return FALSE;
1706 static INT_PTR CALLBACK tabstops_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1708 switch(message)
1710 case WM_INITDIALOG:
1712 HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1713 PARAFORMAT pf;
1714 WCHAR buffer[MAX_STRING_LEN];
1715 int i;
1717 pf.cbSize = sizeof(pf);
1718 pf.dwMask = PFM_TABSTOPS;
1719 SendMessageW(hEditorWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
1720 SendMessageW(hTabWnd, CB_LIMITTEXT, MAX_STRING_LEN-1, 0);
1722 for(i = 0; i < pf.cTabCount; i++)
1724 number_with_units(buffer, pf.rgxTabs[i]);
1725 SendMessageW(hTabWnd, CB_ADDSTRING, 0, (LPARAM)&buffer);
1727 SetFocus(hTabWnd);
1729 break;
1731 case WM_COMMAND:
1732 switch(LOWORD(wParam))
1734 case IDC_TABSTOPS:
1736 HWND hTabWnd = (HWND)lParam;
1737 HWND hAddWnd = GetDlgItem(hWnd, ID_TAB_ADD);
1738 HWND hDelWnd = GetDlgItem(hWnd, ID_TAB_DEL);
1739 HWND hEmptyWnd = GetDlgItem(hWnd, ID_TAB_EMPTY);
1741 if(GetWindowTextLengthW(hTabWnd))
1742 EnableWindow(hAddWnd, TRUE);
1743 else
1744 EnableWindow(hAddWnd, FALSE);
1746 if(SendMessageW(hTabWnd, CB_GETCOUNT, 0, 0))
1748 EnableWindow(hEmptyWnd, TRUE);
1750 if(SendMessageW(hTabWnd, CB_GETCURSEL, 0, 0) == CB_ERR)
1751 EnableWindow(hDelWnd, FALSE);
1752 else
1753 EnableWindow(hDelWnd, TRUE);
1754 } else
1756 EnableWindow(hEmptyWnd, FALSE);
1759 break;
1761 case ID_TAB_ADD:
1763 HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1764 WCHAR buffer[MAX_STRING_LEN];
1765 UNIT unit;
1767 GetWindowTextW(hTabWnd, buffer, MAX_STRING_LEN);
1768 append_current_units(buffer);
1770 if(SendMessageW(hTabWnd, CB_FINDSTRINGEXACT, -1, (LPARAM)&buffer) == CB_ERR)
1772 float number = 0;
1773 int item_count = SendMessageW(hTabWnd, CB_GETCOUNT, 0, 0);
1775 if(!number_from_string(buffer, &number, &unit))
1777 MessageBoxWithResStringW(hWnd, MAKEINTRESOURCEW(STRING_INVALID_NUMBER),
1778 wszAppTitle, MB_OK | MB_ICONINFORMATION);
1779 } else if (item_count >= MAX_TAB_STOPS) {
1780 MessageBoxWithResStringW(hWnd, MAKEINTRESOURCEW(STRING_MAX_TAB_STOPS),
1781 wszAppTitle, MB_OK | MB_ICONINFORMATION);
1782 } else {
1783 int i;
1784 float next_number = -1;
1785 int next_number_in_twips = -1;
1786 int insert_number = units_to_twips(unit, number);
1788 /* linear search for position to insert the string */
1789 for(i = 0; i < item_count; i++)
1791 SendMessageW(hTabWnd, CB_GETLBTEXT, i, (LPARAM)&buffer);
1792 number_from_string(buffer, &next_number, &unit);
1793 next_number_in_twips = units_to_twips(unit, next_number);
1794 if (insert_number <= next_number_in_twips)
1795 break;
1797 if (insert_number != next_number_in_twips)
1799 number_with_units(buffer, insert_number);
1800 SendMessageW(hTabWnd, CB_INSERTSTRING, i, (LPARAM)&buffer);
1801 SetWindowTextW(hTabWnd, 0);
1805 SetFocus(hTabWnd);
1807 break;
1809 case ID_TAB_DEL:
1811 HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1812 LRESULT ret;
1813 ret = SendMessageW(hTabWnd, CB_GETCURSEL, 0, 0);
1814 if(ret != CB_ERR)
1815 SendMessageW(hTabWnd, CB_DELETESTRING, ret, 0);
1817 break;
1819 case ID_TAB_EMPTY:
1821 HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1822 SendMessageW(hTabWnd, CB_RESETCONTENT, 0, 0);
1823 SetFocus(hTabWnd);
1825 break;
1827 case IDOK:
1829 HWND hTabWnd = GetDlgItem(hWnd, IDC_TABSTOPS);
1830 int i;
1831 WCHAR buffer[MAX_STRING_LEN];
1832 PARAFORMAT pf;
1833 float number;
1834 UNIT unit;
1836 pf.cbSize = sizeof(pf);
1837 pf.dwMask = PFM_TABSTOPS;
1839 for(i = 0; SendMessageW(hTabWnd, CB_GETLBTEXT, i,
1840 (LPARAM)&buffer) != CB_ERR &&
1841 i < MAX_TAB_STOPS; i++)
1843 number_from_string(buffer, &number, &unit);
1844 pf.rgxTabs[i] = units_to_twips(unit, number);
1846 pf.cTabCount = i;
1847 SendMessageW(hEditorWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
1849 /* Fall through */
1850 case IDCANCEL:
1851 EndDialog(hWnd, wParam);
1852 return TRUE;
1855 return FALSE;
1858 static LRESULT OnCreate( HWND hWnd )
1860 HWND hToolBarWnd, hFormatBarWnd, hReBarWnd, hFontListWnd, hSizeListWnd, hRulerWnd;
1861 HINSTANCE hInstance = GetModuleHandleW(0);
1862 HANDLE hDLL;
1863 TBADDBITMAP ab;
1864 int nStdBitmaps = 0;
1865 REBARINFO rbi;
1866 REBARBANDINFOW rbb;
1867 RECT rect;
1868 HFONT font;
1869 HDC hdc;
1870 SIZE name_sz, size_sz;
1871 int height, dpi;
1872 static const WCHAR wszRichEditDll[] = {'R','I','C','H','E','D','2','0','.','D','L','L','\0'};
1873 static const WCHAR wszRichEditText[] = {'R','i','c','h','E','d','i','t',' ','t','e','x','t','\0'};
1874 static const WCHAR font_text[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0}; /* a long font name */
1875 static const WCHAR size_text[] = {' ','0','0',0}; /* enough for two digits */
1877 CreateStatusWindowW(CCS_NODIVIDER|WS_CHILD|WS_VISIBLE, wszRichEditText, hWnd, IDC_STATUSBAR);
1879 hReBarWnd = CreateWindowExW(WS_EX_TOOLWINDOW, REBARCLASSNAMEW, NULL,
1880 CCS_NODIVIDER|WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|RBS_VARHEIGHT|CCS_TOP,
1881 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hWnd, (HMENU)IDC_REBAR, hInstance, NULL);
1883 rbi.cbSize = sizeof(rbi);
1884 rbi.fMask = 0;
1885 rbi.himl = NULL;
1886 if(!SendMessageW(hReBarWnd, RB_SETBARINFO, 0, (LPARAM)&rbi))
1887 return -1;
1889 hToolBarWnd = CreateToolbarEx(hReBarWnd, CCS_NOPARENTALIGN|CCS_NOMOVEY|WS_VISIBLE|WS_CHILD|TBSTYLE_TOOLTIPS,
1890 IDC_TOOLBAR,
1891 1, hInstance, IDB_TOOLBAR,
1892 NULL, 0,
1893 24, 24, 16, 16, sizeof(TBBUTTON));
1895 hdc = GetDC(hWnd);
1896 dpi = GetDeviceCaps(hdc, LOGPIXELSY);
1897 ReleaseDC(hWnd, hdc);
1899 ab.hInst = HINST_COMMCTRL;
1900 ab.nID = dpi >= 120 ? IDB_STD_LARGE_COLOR : IDB_STD_SMALL_COLOR;
1901 nStdBitmaps = SendMessageW(hToolBarWnd, TB_ADDBITMAP, 0, (LPARAM)&ab);
1903 AddButton(hToolBarWnd, nStdBitmaps+STD_FILENEW, ID_FILE_NEW);
1904 AddButton(hToolBarWnd, nStdBitmaps+STD_FILEOPEN, ID_FILE_OPEN);
1905 AddButton(hToolBarWnd, nStdBitmaps+STD_FILESAVE, ID_FILE_SAVE);
1906 AddSeparator(hToolBarWnd);
1907 AddButton(hToolBarWnd, nStdBitmaps+STD_PRINT, ID_PRINT_QUICK);
1908 AddButton(hToolBarWnd, nStdBitmaps+STD_PRINTPRE, ID_PREVIEW);
1909 AddSeparator(hToolBarWnd);
1910 AddButton(hToolBarWnd, nStdBitmaps+STD_FIND, ID_FIND);
1911 AddSeparator(hToolBarWnd);
1912 AddButton(hToolBarWnd, nStdBitmaps+STD_CUT, ID_EDIT_CUT);
1913 AddButton(hToolBarWnd, nStdBitmaps+STD_COPY, ID_EDIT_COPY);
1914 AddButton(hToolBarWnd, nStdBitmaps+STD_PASTE, ID_EDIT_PASTE);
1915 AddButton(hToolBarWnd, nStdBitmaps+STD_UNDO, ID_EDIT_UNDO);
1916 AddButton(hToolBarWnd, nStdBitmaps+STD_REDOW, ID_EDIT_REDO);
1917 AddSeparator(hToolBarWnd);
1918 AddButton(hToolBarWnd, 0, ID_DATETIME);
1920 SendMessageW(hToolBarWnd, TB_AUTOSIZE, 0, 0);
1921 height = HIWORD(SendMessageW(hToolBarWnd, TB_GETBUTTONSIZE, 0, 0));
1923 hFontListWnd = CreateWindowExW(0, WC_COMBOBOXEXW, NULL,
1924 WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN | CBS_SORT,
1925 0, 0, 200, 150, hReBarWnd, (HMENU)IDC_FONTLIST, hInstance, NULL);
1926 GetWindowRect(hFontListWnd, &rect);
1927 height = max(height, rect.bottom - rect.top);
1929 SendMessageW(hToolBarWnd, TB_SETBUTTONSIZE, 0, MAKELPARAM(height, height));
1931 rbb.cbSize = REBARBANDINFOW_V6_SIZE;
1932 rbb.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD | RBBIM_STYLE | RBBIM_ID;
1933 rbb.fStyle = RBBS_CHILDEDGE | RBBS_BREAK | RBBS_NOGRIPPER;
1934 rbb.cx = 0;
1935 rbb.hwndChild = hToolBarWnd;
1936 rbb.cxMinChild = 0;
1937 rbb.cyChild = rbb.cyMinChild = height;
1938 rbb.wID = BANDID_TOOLBAR;
1940 SendMessageW(hReBarWnd, RB_INSERTBANDW, -1, (LPARAM)&rbb);
1942 font = (HFONT)SendMessageW(hFontListWnd, WM_GETFONT, 0, 0);
1943 hdc = GetDC(hFontListWnd);
1944 font = SelectObject(hdc, font);
1945 GetTextExtentPointW(hdc, font_text, ARRAY_SIZE(font_text) - 1, &name_sz);
1946 GetTextExtentPointW(hdc, size_text, ARRAY_SIZE(size_text) - 1, &size_sz);
1947 font = SelectObject(hdc, font);
1948 ReleaseDC(hFontListWnd, hdc);
1949 rbb.hwndChild = hFontListWnd;
1950 rbb.cx = MulDiv(name_sz.cx, 3, 2) + height; /* height is space for the dropdown arrow */
1951 rbb.wID = BANDID_FONTLIST;
1953 SendMessageW(hReBarWnd, RB_INSERTBANDW, -1, (LPARAM)&rbb);
1955 hSizeListWnd = CreateWindowExW(0, WC_COMBOBOXEXW, NULL,
1956 WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN,
1957 0, 0, 50, 150, hReBarWnd, (HMENU)IDC_SIZELIST, hInstance, NULL);
1959 rbb.hwndChild = hSizeListWnd;
1960 rbb.cx = MulDiv(size_sz.cx, 3, 2) + height; /* height is space for the dropdown arrow */
1961 rbb.fStyle ^= RBBS_BREAK;
1962 rbb.wID = BANDID_SIZELIST;
1964 SendMessageW(hReBarWnd, RB_INSERTBANDW, -1, (LPARAM)&rbb);
1966 hFormatBarWnd = CreateToolbarEx(hReBarWnd,
1967 CCS_NOPARENTALIGN | CCS_NOMOVEY | WS_VISIBLE | TBSTYLE_TOOLTIPS,
1968 IDC_FORMATBAR, 8, hInstance, IDB_FORMATBAR, NULL, 0, 16, 16, 16, 16, sizeof(TBBUTTON));
1970 SendMessageW(hFormatBarWnd, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS);
1971 SendMessageW(hFormatBarWnd, TB_SETBUTTONSIZE, 0, MAKELPARAM(height, height));
1973 AddButton(hFormatBarWnd, 0, ID_FORMAT_BOLD);
1974 AddButton(hFormatBarWnd, 1, ID_FORMAT_ITALIC);
1975 AddButton(hFormatBarWnd, 2, ID_FORMAT_UNDERLINE);
1976 AddButton(hFormatBarWnd, 3, ID_FORMAT_COLOR);
1977 AddSeparator(hFormatBarWnd);
1978 AddButton(hFormatBarWnd, 4, ID_ALIGN_LEFT);
1979 AddButton(hFormatBarWnd, 5, ID_ALIGN_CENTER);
1980 AddButton(hFormatBarWnd, 6, ID_ALIGN_RIGHT);
1981 AddSeparator(hFormatBarWnd);
1982 AddButtonStyle(hFormatBarWnd, 7, ID_BULLETONOFF, BTNS_DROPDOWN);
1984 SendMessageW(hFormatBarWnd, TB_AUTOSIZE, 0, 0);
1986 rbb.hwndChild = hFormatBarWnd;
1987 rbb.wID = BANDID_FORMATBAR;
1989 SendMessageW(hReBarWnd, RB_INSERTBANDW, -1, (LPARAM)&rbb);
1991 hRulerWnd = CreateWindowExW(0, WC_STATICW, NULL, WS_VISIBLE | WS_CHILD,
1992 0, 0, 200, 10, hReBarWnd, (HMENU)IDC_RULER, hInstance, NULL);
1995 rbb.hwndChild = hRulerWnd;
1996 rbb.wID = BANDID_RULER;
1997 rbb.fStyle |= RBBS_BREAK;
1999 SendMessageW(hReBarWnd, RB_INSERTBANDW, -1, (LPARAM)&rbb);
2001 hDLL = LoadLibraryW(wszRichEditDll);
2002 if(!hDLL)
2004 MessageBoxWithResStringW(hWnd, MAKEINTRESOURCEW(STRING_LOAD_RICHED_FAILED), wszAppTitle,
2005 MB_OK | MB_ICONEXCLAMATION);
2006 PostQuitMessage(1);
2009 hEditorWnd = CreateWindowExW(WS_EX_CLIENTEDGE, RICHEDIT_CLASS20W, NULL,
2010 WS_CHILD|WS_VISIBLE|ES_SELECTIONBAR|ES_MULTILINE|ES_AUTOVSCROLL
2011 |ES_WANTRETURN|WS_VSCROLL|ES_NOHIDESEL|WS_HSCROLL,
2012 0, 0, 1000, 100, hWnd, (HMENU)IDC_EDITOR, hInstance, NULL);
2014 if (!hEditorWnd) return -1;
2016 setup_richedit_olecallback(hEditorWnd);
2017 SetFocus(hEditorWnd);
2018 SendMessageW(hEditorWnd, EM_SETEVENTMASK, 0, ENM_SELCHANGE);
2020 set_default_font();
2022 populate_font_list(hFontListWnd);
2023 populate_size_list(hSizeListWnd);
2024 DoLoadStrings();
2025 SendMessageW(hEditorWnd, EM_SETMODIFY, FALSE, 0);
2027 ID_FINDMSGSTRING = RegisterWindowMessageW(FINDMSGSTRINGW);
2029 registry_read_filelist(hWnd);
2030 registry_read_formatopts_all(barState, wordWrap);
2031 registry_read_options();
2032 DragAcceptFiles(hWnd, TRUE);
2034 return 0;
2037 static LRESULT OnUser( HWND hWnd )
2039 HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
2040 HWND hwndReBar = GetDlgItem(hWnd, IDC_REBAR);
2041 HWND hwndToolBar = GetDlgItem(hwndReBar, IDC_TOOLBAR);
2042 HWND hwndFormatBar = GetDlgItem(hwndReBar, IDC_FORMATBAR);
2043 int from, to;
2044 CHARFORMAT2W fmt;
2045 PARAFORMAT2 pf;
2046 GETTEXTLENGTHEX gt;
2048 ZeroMemory(&fmt, sizeof(fmt));
2049 fmt.cbSize = sizeof(fmt);
2051 ZeroMemory(&pf, sizeof(pf));
2052 pf.cbSize = sizeof(pf);
2054 gt.flags = GTL_NUMCHARS;
2055 gt.codepage = 1200;
2057 SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_FIND,
2058 SendMessageW(hwndEditor, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0) ? 1 : 0);
2060 SendMessageW(hwndEditor, EM_GETCHARFORMAT, TRUE, (LPARAM)&fmt);
2062 SendMessageW(hwndEditor, EM_GETSEL, (WPARAM)&from, (LPARAM)&to);
2063 SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_EDIT_UNDO,
2064 SendMessageW(hwndEditor, EM_CANUNDO, 0, 0));
2065 SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_EDIT_REDO,
2066 SendMessageW(hwndEditor, EM_CANREDO, 0, 0));
2067 SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_EDIT_CUT, from == to ? 0 : 1);
2068 SendMessageW(hwndToolBar, TB_ENABLEBUTTON, ID_EDIT_COPY, from == to ? 0 : 1);
2070 SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_FORMAT_BOLD, (fmt.dwMask & CFM_BOLD) &&
2071 (fmt.dwEffects & CFE_BOLD));
2072 SendMessageW(hwndFormatBar, TB_INDETERMINATE, ID_FORMAT_BOLD, !(fmt.dwMask & CFM_BOLD));
2073 SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_FORMAT_ITALIC, (fmt.dwMask & CFM_ITALIC) &&
2074 (fmt.dwEffects & CFE_ITALIC));
2075 SendMessageW(hwndFormatBar, TB_INDETERMINATE, ID_FORMAT_ITALIC, !(fmt.dwMask & CFM_ITALIC));
2076 SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_FORMAT_UNDERLINE, (fmt.dwMask & CFM_UNDERLINE) &&
2077 (fmt.dwEffects & CFE_UNDERLINE));
2078 SendMessageW(hwndFormatBar, TB_INDETERMINATE, ID_FORMAT_UNDERLINE, !(fmt.dwMask & CFM_UNDERLINE));
2080 SendMessageW(hwndEditor, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
2081 SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_ALIGN_LEFT, (pf.wAlignment == PFA_LEFT));
2082 SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_ALIGN_CENTER, (pf.wAlignment == PFA_CENTER));
2083 SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_ALIGN_RIGHT, (pf.wAlignment == PFA_RIGHT));
2085 SendMessageW(hwndFormatBar, TB_CHECKBUTTON, ID_BULLETONOFF, pf.wNumbering != 0);
2086 return 0;
2089 static LRESULT OnNotify( HWND hWnd, LPARAM lParam)
2091 HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
2092 HWND hwndReBar = GetDlgItem(hWnd, IDC_REBAR);
2093 NMHDR *pHdr = (NMHDR *)lParam;
2094 HWND hwndFontList = GetDlgItem(hwndReBar, IDC_FONTLIST);
2095 HWND hwndSizeList = GetDlgItem(hwndReBar, IDC_SIZELIST);
2096 HWND hwndFormatBar = GetDlgItem(hwndReBar, IDC_FORMATBAR);
2098 if (pHdr->hwndFrom == hwndFontList || pHdr->hwndFrom == hwndSizeList)
2100 if (pHdr->code == CBEN_ENDEDITW)
2102 NMCBEENDEDITW *endEdit = (NMCBEENDEDITW *)lParam;
2103 if(pHdr->hwndFrom == hwndFontList)
2105 on_fontlist_modified(endEdit->szText);
2106 } else if (pHdr->hwndFrom == hwndSizeList)
2108 on_sizelist_modified(hwndSizeList,endEdit->szText);
2111 return 0;
2114 if (pHdr->hwndFrom == hwndFormatBar)
2116 if (pHdr->code == TBN_DROPDOWN)
2118 NMTOOLBARW *tb_notify = (NMTOOLBARW *)lParam;
2119 HMENU menu = GetMenu( hWnd );
2120 MENUITEMINFOW info;
2121 TPMPARAMS params;
2122 RECT rc;
2124 if (!menu) return 0;
2125 info.cbSize = sizeof(info);
2126 info.fMask = MIIM_SUBMENU;
2127 GetMenuItemInfoW( menu, ID_LISTMENU, FALSE, &info );
2128 if (!info.hSubMenu) return 0;
2130 SendMessageW( tb_notify->hdr.hwndFrom, TB_GETRECT, (WPARAM)tb_notify->iItem, (LPARAM)&rc );
2131 MapWindowPoints( tb_notify->hdr.hwndFrom, HWND_DESKTOP, (LPPOINT)&rc, 2 );
2133 params.cbSize = sizeof(params);
2134 params.rcExclude = rc;
2135 TrackPopupMenuEx( info.hSubMenu,
2136 TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL,
2137 rc.left, rc.bottom, hWnd, &params );
2140 return 0;
2143 if (pHdr->hwndFrom == hwndEditor)
2145 if (pHdr->code == EN_SELCHANGE)
2147 SELCHANGE *pSC = (SELCHANGE *)lParam;
2148 char buf[128];
2150 update_font_list();
2152 sprintf( buf,"selection = %ld..%ld, line count=%Id",
2153 pSC->chrg.cpMin, pSC->chrg.cpMax,
2154 SendMessageW(hwndEditor, EM_GETLINECOUNT, 0, 0));
2155 SetWindowTextA(GetDlgItem(hWnd, IDC_STATUSBAR), buf);
2156 SendMessageW(hWnd, WM_USER, 0, 0);
2157 return 1;
2160 return 0;
2163 /* Copied from dlls/comdlg32/fontdlg.c */
2164 static const COLORREF textcolors[]=
2166 0x00000000L,0x00000080L,0x00008000L,0x00008080L,
2167 0x00800000L,0x00800080L,0x00808000L,0x00808080L,
2168 0x00c0c0c0L,0x000000ffL,0x0000ff00L,0x0000ffffL,
2169 0x00ff0000L,0x00ff00ffL,0x00ffff00L,0x00FFFFFFL
2172 static LRESULT OnCommand( HWND hWnd, WPARAM wParam, LPARAM lParam)
2174 HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
2175 static FINDREPLACEW findreplace;
2177 if ((HWND)lParam == hwndEditor)
2178 return 0;
2180 switch(LOWORD(wParam))
2183 case ID_FILE_EXIT:
2184 PostMessageW(hWnd, WM_CLOSE, 0, 0);
2185 break;
2187 case ID_FILE_NEW:
2189 HINSTANCE hInstance = GetModuleHandleW(0);
2190 int ret = DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_NEWFILE), hWnd, newfile_proc);
2192 if(ret != ID_NEWFILE_ABORT)
2194 if(prompt_save_changes())
2196 SETTEXTEX st;
2198 set_caption(NULL);
2199 wszFileName[0] = '\0';
2201 clear_formatting();
2203 st.flags = ST_DEFAULT;
2204 st.codepage = 1200;
2205 SendMessageW(hEditorWnd, EM_SETTEXTEX, (WPARAM)&st, 0);
2207 SendMessageW(hEditorWnd, EM_SETMODIFY, FALSE, 0);
2208 set_fileformat(ret);
2209 update_font_list();
2213 break;
2215 case ID_FILE_OPEN:
2216 DialogOpenFile();
2217 break;
2219 case ID_FILE_SAVE:
2220 if(wszFileName[0])
2222 DoSaveFile(wszFileName, fileFormat);
2223 break;
2225 /* Fall through */
2227 case ID_FILE_SAVEAS:
2228 DialogSaveFile();
2229 break;
2231 case ID_FILE_RECENT1:
2232 case ID_FILE_RECENT2:
2233 case ID_FILE_RECENT3:
2234 case ID_FILE_RECENT4:
2236 HMENU hMenu = GetMenu(hWnd);
2237 MENUITEMINFOW mi;
2239 mi.cbSize = sizeof(MENUITEMINFOW);
2240 mi.fMask = MIIM_DATA;
2241 if(GetMenuItemInfoW(hMenu, LOWORD(wParam), FALSE, &mi))
2242 DoOpenFile((LPWSTR)mi.dwItemData);
2244 break;
2246 case ID_FIND:
2247 dialog_find(&findreplace, FALSE);
2248 break;
2250 case ID_FIND_NEXT:
2251 handle_findmsg(&findreplace);
2252 break;
2254 case ID_REPLACE:
2255 dialog_find(&findreplace, TRUE);
2256 break;
2258 case ID_FONTSETTINGS:
2259 dialog_choose_font();
2260 break;
2262 case ID_PRINT:
2263 dialog_print(hWnd, wszFileName);
2264 target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
2265 break;
2267 case ID_PRINT_QUICK:
2268 print_quick(hMainWnd, wszFileName);
2269 target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
2270 break;
2272 case ID_PREVIEW:
2274 int index = reg_formatindex(fileFormat);
2275 DWORD tmp = barState[index];
2276 barState[index] = 1 << BANDID_STATUSBAR;
2277 set_bar_states();
2278 barState[index] = tmp;
2279 ShowWindow(hEditorWnd, FALSE);
2281 init_preview(hWnd, wszFileName);
2283 SetMenu(hWnd, NULL);
2284 InvalidateRect(0, 0, TRUE);
2286 break;
2288 case ID_PRINTSETUP:
2289 dialog_printsetup(hWnd);
2290 target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
2291 break;
2293 case ID_FORMAT_BOLD:
2294 case ID_FORMAT_ITALIC:
2295 case ID_FORMAT_UNDERLINE:
2297 CHARFORMAT2W fmt;
2298 int effects = CFE_BOLD;
2300 ZeroMemory(&fmt, sizeof(fmt));
2301 fmt.cbSize = sizeof(fmt);
2302 SendMessageW(hwndEditor, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
2304 fmt.dwMask = CFM_BOLD;
2306 if (LOWORD(wParam) == ID_FORMAT_ITALIC)
2308 effects = CFE_ITALIC;
2309 fmt.dwMask = CFM_ITALIC;
2310 } else if (LOWORD(wParam) == ID_FORMAT_UNDERLINE)
2312 effects = CFE_UNDERLINE;
2313 fmt.dwMask = CFM_UNDERLINE;
2316 fmt.dwEffects ^= effects;
2318 SendMessageW(hwndEditor, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
2319 break;
2322 case ID_FORMAT_COLOR:
2324 HWND hReBarWnd = GetDlgItem(hWnd, IDC_REBAR);
2325 HWND hFormatBarWnd = GetDlgItem(hReBarWnd, IDC_FORMATBAR);
2326 HMENU hPop;
2327 RECT itemrc;
2328 POINT pt;
2329 int mid;
2330 int itemidx = SendMessageW(hFormatBarWnd, TB_COMMANDTOINDEX, ID_FORMAT_COLOR, 0);
2332 SendMessageW(hFormatBarWnd, TB_GETITEMRECT, itemidx, (LPARAM)&itemrc);
2333 pt.x = itemrc.left;
2334 pt.y = itemrc.bottom;
2335 ClientToScreen(hFormatBarWnd, &pt);
2336 hPop = GetSubMenu(hColorPopupMenu, 0);
2337 mid = TrackPopupMenu(hPop, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON |
2338 TPM_RETURNCMD | TPM_NONOTIFY,
2339 pt.x, pt.y, 0, hWnd, 0);
2340 if (mid >= ID_COLOR_FIRST && mid <= ID_COLOR_AUTOMATIC)
2342 CHARFORMAT2W fmt;
2344 ZeroMemory(&fmt, sizeof(fmt));
2345 fmt.cbSize = sizeof(fmt);
2346 SendMessageW(hwndEditor, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
2348 fmt.dwMask = CFM_COLOR;
2350 if (mid < ID_COLOR_AUTOMATIC) {
2351 fmt.crTextColor = textcolors[mid - ID_COLOR_FIRST];
2352 fmt.dwEffects &= ~CFE_AUTOCOLOR;
2353 } else {
2354 fmt.dwEffects |= CFE_AUTOCOLOR;
2357 SendMessageW(hwndEditor, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
2359 break;
2362 case ID_EDIT_CUT:
2363 PostMessageW(hwndEditor, WM_CUT, 0, 0);
2364 break;
2366 case ID_EDIT_COPY:
2367 PostMessageW(hwndEditor, WM_COPY, 0, 0);
2368 break;
2370 case ID_EDIT_PASTE:
2371 PostMessageW(hwndEditor, WM_PASTE, 0, 0);
2372 break;
2374 case ID_EDIT_CLEAR:
2375 PostMessageW(hwndEditor, WM_CLEAR, 0, 0);
2376 break;
2378 case ID_EDIT_SELECTALL:
2380 CHARRANGE range = {0, -1};
2381 SendMessageW(hwndEditor, EM_EXSETSEL, 0, (LPARAM)&range);
2382 /* SendMessage(hwndEditor, EM_SETSEL, 0, -1); */
2383 return 0;
2386 case ID_EDIT_GETTEXT:
2388 int nLen = GetWindowTextLengthW(hwndEditor);
2389 LPWSTR data = malloc((nLen+1)*sizeof(WCHAR) );
2390 TEXTRANGEW tr;
2392 GetWindowTextW(hwndEditor, data, nLen+1);
2393 MessageBoxW(NULL, data, wszAppTitle, MB_OK);
2395 free(data);
2396 data = malloc((nLen+1)*sizeof(WCHAR));
2397 tr.chrg.cpMin = 0;
2398 tr.chrg.cpMax = nLen;
2399 tr.lpstrText = data;
2400 SendMessageW(hwndEditor, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
2401 MessageBoxW(NULL, data, wszAppTitle, MB_OK);
2402 free(data);
2404 /* SendMessage(hwndEditor, EM_SETSEL, 0, -1); */
2405 return 0;
2408 case ID_EDIT_CHARFORMAT:
2409 case ID_EDIT_DEFCHARFORMAT:
2411 CHARFORMAT2W cf;
2413 ZeroMemory(&cf, sizeof(cf));
2414 cf.cbSize = sizeof(cf);
2415 cf.dwMask = 0;
2416 SendMessageW(hwndEditor, EM_GETCHARFORMAT,
2417 LOWORD(wParam) == ID_EDIT_CHARFORMAT, (LPARAM)&cf);
2418 return 0;
2421 case ID_EDIT_PARAFORMAT:
2423 PARAFORMAT2 pf;
2424 ZeroMemory(&pf, sizeof(pf));
2425 pf.cbSize = sizeof(pf);
2426 SendMessageW(hwndEditor, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
2427 return 0;
2430 case ID_EDIT_SELECTIONINFO:
2432 CHARRANGE range = {0, -1};
2433 char buf[128];
2434 WCHAR *data = NULL;
2436 SendMessageW(hwndEditor, EM_EXGETSEL, 0, (LPARAM)&range);
2437 data = malloc(sizeof(*data) * (range.cpMax-range.cpMin+1));
2438 SendMessageW(hwndEditor, EM_GETSELTEXT, 0, (LPARAM)data);
2439 sprintf(buf, "Start = %ld, End = %ld", range.cpMin, range.cpMax);
2440 MessageBoxA(hWnd, buf, "Editor", MB_OK);
2441 MessageBoxW(hWnd, data, wszAppTitle, MB_OK);
2442 free(data);
2443 /* SendMessage(hwndEditor, EM_SETSEL, 0, -1); */
2444 return 0;
2447 case ID_EDIT_READONLY:
2449 LONG nStyle = GetWindowLongW(hwndEditor, GWL_STYLE);
2450 if (nStyle & ES_READONLY)
2451 SendMessageW(hwndEditor, EM_SETREADONLY, 0, 0);
2452 else
2453 SendMessageW(hwndEditor, EM_SETREADONLY, 1, 0);
2454 return 0;
2457 case ID_EDIT_MODIFIED:
2458 if (SendMessageW(hwndEditor, EM_GETMODIFY, 0, 0))
2459 SendMessageW(hwndEditor, EM_SETMODIFY, 0, 0);
2460 else
2461 SendMessageW(hwndEditor, EM_SETMODIFY, 1, 0);
2462 return 0;
2464 case ID_EDIT_UNDO:
2465 SendMessageW(hwndEditor, EM_UNDO, 0, 0);
2466 return 0;
2468 case ID_EDIT_REDO:
2469 SendMessageW(hwndEditor, EM_REDO, 0, 0);
2470 return 0;
2472 case ID_BULLETONOFF:
2473 case ID_BULLET:
2474 case ID_NUMBERING:
2475 case ID_LCLETTER:
2476 case ID_UCLETTER:
2477 case ID_LCROMAN:
2478 case ID_UCROMAN:
2480 PARAFORMAT2 pf;
2481 WORD new_number = LOWORD(wParam) - ID_BULLET + PFN_BULLET;
2482 pf.cbSize = sizeof(pf);
2483 pf.dwMask = PFM_NUMBERING;
2484 SendMessageW(hwndEditor, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
2486 pf.dwMask = PFM_NUMBERING | PFM_NUMBERINGSTART | PFM_NUMBERINGSTYLE | PFM_NUMBERINGTAB | PFM_OFFSET | PFM_OFFSETINDENT;
2488 if(pf.wNumbering && ((pf.wNumbering == new_number) || (LOWORD(wParam) == ID_BULLETONOFF)))
2490 pf.wNumbering = 0;
2491 pf.wNumberingStart = 0;
2492 pf.wNumberingStyle = 0;
2493 pf.wNumberingTab = 0;
2494 pf.dxOffset = 0;
2495 pf.dxStartIndent = -360;
2496 } else
2498 pf.dxStartIndent = pf.wNumbering ? 0 : 360;
2500 if (LOWORD(wParam) == ID_BULLETONOFF)
2501 pf.wNumbering = last_bullet;
2502 else
2504 pf.wNumbering = new_number;
2505 last_bullet = pf.wNumbering;
2507 pf.wNumberingStart = 1;
2508 pf.wNumberingStyle = PFNS_PERIOD;
2509 pf.wNumberingTab = 360;
2510 pf.dxOffset = 360;
2513 SendMessageW(hwndEditor, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
2515 break;
2517 case ID_ALIGN_LEFT:
2518 case ID_ALIGN_CENTER:
2519 case ID_ALIGN_RIGHT:
2521 PARAFORMAT2 pf;
2523 pf.cbSize = sizeof(pf);
2524 pf.dwMask = PFM_ALIGNMENT;
2525 switch(LOWORD(wParam)) {
2526 case ID_ALIGN_LEFT: pf.wAlignment = PFA_LEFT; break;
2527 case ID_ALIGN_CENTER: pf.wAlignment = PFA_CENTER; break;
2528 case ID_ALIGN_RIGHT: pf.wAlignment = PFA_RIGHT; break;
2530 SendMessageW(hwndEditor, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
2531 break;
2534 case ID_BACK_1:
2535 SendMessageW(hwndEditor, EM_SETBKGNDCOLOR, 1, 0);
2536 break;
2538 case ID_BACK_2:
2539 SendMessageW(hwndEditor, EM_SETBKGNDCOLOR, 0, RGB(255,255,192));
2540 break;
2542 case ID_TOGGLE_TOOLBAR:
2543 set_toolbar_state(BANDID_TOOLBAR, !is_bar_visible(BANDID_TOOLBAR));
2544 update_window();
2545 break;
2547 case ID_TOGGLE_FORMATBAR:
2548 set_toolbar_state(BANDID_FONTLIST, !is_bar_visible(BANDID_FORMATBAR));
2549 set_toolbar_state(BANDID_SIZELIST, !is_bar_visible(BANDID_FORMATBAR));
2550 set_toolbar_state(BANDID_FORMATBAR, !is_bar_visible(BANDID_FORMATBAR));
2551 update_window();
2552 break;
2554 case ID_TOGGLE_STATUSBAR:
2555 set_statusbar_state(!is_bar_visible(BANDID_STATUSBAR));
2556 update_window();
2557 break;
2559 case ID_TOGGLE_RULER:
2560 set_toolbar_state(BANDID_RULER, !is_bar_visible(BANDID_RULER));
2561 update_window();
2562 break;
2564 case ID_DATETIME:
2565 DialogBoxW(GetModuleHandleW(0), MAKEINTRESOURCEW(IDD_DATETIME), hWnd, datetime_proc);
2566 break;
2568 case ID_PARAFORMAT:
2569 DialogBoxW(GetModuleHandleW(0), MAKEINTRESOURCEW(IDD_PARAFORMAT), hWnd, paraformat_proc);
2570 break;
2572 case ID_TABSTOPS:
2573 DialogBoxW(GetModuleHandleW(0), MAKEINTRESOURCEW(IDD_TABSTOPS), hWnd, tabstops_proc);
2574 break;
2576 case ID_ABOUT:
2577 dialog_about();
2578 break;
2580 case ID_VIEWPROPERTIES:
2581 dialog_viewproperties();
2582 break;
2584 case IDC_FONTLIST:
2585 if (HIWORD(wParam) == CBN_SELENDOK)
2587 WCHAR buffer[LF_FACESIZE];
2588 HWND hwndFontList = (HWND)lParam;
2589 get_comboexlist_selection(hwndFontList, buffer, LF_FACESIZE);
2590 on_fontlist_modified(buffer);
2592 break;
2594 case IDC_SIZELIST:
2595 if (HIWORD(wParam) == CBN_SELENDOK)
2597 WCHAR buffer[MAX_STRING_LEN+1];
2598 HWND hwndSizeList = (HWND)lParam;
2599 get_comboexlist_selection(hwndSizeList, buffer, MAX_STRING_LEN+1);
2600 on_sizelist_modified(hwndSizeList, buffer);
2602 break;
2604 default:
2605 SendMessageW(hwndEditor, WM_COMMAND, wParam, lParam);
2606 break;
2608 return 0;
2611 static LRESULT OnInitPopupMenu( HWND hWnd, WPARAM wParam )
2613 HMENU hMenu = (HMENU)wParam;
2614 HWND hwndEditor = GetDlgItem(hWnd, IDC_EDITOR);
2615 HWND hwndStatus = GetDlgItem(hWnd, IDC_STATUSBAR);
2616 PARAFORMAT pf;
2617 int nAlignment = -1;
2618 int selFrom, selTo;
2619 GETTEXTLENGTHEX gt;
2620 LRESULT textLength;
2621 MENUITEMINFOW mi;
2623 SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&selFrom, (LPARAM)&selTo);
2624 EnableMenuItem(hMenu, ID_EDIT_COPY, (selFrom == selTo) ? MF_GRAYED : MF_ENABLED);
2625 EnableMenuItem(hMenu, ID_EDIT_CUT, (selFrom == selTo) ? MF_GRAYED : MF_ENABLED);
2627 pf.cbSize = sizeof(PARAFORMAT);
2628 SendMessageW(hwndEditor, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
2629 CheckMenuItem(hMenu, ID_EDIT_READONLY,
2630 (GetWindowLongW(hwndEditor, GWL_STYLE) & ES_READONLY) ? MF_CHECKED : MF_UNCHECKED);
2631 CheckMenuItem(hMenu, ID_EDIT_MODIFIED,
2632 SendMessageW(hwndEditor, EM_GETMODIFY, 0, 0) ? MF_CHECKED : MF_UNCHECKED);
2633 if (pf.dwMask & PFM_ALIGNMENT)
2634 nAlignment = pf.wAlignment;
2635 CheckMenuItem(hMenu, ID_ALIGN_LEFT, (nAlignment == PFA_LEFT) ? MF_CHECKED : MF_UNCHECKED);
2636 CheckMenuItem(hMenu, ID_ALIGN_CENTER, (nAlignment == PFA_CENTER) ? MF_CHECKED : MF_UNCHECKED);
2637 CheckMenuItem(hMenu, ID_ALIGN_RIGHT, (nAlignment == PFA_RIGHT) ? MF_CHECKED : MF_UNCHECKED);
2639 CheckMenuItem(hMenu, ID_BULLET, ((pf.wNumbering == PFN_BULLET) ? MF_CHECKED : MF_UNCHECKED));
2640 CheckMenuItem(hMenu, ID_NUMBERING, ((pf.wNumbering == PFN_ARABIC) ? MF_CHECKED : MF_UNCHECKED));
2641 CheckMenuItem(hMenu, ID_LCLETTER, ((pf.wNumbering == PFN_LCLETTER) ? MF_CHECKED : MF_UNCHECKED));
2642 CheckMenuItem(hMenu, ID_UCLETTER, ((pf.wNumbering == PFN_UCLETTER) ? MF_CHECKED : MF_UNCHECKED));
2643 CheckMenuItem(hMenu, ID_LCROMAN, ((pf.wNumbering == PFN_LCROMAN) ? MF_CHECKED : MF_UNCHECKED));
2644 CheckMenuItem(hMenu, ID_UCROMAN, ((pf.wNumbering == PFN_UCROMAN) ? MF_CHECKED : MF_UNCHECKED));
2646 EnableMenuItem(hMenu, ID_EDIT_UNDO, SendMessageW(hwndEditor, EM_CANUNDO, 0, 0) ?
2647 MF_ENABLED : MF_GRAYED);
2648 EnableMenuItem(hMenu, ID_EDIT_REDO, SendMessageW(hwndEditor, EM_CANREDO, 0, 0) ?
2649 MF_ENABLED : MF_GRAYED);
2651 CheckMenuItem(hMenu, ID_TOGGLE_TOOLBAR, is_bar_visible(BANDID_TOOLBAR) ?
2652 MF_CHECKED : MF_UNCHECKED);
2654 CheckMenuItem(hMenu, ID_TOGGLE_FORMATBAR, is_bar_visible(BANDID_FORMATBAR) ?
2655 MF_CHECKED : MF_UNCHECKED);
2657 CheckMenuItem(hMenu, ID_TOGGLE_STATUSBAR, IsWindowVisible(hwndStatus) ?
2658 MF_CHECKED : MF_UNCHECKED);
2660 CheckMenuItem(hMenu, ID_TOGGLE_RULER, is_bar_visible(BANDID_RULER) ? MF_CHECKED : MF_UNCHECKED);
2662 gt.flags = GTL_NUMCHARS;
2663 gt.codepage = 1200;
2664 textLength = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0);
2665 EnableMenuItem(hMenu, ID_FIND, textLength ? MF_ENABLED : MF_GRAYED);
2667 mi.cbSize = sizeof(mi);
2668 mi.fMask = MIIM_DATA;
2670 GetMenuItemInfoW(hMenu, ID_FIND_NEXT, FALSE, &mi);
2672 EnableMenuItem(hMenu, ID_FIND_NEXT, (textLength && mi.dwItemData) ? MF_ENABLED : MF_GRAYED);
2674 EnableMenuItem(hMenu, ID_REPLACE, textLength ? MF_ENABLED : MF_GRAYED);
2676 return 0;
2679 static LRESULT OnSize( HWND hWnd, WPARAM wParam, LPARAM lParam )
2681 int nStatusSize = 0;
2682 RECT rc;
2683 HWND hwndEditor = preview_isactive() ? GetDlgItem(hWnd, IDC_PREVIEW) : GetDlgItem(hWnd, IDC_EDITOR);
2684 HWND hwndStatusBar = GetDlgItem(hWnd, IDC_STATUSBAR);
2685 HWND hwndReBar = GetDlgItem(hWnd, IDC_REBAR);
2686 HWND hRulerWnd = GetDlgItem(hwndReBar, IDC_RULER);
2687 int rebarHeight = 0;
2689 if (hwndStatusBar)
2691 SendMessageW(hwndStatusBar, WM_SIZE, 0, 0);
2692 if (IsWindowVisible(hwndStatusBar))
2694 GetClientRect(hwndStatusBar, &rc);
2695 nStatusSize = rc.bottom - rc.top;
2696 } else
2698 nStatusSize = 0;
2701 if (hwndReBar)
2703 rebarHeight = SendMessageW(hwndReBar, RB_GETBARHEIGHT, 0, 0);
2705 MoveWindow(hwndReBar, 0, 0, LOWORD(lParam), rebarHeight, TRUE);
2707 if (hwndEditor)
2709 GetClientRect(hWnd, &rc);
2710 MoveWindow(hwndEditor, 0, rebarHeight, rc.right, rc.bottom-nStatusSize-rebarHeight, TRUE);
2713 redraw_ruler(hRulerWnd);
2715 return DefWindowProcW(hWnd, WM_SIZE, wParam, lParam);
2718 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
2720 if(msg == ID_FINDMSGSTRING)
2721 return handle_findmsg((LPFINDREPLACEW)lParam);
2723 switch(msg)
2725 case WM_CREATE:
2726 return OnCreate( hWnd );
2728 case WM_USER:
2729 return OnUser( hWnd );
2731 case WM_NOTIFY:
2732 return OnNotify( hWnd, lParam );
2734 case WM_COMMAND:
2735 if(preview_isactive())
2737 return preview_command( hWnd, wParam );
2740 return OnCommand( hWnd, wParam, lParam );
2742 case WM_DESTROY:
2743 PostQuitMessage(0);
2744 break;
2746 case WM_CLOSE:
2747 if(preview_isactive())
2749 preview_exit(hWnd);
2750 } else if(prompt_save_changes())
2752 registry_set_options(hMainWnd);
2753 registry_set_formatopts_all(barState, wordWrap);
2754 PostQuitMessage(0);
2756 break;
2758 case WM_ACTIVATE:
2759 if (LOWORD(wParam))
2760 SetFocus(GetDlgItem(hWnd, IDC_EDITOR));
2761 return 0;
2763 case WM_INITMENUPOPUP:
2764 return OnInitPopupMenu( hWnd, wParam );
2766 case WM_SIZE:
2767 return OnSize( hWnd, wParam, lParam );
2769 case WM_CONTEXTMENU:
2770 return DefWindowProcW(hWnd, msg, wParam, lParam);
2772 case WM_DROPFILES:
2774 WCHAR file[MAX_PATH];
2775 DragQueryFileW((HDROP)wParam, 0, file, MAX_PATH);
2776 DragFinish((HDROP)wParam);
2778 if(prompt_save_changes())
2779 DoOpenFile(file);
2781 break;
2782 case WM_PAINT:
2783 if(!preview_isactive())
2784 return DefWindowProcW(hWnd, msg, wParam, lParam);
2786 default:
2787 return DefWindowProcW(hWnd, msg, wParam, lParam);
2790 return 0;
2793 int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hOldInstance, LPSTR szCmdParagraph, int nCmdShow)
2795 INITCOMMONCONTROLSEX classes = {8, ICC_BAR_CLASSES|ICC_COOL_CLASSES|ICC_USEREX_CLASSES};
2796 HACCEL hAccel;
2797 WNDCLASSEXW wc;
2798 MSG msg;
2799 RECT rc;
2800 UINT_PTR hPrevRulerProc;
2801 HWND hRulerWnd;
2802 POINTL EditPoint;
2803 DWORD bMaximized;
2804 MONITORINFO info;
2805 HMONITOR monitor;
2806 int x, y;
2807 static const WCHAR wszAccelTable[] = {'M','A','I','N','A','C','C','E','L',
2808 'T','A','B','L','E','\0'};
2810 InitCommonControlsEx(&classes);
2812 hAccel = LoadAcceleratorsW(hInstance, wszAccelTable);
2814 wc.cbSize = sizeof(wc);
2815 wc.style = 0;
2816 wc.lpfnWndProc = WndProc;
2817 wc.cbClsExtra = 0;
2818 wc.cbWndExtra = 4;
2819 wc.hInstance = hInstance;
2820 wc.hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_WORDPAD));
2821 wc.hIconSm = LoadImageW(hInstance, MAKEINTRESOURCEW(IDI_WORDPAD), IMAGE_ICON,
2822 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED);
2823 wc.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_IBEAM);
2824 wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
2825 wc.lpszMenuName = MAKEINTRESOURCEW(IDM_MAINMENU);
2826 wc.lpszClassName = wszMainWndClass;
2827 RegisterClassExW(&wc);
2829 wc.style = 0;
2830 wc.lpfnWndProc = preview_proc;
2831 wc.cbClsExtra = 0;
2832 wc.cbWndExtra = 0;
2833 wc.hInstance = hInstance;
2834 wc.hIcon = NULL;
2835 wc.hIconSm = NULL;
2836 wc.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_IBEAM);
2837 wc.hbrBackground = NULL;
2838 wc.lpszMenuName = NULL;
2839 wc.lpszClassName = wszPreviewWndClass;
2840 RegisterClassExW(&wc);
2842 registry_read_winrect(&rc);
2843 monitor = MonitorFromRect(&rc, MONITOR_DEFAULTTOPRIMARY);
2844 info.cbSize = sizeof(info);
2845 GetMonitorInfoW(monitor, &info);
2847 x = rc.left;
2848 y = rc.top;
2849 IntersectRect(&info.rcWork, &info.rcWork, &rc);
2850 if (IsRectEmpty(&info.rcWork))
2851 x = y = CW_USEDEFAULT;
2853 hMainWnd = CreateWindowExW(0, wszMainWndClass, wszAppTitle, WS_CLIPCHILDREN|WS_OVERLAPPEDWINDOW,
2854 x, y, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL);
2855 registry_read_maximized(&bMaximized);
2856 if ((nCmdShow == SW_SHOWNORMAL || nCmdShow == SW_SHOWDEFAULT)
2857 && bMaximized)
2858 nCmdShow = SW_SHOWMAXIMIZED;
2859 ShowWindow(hMainWnd, nCmdShow);
2861 set_caption(NULL);
2862 set_bar_states();
2863 set_fileformat(SF_RTF);
2864 hColorPopupMenu = LoadMenuW(hInstance, MAKEINTRESOURCEW(IDM_COLOR_POPUP));
2865 get_default_printer_opts();
2866 target_device(hMainWnd, wordWrap[reg_formatindex(fileFormat)]);
2868 hRulerWnd = GetDlgItem(GetDlgItem(hMainWnd, IDC_REBAR), IDC_RULER);
2869 SendMessageW(GetDlgItem(hMainWnd, IDC_EDITOR), EM_POSFROMCHAR, (WPARAM)&EditPoint, 0);
2870 hPrevRulerProc = SetWindowLongPtrW(hRulerWnd, GWLP_WNDPROC, (UINT_PTR)ruler_proc);
2871 SendMessageW(hRulerWnd, WM_USER, (WPARAM)&EditPoint, hPrevRulerProc);
2873 HandleCommandLine(GetCommandLineW());
2875 while(GetMessageW(&msg,0,0,0))
2877 if (IsDialogMessageW(hFindWnd, &msg))
2878 continue;
2880 if (TranslateAcceleratorW(hMainWnd, hAccel, &msg))
2881 continue;
2882 TranslateMessage(&msg);
2883 DispatchMessageW(&msg);
2884 if (!PeekMessageW(&msg, 0, 0, 0, PM_NOREMOVE))
2885 SendMessageW(hMainWnd, WM_USER, 0, 0);
2888 return 0;