mirror of
https://github.com/rizonesoft/Notepad3.git
synced 2026-06-28 21:02:59 +08:00
Merge pull request #5655 from RaiKoHoff/Dev_Master
fix: error prone manual numbering of menu child-items for checkboxes
This commit is contained in:
commit
4b074c85b6
4
.github/copilot-instructions.md
vendored
4
.github/copilot-instructions.md
vendored
@ -52,7 +52,8 @@ Notepad3 is a Win32 desktop text editor built on the **Scintilla** editing compo
|
||||
|
||||
### Core modules (in `src\`)
|
||||
|
||||
- **Notepad3.c/h** — Application entry point (`wWinMain`), window procedure, global state structs (`GLOBALS_T`, `SETTINGS_T`, `FLAGS_T`, `PATHS_T`)
|
||||
- **Notepad3.c/h** — Application entry point (`wWinMain`), window procedure, global state structs (`GLOBALS_T`, `SETTINGS_T`, `FLAGS_T`, `PATHS_T`), `MsgCommand()` dispatcher with sub-handlers
|
||||
- **Notepad3Util.c/h** — Utility functions extracted from Notepad3.c: bitmap/toolbar image loading (`NP3Util_LoadBitmapFile`, `NP3Util_CreateScaledImageListFromBitmap`), word-wrap configuration (`NP3Util_SetWrapIndentMode`, `NP3Util_SetWrapVisualFlags`), auto-scroll (`NP3Util_AutoScrollStart/Stop`)
|
||||
- **Edit.c/h** — Text manipulation: find/replace (PCRE2 regex), encoding conversion, clipboard, indentation, sorting, bookmarks, folding, auto-complete
|
||||
- **Styles.c/h** — Scintilla styling, lexer selection, theme management
|
||||
- **Dialogs.c/h** — All dialog boxes and UI interactions
|
||||
@ -243,6 +244,7 @@ Notepad3 follows a **portable-app** design for its configuration file (`Notepad3
|
||||
- **Admin redirect**: An administrator can place `Notepad3.ini=<path>` in `[Notepad3]` section of the app-directory INI to redirect to a per-user path. Up to 2 levels of redirect are supported. Redirect targets **are** auto-created (the admin intended them to exist).
|
||||
- **Key paths**: `Paths.IniFile` = active writable INI (empty if none exists), `Paths.IniFileDefault` = fallback path for "Save Settings Now" recovery.
|
||||
- **Configuration code**: All INI init logic lives in `src\Config\Config.cpp` — `FindIniFile()` → `TestIniFile()` → `CreateIniFile()` → `LoadSettings()`.
|
||||
- **Empty INI = no INI**: An empty (0-byte) INI file must produce identical saved output to having no INI file at all. `SettingsVersion` defaults to `CFG_VER_CURRENT` when missing — a missing key does NOT imply a legacy config. Empty lexer sections are removed after style saving (`IniSectionGetKeyCount()`).
|
||||
- **MiniPath** follows the same portable INI and admin-redirect pattern (`minipath\src\Config.cpp`). Redirect targets are auto-created via `CreateIniFileEx()`.
|
||||
- **New parameters**: When adding new `Settings2` (or other INI) parameters, always document them as commented entries in `Build\Notepad3.ini`
|
||||
|
||||
|
||||
28
CLAUDE.md
28
CLAUDE.md
@ -52,7 +52,8 @@ GitHub Actions (`.github/workflows/build.yml`) builds all four platforms (Win32,
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| **Notepad3.c/h** | Entry point (`wWinMain`), window procedure (`MainWndProc`), global state structs (`Globals`, `Settings`, `Settings2`, `Flags`, `Paths`) |
|
||||
| **Notepad3.c/h** | Entry point (`wWinMain`), window procedure (`MainWndProc`), global state structs (`Globals`, `Settings`, `Settings2`, `Flags`, `Paths`), `MsgCommand()` dispatcher |
|
||||
| **Notepad3Util.c/h** | Utility functions extracted from Notepad3.c: bitmap/toolbar image loading, word-wrap configuration, auto-scroll (middle-click continuous scroll) |
|
||||
| **Edit.c/h** | Text manipulation: find/replace (PCRE2 regex), encoding conversion, clipboard, indentation, sorting, bookmarks, folding, auto-complete |
|
||||
| **Styles.c/h** | Scintilla styling, lexer selection, theme management, margin configuration |
|
||||
| **Dialogs.c/h** | All dialog boxes, DPI-aware UI interactions, window placement |
|
||||
@ -73,6 +74,28 @@ MainWndProc (Notepad3.c)
|
||||
+-- Status Bar (16 configurable fields)
|
||||
```
|
||||
|
||||
### Menu / Command Architecture
|
||||
|
||||
Menu items are defined in resource files (`language/np3_*/menu_*.rc`). Command handling in `Notepad3.c` is structured as:
|
||||
|
||||
- **`MsgInitMenu()`** — `WM_INITMENU` handler; enables/disables/checks menu items based on current state
|
||||
- **`MsgCommand()`** — `WM_COMMAND` thin dispatcher; handles timer/notification cases inline, then delegates to static sub-handlers:
|
||||
|
||||
| Handler | Scope |
|
||||
|---------|-------|
|
||||
| `_HandleFileCommands` | File open/save/print/favorites (`IDM_FILE_*`) |
|
||||
| `_HandleEncodingCommands` | Encoding & line endings (`IDM_ENCODING_*`, `IDM_LINEENDINGS_*`) |
|
||||
| `_HandleEditBasicCommands` | Undo/redo/cut/copy/paste/indent (`IDM_EDIT_UNDO`..`CMD_VK_INSERT`) |
|
||||
| `_HandleEditLineManipulation` | Line modify/sort/join/case (`IDM_EDIT_ENCLOSESELECTION`..`IDM_EDIT_INSERT_GUID`) |
|
||||
| `_HandleEditTextTransform` | Comments/URL encode/escape/hex (`IDM_EDIT_LINECOMMENT`..`IDM_EDIT_HEX2CHAR`) |
|
||||
| `_HandleEditFind` | Find/replace/bookmarks/goto (`IDM_EDIT_FINDMATCHINGBRACE`..`IDM_EDIT_GOTOLINE`) |
|
||||
| `_HandleViewAndSettingsCommands` | View/settings/rendering (`IDM_VIEW_*`, `IDM_SET_*`) |
|
||||
| `_HandleHelpCommands` | Help/about (`IDM_HELP_*`) |
|
||||
| `_HandleCmdCommands` | Keyboard shortcuts/navigation/window positioning (`CMD_*`) |
|
||||
| `_HandleToolbarCommands` | Toolbar button dispatch via `s_ToolbarDispatch[]` table (`IDT_*`) |
|
||||
|
||||
Each handler returns `true` if it handled the command, `false` to try the next. All handlers are `static` in `Notepad3.c`.
|
||||
|
||||
### Vendored Dependencies
|
||||
|
||||
| Directory | Library | Purpose |
|
||||
@ -139,6 +162,9 @@ Resource-based MUI system with 27+ locales. Each locale has a `np3_LANG_COUNTRY\
|
||||
- **Admin redirect**: `Notepad3.ini=<path>` in `[Notepad3]` section redirects to per-user path (up to 2 levels)
|
||||
- Key paths: `Paths.IniFile` (active writable INI), `Paths.IniFileDefault` (fallback for recovery)
|
||||
- INI init flow: `FindIniFile()` -> `TestIniFile()` -> `CreateIniFile()` -> `LoadSettings()`
|
||||
- **SettingsVersion default**: `SettingsVersion` defaults to `CFG_VER_CURRENT` when missing from INI — an INI file without `SettingsVersion` is NOT treated as a legacy (pre-versioning) file. This ensures empty INI files and newly created INI files both get current defaults.
|
||||
- **`bIniFileFromScratch`**: Set when INI file size is 0 bytes. Cleared after `SaveAllSettings()` completes. While true, `MuiLanguage.c` suppresses writing `PreferredLanguageLocaleName` to avoid polluting fresh INI files.
|
||||
- **Style section saving**: `Style_ToIniSection()` removes empty lexer sections after processing via `IniSectionGetKeyCount()`. `Style_CanonicalSectionToIniCache()` establishes canonical section order but empty sections are cleaned up — only sections with non-default style values appear in the saved INI.
|
||||
- **MiniPath** follows the same portable INI and admin-redirect pattern (`minipath\src\Config.cpp`). Redirect targets are auto-created via `CreateIniFileEx()`.
|
||||
- **New parameters**: When adding new `Settings2` (or other INI) parameters, always document them as commented entries in `Build\Notepad3.ini`
|
||||
|
||||
|
||||
21
plans/deasater_recovery_prompt.txt
Normal file
21
plans/deasater_recovery_prompt.txt
Normal file
@ -0,0 +1,21 @@
|
||||
please make a plan for implementing a kind of "disaster file recovery":
|
||||
- on application crash/sigkill/sigint/sys-shutdown there should be a directory (user's %APPDATA%/Notepad3/recovery/) where recovery bundle files are kept
|
||||
- one file to keep the original document (respect encryption)
|
||||
- an accompaning ini file which keeps the original full filepath, original encoding, and other imortant attributes
|
||||
- this recovery file should be updated (if save needed / dirty mode) in background every 2000ms (time should be configurable in settings)
|
||||
- the recovery file bundle should be rmoved, if the application exits normally
|
||||
- there should be a recovery bundle also for dirty non empty drafts (Untitled / No file path given)
|
||||
- the mechanism should be multi instances aware (maybe process number in bundle name ?)
|
||||
- on every application start check the "%APPDATA%/Notepad3/recovery/" if there are unhandled disaster recovery files and
|
||||
start a new app instance to load the recovery, unhandled means, there is no instance taking care of this recovery file, must be tracked somehow:
|
||||
+ instance has file loaded with correct path - normal recovery mode (process-id of recovery file matches)
|
||||
+ file has no instance which is taking care of, new instance has to be started for this recovery file
|
||||
+ recovery file's process id does not fit to a "care of instance", but new instance has already been startet to take care of
|
||||
+ if a new instance takes care of the recovery file, the process-id has to be changed accordingly
|
||||
+ maybe, the commandline interface has to be extended to give an file path for handling and saving in original place
|
||||
+ maybe the modified date of both files must be checked to do not override newer files
|
||||
-
|
||||
|
||||
|
||||
- if you have suggestions derived from best practices for disaster recovery, please suggest
|
||||
- if there are questions/uncertainty please ask
|
||||
230
plans/notepad3_refactoring.md
Normal file
230
plans/notepad3_refactoring.md
Normal file
@ -0,0 +1,230 @@
|
||||
# Notepad3.c Refactoring — Extract Utilities & Split MsgCommand()
|
||||
|
||||
## Context
|
||||
|
||||
`src/Notepad3.c` was the largest module in the project at **12,985 lines**. It contained ~55 static functions and ~60 static variables spanning unrelated concerns (auto-scroll, file observation, bitmap loading, text input helpers, TinyExpr evaluation, etc.) plus a monolithic `MsgCommand()` dispatcher (2,994 lines, 360+ case statements). This refactoring improves navigability and separation of concerns without changing any behavior.
|
||||
|
||||
### Motivation
|
||||
|
||||
- **Navigability**: Finding code in a 13K-line file is slow; logically grouped helpers belong in their own modules
|
||||
- **Maintainability**: The `MsgCommand()` monolith made it hard to reason about individual command groups
|
||||
- **Encapsulation**: Static variables for unrelated subsystems (auto-scroll, file observation, TinyExpr) were all in global file scope, obscuring their true scope
|
||||
- **Consistency**: Other modules (`Edit.c`, `Styles.c`, `Dialogs.c`) already follow clean `.c/.h` pair boundaries
|
||||
|
||||
### What NOT to extract
|
||||
|
||||
These items are intentionally kept in `Notepad3.c`:
|
||||
- **`_InitGlobals()` / `_CleanUpResources()`** — core app lifecycle, touches everything
|
||||
- **Message queue helpers** (`_MQ_AppendCmd`, `MQ_ExecuteNext`) — tightly integrated with timer system and UI updates
|
||||
- **UI update helpers** (`_UpdateStatusbarDelayed`, `_UpdateToolbarDelayed`, `_UpdateTitlebarDelayed`) — depend on message queue + complex global state
|
||||
- **`_EditSubclassProc()`** — Scintilla subclass glue, belongs near `MainWndProc`
|
||||
- **`ParseCmdLnOption()`** — command-line parsing, belongs with app startup
|
||||
- **`MsgInitMenu()`** — reads 20+ state variables to enable/disable menu items; inherently whole-application state
|
||||
|
||||
---
|
||||
|
||||
## Completed Work
|
||||
|
||||
### Part 2: MsgCommand() Split (DONE)
|
||||
|
||||
`MsgCommand()` refactored from a **2,994-line** switch into a **73-line thin dispatcher** that delegates to **10 static handler functions**, all remaining in `Notepad3.c`:
|
||||
|
||||
| Handler | Cases | Purpose |
|
||||
|---------|-------|---------|
|
||||
| `_HandleFileCommands` | ~27 | `IDM_FILE_*` — open/save/print/favorites/grepWin |
|
||||
| `_HandleEncodingCommands` | ~10 | `IDM_ENCODING_*`, `IDM_LINEENDINGS_*` |
|
||||
| `_HandleEditBasicCommands` | ~30 | `IDM_EDIT_UNDO`..`CMD_VK_INSERT` — undo/redo/cut/copy/paste/indent |
|
||||
| `_HandleEditLineManipulation` | ~42 | `IDM_EDIT_ENCLOSESELECTION`..`IDM_EDIT_INSERT_GUID` — line modify/sort/join/case |
|
||||
| `_HandleEditTextTransform` | ~45 | `IDM_EDIT_LINECOMMENT`..`IDM_EDIT_HEX2CHAR` — comments/encode/escape/hex |
|
||||
| `_HandleEditFind` | ~21 | `IDM_EDIT_FINDMATCHINGBRACE`..`IDM_EDIT_GOTOLINE` — find/replace/bookmarks |
|
||||
| `_HandleViewAndSettingsCommands` | ~99 | `IDM_VIEW_*`, `IDM_SET_*` — view/settings/rendering |
|
||||
| `_HandleHelpCommands` | ~5 | `IDM_HELP_*`, `IDM_SETPASS` |
|
||||
| `_HandleCmdCommands` | ~90 | `CMD_*` — keyboard shortcuts/navigation/window positioning |
|
||||
| `_HandleToolbarCommands` | ~30 | `IDT_*` — toolbar dispatch via `s_ToolbarDispatch[]` lookup table |
|
||||
|
||||
**Dispatcher pattern:**
|
||||
```c
|
||||
LRESULT MsgCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
// Language/theme menu range checks (inline)
|
||||
// Timer/notification cases (inline, return immediately)
|
||||
switch(iLoWParam) { case SCEN_CHANGE: ... return FALSE; ... }
|
||||
|
||||
// Handler dispatch chain
|
||||
if (_HandleFileCommands(hwnd, umsg, wParam, lParam)) { return FALSE; }
|
||||
if (_HandleEncodingCommands(...)) { return FALSE; }
|
||||
...
|
||||
return DefWindowProc(hwnd, umsg, wParam, lParam);
|
||||
}
|
||||
```
|
||||
|
||||
Each handler returns `true` if handled, `false` to try the next. The 40 repetitive IDT_* toolbar cases were replaced with a `s_ToolbarDispatch[]` lookup table (29 standard entries + 2 special cases: `IDT_EDIT_COPY` falls back to COPYALL, `IDT_EDIT_CLEAR` falls back to `SciCall_ClearAll`).
|
||||
|
||||
### Part 1, Phases 1-3: Notepad3Util.c/.h (DONE)
|
||||
|
||||
New files created: `src/Notepad3Util.c` (349 lines), `src/Notepad3Util.h` (50 lines).
|
||||
|
||||
**Phase 1 — Bitmap/Image Loading** (LOW risk, ~100 LOC):
|
||||
- `NP3Util_LoadBitmapFile()` — loads toolbar bitmap, validates dimensions
|
||||
- `NP3Util_CreateScaledImageListFromBitmap()` — creates DPI-scaled image list
|
||||
- `NP3Util_XXX_CreateScaledImageListFromBitmap()` — legacy variant using fixed `NUMTOOLBITMAPS`
|
||||
- `NUMTOOLBITMAPS` macro moved from Notepad3.c to Notepad3Util.h
|
||||
|
||||
**Phase 2 — Word-Wrap Configuration** (LOW risk, ~100 LOC):
|
||||
- `NP3Util_SetWrapStartIndent()` — sets wrap start indent based on `Settings.WordWrapIndent`
|
||||
- `NP3Util_SetWrapIndentMode()` — sets wrap indent mode (same/indent/deep/fixed)
|
||||
- `NP3Util_SetWrapVisualFlags(HWND)` — sets wrap visual flag symbols
|
||||
|
||||
**Phase 3 — Auto-Scroll** (LOW-MED risk, ~200 LOC):
|
||||
- 6 static variables moved: `s_bAutoScrollMode`, `s_bAutoScrollHeld`, `s_dwAutoScrollStartTick`, `s_ptAutoScrollOrigin`, `s_ptAutoScrollMouse`, `s_dAutoScrollAccumY`
|
||||
- 4 `AUTOSCROLL_*` constants moved to header
|
||||
- `NP3Util_AutoScrollStart/Stop()`, `NP3Util_AutoScrollTimerProc()` — core scroll logic
|
||||
- `NP3Util_IsAutoScrollMode()`, `NP3Util_IsAutoScrollHeld()`, `NP3Util_GetAutoScrollStartTick()`, `NP3Util_SetAutoScrollHeld()`, `NP3Util_AutoScrollUpdateMouse()` — state accessors for `_EditSubclassProc`
|
||||
|
||||
**Net result:** `Notepad3.c` reduced from 12,985 to 12,713 lines.
|
||||
|
||||
### Files modified
|
||||
- `src/Notepad3.c` — extracted code removed, call sites updated, `#include "Notepad3Util.h"` added
|
||||
- `src/Notepad3Util.c` — new implementation file
|
||||
- `src/Notepad3Util.h` — new header file
|
||||
- `src/Notepad3.vcxproj` — `<ClCompile>` and `<ClInclude>` entries added
|
||||
- `src/Notepad3.vcxproj.filters` — filter entries added (Source Files / Header Files)
|
||||
- `CLAUDE.md` — Core Modules table updated, Menu/Command Architecture section added
|
||||
- `.github/copilot-instructions.md` — Core modules list updated
|
||||
|
||||
---
|
||||
|
||||
## Remaining Work — Phases 4-6
|
||||
|
||||
### Phase 4 — TinyExpr Evaluation (~130 LOC, MEDIUM risk)
|
||||
|
||||
**Static variables to move** (Notepad3.c line 186-187):
|
||||
- `s_dExpression` (double) — last evaluated expression result
|
||||
- `s_iExprError` (te_int_t) — last expression error code
|
||||
|
||||
**Functions to move:**
|
||||
| Current | New | Line | LOC |
|
||||
|---------|-----|------|-----|
|
||||
| `_EvalTinyExpr(bool qmark)` | `NP3Util_EvalTinyExpr(bool)` | 2655 | ~150 |
|
||||
| `_InterpMultiSelectionTinyExpr(te_int_t*)` | `NP3Util_InterpMultiSelectionTinyExpr(te_int_t*)` | 10086 | ~50 |
|
||||
|
||||
**New accessor functions needed:**
|
||||
- `NP3Util_GetLastExpression()` — returns `s_dExpression` (read by `_UpdateStatusbarDelayed`)
|
||||
- `NP3Util_GetLastExprError()` — returns `s_iExprError` (read by `_UpdateStatusbarDelayed`)
|
||||
|
||||
**Call sites to update (3):**
|
||||
- Line 6839: `_EvalTinyExpr(false)` — in `_HandleCmdCommands`, case `CMD_ENTER_RETURN`
|
||||
- Line 8921: `_EvalTinyExpr(true)` — in `_MsgNotifyFromEdit`, on `?` char insert
|
||||
- Line 10399: `s_dExpression = _InterpMultiSelectionTinyExpr(&s_iExprError)` — in `_UpdateStatusbarDelayed`
|
||||
|
||||
**Dependencies:** `Settings.EvalTinyExprOnSelection`, `Encoding_SciCP`, `SciCall_*` (all via headers), `te_interp()` (needs `#include "tinyexpr/tinyexpr.h"` in Notepad3Util.c), `AllocMem`/`FreeMem` (via `Helpers.h`).
|
||||
|
||||
**Risk:** The statusbar code currently reads `s_dExpression`/`s_iExprError` directly — must switch to getters. The `te_interp()` call works on raw char buffers from Scintilla — encoding-sensitive but mechanically straightforward.
|
||||
|
||||
---
|
||||
|
||||
### Phase 5 — Text Input Helpers (~300 LOC, MEDIUM risk)
|
||||
|
||||
**Static variable to move** (line 189):
|
||||
- `s_SelectionBuffer` (char*) — dynamically allocated buffer for auto-close bracket/quote tracking
|
||||
|
||||
**Functions to move:**
|
||||
| Current | New | Line | LOC |
|
||||
|---------|-----|------|-----|
|
||||
| `_HandleAutoIndent(int)` | `NP3Util_HandleAutoIndent(int)` | 8291 | ~45 |
|
||||
| `_HandleAutoCloseTags()` | `NP3Util_HandleAutoCloseTags()` | 8338 | ~58 |
|
||||
| `_SaveSelectionToBuffer()` | `NP3Util_SaveSelectionToBuffer()` | 8398 | ~16 |
|
||||
| `_EncloseSelectionBuffer(char,char)` | `NP3Util_EncloseSelectionBuffer(char,char)` | 8416 | ~17 |
|
||||
| `_HandleInsertCheck(SCNotification*)` | `NP3Util_HandleInsertCheck(...)` | 8435 | ~89 |
|
||||
| `_HandleDeleteCheck(SCNotification*)` | `NP3Util_HandleDeleteCheck(...)` | 8526 | ~60 |
|
||||
|
||||
Skip `_IsIMEOpenInNoNativeMode()` (line 8588) — dead code (`#if 0`).
|
||||
|
||||
**Lifecycle functions needed:**
|
||||
- `NP3Util_TextInputInit()` — allocates `s_SelectionBuffer`; called from `MsgCreate`
|
||||
- `NP3Util_TextInputCleanup()` — frees `s_SelectionBuffer`; called from `_CleanUpResources`
|
||||
|
||||
**Call sites to update (5, all in `_MsgNotifyFromEdit`):**
|
||||
- Line 8635: `_HandleInsertCheck(scn)`
|
||||
- Line 8642: `_SaveSelectionToBuffer()`
|
||||
- Line 8658: `_HandleDeleteCheck(scn)`
|
||||
- Line 8912: `_HandleAutoIndent(ich)`
|
||||
- Line 8917: `_HandleAutoCloseTags()`
|
||||
|
||||
**Dependencies:** `Settings.AutoIndent`, `Settings.AutoCloseQuotes`, `Settings.AutoCloseBrackets`, `Settings.AutoCloseTags` (globals), `SciCall_*`/`Sci_*` (headers), `EditReplaceSelection()` (via `Edit.h`), `AllocMem`/`FreeMem`/`ReAllocMem`/`SizeOfMem` (via `Helpers.h`).
|
||||
|
||||
**Risk:** These functions run on the Scintilla notification hot path (`SCN_MODIFIED`, `SCN_CHARADDED`), but are called once per keystroke (not per character in bulk), so function-call overhead is negligible. Main risk is ensuring `s_SelectionBuffer` lifecycle remains correct.
|
||||
|
||||
---
|
||||
|
||||
### Phase 6 — File Observation (~450 LOC, HIGH risk — do last)
|
||||
|
||||
**Static variable to move** (line 483):
|
||||
- `s_FileChgObsvrData` (`FCOBSRVDATA_T`) — contains event handles (`hEventFileChanged`, `hEventFileDeleted`), file metadata (`fdCurFile`), generation counter (`iObservationGeneration`, uses `InterlockedCompareExchange`/`InterlockedIncrement` seqlock pattern), background worker handle. **48 non-comment references** across Notepad3.c.
|
||||
|
||||
**Functions to move:**
|
||||
| Current | New | Line | LOC |
|
||||
|---------|-----|------|-----|
|
||||
| `IsFileReadOnly()` | `NP3Util_IsFileReadOnly()` | 471 | ~15 |
|
||||
| `IsFileChangedFlagSet()` | `NP3Util_IsFileChangedFlagSet()` | 487 | ~4 |
|
||||
| `IsFileDeletedFlagSet()` | `NP3Util_IsFileDeletedFlagSet()` | 492 | ~4 |
|
||||
| `RaiseFlagIfCurrentFileChanged()` | `NP3Util_RaiseFlagIfCurrentFileChanged()` | 497 | ~50 |
|
||||
| `ResetFileObservationData(bool)` | `NP3Util_ResetFileObservationData(bool)` | 548 | ~20 |
|
||||
| `IsFileVarLogFile()` | `NP3Util_IsFileVarLogFile()` | 10861 | ~10 |
|
||||
| `_ResetFileWatchingMode()` | `NP3Util_ResetFileWatchingMode()` | 10871 | ~10 |
|
||||
| `NotifyIfFileHasChanged()` | `NP3Util_NotifyIfFileHasChanged()` | 12364 | ~20 |
|
||||
| `WatchTimerProc(...)` | `NP3Util_WatchTimerProc(...)` | 12385 | ~15 |
|
||||
| `LogRotateTimerProc(...)` | `NP3Util_LogRotateTimerProc(...)` | 12402 | ~25 |
|
||||
| `AtomicSaveTimerProc(...)` | `NP3Util_AtomicSaveTimerProc(...)` | 12426 | ~50 |
|
||||
|
||||
**Lifecycle functions needed:**
|
||||
- `NP3Util_FileObservationInit()` — creates event handles; replaces code in `InitInstance()` (~lines 1843-1852)
|
||||
- `NP3Util_FileObservationCleanup()` — destroys worker + event handles; replaces code in `_CleanUpResources()` (~lines 824-833)
|
||||
- `NP3Util_GetFileObservationData()` — returns `PFCOBSRVDATA_T` pointer for `InstallFileWatching()` to access the struct
|
||||
|
||||
**Circular dependency:**
|
||||
Timer callbacks call back into Notepad3.c:
|
||||
- `AtomicSaveTimerProc` → `InstallFileWatching(false)`, `FileSave(FSF_SaveAlways)`
|
||||
- `LogRotateTimerProc` → `PostWMCommand(Globals.hwndMain, IDM_VIEW_CHASING_DOCTAIL)`, `InstallFileWatching(true)`
|
||||
- `_ResetFileWatchingMode` → `CheckCmd(GetMenu(...))`
|
||||
|
||||
**Resolution:** `Notepad3Util.c` already `#include`s `Notepad3.h` which declares these functions. The linker resolves cross-module calls — same pattern as `Edit.c` calling `FileLoad()`.
|
||||
|
||||
**Major call sites to update (~48 references):**
|
||||
- `InitInstance()` — event creation → `NP3Util_FileObservationInit()`
|
||||
- `_CleanUpResources()` — cleanup → `NP3Util_FileObservationCleanup()`
|
||||
- `InstallFileWatching()` — direct struct field access → `NP3Util_GetFileObservationData()->`
|
||||
- `MsgFileChangeNotify()` — reads flags, resets observation data
|
||||
- `_UpdateTitlebarDelayed()` — calls `IsFileChangedFlagSet()`/`IsFileDeletedFlagSet()`
|
||||
- `MsgInitMenu()` — calls `IsFileReadOnly()`
|
||||
- `_HandleViewAndSettingsCommands`, `_HandleCmdCommands` — various flag checks
|
||||
|
||||
**Threading concern:** The generation counter uses `InterlockedCompareExchange`/`InterlockedIncrement` for a seqlock pattern (background worker vs. UI thread). Moving the struct doesn't change thread safety, but `NP3Util_GetFileObservationData()` returns a raw pointer — callers must not cache it across calls that could reallocate.
|
||||
|
||||
**Risk: HIGH** — 48 reference sites (most mechanical renames), but `InstallFileWatching()` directly manipulates struct fields (worker start/cancel, event wait). Timer proc function pointers in `SetTimer()` calls must be updated. Threading correctness is critical.
|
||||
|
||||
---
|
||||
|
||||
## Verification Strategy
|
||||
|
||||
After each phase:
|
||||
|
||||
1. **Build:** `Build\Build_x64.cmd Debug` (minimum) — no compile or link errors
|
||||
2. **Diff audit:** `git diff` — confirm purely mechanical moves, no logic changes
|
||||
3. **Smoke test per group:**
|
||||
- Phase 4 (TinyExpr): Select `1+2` → press `?` → verify result inserted; check statusbar expression display with column selection
|
||||
- Phase 5 (Text Input): Type `"` → verify auto-close quote; type `{` → verify auto-close bracket; press Enter after `if (...) {` → verify auto-indent; type `<div>` → verify auto-close `</div>`; press Backspace on `""` → verify pair deletion
|
||||
- Phase 6 (File Observation): Edit file in another editor → Notepad3 must prompt for reload; enable log tail mode (Ctrl+Shift+L) → verify auto-refresh; test atomic save (Settings2.AtomicFileSave=1); test file deletion detection; open/close files rapidly → verify no timer leaks
|
||||
4. **Full build** after all phases: `Build\BuildAll.cmd Release` (all 4 platforms)
|
||||
|
||||
---
|
||||
|
||||
## Estimated Final Result
|
||||
|
||||
| Metric | Before | After (all phases) |
|
||||
|--------|--------|---------------------|
|
||||
| `Notepad3.c` lines | 12,985 | ~11,700 |
|
||||
| `Notepad3Util.c` lines | 0 | ~1,250 |
|
||||
| `MsgCommand()` lines | 2,994 | ~73 (dispatcher) |
|
||||
| Toolbar switch cases | 40 repetitive | dispatch table |
|
||||
| Static helpers in Notepad3.c | ~55 | ~35 |
|
||||
984
src/Notepad3.c
984
src/Notepad3.c
File diff suppressed because it is too large
Load Diff
@ -1077,6 +1077,7 @@
|
||||
<ClCompile Include="Helpers.c" />
|
||||
<ClCompile Include="MuiLanguage.c" />
|
||||
<ClCompile Include="Notepad3.c" />
|
||||
<ClCompile Include="Notepad3Util.c" />
|
||||
<ClCompile Include="Print.cpp" />
|
||||
<ClCompile Include="Resample.c" />
|
||||
<ClCompile Include="StyleLexers\styleLexASM.c" />
|
||||
@ -1180,6 +1181,7 @@
|
||||
<ClInclude Include="Helpers.h" />
|
||||
<ClInclude Include="MuiLanguage.h" />
|
||||
<ClInclude Include="Notepad3.h" />
|
||||
<ClInclude Include="Notepad3Util.h" />
|
||||
<ClInclude Include="Resample.h" />
|
||||
<ClInclude Include="SciCall.h" />
|
||||
<ClInclude Include="StyleLexers\EditLexer.h" />
|
||||
|
||||
@ -72,6 +72,9 @@
|
||||
<ClCompile Include="Notepad3.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Notepad3Util.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Encoding.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -470,6 +473,9 @@
|
||||
<ClInclude Include="Notepad3.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Notepad3Util.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VersionEx.h">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ClInclude>
|
||||
|
||||
349
src/Notepad3Util.c
Normal file
349
src/Notepad3Util.c
Normal file
@ -0,0 +1,349 @@
|
||||
// encoding: UTF-8
|
||||
/******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* Notepad3 *
|
||||
* *
|
||||
* Notepad3Util.c *
|
||||
* Utility functions extracted from Notepad3.c *
|
||||
* Based on code from Notepad2, (c) Florian Balmer 1996-2011 *
|
||||
* *
|
||||
* (c) Rizonesoft 2008-2026 *
|
||||
* https://rizonesoft.com *
|
||||
* *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#include "Helpers.h"
|
||||
|
||||
#include <commctrl.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
#include "PathLib.h"
|
||||
#include "Dialogs.h"
|
||||
#include "Encoding.h"
|
||||
#include "MuiLanguage.h"
|
||||
#include "Notepad3.h"
|
||||
#include "Notepad3Util.h"
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// --- Bitmap / Image Loading ---
|
||||
// ============================================================================
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// NP3Util_LoadBitmapFile()
|
||||
//
|
||||
HBITMAP NP3Util_LoadBitmapFile(const HPATHL hpath)
|
||||
{
|
||||
HBITMAP hbmp = NULL;
|
||||
|
||||
if (Path_IsExistingFile(hpath)) {
|
||||
|
||||
hbmp = (HBITMAP)LoadImage(NULL, Path_Get(hpath), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
|
||||
|
||||
bool bDimOK = false;
|
||||
int height = 16;
|
||||
if (hbmp) {
|
||||
BITMAP bmp = { 0 };
|
||||
GetObject(hbmp, sizeof(BITMAP), &bmp);
|
||||
height = bmp.bmHeight;
|
||||
bDimOK = (bmp.bmWidth >= (height * NUMTOOLBITMAPS));
|
||||
}
|
||||
if (!bDimOK) {
|
||||
InfoBoxLng(MB_ICONWARNING, L"NotSuitableToolbarDim", IDS_MUI_ERR_BITMAP, Path_Get(hpath),
|
||||
(height * NUMTOOLBITMAPS), height, NUMTOOLBITMAPS);
|
||||
}
|
||||
}
|
||||
else {
|
||||
WCHAR displayName[80];
|
||||
Path_GetDisplayName(displayName, 80, hpath, L"<unknown>", false);
|
||||
InfoBoxLng(MB_ICONWARNING, NULL, IDS_MUI_ERR_LOADFILE, displayName);
|
||||
}
|
||||
|
||||
return hbmp;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// NP3Util_XXX_CreateScaledImageListFromBitmap()
|
||||
//
|
||||
HIMAGELIST NP3Util_XXX_CreateScaledImageListFromBitmap(HWND hWnd, HBITMAP hBmp)
|
||||
{
|
||||
BITMAP bmp = { 0 };
|
||||
GetObject(hBmp, sizeof(BITMAP), &bmp);
|
||||
|
||||
int const mod = bmp.bmWidth % NUMTOOLBITMAPS;
|
||||
int const cx = (bmp.bmWidth - mod) / NUMTOOLBITMAPS;
|
||||
int const cy = bmp.bmHeight;
|
||||
|
||||
HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR32 | ILC_MASK, NUMTOOLBITMAPS, NUMTOOLBITMAPS);
|
||||
ImageList_AddMasked(himl, hBmp, CLR_DEFAULT);
|
||||
|
||||
UINT const dpi = Scintilla_GetWindowDPI(hWnd);
|
||||
if (!Settings.DpiScaleToolBar || (dpi == USER_DEFAULT_SCREEN_DPI)) {
|
||||
return himl; // default DPI, we are done
|
||||
}
|
||||
|
||||
// Scale button icons/images
|
||||
int const scx = ScaleIntToDPI(hWnd, cx);
|
||||
int const scy = ScaleIntToDPI(hWnd, cy);
|
||||
|
||||
HIMAGELIST hsciml = ImageList_Create(scx, scy, ILC_COLOR32 | ILC_MASK | ILC_HIGHQUALITYSCALE, NUMTOOLBITMAPS, NUMTOOLBITMAPS);
|
||||
|
||||
for (int i = 0; i < NUMTOOLBITMAPS; ++i) {
|
||||
HICON const hicon = ImageList_GetIcon(himl, i, ILD_TRANSPARENT | ILD_PRESERVEALPHA | ILD_SCALE);
|
||||
ImageList_AddIcon(hsciml, hicon);
|
||||
DestroyIcon(hicon);
|
||||
}
|
||||
|
||||
ImageList_Destroy(himl);
|
||||
|
||||
return hsciml;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// NP3Util_CreateScaledImageListFromBitmap()
|
||||
//
|
||||
HIMAGELIST NP3Util_CreateScaledImageListFromBitmap(HWND hWnd, HBITMAP hBmp)
|
||||
{
|
||||
BITMAP bmp = { 0 };
|
||||
GetObject(hBmp, sizeof(BITMAP), &bmp);
|
||||
|
||||
int const numOfToolBitmaps = (int)(bmp.bmWidth / bmp.bmHeight);
|
||||
|
||||
int const mod = bmp.bmWidth % numOfToolBitmaps;
|
||||
int const cx = (bmp.bmWidth - mod) / numOfToolBitmaps;
|
||||
int const cy = bmp.bmHeight;
|
||||
|
||||
HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR32 | ILC_MASK, numOfToolBitmaps, numOfToolBitmaps);
|
||||
ImageList_AddMasked(himl, hBmp, CLR_DEFAULT);
|
||||
|
||||
UINT const dpi = Scintilla_GetWindowDPI(hWnd);
|
||||
if (!Settings.DpiScaleToolBar || (dpi == USER_DEFAULT_SCREEN_DPI)) {
|
||||
return himl; // default DPI, we are done
|
||||
}
|
||||
|
||||
// Scale button icons/images
|
||||
int const scx = ScaleIntToDPI(hWnd, cx);
|
||||
int const scy = ScaleIntToDPI(hWnd, cy);
|
||||
|
||||
HIMAGELIST hsciml = ImageList_Create(scx, scy, ILC_COLOR32 | ILC_MASK | ILC_HIGHQUALITYSCALE, numOfToolBitmaps, numOfToolBitmaps);
|
||||
|
||||
for (int i = 0; i < numOfToolBitmaps; ++i) {
|
||||
HICON const hicon = ImageList_GetIcon(himl, i, ILD_TRANSPARENT | ILD_PRESERVEALPHA | ILD_SCALE);
|
||||
ImageList_AddIcon(hsciml, hicon);
|
||||
DestroyIcon(hicon);
|
||||
}
|
||||
|
||||
ImageList_Destroy(himl);
|
||||
|
||||
return hsciml;
|
||||
}
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// --- Word-Wrap Configuration ---
|
||||
// ============================================================================
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// NP3Util_SetWrapStartIndent()
|
||||
//
|
||||
void NP3Util_SetWrapStartIndent(void)
|
||||
{
|
||||
int i = 0;
|
||||
switch (Settings.WordWrapIndent) {
|
||||
case 1:
|
||||
i = 1;
|
||||
break;
|
||||
case 2:
|
||||
i = 2;
|
||||
break;
|
||||
case 3:
|
||||
i = (Globals.fvCurFile.iIndentWidth) ? 1 * Globals.fvCurFile.iIndentWidth : 1 * Globals.fvCurFile.iTabWidth;
|
||||
break;
|
||||
case 4:
|
||||
i = (Globals.fvCurFile.iIndentWidth) ? 2 * Globals.fvCurFile.iIndentWidth : 2 * Globals.fvCurFile.iTabWidth;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SciCall_SetWrapStartIndent(i);
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// NP3Util_SetWrapIndentMode()
|
||||
//
|
||||
void NP3Util_SetWrapIndentMode(void)
|
||||
{
|
||||
BeginWaitCursorUID(Flags.bHugeFileLoadState, IDS_MUI_SB_WRAP_LINES);
|
||||
|
||||
Sci_SetWrapModeEx(GET_WRAP_MODE());
|
||||
|
||||
if (Settings.WordWrapIndent == 5) {
|
||||
SciCall_SetWrapIndentMode(SC_WRAPINDENT_SAME);
|
||||
} else if (Settings.WordWrapIndent == 6) {
|
||||
SciCall_SetWrapIndentMode(SC_WRAPINDENT_INDENT);
|
||||
} else if (Settings.WordWrapIndent == 7) {
|
||||
SciCall_SetWrapIndentMode(SC_WRAPINDENT_DEEPINDENT);
|
||||
} else {
|
||||
NP3Util_SetWrapStartIndent();
|
||||
SciCall_SetWrapIndentMode(SC_WRAPINDENT_FIXED);
|
||||
}
|
||||
|
||||
EndWaitCursor();
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// NP3Util_SetWrapVisualFlags()
|
||||
//
|
||||
void NP3Util_SetWrapVisualFlags(HWND hwndEditCtrl)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(hwndEditCtrl);
|
||||
|
||||
if (Settings.ShowWordWrapSymbols) {
|
||||
int wrapVisualFlags = 0;
|
||||
int wrapVisualFlagsLocation = 0;
|
||||
if (Settings.WordWrapSymbols == 0) {
|
||||
Settings.WordWrapSymbols = 22;
|
||||
}
|
||||
switch (Settings.WordWrapSymbols % 10) {
|
||||
case 1:
|
||||
wrapVisualFlags |= SC_WRAPVISUALFLAG_END;
|
||||
wrapVisualFlagsLocation |= SC_WRAPVISUALFLAGLOC_END_BY_TEXT;
|
||||
break;
|
||||
case 2:
|
||||
wrapVisualFlags |= SC_WRAPVISUALFLAG_END;
|
||||
break;
|
||||
}
|
||||
switch (((Settings.WordWrapSymbols % 100) - (Settings.WordWrapSymbols % 10)) / 10) {
|
||||
case 1:
|
||||
wrapVisualFlags |= SC_WRAPVISUALFLAG_START;
|
||||
wrapVisualFlagsLocation |= SC_WRAPVISUALFLAGLOC_START_BY_TEXT;
|
||||
break;
|
||||
case 2:
|
||||
wrapVisualFlags |= SC_WRAPVISUALFLAG_START;
|
||||
break;
|
||||
}
|
||||
SciCall_SetWrapVisualFlags(wrapVisualFlags);
|
||||
SciCall_SetWrapVisualFlagsLocation(wrapVisualFlagsLocation);
|
||||
} else {
|
||||
SciCall_SetWrapVisualFlags(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// --- Auto-Scroll (middle-click continuous scroll, Firefox-style) ---
|
||||
// ============================================================================
|
||||
|
||||
static bool s_bAutoScrollMode = false;
|
||||
static bool s_bAutoScrollHeld = false;
|
||||
static ULONGLONG s_dwAutoScrollStartTick = 0;
|
||||
static POINT s_ptAutoScrollOrigin = { 0, 0 };
|
||||
static POINT s_ptAutoScrollMouse = { 0, 0 };
|
||||
static double s_dAutoScrollAccumY = 0.0;
|
||||
|
||||
bool NP3Util_IsAutoScrollMode(void)
|
||||
{
|
||||
return s_bAutoScrollMode;
|
||||
}
|
||||
|
||||
bool NP3Util_IsAutoScrollHeld(void)
|
||||
{
|
||||
return s_bAutoScrollHeld;
|
||||
}
|
||||
|
||||
ULONGLONG NP3Util_GetAutoScrollStartTick(void)
|
||||
{
|
||||
return s_dwAutoScrollStartTick;
|
||||
}
|
||||
|
||||
void NP3Util_SetAutoScrollHeld(bool held)
|
||||
{
|
||||
s_bAutoScrollHeld = held;
|
||||
}
|
||||
|
||||
void NP3Util_AutoScrollUpdateMouse(POINT pt)
|
||||
{
|
||||
s_ptAutoScrollMouse = pt;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// NP3Util_AutoScrollStop()
|
||||
//
|
||||
void NP3Util_AutoScrollStop(HWND hwndEdit)
|
||||
{
|
||||
if (s_bAutoScrollMode) {
|
||||
KillTimer(hwndEdit, ID_AUTOSCROLLTIMER);
|
||||
ReleaseCapture();
|
||||
SciCall_SetCursor(SC_CURSORNORMAL);
|
||||
s_bAutoScrollMode = false;
|
||||
s_bAutoScrollHeld = false;
|
||||
s_dAutoScrollAccumY = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// NP3Util_AutoScrollTimerProc()
|
||||
//
|
||||
void CALLBACK NP3Util_AutoScrollTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(uMsg);
|
||||
UNREFERENCED_PARAMETER(idEvent);
|
||||
UNREFERENCED_PARAMETER(dwTime);
|
||||
|
||||
if (!s_bAutoScrollMode) {
|
||||
KillTimer(hwnd, ID_AUTOSCROLLTIMER);
|
||||
return;
|
||||
}
|
||||
|
||||
int const deltaY = s_ptAutoScrollMouse.y - s_ptAutoScrollOrigin.y;
|
||||
|
||||
if (abs(deltaY) <= AUTOSCROLL_DEADZONE) {
|
||||
s_dAutoScrollAccumY = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Speed: proportional to distance beyond dead zone
|
||||
double const speed = (double)(deltaY - (deltaY > 0 ? AUTOSCROLL_DEADZONE : -AUTOSCROLL_DEADZONE)) / AUTOSCROLL_DIVISOR;
|
||||
s_dAutoScrollAccumY += speed;
|
||||
|
||||
DocLn const linesToScroll = (DocLn)s_dAutoScrollAccumY;
|
||||
if (linesToScroll != 0) {
|
||||
SciCall_LineScroll(0, linesToScroll);
|
||||
s_dAutoScrollAccumY -= (double)linesToScroll;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// NP3Util_AutoScrollStart()
|
||||
//
|
||||
void NP3Util_AutoScrollStart(HWND hwndEdit, POINT pt)
|
||||
{
|
||||
s_bAutoScrollMode = true;
|
||||
s_bAutoScrollHeld = false;
|
||||
s_dwAutoScrollStartTick = GetTickCount64();
|
||||
s_ptAutoScrollOrigin = pt;
|
||||
s_ptAutoScrollMouse = pt;
|
||||
s_dAutoScrollAccumY = 0.0;
|
||||
SetCapture(hwndEdit);
|
||||
SetCursor(LoadCursor(NULL, IDC_SIZEALL));
|
||||
SetTimer(hwndEdit, ID_AUTOSCROLLTIMER, AUTOSCROLL_TIMER_MS, NP3Util_AutoScrollTimerProc);
|
||||
}
|
||||
50
src/Notepad3Util.h
Normal file
50
src/Notepad3Util.h
Normal file
@ -0,0 +1,50 @@
|
||||
// encoding: UTF-8
|
||||
/******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* Notepad3 *
|
||||
* *
|
||||
* Notepad3Util.h *
|
||||
* Utility functions extracted from Notepad3.c *
|
||||
* Based on code from Notepad2, (c) Florian Balmer 1996-2011 *
|
||||
* *
|
||||
* (c) Rizonesoft 2008-2026 *
|
||||
* https://rizonesoft.com *
|
||||
* *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
#pragma once
|
||||
#ifndef _NP3_NOTEPAD3UTIL_H_
|
||||
#define _NP3_NOTEPAD3UTIL_H_
|
||||
|
||||
#include "TypeDefs.h"
|
||||
#include "SciCall.h"
|
||||
|
||||
// --- Bitmap / Image Loading ---
|
||||
#define NUMTOOLBITMAPS (31)
|
||||
HBITMAP NP3Util_LoadBitmapFile(const HPATHL hpath);
|
||||
HIMAGELIST NP3Util_CreateScaledImageListFromBitmap(HWND hWnd, HBITMAP hBmp);
|
||||
HIMAGELIST NP3Util_XXX_CreateScaledImageListFromBitmap(HWND hWnd, HBITMAP hBmp);
|
||||
|
||||
// --- Word-Wrap Configuration ---
|
||||
void NP3Util_SetWrapStartIndent(void);
|
||||
void NP3Util_SetWrapIndentMode(void);
|
||||
void NP3Util_SetWrapVisualFlags(HWND hwndEditCtrl);
|
||||
|
||||
// --- Auto-Scroll (middle-click continuous scroll) ---
|
||||
#define AUTOSCROLL_TIMER_MS 30
|
||||
#define AUTOSCROLL_DEADZONE 15
|
||||
#define AUTOSCROLL_DIVISOR 60.0
|
||||
#define AUTOSCROLL_CLICK_THRESHOLD_MS 200
|
||||
|
||||
bool NP3Util_IsAutoScrollMode(void);
|
||||
void NP3Util_AutoScrollStop(HWND hwndEdit);
|
||||
void NP3Util_AutoScrollStart(HWND hwndEdit, POINT pt);
|
||||
void NP3Util_AutoScrollUpdateMouse(POINT pt);
|
||||
bool NP3Util_IsAutoScrollHeld(void);
|
||||
ULONGLONG NP3Util_GetAutoScrollStartTick(void);
|
||||
void NP3Util_SetAutoScrollHeld(bool held);
|
||||
|
||||
void CALLBACK NP3Util_AutoScrollTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
|
||||
|
||||
#endif // _NP3_NOTEPAD3UTIL_H_
|
||||
@ -555,7 +555,6 @@ bool Style_InsertThemesMenu(HMENU hMenuBar)
|
||||
WCHAR wchMenuItemStrg[128] = { L'\0' };
|
||||
GetLngString(IDS_MUI_MENU_THEMES, wchMenuItemStrg, COUNTOF(wchMenuItemStrg));
|
||||
|
||||
//bool const res = InsertMenu(hMenuBar, pos, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)s_hmenuThemes, wchMenuItemStrg);
|
||||
bool const res = InsertMenu(hMenuBar, IDM_VIEW_SCHEMECONFIG, MF_BYCOMMAND | MF_POPUP | MF_STRING, (UINT_PTR)s_hmenuThemes, wchMenuItemStrg);
|
||||
|
||||
unsigned const iTheme = Globals.uCurrentThemeIndex;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user