include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / programs / notepad / dialog.c
blob3865bc55426f539372f8d4de8ef035b21187d4ab
1 /*
2 * Notepad (dialog.c)
4 * Copyright 1998,99 Marcel Baur <mbaur@g26.ethz.ch>
5 * Copyright 2002 Sylvain Petreolle <spetreolle@yahoo.fr>
6 * Copyright 2002 Andriy Palamarchuk
7 * Copyright 2007 Rolf Kalbermatter
8 * Copyright 2010 Vitaly Perov
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include <assert.h>
26 #include <stdio.h>
27 #include <windows.h>
28 #include <shellapi.h>
29 #include <commdlg.h>
30 #include <commctrl.h>
31 #include <shlwapi.h>
32 #include <winternl.h>
34 #include "main.h"
35 #include "dialog.h"
37 #define SPACES_IN_TAB 8
38 #define PRINT_LEN_MAX 500
40 static const WCHAR helpfileW[] = { 'n','o','t','e','p','a','d','.','h','l','p',0 };
42 static INT_PTR WINAPI DIALOG_PAGESETUP_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
44 /* Swap bytes of WCHAR buffer (big-endian <-> little-endian). */
45 static inline void byteswap_wide_string(LPWSTR str, UINT num)
47 UINT i;
48 for (i = 0; i < num; i++) str[i] = RtlUshortByteSwap(str[i]);
51 static void load_encoding_name(ENCODING enc, WCHAR* buffer, int length)
53 switch (enc)
55 case ENCODING_UTF16LE:
56 LoadStringW(Globals.hInstance, STRING_UNICODE_LE, buffer, length);
57 break;
59 case ENCODING_UTF16BE:
60 LoadStringW(Globals.hInstance, STRING_UNICODE_BE, buffer, length);
61 break;
63 case ENCODING_UTF8:
64 LoadStringW(Globals.hInstance, STRING_UTF8, buffer, length);
65 break;
67 case ENCODING_ANSI:
69 CPINFOEXW cpi;
70 GetCPInfoExW(CP_ACP, 0, &cpi);
71 lstrcpynW(buffer, cpi.CodePageName, length);
72 break;
75 default:
76 assert(0 && "bad encoding in load_encoding_name");
77 break;
81 VOID ShowLastError(void)
83 DWORD error = GetLastError();
84 if (error != NO_ERROR)
86 LPWSTR lpMsgBuf;
87 WCHAR szTitle[MAX_STRING_LEN];
89 LoadStringW(Globals.hInstance, STRING_ERROR, szTitle, ARRAY_SIZE(szTitle));
90 FormatMessageW(
91 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
92 NULL, error, 0, (LPWSTR)&lpMsgBuf, 0, NULL);
93 MessageBoxW(NULL, lpMsgBuf, szTitle, MB_OK | MB_ICONERROR);
94 LocalFree(lpMsgBuf);
98 /**
99 * Sets the caption of the main window according to Globals.szFileTitle:
100 * Untitled - Notepad if no file is open
101 * filename - Notepad if a file is given
103 void UpdateWindowCaption(void)
105 static const WCHAR hyphenW[] = { ' ','-',' ',0 };
106 WCHAR szNotepad[64];
107 WCHAR szCaption[ARRAY_SIZE(Globals.szFileTitle) + ARRAY_SIZE(hyphenW) + ARRAY_SIZE(szNotepad)];
109 if (Globals.szFileTitle[0] != '\0')
110 lstrcpyW(szCaption, Globals.szFileTitle);
111 else
112 LoadStringW(Globals.hInstance, STRING_UNTITLED, szCaption, ARRAY_SIZE(szCaption));
114 LoadStringW(Globals.hInstance, STRING_NOTEPAD, szNotepad, ARRAY_SIZE(szNotepad));
115 lstrcatW(szCaption, hyphenW);
116 lstrcatW(szCaption, szNotepad);
118 SetWindowTextW(Globals.hMainWnd, szCaption);
121 int DIALOG_StringMsgBox(HWND hParent, int formatId, LPCWSTR szString, DWORD dwFlags)
123 WCHAR szMessage[MAX_STRING_LEN];
124 WCHAR szResource[MAX_STRING_LEN];
126 /* Load and format szMessage */
127 LoadStringW(Globals.hInstance, formatId, szResource, ARRAY_SIZE(szResource));
128 wnsprintfW(szMessage, ARRAY_SIZE(szMessage), szResource, szString);
130 /* Load szCaption */
131 if ((dwFlags & MB_ICONMASK) == MB_ICONEXCLAMATION)
132 LoadStringW(Globals.hInstance, STRING_ERROR, szResource, ARRAY_SIZE(szResource));
133 else
134 LoadStringW(Globals.hInstance, STRING_NOTEPAD, szResource, ARRAY_SIZE(szResource));
136 /* Display Modal Dialog */
137 if (hParent == NULL)
138 hParent = Globals.hMainWnd;
139 return MessageBoxW(hParent, szMessage, szResource, dwFlags);
142 static void AlertFileNotFound(LPCWSTR szFileName)
144 DIALOG_StringMsgBox(NULL, STRING_NOTFOUND, szFileName, MB_ICONEXCLAMATION|MB_OK);
147 static int AlertFileNotSaved(LPCWSTR szFileName)
149 WCHAR szUntitled[MAX_STRING_LEN];
151 LoadStringW(Globals.hInstance, STRING_UNTITLED, szUntitled, ARRAY_SIZE(szUntitled));
152 return DIALOG_StringMsgBox(NULL, STRING_NOTSAVED, szFileName[0] ? szFileName : szUntitled,
153 MB_ICONQUESTION|MB_YESNOCANCEL);
156 static int AlertUnicodeCharactersLost(LPCWSTR szFileName)
158 WCHAR szCaption[MAX_STRING_LEN];
159 WCHAR szMsgFormat[MAX_STRING_LEN];
160 WCHAR szEnc[MAX_STRING_LEN];
161 WCHAR* szMsg;
162 DWORD_PTR args[2];
163 int rc;
165 LoadStringW(Globals.hInstance, STRING_NOTEPAD, szCaption,
166 ARRAY_SIZE(szCaption));
167 LoadStringW(Globals.hInstance, STRING_LOSS_OF_UNICODE_CHARACTERS,
168 szMsgFormat, ARRAY_SIZE(szMsgFormat));
169 load_encoding_name(ENCODING_ANSI, szEnc, ARRAY_SIZE(szEnc));
170 args[0] = (DWORD_PTR)szFileName;
171 args[1] = (DWORD_PTR)szEnc;
172 FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_ARGUMENT_ARRAY, szMsgFormat, 0, 0, (LPWSTR)&szMsg, 0, (va_list *)args);
173 rc = MessageBoxW(Globals.hMainWnd, szMsg, szCaption,
174 MB_OKCANCEL|MB_ICONEXCLAMATION);
175 LocalFree(szMsg);
176 return rc;
180 * Returns:
181 * TRUE - if file exists
182 * FALSE - if file does not exist
184 BOOL FileExists(LPCWSTR szFilename)
186 WIN32_FIND_DATAW entry;
187 HANDLE hFile;
189 hFile = FindFirstFileW(szFilename, &entry);
190 FindClose(hFile);
192 return (hFile != INVALID_HANDLE_VALUE);
195 static inline BOOL is_conversion_to_ansi_lossy(LPCWSTR textW, int lenW)
197 BOOL ret = FALSE;
198 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, textW, lenW, NULL, 0,
199 NULL, &ret);
200 return ret;
203 typedef enum
205 SAVED_OK,
206 SAVE_FAILED,
207 SHOW_SAVEAS_DIALOG
208 } SAVE_STATUS;
210 /* szFileName is the filename to save under; enc is the encoding to use.
212 * If the function succeeds, it returns SAVED_OK.
213 * If the function fails, it returns SAVE_FAILED.
214 * If Unicode data could be lost due to conversion to a non-Unicode character
215 * set, a warning is displayed. The user can continue (and the function carries
216 * on), or cancel (and the function returns SHOW_SAVEAS_DIALOG).
218 static SAVE_STATUS DoSaveFile(LPCWSTR szFileName, ENCODING enc)
220 int lenW;
221 WCHAR* textW;
222 HANDLE hFile;
223 DWORD dwNumWrite;
224 PVOID pBytes;
225 DWORD size;
227 /* lenW includes the byte-order mark, but not the \0. */
228 lenW = GetWindowTextLengthW(Globals.hEdit) + 1;
229 textW = HeapAlloc(GetProcessHeap(), 0, (lenW+1) * sizeof(WCHAR));
230 if (!textW)
232 ShowLastError();
233 return SAVE_FAILED;
235 textW[0] = (WCHAR) 0xfeff;
236 lenW = GetWindowTextW(Globals.hEdit, textW+1, lenW) + 1;
238 switch (enc)
240 case ENCODING_UTF16BE:
241 byteswap_wide_string(textW, lenW);
242 /* fall through */
244 case ENCODING_UTF16LE:
245 size = lenW * sizeof(WCHAR);
246 pBytes = textW;
247 break;
249 case ENCODING_UTF8:
250 size = WideCharToMultiByte(CP_UTF8, 0, textW, lenW, NULL, 0, NULL, NULL);
251 pBytes = HeapAlloc(GetProcessHeap(), 0, size);
252 if (!pBytes)
254 ShowLastError();
255 HeapFree(GetProcessHeap(), 0, textW);
256 return SAVE_FAILED;
258 WideCharToMultiByte(CP_UTF8, 0, textW, lenW, pBytes, size, NULL, NULL);
259 HeapFree(GetProcessHeap(), 0, textW);
260 break;
262 default:
263 if (is_conversion_to_ansi_lossy(textW+1, lenW-1)
264 && AlertUnicodeCharactersLost(szFileName) == IDCANCEL)
266 HeapFree(GetProcessHeap(), 0, textW);
267 return SHOW_SAVEAS_DIALOG;
270 size = WideCharToMultiByte(CP_ACP, 0, textW+1, lenW-1, NULL, 0, NULL, NULL);
271 pBytes = HeapAlloc(GetProcessHeap(), 0, size);
272 if (!pBytes)
274 ShowLastError();
275 HeapFree(GetProcessHeap(), 0, textW);
276 return SAVE_FAILED;
278 WideCharToMultiByte(CP_ACP, 0, textW+1, lenW-1, pBytes, size, NULL, NULL);
279 HeapFree(GetProcessHeap(), 0, textW);
280 break;
283 hFile = CreateFileW(szFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
284 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
285 if(hFile == INVALID_HANDLE_VALUE)
287 ShowLastError();
288 HeapFree(GetProcessHeap(), 0, pBytes);
289 return SAVE_FAILED;
291 if (!WriteFile(hFile, pBytes, size, &dwNumWrite, NULL))
293 ShowLastError();
294 CloseHandle(hFile);
295 HeapFree(GetProcessHeap(), 0, pBytes);
296 return SAVE_FAILED;
298 SetEndOfFile(hFile);
299 CloseHandle(hFile);
300 HeapFree(GetProcessHeap(), 0, pBytes);
302 SendMessageW(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
303 return SAVED_OK;
307 * Returns:
308 * TRUE - User agreed to close (both save/don't save)
309 * FALSE - User cancelled close by selecting "Cancel"
311 BOOL DoCloseFile(void)
313 int nResult;
314 static const WCHAR empty_strW[] = { 0 };
316 nResult=GetWindowTextLengthW(Globals.hEdit);
317 if (SendMessageW(Globals.hEdit, EM_GETMODIFY, 0, 0) &&
318 (nResult || Globals.szFileName[0]))
320 /* prompt user to save changes */
321 nResult = AlertFileNotSaved(Globals.szFileName);
322 switch (nResult) {
323 case IDYES: return DIALOG_FileSave();
325 case IDNO: break;
327 case IDCANCEL: return(FALSE);
329 default: return(FALSE);
330 } /* switch */
331 } /* if */
333 SetFileNameAndEncoding(empty_strW, ENCODING_ANSI);
335 UpdateWindowCaption();
336 return(TRUE);
339 static inline ENCODING detect_encoding_of_buffer(const void* buffer, int size)
341 static const char bom_utf8[] = { 0xef, 0xbb, 0xbf };
342 if (size >= sizeof(bom_utf8) && !memcmp(buffer, bom_utf8, sizeof(bom_utf8)))
343 return ENCODING_UTF8;
344 else
346 int flags = IS_TEXT_UNICODE_SIGNATURE |
347 IS_TEXT_UNICODE_REVERSE_SIGNATURE |
348 IS_TEXT_UNICODE_ODD_LENGTH;
349 IsTextUnicode(buffer, size, &flags);
350 if (flags & IS_TEXT_UNICODE_SIGNATURE)
351 return ENCODING_UTF16LE;
352 else if (flags & IS_TEXT_UNICODE_REVERSE_SIGNATURE)
353 return ENCODING_UTF16BE;
354 else
355 return ENCODING_ANSI;
359 void DoOpenFile(LPCWSTR szFileName, ENCODING enc)
361 static const WCHAR dotlog[] = { '.','L','O','G',0 };
362 HANDLE hFile;
363 LPSTR pTemp;
364 DWORD size;
365 DWORD dwNumRead;
366 int lenW;
367 WCHAR* textW;
368 int i;
369 WCHAR log[5];
371 /* Close any files and prompt to save changes */
372 if (!DoCloseFile())
373 return;
375 hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
376 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
377 if(hFile == INVALID_HANDLE_VALUE)
379 AlertFileNotFound(szFileName);
380 return;
383 size = GetFileSize(hFile, NULL);
384 if (size == INVALID_FILE_SIZE)
386 CloseHandle(hFile);
387 ShowLastError();
388 return;
391 /* Extra memory for (WCHAR)'\0'-termination. */
392 pTemp = HeapAlloc(GetProcessHeap(), 0, size+2);
393 if (!pTemp)
395 CloseHandle(hFile);
396 ShowLastError();
397 return;
400 if (!ReadFile(hFile, pTemp, size, &dwNumRead, NULL))
402 CloseHandle(hFile);
403 HeapFree(GetProcessHeap(), 0, pTemp);
404 ShowLastError();
405 return;
408 CloseHandle(hFile);
410 size = dwNumRead;
412 if (enc == ENCODING_AUTO)
413 enc = detect_encoding_of_buffer(pTemp, size);
414 else if (size >= 2 && (enc==ENCODING_UTF16LE || enc==ENCODING_UTF16BE))
416 /* If UTF-16 (BE or LE) is selected, and there is a UTF-16 BOM,
417 * override the selection (like native Notepad).
419 if ((BYTE)pTemp[0] == 0xff && (BYTE)pTemp[1] == 0xfe)
420 enc = ENCODING_UTF16LE;
421 else if ((BYTE)pTemp[0] == 0xfe && (BYTE)pTemp[1] == 0xff)
422 enc = ENCODING_UTF16BE;
425 switch (enc)
427 case ENCODING_UTF16BE:
428 byteswap_wide_string((WCHAR*) pTemp, size/sizeof(WCHAR));
429 /* Forget whether the file is BE or LE, like native Notepad. */
430 enc = ENCODING_UTF16LE;
432 /* fall through */
434 case ENCODING_UTF16LE:
435 textW = (LPWSTR)pTemp;
436 lenW = size/sizeof(WCHAR);
437 break;
439 default:
441 int cp = (enc==ENCODING_UTF8) ? CP_UTF8 : CP_ACP;
442 lenW = MultiByteToWideChar(cp, 0, pTemp, size, NULL, 0);
443 textW = HeapAlloc(GetProcessHeap(), 0, (lenW+1) * sizeof(WCHAR));
444 if (!textW)
446 ShowLastError();
447 HeapFree(GetProcessHeap(), 0, pTemp);
448 return;
450 MultiByteToWideChar(cp, 0, pTemp, size, textW, lenW);
451 HeapFree(GetProcessHeap(), 0, pTemp);
452 break;
456 /* Replace '\0's with spaces. Other than creating a custom control that
457 * can deal with '\0' characters, it's the best that can be done.
459 for (i = 0; i < lenW; i++)
460 if (textW[i] == '\0')
461 textW[i] = ' ';
462 textW[lenW] = '\0';
464 if (lenW >= 1 && textW[0] == 0xfeff)
465 SetWindowTextW(Globals.hEdit, textW+1);
466 else
467 SetWindowTextW(Globals.hEdit, textW);
469 HeapFree(GetProcessHeap(), 0, textW);
471 SendMessageW(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
472 SendMessageW(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
473 SetFocus(Globals.hEdit);
475 /* If the file starts with .LOG, add a time/date at the end and set cursor after */
476 if (GetWindowTextW(Globals.hEdit, log, ARRAY_SIZE(log)) && !lstrcmpW(log, dotlog))
478 static const WCHAR lfW[] = { '\r','\n',0 };
479 SendMessageW(Globals.hEdit, EM_SETSEL, GetWindowTextLengthW(Globals.hEdit), -1);
480 SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lfW);
481 DIALOG_EditTimeDate();
482 SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lfW);
485 SetFileNameAndEncoding(szFileName, enc);
486 UpdateWindowCaption();
489 VOID DIALOG_FileNew(VOID)
491 static const WCHAR empty_strW[] = { 0 };
493 /* Close any files and prompt to save changes */
494 if (DoCloseFile()) {
495 SetWindowTextW(Globals.hEdit, empty_strW);
496 SendMessageW(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
497 SetFocus(Globals.hEdit);
501 /* Used to detect encoding of files selected in Open dialog.
502 * Returns ENCODING_AUTO if file can't be read, etc.
504 static ENCODING detect_encoding_of_file(LPCWSTR szFileName)
506 DWORD size;
507 HANDLE hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
508 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
509 if (hFile == INVALID_HANDLE_VALUE)
510 return ENCODING_AUTO;
511 size = GetFileSize(hFile, NULL);
512 if (size == INVALID_FILE_SIZE)
514 CloseHandle(hFile);
515 return ENCODING_AUTO;
517 else
519 DWORD dwNumRead;
520 BYTE buffer[MAX_STRING_LEN];
521 if (!ReadFile(hFile, buffer, min(size, sizeof(buffer)), &dwNumRead, NULL))
523 CloseHandle(hFile);
524 return ENCODING_AUTO;
526 CloseHandle(hFile);
527 return detect_encoding_of_buffer(buffer, dwNumRead);
531 static LPWSTR dialog_print_to_file(HWND hMainWnd)
533 OPENFILENAMEW ofn;
534 static WCHAR file[MAX_PATH] = {'o','u','t','p','u','t','.','p','r','n',0};
535 static const WCHAR defExt[] = {'p','r','n',0};
537 ZeroMemory(&ofn, sizeof(ofn));
539 ofn.lStructSize = sizeof(ofn);
540 ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
541 ofn.hwndOwner = hMainWnd;
542 ofn.lpstrFile = file;
543 ofn.nMaxFile = MAX_PATH;
544 ofn.lpstrDefExt = defExt;
546 if(GetSaveFileNameW(&ofn))
547 return file;
548 else
549 return FALSE;
551 static UINT_PTR CALLBACK OfnHookProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
553 static HWND hEncCombo;
555 switch (uMsg)
557 case WM_INITDIALOG:
559 ENCODING enc;
560 hEncCombo = GetDlgItem(hdlg, IDC_OFN_ENCCOMBO);
561 for (enc = MIN_ENCODING; enc <= MAX_ENCODING; enc++)
563 WCHAR szEnc[MAX_STRING_LEN];
564 load_encoding_name(enc, szEnc, ARRAY_SIZE(szEnc));
565 SendMessageW(hEncCombo, CB_ADDSTRING, 0, (LPARAM)szEnc);
567 SendMessageW(hEncCombo, CB_SETCURSEL, (WPARAM)Globals.encOfnCombo, 0);
569 break;
571 case WM_COMMAND:
572 if (LOWORD(wParam) == IDC_OFN_ENCCOMBO &&
573 HIWORD(wParam) == CBN_SELCHANGE)
575 int index = SendMessageW(hEncCombo, CB_GETCURSEL, 0, 0);
576 Globals.encOfnCombo = index==CB_ERR ? ENCODING_ANSI : (ENCODING)index;
579 break;
581 case WM_NOTIFY:
582 switch (((OFNOTIFYW*)lParam)->hdr.code)
584 case CDN_SELCHANGE:
585 if (Globals.bOfnIsOpenDialog)
587 /* Check the start of the selected file for a BOM. */
588 ENCODING enc;
589 WCHAR szFileName[MAX_PATH];
590 SendMessageW(GetParent(hdlg), CDM_GETFILEPATH,
591 ARRAY_SIZE(szFileName), (LPARAM)szFileName);
592 enc = detect_encoding_of_file(szFileName);
593 if (enc != ENCODING_AUTO)
595 Globals.encOfnCombo = enc;
596 SendMessageW(hEncCombo, CB_SETCURSEL, (WPARAM)enc, 0);
599 break;
601 default:
602 break;
604 break;
606 default:
607 break;
609 return 0;
612 VOID DIALOG_FileOpen(VOID)
614 OPENFILENAMEW openfilename;
615 WCHAR szPath[MAX_PATH];
616 static const WCHAR szDefaultExt[] = { 't','x','t',0 };
617 static const WCHAR txt_files[] = { '*','.','t','x','t',0 };
619 ZeroMemory(&openfilename, sizeof(openfilename));
621 lstrcpyW(szPath, txt_files);
623 openfilename.lStructSize = sizeof(openfilename);
624 openfilename.hwndOwner = Globals.hMainWnd;
625 openfilename.hInstance = Globals.hInstance;
626 openfilename.lpstrFilter = Globals.szFilter;
627 openfilename.lpstrFile = szPath;
628 openfilename.nMaxFile = ARRAY_SIZE(szPath);
629 openfilename.Flags = OFN_ENABLETEMPLATE | OFN_ENABLEHOOK | OFN_EXPLORER |
630 OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST |
631 OFN_HIDEREADONLY | OFN_ENABLESIZING;
632 openfilename.lpfnHook = OfnHookProc;
633 openfilename.lpTemplateName = MAKEINTRESOURCEW(IDD_OFN_TEMPLATE);
634 openfilename.lpstrDefExt = szDefaultExt;
636 Globals.encOfnCombo = ENCODING_ANSI;
637 Globals.bOfnIsOpenDialog = TRUE;
639 if (GetOpenFileNameW(&openfilename))
640 DoOpenFile(openfilename.lpstrFile, Globals.encOfnCombo);
643 /* Return FALSE to cancel close */
644 BOOL DIALOG_FileSave(VOID)
646 if (Globals.szFileName[0] == '\0')
647 return DIALOG_FileSaveAs();
648 else
650 switch (DoSaveFile(Globals.szFileName, Globals.encFile))
652 case SAVED_OK: return TRUE;
653 case SHOW_SAVEAS_DIALOG: return DIALOG_FileSaveAs();
654 default: return FALSE;
659 BOOL DIALOG_FileSaveAs(VOID)
661 OPENFILENAMEW saveas;
662 WCHAR szPath[MAX_PATH];
663 static const WCHAR szDefaultExt[] = { 't','x','t',0 };
664 static const WCHAR txt_files[] = { '*','.','t','x','t',0 };
666 ZeroMemory(&saveas, sizeof(saveas));
668 lstrcpyW(szPath, txt_files);
670 saveas.lStructSize = sizeof(OPENFILENAMEW);
671 saveas.hwndOwner = Globals.hMainWnd;
672 saveas.hInstance = Globals.hInstance;
673 saveas.lpstrFilter = Globals.szFilter;
674 saveas.lpstrFile = szPath;
675 saveas.nMaxFile = ARRAY_SIZE(szPath);
676 saveas.Flags = OFN_ENABLETEMPLATE | OFN_ENABLEHOOK | OFN_EXPLORER |
677 OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT |
678 OFN_HIDEREADONLY | OFN_ENABLESIZING;
679 saveas.lpfnHook = OfnHookProc;
680 saveas.lpTemplateName = MAKEINTRESOURCEW(IDD_OFN_TEMPLATE);
681 saveas.lpstrDefExt = szDefaultExt;
683 /* Preset encoding to what file was opened/saved last with. */
684 Globals.encOfnCombo = Globals.encFile;
685 Globals.bOfnIsOpenDialog = FALSE;
687 retry:
688 if (!GetSaveFileNameW(&saveas))
689 return FALSE;
691 switch (DoSaveFile(szPath, Globals.encOfnCombo))
693 case SAVED_OK:
694 SetFileNameAndEncoding(szPath, Globals.encOfnCombo);
695 UpdateWindowCaption();
696 return TRUE;
698 case SHOW_SAVEAS_DIALOG:
699 goto retry;
701 default:
702 return FALSE;
706 typedef struct {
707 LPWSTR mptr;
708 LPWSTR mend;
709 LPWSTR lptr;
710 DWORD len;
711 } TEXTINFO, *LPTEXTINFO;
713 static int notepad_print_header(HDC hdc, RECT *rc, BOOL dopage, BOOL header, int page, LPWSTR text)
715 SIZE szMetric;
717 if (*text)
719 /* Write the header or footer */
720 GetTextExtentPoint32W(hdc, text, lstrlenW(text), &szMetric);
721 if (dopage)
722 ExtTextOutW(hdc, (rc->left + rc->right - szMetric.cx) / 2,
723 header ? rc->top : rc->bottom - szMetric.cy,
724 ETO_CLIPPED, rc, text, lstrlenW(text), NULL);
725 return 1;
727 return 0;
730 static WCHAR *expand_header_vars(WCHAR *pattern, int page)
732 int length = 0;
733 int i;
734 BOOL inside = FALSE;
735 WCHAR *buffer = NULL;
737 for (i = 0; pattern[i]; i++)
739 if (inside)
741 if (pattern[i] == '&')
742 length++;
743 else if (pattern[i] == 'p')
744 length += 11;
745 inside = FALSE;
747 else if (pattern[i] == '&')
748 inside = TRUE;
749 else
750 length++;
753 buffer = HeapAlloc(GetProcessHeap(), 0, (length + 1) * sizeof(WCHAR));
754 if (buffer)
756 int j = 0;
757 inside = FALSE;
758 for (i = 0; pattern[i]; i++)
760 if (inside)
762 if (pattern[i] == '&')
763 buffer[j++] = '&';
764 else if (pattern[i] == 'p')
766 static const WCHAR percent_dW[] = {'%','d',0};
767 j += wnsprintfW(&buffer[j], 11, percent_dW, page);
769 inside = FALSE;
771 else if (pattern[i] == '&')
772 inside = TRUE;
773 else
774 buffer[j++] = pattern[i];
776 buffer[j++] = 0;
778 return buffer;
781 static BOOL notepad_print_page(HDC hdc, RECT *rc, BOOL dopage, int page, LPTEXTINFO tInfo)
783 int b, y;
784 TEXTMETRICW tm;
785 SIZE szMetrics;
786 WCHAR *footer_text = NULL;
788 footer_text = expand_header_vars(Globals.szFooter, page);
789 if (footer_text == NULL)
790 return FALSE;
792 if (dopage)
794 if (StartPage(hdc) <= 0)
796 static const WCHAR failedW[] = { 'S','t','a','r','t','P','a','g','e',' ','f','a','i','l','e','d',0 };
797 static const WCHAR errorW[] = { 'P','r','i','n','t',' ','E','r','r','o','r',0 };
798 MessageBoxW(Globals.hMainWnd, failedW, errorW, MB_ICONEXCLAMATION);
799 HeapFree(GetProcessHeap(), 0, footer_text);
800 return FALSE;
804 GetTextMetricsW(hdc, &tm);
805 y = rc->top + notepad_print_header(hdc, rc, dopage, TRUE, page, Globals.szFileName) * tm.tmHeight;
806 b = rc->bottom - 2 * notepad_print_header(hdc, rc, FALSE, FALSE, page, footer_text) * tm.tmHeight;
808 do {
809 INT m, n;
811 if (!tInfo->len)
813 /* find the end of the line */
814 while (tInfo->mptr < tInfo->mend && *tInfo->mptr != '\n' && *tInfo->mptr != '\r')
816 if (*tInfo->mptr == '\t')
818 /* replace tabs with spaces */
819 for (m = 0; m < SPACES_IN_TAB; m++)
821 if (tInfo->len < PRINT_LEN_MAX)
822 tInfo->lptr[tInfo->len++] = ' ';
823 else if (Globals.bWrapLongLines)
824 break;
827 else if (tInfo->len < PRINT_LEN_MAX)
828 tInfo->lptr[tInfo->len++] = *tInfo->mptr;
830 if (tInfo->len >= PRINT_LEN_MAX && Globals.bWrapLongLines)
831 break;
833 tInfo->mptr++;
837 /* Find out how much we should print if line wrapping is enabled */
838 if (Globals.bWrapLongLines)
840 GetTextExtentExPointW(hdc, tInfo->lptr, tInfo->len, rc->right - rc->left, &n, NULL, &szMetrics);
841 if (n < tInfo->len && tInfo->lptr[n] != ' ')
843 m = n;
844 /* Don't wrap words unless it's a single word over the entire line */
845 while (m && tInfo->lptr[m] != ' ') m--;
846 if (m > 0) n = m + 1;
849 else
850 n = tInfo->len;
852 if (dopage)
853 ExtTextOutW(hdc, rc->left, y, ETO_CLIPPED, rc, tInfo->lptr, n, NULL);
855 tInfo->len -= n;
857 if (tInfo->len)
859 memcpy(tInfo->lptr, tInfo->lptr + n, tInfo->len * sizeof(WCHAR));
860 y += tm.tmHeight + tm.tmExternalLeading;
862 else
864 /* find the next line */
865 while (tInfo->mptr < tInfo->mend && y < b && (*tInfo->mptr == '\n' || *tInfo->mptr == '\r'))
867 if (*tInfo->mptr == '\n')
868 y += tm.tmHeight + tm.tmExternalLeading;
869 tInfo->mptr++;
872 } while (tInfo->mptr < tInfo->mend && y < b);
874 notepad_print_header(hdc, rc, dopage, FALSE, page, footer_text);
875 if (dopage)
877 EndPage(hdc);
879 HeapFree(GetProcessHeap(), 0, footer_text);
880 return TRUE;
883 VOID DIALOG_FilePrint(VOID)
885 DOCINFOW di;
886 PRINTDLGW printer;
887 int page, dopage, copy;
888 LOGFONTW lfFont;
889 HFONT hTextFont, old_font = 0;
890 DWORD size;
891 BOOL ret = FALSE;
892 RECT rc;
893 LPWSTR pTemp;
894 TEXTINFO tInfo;
895 WCHAR cTemp[PRINT_LEN_MAX];
897 /* Get Current Settings */
898 ZeroMemory(&printer, sizeof(printer));
899 printer.lStructSize = sizeof(printer);
900 printer.hwndOwner = Globals.hMainWnd;
901 printer.hDevMode = Globals.hDevMode;
902 printer.hDevNames = Globals.hDevNames;
903 printer.hInstance = Globals.hInstance;
905 /* Set some default flags */
906 printer.Flags = PD_RETURNDC | PD_NOSELECTION;
907 printer.nFromPage = 0;
908 printer.nMinPage = 1;
909 /* we really need to calculate number of pages to set nMaxPage and nToPage */
910 printer.nToPage = 0;
911 printer.nMaxPage = -1;
912 /* Let commdlg manage copy settings */
913 printer.nCopies = (WORD)PD_USEDEVMODECOPIES;
915 if (!PrintDlgW(&printer)) return;
917 Globals.hDevMode = printer.hDevMode;
918 Globals.hDevNames = printer.hDevNames;
920 SetMapMode(printer.hDC, MM_TEXT);
922 /* initialize DOCINFO */
923 di.cbSize = sizeof(DOCINFOW);
924 di.lpszDocName = Globals.szFileTitle;
925 di.lpszOutput = NULL;
926 di.lpszDatatype = NULL;
927 di.fwType = 0;
929 if(printer.Flags & PD_PRINTTOFILE)
931 di.lpszOutput = dialog_print_to_file(printer.hwndOwner);
932 if(!di.lpszOutput)
933 return;
936 /* Get the file text */
937 size = GetWindowTextLengthW(Globals.hEdit) + 1;
938 pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
939 if (!pTemp)
941 DeleteDC(printer.hDC);
942 ShowLastError();
943 return;
945 size = GetWindowTextW(Globals.hEdit, pTemp, size);
947 if (StartDocW(printer.hDC, &di) > 0)
949 /* Get the page margins in pixels. */
950 rc.top = MulDiv(Globals.iMarginTop, GetDeviceCaps(printer.hDC, LOGPIXELSY), 2540) -
951 GetDeviceCaps(printer.hDC, PHYSICALOFFSETY);
952 rc.bottom = GetDeviceCaps(printer.hDC, PHYSICALHEIGHT) -
953 MulDiv(Globals.iMarginBottom, GetDeviceCaps(printer.hDC, LOGPIXELSY), 2540);
954 rc.left = MulDiv(Globals.iMarginLeft, GetDeviceCaps(printer.hDC, LOGPIXELSX), 2540) -
955 GetDeviceCaps(printer.hDC, PHYSICALOFFSETX);
956 rc.right = GetDeviceCaps(printer.hDC, PHYSICALWIDTH) -
957 MulDiv(Globals.iMarginRight, GetDeviceCaps(printer.hDC, LOGPIXELSX), 2540);
959 /* Create a font for the printer resolution */
960 lfFont = Globals.lfFont;
961 lfFont.lfHeight = MulDiv(lfFont.lfHeight, GetDeviceCaps(printer.hDC, LOGPIXELSY), GetDpiForWindow(Globals.hMainWnd));
962 /* Make the font a bit lighter */
963 lfFont.lfWeight -= 100;
964 hTextFont = CreateFontIndirectW(&lfFont);
965 old_font = SelectObject(printer.hDC, hTextFont);
967 for (copy = 1; copy <= printer.nCopies; copy++)
969 page = 1;
971 tInfo.mptr = pTemp;
972 tInfo.mend = pTemp + size;
973 tInfo.lptr = cTemp;
974 tInfo.len = 0;
976 do {
977 if (printer.Flags & PD_PAGENUMS)
979 /* a specific range of pages is selected, so
980 * skip pages that are not to be printed
982 if (page > printer.nToPage)
983 break;
984 else if (page >= printer.nFromPage)
985 dopage = 1;
986 else
987 dopage = 0;
989 else
990 dopage = 1;
992 ret = notepad_print_page(printer.hDC, &rc, dopage, page, &tInfo);
993 page++;
994 } while (ret && tInfo.mptr < tInfo.mend);
996 if (!ret) break;
998 EndDoc(printer.hDC);
999 SelectObject(printer.hDC, old_font);
1000 DeleteObject(hTextFont);
1002 DeleteDC(printer.hDC);
1003 HeapFree(GetProcessHeap(), 0, pTemp);
1006 VOID DIALOG_FilePrinterSetup(VOID)
1008 PRINTDLGW printer;
1010 ZeroMemory(&printer, sizeof(printer));
1011 printer.lStructSize = sizeof(printer);
1012 printer.hwndOwner = Globals.hMainWnd;
1013 printer.hDevMode = Globals.hDevMode;
1014 printer.hDevNames = Globals.hDevNames;
1015 printer.hInstance = Globals.hInstance;
1016 printer.Flags = PD_PRINTSETUP;
1017 printer.nCopies = 1;
1019 PrintDlgW(&printer);
1021 Globals.hDevMode = printer.hDevMode;
1022 Globals.hDevNames = printer.hDevNames;
1025 VOID DIALOG_FileExit(VOID)
1027 PostMessageW(Globals.hMainWnd, WM_CLOSE, 0, 0l);
1030 VOID DIALOG_EditUndo(VOID)
1032 SendMessageW(Globals.hEdit, EM_UNDO, 0, 0);
1035 VOID DIALOG_EditCut(VOID)
1037 SendMessageW(Globals.hEdit, WM_CUT, 0, 0);
1040 VOID DIALOG_EditCopy(VOID)
1042 SendMessageW(Globals.hEdit, WM_COPY, 0, 0);
1045 VOID DIALOG_EditPaste(VOID)
1047 SendMessageW(Globals.hEdit, WM_PASTE, 0, 0);
1050 VOID DIALOG_EditDelete(VOID)
1052 SendMessageW(Globals.hEdit, WM_CLEAR, 0, 0);
1055 VOID DIALOG_EditSelectAll(VOID)
1057 SendMessageW(Globals.hEdit, EM_SETSEL, 0, -1);
1060 VOID DIALOG_EditTimeDate(VOID)
1062 SYSTEMTIME st;
1063 WCHAR szDate[MAX_STRING_LEN];
1064 static const WCHAR spaceW[] = { ' ',0 };
1066 GetLocalTime(&st);
1068 GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, szDate, MAX_STRING_LEN);
1069 SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)szDate);
1071 SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)spaceW);
1073 GetDateFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, szDate, MAX_STRING_LEN);
1074 SendMessageW(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)szDate);
1077 VOID DIALOG_EditWrap(VOID)
1079 BOOL modify = FALSE;
1080 static const WCHAR editW[] = { 'e','d','i','t',0 };
1081 DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL |
1082 ES_AUTOVSCROLL | ES_MULTILINE;
1083 RECT rc;
1084 DWORD size;
1085 LPWSTR pTemp;
1087 size = GetWindowTextLengthW(Globals.hEdit) + 1;
1088 pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
1089 if (!pTemp)
1091 ShowLastError();
1092 return;
1094 GetWindowTextW(Globals.hEdit, pTemp, size);
1095 modify = SendMessageW(Globals.hEdit, EM_GETMODIFY, 0, 0);
1096 DestroyWindow(Globals.hEdit);
1097 GetClientRect(Globals.hMainWnd, &rc);
1098 if( Globals.bWrapLongLines ) dwStyle |= WS_HSCROLL | ES_AUTOHSCROLL;
1099 Globals.hEdit = CreateWindowExW(WS_EX_CLIENTEDGE, editW, NULL, dwStyle,
1100 0, 0, rc.right, rc.bottom, Globals.hMainWnd,
1101 NULL, Globals.hInstance, NULL);
1102 SendMessageW(Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, FALSE);
1103 SetWindowTextW(Globals.hEdit, pTemp);
1104 SendMessageW(Globals.hEdit, EM_SETMODIFY, modify, 0);
1105 SetFocus(Globals.hEdit);
1106 HeapFree(GetProcessHeap(), 0, pTemp);
1108 Globals.bWrapLongLines = !Globals.bWrapLongLines;
1109 CheckMenuItem(GetMenu(Globals.hMainWnd), CMD_WRAP,
1110 MF_BYCOMMAND | (Globals.bWrapLongLines ? MF_CHECKED : MF_UNCHECKED));
1111 SetWindowSubclass(Globals.hEdit, EDIT_CallBackProc, 0, 0);
1112 updateWindowSize(rc.right, rc.bottom);
1115 VOID DIALOG_SelectFont(VOID)
1117 CHOOSEFONTW cf;
1118 LOGFONTW lf=Globals.lfFont;
1120 ZeroMemory( &cf, sizeof(cf) );
1121 cf.lStructSize=sizeof(cf);
1122 cf.hwndOwner=Globals.hMainWnd;
1123 cf.lpLogFont=&lf;
1124 cf.Flags=CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT | CF_NOVERTFONTS;
1126 if( ChooseFontW(&cf) )
1128 HFONT currfont=Globals.hFont;
1130 Globals.hFont=CreateFontIndirectW( &lf );
1131 Globals.lfFont=lf;
1132 SendMessageW( Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, TRUE );
1133 if( currfont!=NULL )
1134 DeleteObject( currfont );
1138 VOID DIALOG_Search(VOID)
1140 /* Allow only one search/replace dialog to open */
1141 if(Globals.hFindReplaceDlg != NULL)
1143 SetActiveWindow(Globals.hFindReplaceDlg);
1144 return;
1147 ZeroMemory(&Globals.find, sizeof(Globals.find));
1148 Globals.find.lStructSize = sizeof(Globals.find);
1149 Globals.find.hwndOwner = Globals.hMainWnd;
1150 Globals.find.hInstance = Globals.hInstance;
1151 Globals.find.lpstrFindWhat = Globals.szFindText;
1152 Globals.find.wFindWhatLen = ARRAY_SIZE(Globals.szFindText);
1153 Globals.find.Flags = FR_DOWN|FR_HIDEWHOLEWORD;
1155 /* We only need to create the modal FindReplace dialog which will */
1156 /* notify us of incoming events using hMainWnd Window Messages */
1158 Globals.hFindReplaceDlg = FindTextW(&Globals.find);
1159 assert(Globals.hFindReplaceDlg !=0);
1162 VOID DIALOG_SearchNext(VOID)
1164 if (Globals.lastFind.lpstrFindWhat == NULL)
1165 DIALOG_Search();
1166 else /* use the last find data */
1167 NOTEPAD_DoFind(&Globals.lastFind);
1170 VOID DIALOG_Replace(VOID)
1172 /* Allow only one search/replace dialog to open */
1173 if(Globals.hFindReplaceDlg != NULL)
1175 SetActiveWindow(Globals.hFindReplaceDlg);
1176 return;
1179 ZeroMemory(&Globals.find, sizeof(Globals.find));
1180 Globals.find.lStructSize = sizeof(Globals.find);
1181 Globals.find.hwndOwner = Globals.hMainWnd;
1182 Globals.find.hInstance = Globals.hInstance;
1183 Globals.find.lpstrFindWhat = Globals.szFindText;
1184 Globals.find.wFindWhatLen = ARRAY_SIZE(Globals.szFindText);
1185 Globals.find.lpstrReplaceWith = Globals.szReplaceText;
1186 Globals.find.wReplaceWithLen = ARRAY_SIZE(Globals.szReplaceText);
1187 Globals.find.Flags = FR_DOWN|FR_HIDEWHOLEWORD;
1189 /* We only need to create the modal FindReplace dialog which will */
1190 /* notify us of incoming events using hMainWnd Window Messages */
1192 Globals.hFindReplaceDlg = ReplaceTextW(&Globals.find);
1193 assert(Globals.hFindReplaceDlg !=0);
1196 VOID DIALOG_HelpContents(VOID)
1198 WinHelpW(Globals.hMainWnd, helpfileW, HELP_INDEX, 0);
1201 VOID DIALOG_HelpAboutNotepad(VOID)
1203 static const WCHAR notepadW[] = { 'W','i','n','e',' ','N','o','t','e','p','a','d',0 };
1204 WCHAR szNotepad[MAX_STRING_LEN];
1205 HICON icon = LoadImageW(Globals.hInstance, MAKEINTRESOURCEW(IDI_NOTEPAD),
1206 IMAGE_ICON, 48, 48, LR_SHARED);
1208 LoadStringW(Globals.hInstance, STRING_NOTEPAD, szNotepad, ARRAY_SIZE(szNotepad));
1209 ShellAboutW(Globals.hMainWnd, szNotepad, notepadW, icon);
1213 /***********************************************************************
1215 * DIALOG_FilePageSetup
1217 VOID DIALOG_FilePageSetup(void)
1219 DialogBoxW(Globals.hInstance, MAKEINTRESOURCEW(DIALOG_PAGESETUP),
1220 Globals.hMainWnd, DIALOG_PAGESETUP_DlgProc);
1224 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1226 * DIALOG_PAGESETUP_DlgProc
1229 static INT_PTR WINAPI DIALOG_PAGESETUP_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
1232 switch (msg)
1234 case WM_COMMAND:
1235 switch (wParam)
1237 case IDOK:
1238 /* save user input and close dialog */
1239 GetDlgItemTextW(hDlg, IDC_PAGESETUP_HEADERVALUE, Globals.szHeader, ARRAY_SIZE(Globals.szHeader));
1240 GetDlgItemTextW(hDlg, IDC_PAGESETUP_FOOTERVALUE, Globals.szFooter, ARRAY_SIZE(Globals.szFooter));
1242 Globals.iMarginTop = GetDlgItemInt(hDlg, IDC_PAGESETUP_TOPVALUE, NULL, FALSE) * 100;
1243 Globals.iMarginBottom = GetDlgItemInt(hDlg, IDC_PAGESETUP_BOTTOMVALUE, NULL, FALSE) * 100;
1244 Globals.iMarginLeft = GetDlgItemInt(hDlg, IDC_PAGESETUP_LEFTVALUE, NULL, FALSE) * 100;
1245 Globals.iMarginRight = GetDlgItemInt(hDlg, IDC_PAGESETUP_RIGHTVALUE, NULL, FALSE) * 100;
1246 EndDialog(hDlg, IDOK);
1247 return TRUE;
1249 case IDCANCEL:
1250 /* discard user input and close dialog */
1251 EndDialog(hDlg, IDCANCEL);
1252 return TRUE;
1254 case IDHELP:
1256 /* FIXME: Bring this to work */
1257 static const WCHAR sorryW[] = { 'S','o','r','r','y',',',' ','n','o',' ','h','e','l','p',' ','a','v','a','i','l','a','b','l','e',0 };
1258 static const WCHAR helpW[] = { 'H','e','l','p',0 };
1259 MessageBoxW(Globals.hMainWnd, sorryW, helpW, MB_ICONEXCLAMATION);
1260 return TRUE;
1263 default:
1264 break;
1266 break;
1268 case WM_INITDIALOG:
1269 /* fetch last user input prior to display dialog */
1270 SetDlgItemTextW(hDlg, IDC_PAGESETUP_HEADERVALUE, Globals.szHeader);
1271 SetDlgItemTextW(hDlg, IDC_PAGESETUP_FOOTERVALUE, Globals.szFooter);
1272 SetDlgItemInt(hDlg, IDC_PAGESETUP_TOPVALUE, Globals.iMarginTop / 100, FALSE);
1273 SetDlgItemInt(hDlg, IDC_PAGESETUP_BOTTOMVALUE, Globals.iMarginBottom / 100, FALSE);
1274 SetDlgItemInt(hDlg, IDC_PAGESETUP_LEFTVALUE, Globals.iMarginLeft / 100, FALSE);
1275 SetDlgItemInt(hDlg, IDC_PAGESETUP_RIGHTVALUE, Globals.iMarginRight / 100, FALSE);
1276 break;
1279 return FALSE;
1282 static INT_PTR WINAPI DIALOG_GOTO_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
1284 switch(msg)
1286 case WM_COMMAND:
1288 switch (wParam)
1290 case IDOK:
1292 int lineValue = GetDlgItemInt(hDlg, IDC_GOTO_LINEVALUE, NULL, FALSE) - 1;
1293 long lineIndex = SendMessageW(Globals.hEdit, EM_LINEINDEX, lineValue, 0);
1295 SendMessageW(Globals.hEdit, EM_SETSEL, lineIndex, lineIndex);
1296 UpdateStatusBar();
1297 EndDialog(hDlg, IDOK);
1298 return TRUE;
1300 case IDCANCEL:
1302 EndDialog(hDlg, IDCANCEL);
1303 return TRUE;
1305 default:
1307 break;
1310 break;
1312 case WM_INITDIALOG:
1314 int currentLine = SendMessageW(Globals.hEdit, EM_LINEFROMCHAR, -1, 0) + 1;
1315 SetDlgItemInt(hDlg, IDC_GOTO_LINEVALUE, currentLine, FALSE);
1316 break;
1319 return FALSE;
1322 void DIALOG_EditGoTo(void)
1324 DialogBoxW(Globals.hInstance, MAKEINTRESOURCEW(DIALOG_GOTO),
1325 Globals.hMainWnd, DIALOG_GOTO_DlgProc);