2 * PROJECT: ReactOS Notepad
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Providing a Windows-compatible simple text editor for ReactOS
5 * COPYRIGHT: Copyright 1998,99 Marcel Baur <mbaur@g26.ethz.ch>
6 * Copyright 2002 Sylvain Petreolle <spetreolle@yahoo.fr>
7 * Copyright 2002 Andriy Palamarchuk
8 * Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
17 LRESULT CALLBACK
EDIT_WndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
19 static const TCHAR helpfile
[] = _T("notepad.hlp");
20 static const TCHAR empty_str
[] = _T("");
21 static const TCHAR szDefaultExt
[] = _T("txt");
22 static const TCHAR txt_files
[] = _T("*.txt");
24 /* Status bar parts index */
25 #define SBPART_CURPOS 0
27 #define SBPART_ENCODING 2
29 /* Line endings - string resource ID mapping table */
30 static UINT EolnToStrId
[] = {
36 /* Encoding - string resource ID mapping table */
37 static UINT EncToStrId
[] = {
45 VOID
ShowLastError(VOID
)
47 DWORD error
= GetLastError();
48 if (error
!= NO_ERROR
)
50 LPTSTR lpMsgBuf
= NULL
;
51 TCHAR szTitle
[MAX_STRING_LEN
];
53 LoadString(Globals
.hInstance
, STRING_ERROR
, szTitle
, _countof(szTitle
));
55 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
63 MessageBox(Globals
.hMainWnd
, lpMsgBuf
, szTitle
, MB_OK
| MB_ICONERROR
);
69 * Sets the caption of the main window according to Globals.szFileTitle:
70 * (untitled) - Notepad if no file is open
71 * [filename] - Notepad if a file is given
73 void UpdateWindowCaption(BOOL clearModifyAlert
)
75 TCHAR szCaption
[MAX_STRING_LEN
];
76 TCHAR szNotepad
[MAX_STRING_LEN
];
77 TCHAR szFilename
[MAX_STRING_LEN
];
82 /* When a file is being opened or created, there is no need to have
83 * the edited flag shown when the file has not been edited yet. */
88 /* Check whether the user has modified the file or not. If we are
89 * in the same state as before, don't change the caption. */
90 isModified
= !!SendMessage(Globals
.hEdit
, EM_GETMODIFY
, 0, 0);
91 if (isModified
== Globals
.bWasModified
)
95 /* Remember the state for later calls */
96 Globals
.bWasModified
= isModified
;
98 /* Load the name of the application */
99 LoadString(Globals
.hInstance
, STRING_NOTEPAD
, szNotepad
, _countof(szNotepad
));
101 /* Determine if the file has been saved or if this is a new file */
102 if (Globals
.szFileTitle
[0] != 0)
103 StringCchCopy(szFilename
, _countof(szFilename
), Globals
.szFileTitle
);
105 LoadString(Globals
.hInstance
, STRING_UNTITLED
, szFilename
, _countof(szFilename
));
107 /* Update the window caption based upon whether the user has modified the file or not */
108 StringCbPrintf(szCaption
, sizeof(szCaption
), _T("%s%s - %s"),
109 (isModified
? _T("*") : _T("")), szFilename
, szNotepad
);
111 SetWindowText(Globals
.hMainWnd
, szCaption
);
114 VOID
WaitCursor(BOOL bBegin
)
116 static HCURSOR s_hWaitCursor
= NULL
;
117 static HCURSOR s_hOldCursor
= NULL
;
118 static INT s_nLock
= 0;
124 if (s_hWaitCursor
== NULL
)
125 s_hWaitCursor
= LoadCursor(NULL
, IDC_WAIT
);
126 s_hOldCursor
= SetCursor(s_hWaitCursor
);
130 SetCursor(s_hWaitCursor
);
136 SetCursor(s_hOldCursor
);
141 VOID
DIALOG_StatusBarAlignParts(VOID
)
143 static const int defaultWidths
[] = {120, 120, 120};
147 GetClientRect(Globals
.hStatusBar
, &rcStatusBar
);
149 parts
[0] = rcStatusBar
.right
- (defaultWidths
[1] + defaultWidths
[2]);
150 parts
[1] = rcStatusBar
.right
- defaultWidths
[2];
151 parts
[2] = -1; // the right edge of the status bar
153 parts
[0] = max(parts
[0], defaultWidths
[0]);
154 parts
[1] = max(parts
[1], defaultWidths
[0] + defaultWidths
[1]);
156 SendMessageW(Globals
.hStatusBar
, SB_SETPARTS
, _countof(parts
), (LPARAM
)parts
);
159 static VOID
DIALOG_StatusBarUpdateLineEndings(VOID
)
163 LoadStringW(Globals
.hInstance
, EolnToStrId
[Globals
.iEoln
], szText
, _countof(szText
));
165 SendMessageW(Globals
.hStatusBar
, SB_SETTEXTW
, SBPART_EOLN
, (LPARAM
)szText
);
168 static VOID
DIALOG_StatusBarUpdateEncoding(VOID
)
170 WCHAR szText
[128] = L
"";
172 if (Globals
.encFile
!= ENCODING_AUTO
)
174 LoadStringW(Globals
.hInstance
, EncToStrId
[Globals
.encFile
], szText
, _countof(szText
));
177 SendMessageW(Globals
.hStatusBar
, SB_SETTEXTW
, SBPART_ENCODING
, (LPARAM
)szText
);
180 static VOID
DIALOG_StatusBarUpdateAll(VOID
)
182 DIALOG_StatusBarUpdateCaretPos();
183 DIALOG_StatusBarUpdateLineEndings();
184 DIALOG_StatusBarUpdateEncoding();
187 int DIALOG_StringMsgBox(HWND hParent
, int formatId
, LPCTSTR szString
, DWORD dwFlags
)
189 TCHAR szMessage
[MAX_STRING_LEN
];
190 TCHAR szResource
[MAX_STRING_LEN
];
192 /* Load and format szMessage */
193 LoadString(Globals
.hInstance
, formatId
, szResource
, _countof(szResource
));
194 StringCchPrintf(szMessage
, _countof(szMessage
), szResource
, szString
);
197 if ((dwFlags
& MB_ICONMASK
) == MB_ICONEXCLAMATION
)
198 LoadString(Globals
.hInstance
, STRING_ERROR
, szResource
, _countof(szResource
));
200 LoadString(Globals
.hInstance
, STRING_NOTEPAD
, szResource
, _countof(szResource
));
202 /* Display Modal Dialog */
203 // if (hParent == NULL)
204 // hParent = Globals.hMainWnd;
205 return MessageBox(hParent
, szMessage
, szResource
, dwFlags
);
208 static void AlertFileNotFound(LPCTSTR szFileName
)
210 DIALOG_StringMsgBox(Globals
.hMainWnd
, STRING_NOTFOUND
, szFileName
, MB_ICONEXCLAMATION
| MB_OK
);
213 static int AlertFileNotSaved(LPCTSTR szFileName
)
215 TCHAR szUntitled
[MAX_STRING_LEN
];
217 LoadString(Globals
.hInstance
, STRING_UNTITLED
, szUntitled
, _countof(szUntitled
));
219 return DIALOG_StringMsgBox(Globals
.hMainWnd
, STRING_NOTSAVED
,
220 szFileName
[0] ? szFileName
: szUntitled
,
221 MB_ICONQUESTION
| MB_YESNOCANCEL
);
226 * TRUE - if file exists
227 * FALSE - if file does not exist
229 BOOL
FileExists(LPCTSTR szFilename
)
231 return GetFileAttributes(szFilename
) != INVALID_FILE_ATTRIBUTES
;
234 BOOL
HasFileExtension(LPCTSTR szFilename
)
238 s
= _tcsrchr(szFilename
, _T('\\'));
241 return _tcsrchr(szFilename
, _T('.')) != NULL
;
244 static BOOL
DoSaveFile(VOID
)
252 hFile
= CreateFileW(Globals
.szFileName
, GENERIC_WRITE
, FILE_SHARE_WRITE
,
253 NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
254 if (hFile
== INVALID_HANDLE_VALUE
)
261 cchText
= GetWindowTextLengthW(Globals
.hEdit
);
268 HLOCAL hLocal
= (HLOCAL
)SendMessageW(Globals
.hEdit
, EM_GETHANDLE
, 0, 0);
269 LPWSTR pszText
= LocalLock(hLocal
);
272 bRet
= WriteText(hFile
, pszText
, cchText
, Globals
.encFile
, Globals
.iEoln
);
288 SendMessage(Globals
.hEdit
, EM_SETMODIFY
, FALSE
, 0);
289 SetFileName(Globals
.szFileName
);
298 * TRUE - User agreed to close (both save/don't save)
299 * FALSE - User cancelled close by selecting "Cancel"
301 BOOL
DoCloseFile(VOID
)
305 if (SendMessage(Globals
.hEdit
, EM_GETMODIFY
, 0, 0))
307 /* prompt user to save changes */
308 nResult
= AlertFileNotSaved(Globals
.szFileName
);
312 if(!DIALOG_FileSave())
325 SetFileName(empty_str
);
326 UpdateWindowCaption(TRUE
);
331 VOID
DoOpenFile(LPCTSTR szFileName
)
337 /* Close any files and prompt to save changes */
343 hFile
= CreateFile(szFileName
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
344 OPEN_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
345 if (hFile
== INVALID_HANDLE_VALUE
)
351 /* To make loading file quicker, we use the internal handle of EDIT control */
352 hLocal
= (HLOCAL
)SendMessageW(Globals
.hEdit
, EM_GETHANDLE
, 0, 0);
353 if (!ReadText(hFile
, &hLocal
, &Globals
.encFile
, &Globals
.iEoln
))
358 SendMessageW(Globals
.hEdit
, EM_SETHANDLE
, (WPARAM
)hLocal
, 0);
359 /* No need of EM_SETMODIFY and EM_EMPTYUNDOBUFFER here. EM_SETHANDLE does instead. */
361 SetFocus(Globals
.hEdit
);
363 /* If the file starts with .LOG, add a time/date at the end and set cursor after
364 * See http://web.archive.org/web/20090627165105/http://support.microsoft.com/kb/260563
366 if (GetWindowText(Globals
.hEdit
, log
, _countof(log
)) && !_tcscmp(log
, _T(".LOG")))
368 static const TCHAR lf
[] = _T("\r\n");
369 SendMessage(Globals
.hEdit
, EM_SETSEL
, GetWindowTextLength(Globals
.hEdit
), -1);
370 SendMessage(Globals
.hEdit
, EM_REPLACESEL
, TRUE
, (LPARAM
)lf
);
371 DIALOG_EditTimeDate();
372 SendMessage(Globals
.hEdit
, EM_REPLACESEL
, TRUE
, (LPARAM
)lf
);
375 SetFileName(szFileName
);
376 UpdateWindowCaption(TRUE
);
377 NOTEPAD_EnableSearchMenu();
378 DIALOG_StatusBarUpdateAll();
381 if (hFile
!= INVALID_HANDLE_VALUE
)
386 VOID
DIALOG_FileNew(VOID
)
388 /* Close any files and prompt to save changes */
394 SetWindowText(Globals
.hEdit
, NULL
);
395 SendMessage(Globals
.hEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
396 Globals
.iEoln
= EOLN_CRLF
;
397 Globals
.encFile
= ENCODING_DEFAULT
;
399 NOTEPAD_EnableSearchMenu();
400 DIALOG_StatusBarUpdateAll();
405 VOID
DIALOG_FileNewWindow(VOID
)
407 TCHAR pszNotepadExe
[MAX_PATH
];
411 GetModuleFileName(NULL
, pszNotepadExe
, _countof(pszNotepadExe
));
412 ShellExecute(NULL
, NULL
, pszNotepadExe
, NULL
, NULL
, SW_SHOWNORMAL
);
417 VOID
DIALOG_FileOpen(VOID
)
419 OPENFILENAME openfilename
;
420 TCHAR szPath
[MAX_PATH
];
422 ZeroMemory(&openfilename
, sizeof(openfilename
));
424 if (Globals
.szFileName
[0] == 0)
425 _tcscpy(szPath
, txt_files
);
427 _tcscpy(szPath
, Globals
.szFileName
);
429 openfilename
.lStructSize
= sizeof(openfilename
);
430 openfilename
.hwndOwner
= Globals
.hMainWnd
;
431 openfilename
.hInstance
= Globals
.hInstance
;
432 openfilename
.lpstrFilter
= Globals
.szFilter
;
433 openfilename
.lpstrFile
= szPath
;
434 openfilename
.nMaxFile
= _countof(szPath
);
435 openfilename
.Flags
= OFN_EXPLORER
| OFN_FILEMUSTEXIST
| OFN_PATHMUSTEXIST
| OFN_HIDEREADONLY
;
436 openfilename
.lpstrDefExt
= szDefaultExt
;
438 if (GetOpenFileName(&openfilename
)) {
439 if (FileExists(openfilename
.lpstrFile
))
440 DoOpenFile(openfilename
.lpstrFile
);
442 AlertFileNotFound(openfilename
.lpstrFile
);
446 BOOL
DIALOG_FileSave(VOID
)
448 if (Globals
.szFileName
[0] == 0)
450 return DIALOG_FileSaveAs();
452 else if (DoSaveFile())
454 UpdateWindowCaption(TRUE
);
462 DIALOG_FileSaveAs_Hook(HWND hDlg
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
467 UNREFERENCED_PARAMETER(wParam
);
472 hCombo
= GetDlgItem(hDlg
, ID_ENCODING
);
474 LoadString(Globals
.hInstance
, STRING_ANSI
, szText
, _countof(szText
));
475 SendMessage(hCombo
, CB_ADDSTRING
, 0, (LPARAM
) szText
);
477 LoadString(Globals
.hInstance
, STRING_UNICODE
, szText
, _countof(szText
));
478 SendMessage(hCombo
, CB_ADDSTRING
, 0, (LPARAM
) szText
);
480 LoadString(Globals
.hInstance
, STRING_UNICODE_BE
, szText
, _countof(szText
));
481 SendMessage(hCombo
, CB_ADDSTRING
, 0, (LPARAM
) szText
);
483 LoadString(Globals
.hInstance
, STRING_UTF8
, szText
, _countof(szText
));
484 SendMessage(hCombo
, CB_ADDSTRING
, 0, (LPARAM
) szText
);
486 LoadString(Globals
.hInstance
, STRING_UTF8_BOM
, szText
, _countof(szText
));
487 SendMessage(hCombo
, CB_ADDSTRING
, 0, (LPARAM
) szText
);
489 SendMessage(hCombo
, CB_SETCURSEL
, Globals
.encFile
, 0);
491 hCombo
= GetDlgItem(hDlg
, ID_EOLN
);
493 LoadString(Globals
.hInstance
, STRING_CRLF
, szText
, _countof(szText
));
494 SendMessage(hCombo
, CB_ADDSTRING
, 0, (LPARAM
) szText
);
496 LoadString(Globals
.hInstance
, STRING_LF
, szText
, _countof(szText
));
497 SendMessage(hCombo
, CB_ADDSTRING
, 0, (LPARAM
) szText
);
499 LoadString(Globals
.hInstance
, STRING_CR
, szText
, _countof(szText
));
500 SendMessage(hCombo
, CB_ADDSTRING
, 0, (LPARAM
) szText
);
502 SendMessage(hCombo
, CB_SETCURSEL
, Globals
.iEoln
, 0);
506 if (((NMHDR
*) lParam
)->code
== CDN_FILEOK
)
508 hCombo
= GetDlgItem(hDlg
, ID_ENCODING
);
510 Globals
.encFile
= (ENCODING
) SendMessage(hCombo
, CB_GETCURSEL
, 0, 0);
512 hCombo
= GetDlgItem(hDlg
, ID_EOLN
);
514 Globals
.iEoln
= (EOLN
)SendMessage(hCombo
, CB_GETCURSEL
, 0, 0);
521 BOOL
DIALOG_FileSaveAs(VOID
)
524 TCHAR szPath
[MAX_PATH
];
526 ZeroMemory(&saveas
, sizeof(saveas
));
528 if (Globals
.szFileName
[0] == 0)
529 _tcscpy(szPath
, txt_files
);
531 _tcscpy(szPath
, Globals
.szFileName
);
533 saveas
.lStructSize
= sizeof(OPENFILENAME
);
534 saveas
.hwndOwner
= Globals
.hMainWnd
;
535 saveas
.hInstance
= Globals
.hInstance
;
536 saveas
.lpstrFilter
= Globals
.szFilter
;
537 saveas
.lpstrFile
= szPath
;
538 saveas
.nMaxFile
= _countof(szPath
);
539 saveas
.Flags
= OFN_PATHMUSTEXIST
| OFN_OVERWRITEPROMPT
| OFN_HIDEREADONLY
|
540 OFN_EXPLORER
| OFN_ENABLETEMPLATE
| OFN_ENABLEHOOK
;
541 saveas
.lpstrDefExt
= szDefaultExt
;
542 saveas
.lpTemplateName
= MAKEINTRESOURCE(DIALOG_ENCODING
);
543 saveas
.lpfnHook
= DIALOG_FileSaveAs_Hook
;
545 if (GetSaveFileName(&saveas
))
547 /* HACK: Because in ROS, Save-As boxes don't check the validity
548 * of file names and thus, here, szPath can be invalid !! We only
549 * see its validity when we call DoSaveFile()... */
553 UpdateWindowCaption(TRUE
);
554 DIALOG_StatusBarUpdateAll();
569 VOID
DIALOG_FileExit(VOID
)
571 PostMessage(Globals
.hMainWnd
, WM_CLOSE
, 0, 0);
574 VOID
DIALOG_EditUndo(VOID
)
576 SendMessage(Globals
.hEdit
, EM_UNDO
, 0, 0);
579 VOID
DIALOG_EditCut(VOID
)
581 SendMessage(Globals
.hEdit
, WM_CUT
, 0, 0);
584 VOID
DIALOG_EditCopy(VOID
)
586 SendMessage(Globals
.hEdit
, WM_COPY
, 0, 0);
589 VOID
DIALOG_EditPaste(VOID
)
591 SendMessage(Globals
.hEdit
, WM_PASTE
, 0, 0);
594 VOID
DIALOG_EditDelete(VOID
)
596 SendMessage(Globals
.hEdit
, WM_CLEAR
, 0, 0);
599 VOID
DIALOG_EditSelectAll(VOID
)
601 SendMessage(Globals
.hEdit
, EM_SETSEL
, 0, -1);
604 VOID
DIALOG_EditTimeDate(VOID
)
607 TCHAR szDate
[MAX_STRING_LEN
];
608 TCHAR szText
[MAX_STRING_LEN
* 2 + 2];
612 GetTimeFormat(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, szDate
, MAX_STRING_LEN
);
613 _tcscpy(szText
, szDate
);
614 _tcscat(szText
, _T(" "));
615 GetDateFormat(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, szDate
, MAX_STRING_LEN
);
616 _tcscat(szText
, szDate
);
617 SendMessage(Globals
.hEdit
, EM_REPLACESEL
, TRUE
, (LPARAM
)szText
);
620 VOID
DoShowHideStatusBar(VOID
)
622 /* Check if status bar object already exists. */
623 if (Globals
.bShowStatusBar
&& Globals
.hStatusBar
== NULL
)
625 /* Try to create the status bar */
626 Globals
.hStatusBar
= CreateStatusWindow(WS_CHILD
| CCS_BOTTOM
| SBARS_SIZEGRIP
,
629 CMD_STATUSBAR_WND_ID
);
631 if (Globals
.hStatusBar
== NULL
)
637 /* Load the string for formatting column/row text output */
638 LoadString(Globals
.hInstance
, STRING_LINE_COLUMN
, Globals
.szStatusBarLineCol
, MAX_PATH
- 1);
641 /* Update layout of controls */
642 SendMessageW(Globals
.hMainWnd
, WM_SIZE
, 0, 0);
644 if (Globals
.hStatusBar
== NULL
)
647 /* Update visibility of status bar */
648 ShowWindow(Globals
.hStatusBar
, (Globals
.bShowStatusBar
? SW_SHOWNOACTIVATE
: SW_HIDE
));
650 /* Update status bar contents */
651 DIALOG_StatusBarUpdateAll();
654 VOID
DoCreateEditWindow(VOID
)
659 BOOL bModified
= FALSE
;
663 /* If the edit control already exists, try to save its content */
664 if (Globals
.hEdit
!= NULL
)
666 /* number of chars currently written into the editor. */
667 iSize
= GetWindowTextLength(Globals
.hEdit
);
670 /* Allocates temporary buffer. */
671 pTemp
= HeapAlloc(GetProcessHeap(), 0, (iSize
+ 1) * sizeof(TCHAR
));
678 /* Recover the text into the control. */
679 GetWindowText(Globals
.hEdit
, pTemp
, iSize
+ 1);
681 if (SendMessage(Globals
.hEdit
, EM_GETMODIFY
, 0, 0))
685 /* Restore original window procedure */
686 SetWindowLongPtr(Globals
.hEdit
, GWLP_WNDPROC
, (LONG_PTR
)Globals
.EditProc
);
688 /* Destroy the edit control */
689 DestroyWindow(Globals
.hEdit
);
692 /* Update wrap status into the main menu and recover style flags */
693 dwStyle
= (Globals
.bWrapLongLines
? EDIT_STYLE_WRAP
: EDIT_STYLE
);
695 /* Create the new edit control */
696 Globals
.hEdit
= CreateWindowEx(WS_EX_CLIENTEDGE
,
708 if (Globals
.hEdit
== NULL
)
712 HeapFree(GetProcessHeap(), 0, pTemp
);
719 SendMessage(Globals
.hEdit
, WM_SETFONT
, (WPARAM
)Globals
.hFont
, FALSE
);
720 SendMessage(Globals
.hEdit
, EM_LIMITTEXT
, 0, 0);
722 /* If some text was previously saved, restore it. */
725 SetWindowText(Globals
.hEdit
, pTemp
);
726 HeapFree(GetProcessHeap(), 0, pTemp
);
729 SendMessage(Globals
.hEdit
, EM_SETMODIFY
, TRUE
, 0);
732 /* Sub-class a new window callback for row/column detection. */
733 Globals
.EditProc
= (WNDPROC
)SetWindowLongPtr(Globals
.hEdit
,
735 (LONG_PTR
)EDIT_WndProc
);
737 /* Finally shows new edit control and set focus into it. */
738 ShowWindow(Globals
.hEdit
, SW_SHOW
);
739 SetFocus(Globals
.hEdit
);
741 /* Re-arrange controls */
742 PostMessageW(Globals
.hMainWnd
, WM_SIZE
, 0, 0);
745 VOID
DIALOG_EditWrap(VOID
)
747 Globals
.bWrapLongLines
= !Globals
.bWrapLongLines
;
749 EnableMenuItem(Globals
.hMenu
, CMD_GOTO
, (Globals
.bWrapLongLines
? MF_GRAYED
: MF_ENABLED
));
751 DoCreateEditWindow();
752 DoShowHideStatusBar();
755 VOID
DIALOG_SelectFont(VOID
)
758 LOGFONT lf
= Globals
.lfFont
;
760 ZeroMemory( &cf
, sizeof(cf
) );
761 cf
.lStructSize
= sizeof(cf
);
762 cf
.hwndOwner
= Globals
.hMainWnd
;
764 cf
.Flags
= CF_SCREENFONTS
| CF_INITTOLOGFONTSTRUCT
| CF_NOVERTFONTS
;
768 HFONT currfont
= Globals
.hFont
;
770 Globals
.hFont
= CreateFontIndirect(&lf
);
772 SendMessage(Globals
.hEdit
, WM_SETFONT
, (WPARAM
)Globals
.hFont
, TRUE
);
773 if (currfont
!= NULL
)
774 DeleteObject(currfont
);
778 typedef HWND (WINAPI
*FINDPROC
)(LPFINDREPLACE lpfr
);
780 static VOID
DIALOG_SearchDialog(FINDPROC pfnProc
)
782 if (Globals
.hFindReplaceDlg
!= NULL
)
784 SetFocus(Globals
.hFindReplaceDlg
);
788 if (!Globals
.find
.lpstrFindWhat
)
790 ZeroMemory(&Globals
.find
, sizeof(Globals
.find
));
791 Globals
.find
.lStructSize
= sizeof(Globals
.find
);
792 Globals
.find
.hwndOwner
= Globals
.hMainWnd
;
793 Globals
.find
.lpstrFindWhat
= Globals
.szFindText
;
794 Globals
.find
.wFindWhatLen
= _countof(Globals
.szFindText
);
795 Globals
.find
.lpstrReplaceWith
= Globals
.szReplaceText
;
796 Globals
.find
.wReplaceWithLen
= _countof(Globals
.szReplaceText
);
797 Globals
.find
.Flags
= FR_DOWN
;
800 /* We only need to create the modal FindReplace dialog which will */
801 /* notify us of incoming events using hMainWnd Window Messages */
803 Globals
.hFindReplaceDlg
= pfnProc(&Globals
.find
);
804 assert(Globals
.hFindReplaceDlg
!= NULL
);
807 VOID
DIALOG_Search(VOID
)
809 DIALOG_SearchDialog(FindText
);
812 VOID
DIALOG_SearchNext(BOOL bDown
)
815 Globals
.find
.Flags
|= FR_DOWN
;
817 Globals
.find
.Flags
&= ~FR_DOWN
;
819 if (Globals
.find
.lpstrFindWhat
!= NULL
)
820 NOTEPAD_FindNext(&Globals
.find
, FALSE
, TRUE
);
825 VOID
DIALOG_Replace(VOID
)
827 DIALOG_SearchDialog(ReplaceText
);
830 typedef struct tagGOTO_DATA
834 } GOTO_DATA
, *PGOTO_DATA
;
838 DIALOG_GoTo_DialogProc(HWND hwndDialog
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
840 static PGOTO_DATA s_pGotoData
;
845 s_pGotoData
= (PGOTO_DATA
)lParam
;
846 SetDlgItemInt(hwndDialog
, ID_LINENUMBER
, s_pGotoData
->iLine
, FALSE
);
847 return TRUE
; /* Set focus */
851 if (LOWORD(wParam
) == IDOK
)
853 UINT iLine
= GetDlgItemInt(hwndDialog
, ID_LINENUMBER
, NULL
, FALSE
);
854 if (iLine
<= 0 || s_pGotoData
->cLines
< iLine
) /* Out of range */
856 /* Show error message */
857 WCHAR title
[128], text
[256];
858 LoadStringW(Globals
.hInstance
, STRING_NOTEPAD
, title
, _countof(title
));
859 LoadStringW(Globals
.hInstance
, STRING_LINE_NUMBER_OUT_OF_RANGE
, text
, _countof(text
));
860 MessageBoxW(hwndDialog
, text
, title
, MB_OK
);
862 SendDlgItemMessageW(hwndDialog
, ID_LINENUMBER
, EM_SETSEL
, 0, -1);
863 SetFocus(GetDlgItem(hwndDialog
, ID_LINENUMBER
));
866 s_pGotoData
->iLine
= iLine
;
867 EndDialog(hwndDialog
, IDOK
);
869 else if (LOWORD(wParam
) == IDCANCEL
)
871 EndDialog(hwndDialog
, IDCANCEL
);
880 VOID
DIALOG_GoTo(VOID
)
883 DWORD dwStart
= 0, dwEnd
= 0;
884 INT ich
, cch
= GetWindowTextLength(Globals
.hEdit
);
886 /* Get the current line number and the total line number */
887 SendMessage(Globals
.hEdit
, EM_GETSEL
, (WPARAM
) &dwStart
, (LPARAM
) &dwEnd
);
888 GotoData
.iLine
= (UINT
)SendMessage(Globals
.hEdit
, EM_LINEFROMCHAR
, dwStart
, 0) + 1;
889 GotoData
.cLines
= (UINT
)SendMessage(Globals
.hEdit
, EM_GETLINECOUNT
, 0, 0);
891 /* Ask the user for line number */
892 if (DialogBoxParam(Globals
.hInstance
,
893 MAKEINTRESOURCE(DIALOG_GOTO
),
895 DIALOG_GoTo_DialogProc
,
896 (LPARAM
)&GotoData
) != IDOK
)
898 return; /* Canceled */
901 --GotoData
.iLine
; /* Make it zero-based */
903 /* Get ich (the target character index) from line number */
904 if (GotoData
.iLine
<= 0)
906 else if (GotoData
.iLine
>= GotoData
.cLines
)
909 ich
= (INT
)SendMessage(Globals
.hEdit
, EM_LINEINDEX
, GotoData
.iLine
, 0);
911 /* EM_LINEINDEX can return -1 on failure */
916 SendMessage(Globals
.hEdit
, EM_SETSEL
, ich
, ich
);
917 SendMessage(Globals
.hEdit
, EM_SCROLLCARET
, 0, 0);
920 VOID
DIALOG_StatusBarUpdateCaretPos(VOID
)
923 TCHAR buff
[MAX_PATH
];
924 DWORD dwStart
, dwSize
;
926 SendMessage(Globals
.hEdit
, EM_GETSEL
, (WPARAM
)&dwStart
, (LPARAM
)&dwSize
);
927 line
= SendMessage(Globals
.hEdit
, EM_LINEFROMCHAR
, (WPARAM
)dwStart
, 0);
928 ich
= (int)SendMessage(Globals
.hEdit
, EM_LINEINDEX
, (WPARAM
)line
, 0);
930 /* EM_LINEINDEX can return -1 on failure */
931 col
= ((ich
< 0) ? 0 : (dwStart
- ich
));
933 StringCchPrintf(buff
, _countof(buff
), Globals
.szStatusBarLineCol
, line
+ 1, col
+ 1);
934 SendMessage(Globals
.hStatusBar
, SB_SETTEXT
, SBPART_CURPOS
, (LPARAM
)buff
);
937 VOID
DIALOG_ViewStatusBar(VOID
)
939 Globals
.bShowStatusBar
= !Globals
.bShowStatusBar
;
940 DoShowHideStatusBar();
943 VOID
DIALOG_HelpContents(VOID
)
945 WinHelp(Globals
.hMainWnd
, helpfile
, HELP_INDEX
, 0);
948 VOID
DIALOG_HelpAboutNotepad(VOID
)
950 TCHAR szNotepad
[MAX_STRING_LEN
];
951 TCHAR szNotepadAuthors
[MAX_STRING_LEN
];
953 LoadString(Globals
.hInstance
, STRING_NOTEPAD
, szNotepad
, _countof(szNotepad
));
954 LoadString(Globals
.hInstance
, STRING_NOTEPAD_AUTHORS
, szNotepadAuthors
, _countof(szNotepadAuthors
));
956 ShellAbout(Globals
.hMainWnd
, szNotepad
, szNotepadAuthors
,
957 LoadIcon(Globals
.hInstance
, MAKEINTRESOURCE(IDI_NPICON
)));