diff --git a/Readme.md b/Readme.md
index add4bbb32..f91c527e9 100644
--- a/Readme.md
+++ b/Readme.md
@@ -1,613 +1,157 @@
# Notepad3
-Notepad3 is free and open source. Your support helps keep development active.
+**A fast, lightweight, Scintilla-based text editor for Windows**
-[](https://github.com/sponsors/rizonesoft)
-[](https://www.paypal.com/donate/?hosted_button_id=7UGGCSDUZJPFE)
[](https://opensource.org/licenses/BSD-3-Clause)
-
-### Build Status
-Continuous integration ensures code quality across compilers and platforms.
-
-[](https://ci.appveyor.com/project/rizonesoft/notepad3/branch/master)
[](https://github.com/rizonesoft/Notepad3/actions/workflows/build.yml)
-[](https://rizonesoft.com/downloads/notepad3/)
+[](https://ci.appveyor.com/project/rizonesoft/notepad3/branch/master)
+[](https://rizonesoft.com/downloads/notepad3/)
[](https://github.com/rizonesoft/Notepad3/releases)
-### Tech Stack
-Built with modern C++ on the powerful Scintilla editing component.
-
-[](https://rizonesoft.com/downloads/notepad3/)
-[](https://github.com/rizonesoft/Notepad3)
-[](https://www.scintilla.org/)
-[](https://rizonesoft.com/downloads/notepad3/)
-
-Notepad3 is a fast and light-weight Scintilla-based text editor with syntax highlighting. It has a small memory footprint, but is powerful enough to handle most programming jobs. [Download Notepad3 here](https://rizonesoft.com/downloads/notepad3).
-
-> *Notepad3 is based on code from Florian Balmer's Notepad2 and XhmikosR's Notepad2-mod. MiniPath is based on code from Florian Balmer's metapath.*
-
-## Important links!
-* Download page - https://rizonesoft.com/downloads/notepad3
-* Latest changelog (release notes) - https://rizonesoft.com/downloads/notepad3/update
-* Full changelog (all versions/builds) - [Notepad3 - Full Changelog](https://raw.githubusercontent.com/rizonesoft/Notepad3/master/Build/Changes.txt)
-* Documentation - https://rizonesoft.com/documents/notepad3
-
-## Rizonesoft Support
-
-* **[GET IN TOUCH](https://rizonesoft.com/contact-us)**
-* **Premium Support** - On Rizonesoft, support is free and we will assist you the best we can. Please be patient when contacting us; there are mainly volunteers working on Rizonesoft projects, and time is a precious commodity.
-
-## Changes compared to Flo's official [Notepad2](https://www.flos-freeware.ch/notepad2.html) (made in [Notepad2-mod](https://xhmikosr.github.io/notepad2-mod/)):
-
-* Code folding
-* Support for bookmarks
-* Option to mark all occurrences of a word
-* Updated Scintilla component
-* Word auto-completion
-* Syntax highlighting support for AutoHotkey (AHK), AutoIt3, AviSynth, Bash, CMake, CoffeeScript,
- Inno Setup, LaTeX, Lua, Markdown, NSIS, Ruby, Tcl, YAML and VHDL scripts.
-* Improved support for NFO ANSI art
-* Other various minor changes and tweaks
-
-## Changes compared to the Notepad2-mod fork:
-
-* Additional syntax highlighting support for Awk, D, golang, MATLAB
-* Regular Expression search engine ([Oniguruma](https://github.com/kkos/oniguruma))
-* New toolbar icons based on Yusuke Kamiyaman's Fugue Icons (purchased by [Rizonesoft](https://rizonesoft.com))
-* Hyperlink hotspot highlighting (single-click Open in Browser (Ctrl) / Load in Editor (Alt)
-* Syntax highlighting support for D Source Script, Go Source Script, JSON, Makefiles, MATLAB, Nim Source Code, Power Shell Script, Resource Script, Shell Script
-* New program icon and other small cosmetic changes
-* In-App support for AES-256 Rijndael encryption/decryption of files (incl. external command line tool for batch processing)
-* Virtual space rectangular selection box (Alt-key down)
-* High-DPI awareness, including high definition toolbar icons
-* Undo/Redo preserves selection
-* File history preserves caret position (optional) and remembers encoding of file
-* Accelerated word navigation
-* Preserve caret position of items in file history
-* Count occurrences of a marked selection or word
-* Count and mark occurrences of matching search/find expression
-* Visual Studio style copy/paste current line (no selection)
-* Insert GUIDs
-* Dropped support for Windows XP
-* Other various minor changes, tweaks, and bugfixes
-
-## Supported Operating Systems:
-
-* Windows 7, 8, 8.1, 10, and 11 (both 32-bit and 64-bit)
-
-
-
-# References
-
-Seen on Nsane Forums: [Notepad3 is an advanced text editor...](https://www.nsaneforums.com/topic/382910-guidereview-notepad3-is-an-advanced-text-editor-that-supports-many-programming-languages/), a review of **Notepad3** posted by the moderator [Karston](https://www.nsaneforums.com/profile/12756-karlston/) at [nsane.forums](https://www.nsaneforums.com/).
-
-**Notepad3's review**: **[Notepad3 is an advanced text editor that supports many programming languages](https://www.ghacks.net/2020/08/11/notepad3-is-an-advanced-text-editor-that-supports-many-programming-languages/)**.
-
-
-
-# **Notepad3 Settings (Notepad3.ini)**
-
-
-## **`[Notepad3]`**
-
-This section can be used to redirect to a settings file which will be used by Notepad3.
-If a non-elevated user is not allowed to write to the program directory of Notepad3.exe,
-the side-by-side Notepad3.ini can point to a place where the user is allowed to write their settings,
-for example:
-
-`Notepad3.ini=%APPDATA%\Rizonesoft\Notepad3\Notepad3.ini`
-
-or a to have user-specific settings:
-
-`Notepad3.ini=%WINDIR%\Notepad3-%USERNAME%.ini`
-
-
-## **`[Settings]`**
-
-These settings are read and written by Notepad3’s user interface.
-For example, all Menu ? Settings will go here.
-
-#### `SettingsVersion=5`
-
-#### `Favorites=%APPDATA%\Rizonesoft\Notepad3\Favorites\`
-
-
-## **`[Settings2]`**
-
-This section offers some advanced Notepad3 program settings, and can only be edited manually.
-Press Ctrl+F7 to open the Notepad3 ini-file. Most changes only take effect upon restarting Notepad3.
-
-#### `PreferredLanguageLocaleName=en-US`
-
-The default value for the already supported languages is defined by the: “OS language setting”.
-- The fallback is: “en-US”.
-
-##### Available languages:
+[Website](https://rizonesoft.com/downloads/notepad3/) · [Downloads](https://github.com/rizonesoft/Notepad3/releases) · [Documentation](https://rizonesoft.com/documents/notepad3/) · [Changelog](https://rizonesoft.com/downloads/notepad3/update) · [Sponsor](https://github.com/sponsors/rizonesoft)
-```
-English/United States (en-US) (internal default)
-Afrikaans/South Africa (af-ZA)
-Belarusian/Belarus (be-BY)
-German/Germany (de-DE)
-Greek/Greece (el-GR)
-English/United Kingdom (en-GB)
-Spanish/Spain (es-ES)
-French/France (fr-FR)
-Hindi/India (hi-IN)
-Hungarian/Hungary (hu-HU)
-Indonesian/Indonesia (id-ID)
-Italian/Italy (it-IT)
-Japanese/Japan (ja-JP)
-Korean/Korea (ko-KR)
-Dutch/Netherlands (nl-NL)
-Polish/Poland (pl-PL)
-Portuguese/Brazil (pt-BR)
-Portuguese/Portugal (pt-PT)
-Russian/Russia (ru/RU)
-Slovak/Slovakia (sk-SK)
-Swedish/Sweden (sv-SE)
-Turkish/Turkey (tr-TR)
-Vietnamese/Vietnam (vi-VN)
-Chinese Simplified/China (zh-CN)
-Chinese Traditional/Taiwan (zh-TW)
-```
-
-#### `IMEInteraction=0`
-
-#### `DateTimeFormat=`
-
-- (-> (Locale dependent short format)
-
-#### `DateTimeLongFormat=`
-
-- (-> (Locale dependent long format)
-
-Specify the short/long date and time formats. This is the format parameter passed to
-the `strftime()` function.
-Note that the locale will be set to English (because of the English Visual C++ Run-time
-Library used by Notepad3).
-
-#### `TimeStampRegEx=`
-
-- (-> \$Date:[^\$]+\$) (Find-Pattern to Update Stamps)
-
-#### `TimeStampFormat=`
-
-- (-> \\$Date:[^\\$]+\\$ | $Date: %Y/%m/%d %H:%M:%S $
-- (-> $Date: %s $) (Print format should fit to TimeStampRegEx)
-
-This parameter is used as a regex pattern to match time-stamps which will be updated to
-current date-time by `Shift+F5`, e.g. `$Date: 2018/04/26 00:52:39 $`
-
-- Default `DateTime` formats are:
- 1. SHORT: `[Settings2] DateTimeFormat=` (empty) - Notepad3's language locale short ' ' format is used
- 2. LONG: `[Settings2] DateTimeLongFormat=` (empty) - Notepad3's language locale long ' ' format is used
- 3. TIME_STAMP: `[Settings2] TimeStampFormat=` (empty) - "$Date: %s $" where '%s' is replaced by time/date in
- `DateTimeFormat`. E.g. `[Settings2] TimeStampFormat=#TimeStamp=2020-07-21 16:02:23 #`
-- All `DateTime` formats accept the [`strftime()`](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/strftime-wcsftime-strftime-l-wcsftime-l?view=vs-2019) format string.
- Addon: `TimeStampFormat` accepts '%s' (which is no valid `strftime()` formatting code) - a placeholder for a `DateTimeFormat` formatted current date/time string. (mixing of `strftime()` and '%s' is not allowed).
-- If you define your own `TimeStampFormat`, you should define the corresponding `TimeStampRegEx` regular expression pattern accordingly (for our example: `[Settings2] TimeStampRegEx="#TimeStamp=[^#]+#"`), so that` Update Timestamps` operation can find and update them correctly.
-- Additional Menu Point: Insert Current Timestamp.
-
-#### `DefaultDirectory=`
-
-Specify the default directory for the open and save dialogs, used if no file is opened.
-- Path-names can be relative to the Notepad3 program directory.
-
-#### `DefaultExtension=txt`
-
-Specify the default extension for saved files (omit the leading dot, just like txt or html).
-
-#### `DenyVirtualSpaceAccess=0`
-
-#### `filebrowser.exe=minipath.exe`
+---
-Specify the path of an external program that is launched when pressing the Browse toolbar button.
-Defaults to `minipath.exe`, which is the file browser plugin.
+Notepad3 is a free, open-source text editor with syntax highlighting for Windows. Built on the [Scintilla](https://www.scintilla.org/) editing component and [Lexilla](https://www.scintilla.org/Lexilla.html) lexer library, it has a small memory footprint while being powerful enough for professional programming and everyday text editing.
-You can specify additional command line switches, and the file currently opened in Notepad3 will be appended as the last command line parameter.
+> Notepad3 is based on code from Florian Balmer's [Notepad2](https://www.flos-freeware.ch/notepad2.html) and XhmikosR's [Notepad2-mod](https://xhmikosr.github.io/notepad2-mod/). MiniPath is based on Florian Balmer's metapath.
-Note: Due to special treatment of quotes by the Win32 ini-file APIs, pathnames with spaces need to be quadruple-quoted (""path to/file.exe""), but only double-quoted if there's additional command line arguments ("path to/file.exe" /arg).
+
-On the other hand, our preferred file browser is `minipath.exe` (Menu->File->Browse... Ctrl+M) + Toolbar-Button.
+## Features
-If you don't like it, you can configure e.g.
-- [Settings2] filebrowser.exe=explorer.exe (system's file explorer), or
-- [Settings2] filebrowser.exe=Explorer++.exe (https://explorerplusplus.com/) (side-by-side Notepad3), or
-- [Settings2] filebrowser.exe=Q-Dir_x64+.exe (https://www.softwareok.de/?seite=Freeware/Q-Dir/) (side-by-side Notepad3)
+### Editing
+- **Code folding** with toggle-all support
+- **Bookmarks** for quick navigation within files
+- **Word auto-completion** with configurable fill-up characters
+- **Mark all occurrences** of a selected word with occurrence count display
+- **Find and Replace** with [Oniguruma](https://github.com/kkos/oniguruma) regular expression engine
+- **Undo/Redo** that preserves selection state
+- **Visual Studio–style** copy/paste of the current line (when nothing is selected)
+- **Virtual space** rectangular selection (Alt+Drag)
+- **Accelerated word navigation** with configurable delimiters
+- **Insert GUIDs** directly into your document
-#### `grepWin.exe=grepWinNP3.exe`
+### Syntax Highlighting
+Over 55 languages supported, including:
-We have integrated a powerful external tool called **grepWinNP3**.
-**grepWinNP3** is a search and replace tool which can use regular expressions to perform its job.
-This allows you to perform much more powerful search and replace operations in files.
+> ANSI Art, Apache Config, Assembly, AutoHotkey, AutoIt3, AviSynth, Awk, Batch, C/C++, C#, CMake, CoffeeScript, CSS, CSV, D, Dart, Diff, F77/Fortran, Go, HTML/XML, Java, JavaScript, JSON, Julia, Kotlin, KiXtart, LaTeX, Lua, Makefiles, Markdown, MATLAB, Nim, NSIS, Pascal, Perl, PHP, PowerShell, Python, R/S-Plus, Registry, Resource Script, Ruby, Rust, Shell Script, SQL, SystemVerilog, Tcl, TOML, VBScript, VHDL, Verilog, Visual Basic, YAML, and more.
-**grepWinNP3** can be launched:
-- from "File --> Launch --> Search in Files"
-- or from "Edit --> Search --> Search in Files"
-- or simply with "`Ctrl+Shift+F`"
+### File Handling
+- **AES-256 Rijndael** encryption/decryption (in-app and command-line batch tool)
+- **Encoding detection** powered by [uchardet](https://www.freedesktop.org/wiki/Software/uchardet/)
+- **File change monitoring** with configurable check intervals
+- **Emacs file variables** support (encoding, mode, tab-width, etc.)
+- **File history** that preserves caret position and encoding
+- **Portable design** — runs from USB drives with relative path storage
-#### `FileCheckInterval=2000`
+### Search
+- **grepWinNP3** — integrated search-in-files tool with regex support (**Ctrl+Shift+F**)
+- **Hyperlink hotspot highlighting** — Ctrl+Click to open in browser, Alt+Click to load in editor
-The interval (in milliseconds) to check for external modification of the currently opened file.
-- Defaults is 2000 msec.
-- Min: 200[msec] - if equal or less, notify immediately.
+### User Interface
+- **High-DPI aware** with high-definition toolbar icons
+- **Dark mode** support with customizable colors
+- **Customizable status bar** with 16 configurable fields (line, column, encoding, TinyExpr evaluation, Unicode code point, and more)
+- **Customizable toolbar labels** — display function names next to icons
+- **Zoom** from 10% to 1000% (Ctrl+Scroll or toolbar buttons)
+- **Transparent window mode** with configurable opacity
-#### `FileChangedIndicator=[@]`
+### Localization
+27 language translations:
-#### `FileDeletedIndicator=[X]`
+> Afrikaans, Belarusian, Chinese (Simplified & Traditional), Dutch, English (US & UK), Finnish, French, German, Greek, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Polish, Portuguese (Brazil & Portugal), Russian, Slovak, Spanish (Spain & Latin America), Swedish, Turkish, Vietnamese
-#### `FileDlgFilters=`
+### Companion Tools
+- **[MiniPath](minipath/)** — fast file browser plugin (Ctrl+M)
+- **[grepWinNP3](grepWinNP3/)** — powerful search-and-replace across files
-Specify filters for the open and save dialogs
-- (Example: `Text Files|*.txt;*.wtx;*.log;*.asc;*.doc;*.diz;*.nfo|All Files|*.*`).
+## System Requirements
-#### `FileLoadWarningMB=4`
+- **OS:** Windows 8.1, 10, or 11
+- **Architectures:** x86 (Win32), x64, x64 with AVX2, ARM64
-The size limit, in megabytes, to display a warning message for large files.
-- A value of 0 disables the warning.
+## Download & Install
-#### `MultiFileArg=0`
+| Channel | Link |
+|---------|------|
+| **Stable Release** | [rizonesoft.com/downloads/notepad3](https://rizonesoft.com/downloads/notepad3/) |
+| **GitHub Releases** | [github.com/rizonesoft/Notepad3/releases](https://github.com/rizonesoft/Notepad3/releases) |
+| **Nightly Builds** | [Pre-releases on GitHub](https://github.com/rizonesoft/Notepad3/releases) |
-Control if Notepad3 should allow multiple files on the command line (set to 1).
-The default behavior is to accept only a single file, without quoted spaces, like Windows Notepad (set to 0).
-The command line switches + and - can be used to override this setting on the fly, and the /z command-line switch has the same effect as the - switch.
+Notepad3 is fully **portable** — no installation required. Extract the archive and run `Notepad3.exe`. Settings are stored in `Notepad3.ini` alongside the executable. See [Replacing Windows Notepad](https://rizonesoft.com/documents/notepad3/) for system-wide integration.
-#### `NoCGIGuess=0`
+## Building from Source
-Set to 1 to disable simple language detection for cgi and fcgi files.
+Notepad3 is built with **Visual Studio 2022** (toolset v143) targeting the Windows SDK.
-#### `NoCopyLineOnEmptySelection=0`
+```powershell
+# Restore NuGet packages (required once)
+nuget restore Notepad3.sln
-NoCopyLineOnEmptySelection=1 to avoid the copy line (`Ctrl+C`) on empty selection.
+# Build a specific platform
+Build\Build_x64.cmd Release
-#### `NoCutLineOnEmptySelection=0`
+# Build all platforms (Win32, x64, x64_AVX2, ARM64)
+Build\BuildAll.cmd Release
-NoCutLineOnEmptySelection=1 to avoid the cut line (`Ctrl+X`) on empty selection.
-
-#### `NoFadeHidden=0`
-
-Set to 1 to disable fading of hidden objects in file lists (such as Favorites, etc.).
-
-#### `NoFileVariables=0`
-
-Set to 1 to disable file variable parsing.
-Encoding tag parsing can be disabled in the Menu ? File ? Encoding ? Default dialog box.
-
-Notepad3 can parse a few of the Emacs variables that can be used in source code files.
-The first 512 bytes of a file (and, if nothing is found, also the last 512 bytes) are checked for the following constructs (can be manually disabled in the ini-file, or the File, Encoding, Default dialog box, respectively):
+# Or use MSBuild directly
+msbuild Notepad3.sln /m /p:Configuration=Release /p:Platform=x64
```
-coding: utf-8;
-mode: python;
-tab-width: 8;
-c-basic-indent: 2;
-indent-tabs-mode: nil;
-c-tab-always-indent: true;
-fill-column: 64;
-truncate-lines: false;
-enable-local-variables: true;
-```
-`coding`: Serves as a file encoding tag. Details about using encoding tags are outlined in the
-Notepad2 Encoding Tutorial.
-`mode`: Indicates the syntax scheme to be used, and is either the name of a scheme, or a
-file name extension.
-`tab-width`:
-`c-basic-indent`: Denote tab and indentation settings.
-`indent-tabs-mode`: Determines whether to insert tabs as spaces (nil, false or 0)
-or not (true or 1).
-`c-tab-always-indent`: Configures whether the tab key re-formats indenting white-space
-(true or 1) or not (nil, false or 0).
-`fill-column`: Sets the desired limit for long lines (but does not automatically display
-the visual marker).
-`truncate-lines`: Controls word wrap (enable: nil, false or 0; disable: true or 1).
-`enable-local-variables`: Disables file variable parsing (nil, false or 0), but keeps
-evaluating encoding tags.
-
-To bypass both file variable and encoding tag parsing, reload the file with Alt+F8.
-Adapt the settings mentioned above to permanently turn off file variables and encoding tags.
-
-#### `NoHTMLGuess=0`
-
-Set to 1 to disable simple HTML/XML detection for files without extensions.
-
-#### `PortableMyDocs=1`
-
-If set to 1, recent files and other path settings referring to the `My Documents` directory tree are stored relative to `My Documents`.
-This enhances USB stick portability between different versions of Windows, which are using different locations for `My Documents`.
-This setting has no effect if Notepad3.exe itself is located inside `My Documents` (or a sub-directory thereof).
-- The default is 1 (enabled) if `RelativeFileMRU` is enabled, and 0 (disabled) otherwise.
-
-#### `OpacityLevel=75`
-
-Opacity level (in %) of the Notepad3 window in transparent mode.
-
-#### `FindReplaceOpacityLevel=50`
-
-Opacity level (in %) of the Find/Replace window in transparent mode.
-
-#### `RelativeFileMRU=1`
-
-Set to 0 to disable recent files on the same drive or network share as Notepad3.exe being saved with relative path-names.
-- The default is 1 (enabled).
-
-#### `ReuseWindow=0`
-
-This items are managed by Notepad3. (`Menu->Settings->Window->Reuse Window Ctrl+Shift+L`)
-- If set, another started Notepad3 instance will try to give control to the currently opened Window and quit.
-
-#### `SaveBlankNewFile=true`
-New file (not exists on file system ("Untitled")) asking('true')/not asking('false') for file save if document contains any whitespace (blank/space, tab, line-break) character.
+Run `Version.ps1` before building to generate version headers from templates in `Versions\`.
-#### `SciFontQuality=3`
+## Configuration
-#### `SimpleIndentGuides=0`
+Notepad3 uses a portable INI file for all settings. Press **Ctrl+F7** to open it directly in the editor.
-Set to 1 to prevent indentation guides from jumping across empty lines.
+- **UI settings** (`[Settings]`) — managed through Menu → Settings
+- **Advanced settings** (`[Settings2]`) — edit manually; most require a restart
+- **Status bar** (`[Statusbar Settings]`) — customize field layout, order, and width
+- **Toolbar labels** (`[Toolbar Labels]`) — show function names next to icons
-#### `SingleFileInstance=1`
+📖 **Full configuration reference:** [doc/Configuration.md](doc/Configuration.md)
-This items are managed by Notepad3.
+## Contributing
-#### `ShellAppUserModelID=Rizonesoft.Notepad3`
+Contributions are welcome! Here's how to help:
-#### `ShellUseSystemMRU=1`
+1. **Report bugs** — [Open an issue](https://github.com/rizonesoft/Notepad3/issues) with steps to reproduce
+2. **Submit pull requests** — Fork the repo, create a feature branch, and submit a PR against `master`
+3. **Translate** — Add or improve translations in the `language\` directory
+4. **Spread the word** — Star the repo and share with others
-Application User Model IDs (AppUserModelIDs) are used extensively by the taskbar in Windows 7 and later systems to associate processes, files, and windows with a particular application.
-In some cases, it is sufficient to rely on the internal AppUserModelID assigned to a process by the system.
-However, an application that owns multiple processes or an application that is running in a host process might need to explicitly identify itself so that it can group its otherwise disparate windows under a single taskbar button and control the contents of that application's Jump List.
+For support, visit [rizonesoft.com/contact-us](https://rizonesoft.com/contact-us).
-Most recently used (MRU) source lists are resident on the user's computer and contain information about source paths used in previous installations.
-This information can be used when prompting the user for a source path.
-Control system MRU, task-bar and jump list behavior.
-See Replacing Windows Notepad for detailed explanations.
+## Credits
-#### `StickyWindowPosition=0`
+Notepad3 builds upon the work of:
-This items are managed by Notepad3.
-- `Menu->View->Position->Sticky Window Position` (Will remember current window position on restart, instead of last closed position (save on exit))
+| Project | Author | Role |
+|---------|--------|------|
+| [Notepad2](https://www.flos-freeware.ch/notepad2.html) | Florian Balmer | Original editor |
+| [Notepad2-mod](https://xhmikosr.github.io/notepad2-mod/) | XhmikosR | Extended fork |
+| [Scintilla](https://www.scintilla.org/) 5.5.8 | Neil Hodgson | Editing component |
+| [Lexilla](https://www.scintilla.org/Lexilla.html) 5.4.6 | Neil Hodgson | Syntax highlighting |
+| [Oniguruma](https://github.com/kkos/oniguruma) | K. Kosako | Regex engine |
+| [uchardet](https://www.freedesktop.org/wiki/Software/uchardet/) | Mozilla / freedesktop | Encoding detection |
+| Fugue Icons | Yusuke Kamiyamane | Toolbar icons |
-#### `SubWrappedLineSelectOnMarginClick=false`
+## Reviews
-Set to `true` to revert to old selection behavior:
-- 1 click on line-number margin selects the entire corresponding line
-- 1 double click on line-number margin selects the entire line with all sub-lines.
+- [Notepad3 is an advanced text editor that supports many programming languages](https://www.ghacks.net/2020/08/11/notepad3-is-an-advanced-text-editor-that-supports-many-programming-languages/) — gHacks
+- [Notepad3 review on Nsane Forums](https://www.nsaneforums.com/topic/382910-guidereview-notepad3-is-an-advanced-text-editor-that-supports-many-programming-languages/) — Nsane Forums
-#### `LaunchInstanceWndPosOffset=28`
+## License
-#### `LaunchInstanceFullVisible=true`
+Notepad3 is licensed under the [BSD 3-Clause License](License.txt).
-#### `UseOldStyleBraceMatching=0`
+Copyright © 2008–2026 [Rizonesoft](https://rizonesoft.com). All rights reserved.
-UseOldStyleBraceMatching=1 to switch back to (not recommended) old style behavior
+---
-#### `WebTemplate1=https://google.com/search?q=%s`
-
-#### `WebTmpl1MenuName=Open Web Action 1`
-
-#### `WebTemplate2=https://en.wikipedia.org/w/index.php?search=%s`
-
-#### `WebTmpl2MenuName=Open Web Action 2
-
-#### `ExtendedWhiteSpaceChars=:`
-
-Put in here all ASCII chars which will be word delimiters for "Accelerated Word Navigation".
-
-#### `AutoCompleteWordCharSet=`
-
-Is set automatically for CJK input languages (GetACP()).
-
-If you define your own character-set in AutoCompleteWordCharSet, Auto-Completion word list is limited to words composed of these chars only (case insensitive).)
-
-#### `AutoCompleteFillUpChars=`
-
-New configuration .ini-file: [Settings2] AutoCompleteFillUpChars=
-To get the "Enter" completion behavior back, define: [Settings2] AutoCompleteFillUpChars=\r\n
-I you like to allow more "fill-up" characters (accept completion item), just add them:
-- e.g. [Settings2] AutoCompleteFillUpChars=\r\n[(. (will accept completion item & adds the char).
-
-#### `LineCommentPostfixStrg=`
-
-It will be appended/removed to the comment tag on line comment block toggle.
-If the string contains spaces, you have to double-quote it,
-- e.g. [Settings2] LineCommentPostfixStrg=" " to add a space after the comment tag (origin and title of this feature request).
-
-#### `UpdateDelayMarkAllOccurrences=50`
-
-#### `CurrentLineHorizontalSlop=40`
-
-#### `CurrentLineVerticalSlop=5`
-
-#### `UndoTransactionTimeout=0`
-
-- in [msec]
-
-UndoTransactionTimeout=1 (will be clamped to 10msec min.) will separate nearly every keystroke as single undo action.
-(UndoTransactionTimeout=0 will switch this timer OFF)
-
-#### `AdministrationTool.exe=`
-
-This parameter is not used at the moment.
-
-#### `DevDebugMode=0`
-
-Encoding Detector information in Titlebar. This parameter is used to "debug" UCHARDET.
-
-#### `AnalyzeReliableConfidenceLevel=90`
-
-Confidence/Reliability level for reliability switch in encoding dialog.
-
-#### `LocaleAnsiCodePageAnalysisBonus=33`
-
-Bias/Bonus on top of Confidence/Reliability if current system's ANSI Code-Page is file encoding analysis result.
-(This will push detection algorithm to like system's ANSI Code-Page more than other detection result)
-
-#### `LexerSQLNumberSignAsComment=1`
-
-The # (hash) is the start of a line comment in MySQL dialect.
-But if this is confusing, it can be switched off by providing an option to Scintilla's SQL-Lexer
-(set option: lexer.sql.numbersign.comment to 0 (zero)).
-
-Unfortunately, in Notepad3, this can not be done by configuration, it can only be done hard coded.
-- Ed.: The default is "OFF", it is set to "ON" explicitly in Notepad3 (hard coded) to preserve old behavior,
-
-#### `ExitOnESCSkipLevel=2`
-
-The leveling of ESC behavior (msg-boxes -> selection -> exit) leads to following implementation:
-
-New parameter "[Settings2] ExitOnESCSkipLevel = 2"
-- Level 2 : ESC cancels every single state separately (the default).
-- Level 1 : ESC cancels message-box and ignores Selection.
-- Level 0 : ESC cancels all states and proceeds to Exit (if configured).
-
-#### `ZoomTooltipTimeout=3200`
-
-- in [msec]
-- A value of zero (0) (or less than 100 msec) will disable the tooltip display.
-
-#### `WrapAroundTooltipTimeout=2000`
-
-- in [msec]
-- A value of zero (0) (or less than 100 msec) will disable the tooltip display.
-
-#### `LargeIconScalePrecent=150`
-
-- `Screen/Display Scale Percent` threshold to switch to bigger file types icons (lexer style selections)
-
-#### `DarkModeBkgColor=0x1F1F1F`
-
-#### `DarkModeBtnFaceColor=0x333333`
-
-#### `DarkModeTxtColor=0xEFEFEF`
-
-#### `HyperlinkShellExURLWithApp=""`
-
-- If not defined or empty the default behavior on `Ctrl+Click` URL is performed:
-- The URL-String is sent to the OS via ShellExecute(), which will try open the URL using the registered protocol (e.g. http:// or file://) - in most cases the default browser resp. the file, if extension is known.
-- If defined, e.g. "`D:\PortableApps\GoogleChromePortable\GoogleChromePortable.exe`", this application will be started on `Ctrl+Click`.
-
-#### `HyperlinkShellExURLCmdLnArgs="${URL}"`
-
-- (use ${URL} as place holder for clicked Hyperlink URL string)
-- Defining the argument/parameter string for the above application (only taken into account if `HyperlinkShellExURLWithApp` is defined).
-- If not defined, empty or set to "${URL}", the argument for the app will be the URL-String clicked.
-You can specify more command line parameter for the app here. The token `${URL}` within the string will be replaced by the URL-String clicked. E.g. `HyperlinkShellExURLCmdLnArgs="--incognito "${URL}""` will start the Chrome-Browser (see `HyperlinkShellExURLWithApp`) in "incognito mode" trying to open the clicked URL.
-
-#### `HyperlinkFileProtocolVerb=""`
-
-- `ShellExecuteEx()::lpVerb (""=default, "edit", "explore", "find", "open", "print", "properties", "runas")`
-
-#### `CodeFontPrefPrioList="Cascadia Code,Cascadia Mono,Cousine,Fira Code,Source Code Pro,Roboto Mono,DejaVu Sans Mono,Inconsolata,Consolas,Lucida Console"`
-
-Configurable Fonts priority list for for "Common Base" Scheme.
-
-#### `TextFontPrefPrioList="Cascadia Mono,Cousine,Roboto Mono,DejaVu Sans Mono,Inconsolata,Consolas,Lucida Console"`
-
-Configurable Fonts priority list for "Text Files" Scheme.
-
-
-## **`[Statusbar Settings]`**
-
-This section provides the ability to set the number, order and width of columns,
-and the prefix text of the status bar fields.
-
-#### `VisibleSections=0 1 15 14 2 4 5 6 7 8 9 10 11` (internal default)
-
-This parameter is used to define, which fields of the Status Bar should be visible.
-If used, this setting also defines the field ordering.
-
-- Section 0 = Ln : Line number of Caret position / Number total of lines in the file
-- Section 1 = Col : Column number of Caret position / Limit for Long Line settings
-- Section 2 = Sel : Number of characters selected
-- Section 3 = Sb : Number of bytes (Bytes in [UTF-8]) selected
-- Section 4 = SLn : Number of selected lines
-- Section 5 = Occ : Number of Marked Occurrences
-- Section 6 = Size of file in [UTF-8] Mode
-- Section 7 = Encoding Mode (double click to open `Encoding F9` )
-- Section 8 = EOL Mode (Toggle CR+LF, LF, CR)
-- Section 9 = Toggle INS/OVR Mode
-- Section 10 = Toggle STD/2ND Text Mode (Default Text or 2nd Default Text)
-- Section 11 = Current Scheme (double click to open `Select Scheme` )
-- Section 12 = Character Count (per line from line start)
-- Section 13 = Replaced Occurrences
-- Section 14 = TinyExpr Evaluation
-- Section 15 = Unicode point display (UTF-16 encoding) of current (caret pos) character.
-
-#### `SectionPrefixes=Ln ,Col ,Sel ,Sb ,SLn ,Occ ,,,,,,,Ch ,Repl ,Eval ,U+,` (internal default)
-
-This parameter is used to redefines the displayed Prefixes in the sections of the Status Bar
-- A “,” (comma) is used as separator. Spaces are **NOT** ignored.
-
-#### `SectionPostfixes=,,,,,,,,,,,,,,,,` (internal default)
-
-This parameter is used to redefines the displayed Postfixes in the sections of the Status Bar
-- A “,” (comma) is used as separator. Spaces are **NOT** ignored.
-
-#### `SectionWidthSpecs=30 20 20 20 20 20 20 0 0 0 0 0 0 0 20 24` (internal default)
-
-This parameter is used to define the relative width of each field of the Status Bar
-- 0 = space optimized fit to text (dynamically adapted to width changes)
-- -n (neg. val) = fixed width of section [pix] , longer text is truncated
-
-Fine tuning: increase, decrease or modify the value of numbers,
-- e.g.: `;;;;;;;;;;;;;;;;; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15`
-- `SectionWidthSpecs=50 40 42 40 36 40 0 0 0 0 0 -10 40 40 -40 40`
-
-#### `ZeroBasedColumnIndex=0`
-
-This parameter is used to define start counting of column (`Col`) at 0 or 1.
-
-#### `ZeroBasedCharacterCount=0`
-
-This parameter is used to define start counting of characters (of current line) (`Ch`) at 0 or 1.
-
-
-## **`[Toolbar Labels]`**
-
-This section offers the possibility to display the name of the function to the right of its corresponding icon.
-
-```
-01=New
-02=Open
-03=Browse
-04=Save
-05=Undo
-06=Redo
-07=Cut
-08=Copy
-09=Paste
-10=Find
-11=Replace
-12=Word Wrap
-13=Zoom In
-14=Zoom Out
-15=Scheme
-16=Customize Schemes
-17=Exit
-18=Save As
-19=Save Copy
-20=Delete
-21=Print
-22=Favorites
-23=Add to Favorites
-24=Toggle Folds
-25=Execute Document
-26=Focused View
-27=Monitoring Log
-28=History
-29=Always On Top
-30=Search in Files
-31=Reset Zoom
-32=New Empty Window
-```
-
-
-## **`[Window]`**
-
-#### `x DefaultWindowPosition=`
-
-This items are managed by Notepad3. (`Menu->View->Position->Save as Default Position`)
-(Will set current window position as "Default Position" - can be recalled by `Ctrl+Shift+P` Hotkey)
-
-
-
+[](https://github.com/sponsors/rizonesoft)
+[](https://www.paypal.com/donate/?hosted_button_id=7UGGCSDUZJPFE)
diff --git a/doc/Configuration.md b/doc/Configuration.md
new file mode 100644
index 000000000..eafee8c7d
--- /dev/null
+++ b/doc/Configuration.md
@@ -0,0 +1,485 @@
+# Notepad3 Configuration Reference
+
+Notepad3 stores its settings in a portable INI file (`Notepad3.ini`). Press **Ctrl+F7** to open it directly in the editor. Most `[Settings2]` changes require restarting Notepad3.
+
+---
+
+## `[Notepad3]`
+
+This section can redirect to a different settings file. Useful when a non-elevated user cannot write to the Notepad3 program directory:
+
+```ini
+Notepad3.ini=%APPDATA%\Rizonesoft\Notepad3\Notepad3.ini
+```
+
+Or for per-user settings:
+
+```ini
+Notepad3.ini=%WINDIR%\Notepad3-%USERNAME%.ini
+```
+
+---
+
+## `[Settings]`
+
+These settings are managed through Notepad3's user interface (Menu → Settings). For example:
+
+#### `SettingsVersion=5`
+
+#### `Favorites=%APPDATA%\Rizonesoft\Notepad3\Favorites\`
+
+---
+
+## `[Settings2]`
+
+Advanced settings that can only be edited manually. Press **Ctrl+F7** to open the INI file.
+
+### Localization
+
+#### `PreferredLanguageLocaleName=en-US`
+
+The default value is determined by the OS language setting. Fallback: `en-US`.
+
+Available languages:
+
+| Language | Locale Code |
+|----------|-------------|
+| English/United States | `en-US` (internal default) |
+| Afrikaans/South Africa | `af-ZA` |
+| Belarusian/Belarus | `be-BY` |
+| German/Germany | `de-DE` |
+| Greek/Greece | `el-GR` |
+| English/United Kingdom | `en-GB` |
+| Spanish/Spain | `es-ES` |
+| French/France | `fr-FR` |
+| Hindi/India | `hi-IN` |
+| Hungarian/Hungary | `hu-HU` |
+| Indonesian/Indonesia | `id-ID` |
+| Italian/Italy | `it-IT` |
+| Japanese/Japan | `ja-JP` |
+| Korean/Korea | `ko-KR` |
+| Dutch/Netherlands | `nl-NL` |
+| Polish/Poland | `pl-PL` |
+| Portuguese/Brazil | `pt-BR` |
+| Portuguese/Portugal | `pt-PT` |
+| Russian/Russia | `ru-RU` |
+| Slovak/Slovakia | `sk-SK` |
+| Swedish/Sweden | `sv-SE` |
+| Turkish/Turkey | `tr-TR` |
+| Vietnamese/Vietnam | `vi-VN` |
+| Chinese Simplified/China | `zh-CN` |
+| Chinese Traditional/Taiwan | `zh-TW` |
+
+### IME & Input
+
+#### `IMEInteraction=0`
+
+### Date & Time
+
+#### `DateTimeFormat=`
+
+Locale-dependent short format. Specify the short date/time format using [`strftime()`](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/strftime-wcsftime-strftime-l-wcsftime-l?view=vs-2019) syntax.
+
+#### `DateTimeLongFormat=`
+
+Locale-dependent long format.
+
+#### `TimeStampRegEx=`
+
+Default: `\$Date:[^\$]+\$` — Find pattern to match timestamps for update.
+
+#### `TimeStampFormat=`
+
+Default: `$Date: %Y/%m/%d %H:%M:%S $`
+
+This pattern is used by **Shift+F5** to update timestamps, e.g., `$Date: 2018/04/26 00:52:39 $`.
+
+**Notes:**
+- All `DateTime` formats accept [`strftime()`](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/strftime-wcsftime-strftime-l-wcsftime-l?view=vs-2019) format strings.
+- `TimeStampFormat` also accepts `%s` as a placeholder for a `DateTimeFormat`-formatted current date/time string (mixing `strftime()` codes with `%s` is not allowed).
+- If you define a custom `TimeStampFormat`, define a matching `TimeStampRegEx` so that "Update Timestamps" can find and replace them correctly.
+
+### Files & Directories
+
+#### `DefaultDirectory=`
+
+Default directory for open/save dialogs when no file is open. Paths can be relative to the Notepad3 program directory.
+
+#### `DefaultExtension=txt`
+
+Default extension for saved files (omit the leading dot).
+
+#### `DenyVirtualSpaceAccess=0`
+
+#### `filebrowser.exe=minipath.exe`
+
+External program launched by the Browse toolbar button. Defaults to MiniPath.
+
+Additional command line switches can be appended. The currently opened file is passed as the last argument.
+
+> **Note:** Pathnames with spaces need quadruple quoting (`""path to/file.exe""`) when no arguments follow, or double quoting (`"path to/file.exe" /arg`) with arguments.
+
+Alternative file browsers:
+- `filebrowser.exe=explorer.exe` — Windows Explorer
+- `filebrowser.exe=Explorer++.exe` — [Explorer++](https://explorerplusplus.com/)
+- `filebrowser.exe=Q-Dir_x64+.exe` — [Q-Dir](https://www.softwareok.de/?seite=Freeware/Q-Dir/)
+
+#### `grepWin.exe=grepWinNP3.exe`
+
+Integrated search-and-replace tool with regex support. Launch via:
+- File → Launch → Search in Files
+- Edit → Search → Search in Files
+- **Ctrl+Shift+F**
+
+#### `FileCheckInterval=2000`
+
+Interval in milliseconds to check for external file modification. Min: 200 ms (notify immediately if ≤ 200).
+
+#### `FileChangedIndicator=[@]`
+
+#### `FileDeletedIndicator=[X]`
+
+#### `FileDlgFilters=`
+
+Custom filters for open/save dialogs. Example:
+
+```
+Text Files|*.txt;*.wtx;*.log;*.asc;*.doc;*.diz;*.nfo|All Files|*.*
+```
+
+#### `FileLoadWarningMB=4`
+
+Size limit (MB) for large-file warning. Set to `0` to disable.
+
+#### `MultiFileArg=0`
+
+Set to `1` to allow multiple files on the command line. Default (`0`) accepts a single file like Windows Notepad. Use `+` and `-` command-line switches to override; `/z` behaves like `-`.
+
+### Language Detection
+
+#### `NoCGIGuess=0`
+
+Set to `1` to disable language detection for `.cgi` and `.fcgi` files.
+
+#### `NoHTMLGuess=0`
+
+Set to `1` to disable HTML/XML detection for files without extensions.
+
+### Editing Behavior
+
+#### `NoCopyLineOnEmptySelection=0`
+
+Set to `1` to prevent **Ctrl+C** from copying the current line when nothing is selected.
+
+#### `NoCutLineOnEmptySelection=0`
+
+Set to `1` to prevent **Ctrl+X** from cutting the current line when nothing is selected.
+
+#### `NoFadeHidden=0`
+
+Set to `1` to disable fading of hidden objects in file lists (Favorites, etc.).
+
+#### `NoFileVariables=0`
+
+Set to `1` to disable file variable parsing. Encoding tag parsing can be disabled separately in Menu → File → Encoding → Default.
+
+Notepad3 parses Emacs-style variables in the first and last 512 bytes of a file:
+
+| Variable | Effect |
+|----------|--------|
+| `coding: utf-8;` | File encoding tag |
+| `mode: python;` | Syntax scheme (name or extension) |
+| `tab-width: 8;` | Tab width |
+| `c-basic-indent: 2;` | Indentation size |
+| `indent-tabs-mode: nil;` | Insert tabs as spaces (`nil`/`false`/`0`) or not (`true`/`1`) |
+| `c-tab-always-indent: true;` | Tab key reformats whitespace (`true`/`1`) or not |
+| `fill-column: 64;` | Long-line limit (does not auto-show the visual marker) |
+| `truncate-lines: false;` | Word wrap: enable (`nil`/`false`/`0`), disable (`true`/`1`) |
+| `enable-local-variables: false;` | Disable variable parsing but keep encoding tags |
+
+To bypass both file variable and encoding tag parsing, reload the file with **Alt+F8**.
+
+### Portability & Window
+
+#### `PortableMyDocs=1`
+
+Store recent file paths relative to `My Documents` for USB portability across Windows versions. Enabled by default when `RelativeFileMRU=1`.
+
+#### `OpacityLevel=75`
+
+Window opacity (%) in transparent mode.
+
+#### `FindReplaceOpacityLevel=50`
+
+Find/Replace dialog opacity (%) in transparent mode.
+
+#### `RelativeFileMRU=1`
+
+Store recent file paths as relative when on the same drive/share as Notepad3.exe.
+
+#### `ReuseWindow=0`
+
+Managed by Notepad3 (Menu → Settings → Window → Reuse Window, **Ctrl+Shift+L**). When enabled, new instances hand off to the existing window.
+
+#### `SaveBlankNewFile=true`
+
+Whether to prompt for save when closing an untitled document that contains only whitespace.
+
+#### `SciFontQuality=3`
+
+#### `SimpleIndentGuides=0`
+
+Set to `1` to prevent indentation guides from jumping across empty lines.
+
+#### `SingleFileInstance=1`
+
+Managed by Notepad3.
+
+#### `ShellAppUserModelID=Rizonesoft.Notepad3`
+
+#### `ShellUseSystemMRU=1`
+
+Controls taskbar grouping, Jump List, and system MRU behavior. See [Replacing Windows Notepad](https://rizonesoft.com/documents/notepad3/) for details.
+
+#### `StickyWindowPosition=0`
+
+Managed by Notepad3 (Menu → View → Position → Sticky Window Position). Remembers current position on restart instead of last-closed position.
+
+#### `SubWrappedLineSelectOnMarginClick=false`
+
+Set to `true` for old selection behavior: single click selects the visible sub-line, double click selects the entire wrapped line.
+
+#### `LaunchInstanceWndPosOffset=28`
+
+#### `LaunchInstanceFullVisible=true`
+
+### Appearance
+
+#### `UseOldStyleBraceMatching=0`
+
+Set to `1` for legacy brace-matching style.
+
+#### `LargeIconScalePrecent=150`
+
+Display scale percent threshold to switch to larger file-type icons.
+
+#### `DarkModeBkgColor=0x1F1F1F`
+
+#### `DarkModeBtnFaceColor=0x333333`
+
+#### `DarkModeTxtColor=0xEFEFEF`
+
+### Web Actions
+
+#### `WebTemplate1=https://google.com/search?q=%s`
+
+#### `WebTmpl1MenuName=Open Web Action 1`
+
+#### `WebTemplate2=https://en.wikipedia.org/w/index.php?search=%s`
+
+#### `WebTmpl2MenuName=Open Web Action 2`
+
+### Auto-Completion & Editing
+
+#### `ExtendedWhiteSpaceChars=:`
+
+Additional ASCII characters treated as word delimiters for Accelerated Word Navigation.
+
+#### `AutoCompleteWordCharSet=`
+
+Set automatically for CJK input languages. Custom character sets limit the auto-completion word list to words composed of these characters only (case-insensitive).
+
+#### `AutoCompleteFillUpChars=`
+
+Characters that accept an auto-completion item. For Enter-to-complete behavior:
+
+```ini
+AutoCompleteFillUpChars=\r\n
+```
+
+To also accept on `(` or `.`:
+
+```ini
+AutoCompleteFillUpChars=\r\n(.
+```
+
+#### `LineCommentPostfixStrg=`
+
+String appended/removed after comment tags on line-comment toggle. Double-quote if it contains spaces:
+
+```ini
+LineCommentPostfixStrg=" "
+```
+
+### Hyperlinks
+
+#### `HyperlinkShellExURLWithApp=""`
+
+External application for **Ctrl+Click** on URLs. If empty, the OS default handler is used.
+
+#### `HyperlinkShellExURLCmdLnArgs="${URL}"`
+
+Command-line arguments for the URL application. Use `${URL}` as placeholder:
+
+```ini
+HyperlinkShellExURLCmdLnArgs="--incognito "${URL}""
+```
+
+#### `HyperlinkFileProtocolVerb=""`
+
+`ShellExecuteEx` verb: `""` (default), `"edit"`, `"explore"`, `"find"`, `"open"`, `"print"`, `"properties"`, `"runas"`.
+
+### Fonts
+
+#### `CodeFontPrefPrioList="Cascadia Code,Cascadia Mono,Cousine,Fira Code,Source Code Pro,Roboto Mono,DejaVu Sans Mono,Inconsolata,Consolas,Lucida Console"`
+
+Font priority list for the "Common Base" scheme.
+
+#### `TextFontPrefPrioList="Cascadia Mono,Cousine,Roboto Mono,DejaVu Sans Mono,Inconsolata,Consolas,Lucida Console"`
+
+Font priority list for the "Text Files" scheme.
+
+### Miscellaneous
+
+#### `UpdateDelayMarkAllOccurrences=50`
+
+#### `CurrentLineHorizontalSlop=40`
+
+#### `CurrentLineVerticalSlop=5`
+
+#### `UndoTransactionTimeout=0`
+
+Timeout in milliseconds. Set to `1` (clamped to 10 ms minimum) to make nearly every keystroke a separate undo action. `0` disables the timer.
+
+#### `AdministrationTool.exe=`
+
+Reserved for future use.
+
+#### `DevDebugMode=0`
+
+Show encoding detector (UCHARDET) info in the title bar for debugging.
+
+#### `AnalyzeReliableConfidenceLevel=90`
+
+Confidence threshold for the encoding reliability indicator.
+
+#### `LocaleAnsiCodePageAnalysisBonus=33`
+
+Bias added to confidence when the system's ANSI code page matches the detected encoding.
+
+#### `LexerSQLNumberSignAsComment=1`
+
+Enable `#` as a line-comment character in MySQL-dialect SQL. Set to `0` to disable.
+
+#### `ExitOnESCSkipLevel=2`
+
+Controls ESC key behavior:
+- **2** (default): Cancel each state separately (message boxes → selection → exit)
+- **1**: Cancel message boxes, skip selection state
+- **0**: Cancel all states and proceed to exit (if configured)
+
+#### `ZoomTooltipTimeout=3200`
+
+Zoom tooltip display duration in milliseconds. Set to `0` to disable.
+
+#### `WrapAroundTooltipTimeout=2000`
+
+Search wrap-around tooltip duration in milliseconds. Set to `0` to disable.
+
+---
+
+## `[Statusbar Settings]`
+
+Customize the status bar layout: number, order, width, and prefix/postfix text of fields.
+
+#### `VisibleSections=0 1 15 14 2 4 5 6 7 8 9 10 11`
+
+Defines visible fields and their order:
+
+| Section | Content |
+|---------|---------|
+| 0 | Ln — Line number / Total lines |
+| 1 | Col — Column number / Long-line limit |
+| 2 | Sel — Selected characters |
+| 3 | Sb — Selected bytes (UTF-8) |
+| 4 | SLn — Selected lines |
+| 5 | Occ — Marked occurrences |
+| 6 | File size (UTF-8 mode) |
+| 7 | Encoding (double-click to open Encoding dialog) |
+| 8 | EOL mode (toggle CR+LF / LF / CR) |
+| 9 | INS/OVR mode toggle |
+| 10 | STD/2ND text mode toggle |
+| 11 | Current scheme (double-click to open scheme selector) |
+| 12 | Ch — Character count from line start |
+| 13 | Repl — Replaced occurrences |
+| 14 | Eval — TinyExpr evaluation |
+| 15 | U+ — Unicode code point (UTF-16) at caret |
+
+#### `SectionPrefixes=Ln ,Col ,Sel ,Sb ,SLn ,Occ ,,,,,,,Ch ,Repl ,Eval ,U+,`
+
+Redefine display prefixes. Comma-separated; spaces are significant.
+
+#### `SectionPostfixes=,,,,,,,,,,,,,,,,`
+
+Redefine display postfixes. Comma-separated; spaces are significant.
+
+#### `SectionWidthSpecs=30 20 20 20 20 20 20 0 0 0 0 0 0 0 20 24`
+
+Relative field widths. `0` = auto-fit, negative = fixed pixel width (text truncated).
+
+#### `ZeroBasedColumnIndex=0`
+
+Start column counting at 0 or 1.
+
+#### `ZeroBasedCharacterCount=0`
+
+Start character counting at 0 or 1.
+
+---
+
+## `[Toolbar Labels]`
+
+Display function names next to toolbar icons:
+
+```ini
+01=New
+02=Open
+03=Browse
+04=Save
+05=Undo
+06=Redo
+07=Cut
+08=Copy
+09=Paste
+10=Find
+11=Replace
+12=Word Wrap
+13=Zoom In
+14=Zoom Out
+15=Scheme
+16=Customize Schemes
+17=Exit
+18=Save As
+19=Save Copy
+20=Delete
+21=Print
+22=Favorites
+23=Add to Favorites
+24=Toggle Folds
+25=Execute Document
+26=Focused View
+27=Monitoring Log
+28=History
+29=Always On Top
+30=Search in Files
+31=Reset Zoom
+32=New Empty Window
+```
+
+---
+
+## `[Window]`
+
+#### `x DefaultWindowPosition=`
+
+Managed by Notepad3 (Menu → View → Position → Save as Default Position). Recall with **Ctrl+Shift+P**.
diff --git a/scintilla/include/Scintilla.h b/scintilla/include/Scintilla.h
index c29cf44da..066289357 100644
--- a/scintilla/include/Scintilla.h
+++ b/scintilla/include/Scintilla.h
@@ -863,8 +863,6 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP
#define SC_POPUP_TEXT 2
#define SCI_USEPOPUP 2371
#define SCI_SELECTIONISRECTANGLE 2372
-#define SC_MIN_ZOOM_LEVEL 10
-#define SC_MAX_ZOOM_LEVEL 1000
#define SCI_SETZOOM 2373
#define SCI_GETZOOM 2374
#define SC_DOCUMENTOPTION_DEFAULT 0
diff --git a/scintilla/include/Scintilla.iface b/scintilla/include/Scintilla.iface
index 3f9e5988d..a44073192 100644
--- a/scintilla/include/Scintilla.iface
+++ b/scintilla/include/Scintilla.iface
@@ -2265,12 +2265,6 @@ fun void UsePopUp=2371(PopUp popUpMode,)
# Is the selection rectangular? The alternative is the more common stream selection.
get bool SelectionIsRectangle=2372(,)
-# >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>>
-# 2018-09-06 change zoom level and print magnification to percent value
-val SC_MIN_ZOOM_LEVEL=10
-val SC_MAX_ZOOM_LEVEL=1000
-# <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<<
-
# Set the zoom level. This number of points is added to the size of all fonts.
# It may be positive to magnify or negative to reduce.
set void SetZoom=2373(int zoomInPoints,)
diff --git a/scintilla/src/EditView.cxx b/scintilla/src/EditView.cxx
index 749af561a..7215307fa 100644
--- a/scintilla/src/EditView.cxx
+++ b/scintilla/src/EditView.cxx
@@ -71,9 +71,7 @@ using namespace Scintilla;
using namespace Scintilla::Internal;
PrintParameters::PrintParameters() noexcept {
- // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>>
- magnification = 100;
- // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<<
+ magnification = 0;
colourMode = PrintOption::Normal;
wrapState = Wrap::Word;
}
diff --git a/scintilla/src/ViewStyle.cxx b/scintilla/src/ViewStyle.cxx
index da7d7fd06..75370f04b 100644
--- a/scintilla/src/ViewStyle.cxx
+++ b/scintilla/src/ViewStyle.cxx
@@ -63,12 +63,8 @@ bool MarginStyle::ShowsFolding() const noexcept {
void FontRealised::Realise(Surface &surface, int zoomLevel, Technology technology, const FontSpecification &fs, const char *localeName) {
PLATFORM_ASSERT(fs.fontName);
- // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>>
- //~measurements.sizeZoomed = fs.size + zoomLevel * FontSizeMultiplier;
- //~if (measurements.sizeZoomed <= FontSizeMultiplier) // May fail if sizeZoomed < 1
- //~ measurements.sizeZoomed = FontSizeMultiplier;
- measurements.sizeZoomed = GetFontSizeZoomed(fs.size, zoomLevel);
- // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<<
+ // If negative zoomLevel, ensure sizeZoomed at least minimum positive size
+ measurements.sizeZoomed = std::max(fs.size + (zoomLevel * FontSizeMultiplier), FontSizeMultiplier);
const float deviceHeight = static_cast(surface.DeviceHeightFont(measurements.sizeZoomed));
const FontParameters fp(fs.fontName, deviceHeight / FontSizeMultiplier, fs.weight,
@@ -234,9 +230,7 @@ ViewStyle::ViewStyle(size_t stylesSize_) :
marginInside = true;
CalculateMarginWidthAndMask();
textStart = marginInside ? fixedColumnWidth : leftMarginWidth;
- // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>>
- zoomLevel = 100; /// @ 20018-09-06 Changed to percent
- // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<<
+ zoomLevel = 0;
viewWhitespace = WhiteSpace::Invisible;
tabDrawMode = TabDrawMode::LongArrow;
whitespaceSize = 1;
@@ -771,44 +765,6 @@ ViewStyle::CaretShape ViewStyle::CaretShapeForMode(bool inOverstrike, bool isMai
return (caretStyle <= CaretStyle::Block) ? static_cast(caretStyle) : CaretShape::line;
}
-// >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>>
-bool ViewStyle::ZoomIn() noexcept {
- if (zoomLevel < SC_MAX_ZOOM_LEVEL) {
- int level = zoomLevel;
- if (level < 200) {
- level += 10;
- } else {
- level += 25;
- }
-
- level = std::min(level, SC_MAX_ZOOM_LEVEL);
- if (level != zoomLevel) {
- zoomLevel = level;
- return true;
- }
- }
- return false;
-}
-
-bool ViewStyle::ZoomOut() noexcept {
- if (zoomLevel > SC_MIN_ZOOM_LEVEL) {
- int level = zoomLevel;
- if (level <= 200) {
- level -= 10;
- } else {
- level -= 25;
- }
-
- level = std::max(level, SC_MIN_ZOOM_LEVEL);
- if (level != zoomLevel) {
- zoomLevel = level;
- return true;
- }
- }
- return false;
-}
-// <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<<
-
void ViewStyle::AllocStyles(size_t sizeNew) {
size_t i=styles.size();
styles.resize(sizeNew);
diff --git a/scintilla/src/ViewStyle.h b/scintilla/src/ViewStyle.h
index 28474d536..4e4ea0d73 100644
--- a/scintilla/src/ViewStyle.h
+++ b/scintilla/src/ViewStyle.h
@@ -71,14 +71,6 @@ struct CaretLineAppearance {
int frame = 0;
};
-// >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>>
-constexpr int GetFontSizeZoomed(int size, int zoomLevel) noexcept {
- size = (size * zoomLevel + 50) / 100;
- // Hangs if sizeZoomed (in point) <= 1
- return std::max(size, 2 * FontSizeMultiplier);
-}
-// <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<<
-
struct CaretAppearance {
// Line, block, over-strike bar ...
Scintilla::CaretStyle style = CaretStyle::Line;
@@ -160,9 +152,7 @@ class ViewStyle {
int fixedColumnWidth = 0; ///< Total width of margins
bool marginInside; ///< true: margin included in text view, false: separate views
int textStart; ///< Starting x position of text within the view
- // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>>
- int zoomLevel; /// @ 2018-09-06 Changed to a percent value
- // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<<
+ int zoomLevel;
Scintilla::WhiteSpace viewWhitespace;
Scintilla::TabDrawMode tabDrawMode;
int whitespaceSize;
@@ -259,10 +249,6 @@ class ViewStyle {
bool IsCaretVisible(bool isMainSelection) const noexcept;
bool DrawCaretInsideSelection(bool inOverstrike, bool imeCaretBlockOverride) const noexcept;
CaretShape CaretShapeForMode(bool inOverstrike, bool isMainSelection) const noexcept;
- // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>>
- bool ZoomIn() noexcept;
- bool ZoomOut() noexcept;
- // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<<
private:
void AllocStyles(size_t sizeNew);
diff --git a/scintilla/win32/ScintillaWin.cxx b/scintilla/win32/ScintillaWin.cxx
index e39656e88..54f89e0b7 100644
--- a/scintilla/win32/ScintillaWin.cxx
+++ b/scintilla/win32/ScintillaWin.cxx
@@ -333,12 +333,9 @@ class IMContext {
void SetCompositionFont(const ViewStyle &vs, int style, UINT dpi) const {
LOGFONTW lf{};
- // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>>
- //int sizeZoomed = vs.styles[style].size + (vs.zoomLevel * FontSizeMultiplier);
- //if (sizeZoomed <= 2 * FontSizeMultiplier) // Hangs if sizeZoomed <= 1
- // sizeZoomed = 2 * FontSizeMultiplier;
- int const sizeZoomed = GetFontSizeZoomed(vs.styles[style].size, vs.zoomLevel);
- // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<<
+ int sizeZoomed = vs.styles[style].size + (vs.zoomLevel * FontSizeMultiplier);
+ if (sizeZoomed <= 2 * FontSizeMultiplier) // Hangs if sizeZoomed <= 1
+ sizeZoomed = 2 * FontSizeMultiplier;
// The negative is to allow for leading
lf.lfHeight = -::MulDiv(sizeZoomed, dpi, pointsPerInch * FontSizeMultiplier);
lf.lfWeight = static_cast(vs.styles[style].weight);
@@ -1959,15 +1956,7 @@ sptr_t ScintillaWin::MouseMessage(unsigned int iMessage, uptr_t wParam, sptr_t l
// >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>>
if (wParam & (MK_CONTROL | MK_RBUTTON)) {
- if (wParam & (MK_CONTROL)) {
- // Zoom! We play with the font sizes in the styles.
- // Number of steps/line is ignored, we just care if sizing up or down
- if (linesToScroll < 0)
- KeyCommand(Message::ZoomIn);
- else
- KeyCommand(Message::ZoomOut);
- }
- // send to main window (trigger zoom callTip or undo/redo history) !
+ // Forward to parent (NP3 handles zoom steps and undo/redo history)
::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
} else {
// Scroll
diff --git a/src/Config/Config.cpp b/src/Config/Config.cpp
index f99b92ba2..4713c610b 100644
--- a/src/Config/Config.cpp
+++ b/src/Config/Config.cpp
@@ -1713,11 +1713,11 @@ void LoadSettings()
int const prtFontSize = 10;
int const zoomScale = MulDiv(baseZoom, prtFontSize, f2int(GLOBAL_INITIAL_FONTSIZE));
Defaults.PrintZoom = (Globals.iCfgVersionRead < CFG_VER_0001) ? (zoomScale / 10) : zoomScale;
- int iPrintZoom = clampi(IniSectionGetInt(IniSecSettings, L"PrintZoom", Defaults.PrintZoom), 0, SC_MAX_ZOOM_LEVEL);
+ int iPrintZoom = clampi(IniSectionGetInt(IniSecSettings, L"PrintZoom", Defaults.PrintZoom), 0, NP3_MAX_ZOOM_PERCENT);
if (Globals.iCfgVersionRead < CFG_VER_0001) {
iPrintZoom = 100 + (iPrintZoom - 10) * 10;
}
- Settings.PrintZoom = clampi(iPrintZoom, SC_MIN_ZOOM_LEVEL, SC_MAX_ZOOM_LEVEL);
+ Settings.PrintZoom = clampi(iPrintZoom, NP3_MIN_ZOOM_PERCENT, NP3_MAX_ZOOM_PERCENT);
GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_IMEASURE, tchKeyName, COUNTOF(tchKeyName));
LONG const _margin = (tchKeyName[0] == L'0') ? 2000L : 1000L; // Metric system. L'1' is US System
@@ -1886,7 +1886,7 @@ void LoadSettings()
if (Globals.iCfgVersionRead < CFG_VER_0001) {
winInfo.zoom = (winInfo.zoom + 10) * 10;
}
- winInfo.zoom = clampi(winInfo.zoom, SC_MIN_ZOOM_LEVEL, SC_MAX_ZOOM_LEVEL);
+ winInfo.zoom = clampi(winInfo.zoom, NP3_MIN_ZOOM_PERCENT, NP3_MAX_ZOOM_PERCENT);
winInfo.dpi = IniSectionGetInt(IniSecWindow, tchDPI, USER_DEFAULT_SCREEN_DPI);
int const offset = Settings2.LaunchInstanceWndPosOffset;
diff --git a/src/Dialogs.c b/src/Dialogs.c
index 7982ef72a..d1826cc73 100644
--- a/src/Dialogs.c
+++ b/src/Dialogs.c
@@ -1338,7 +1338,7 @@ INT_PTR CALLBACK AboutDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam
StringCchPrintf(wchBuf, COUNTOF(wchBuf), L"\n- Rendering-Technology -> '%s'", Settings.RenderingTechnology ? L"DIRECT-WRITE" : L"GDI");
StringCchCat(wchVerInfo, COUNTOF(wchVerInfo), wchBuf);
- StringCchPrintf(wchBuf, COUNTOF(wchBuf), L"\n- Zoom -> %i%%.", SciCall_GetZoom());
+ StringCchPrintf(wchBuf, COUNTOF(wchBuf), L"\n- Zoom -> %i%%.", NP3_GetZoomPercent());
StringCchCat(wchVerInfo, COUNTOF(wchVerInfo), wchBuf);
Style_GetLexerDisplayName(Style_GetCurrentLexerPtr(), wchBuf, COUNTOF(wchBuf));
@@ -4698,7 +4698,7 @@ WININFO GetMyWindowPlacement(HWND hwnd, MONITORINFO *hMonitorInfo, const int off
wi.cx = wndpl.rcNormalPosition.right - wndpl.rcNormalPosition.left;
wi.cy = wndpl.rcNormalPosition.bottom - wndpl.rcNormalPosition.top;
wi.max = (hwnd ? IsZoomed(hwnd) : false) || (wndpl.flags & WPF_RESTORETOMAXIMIZED);
- wi.zoom = hwnd ? SciCall_GetZoom() : 100;
+ wi.zoom = hwnd ? NP3_GetZoomPercent() : NP3_DEFAULT_ZOOM;
wi.dpi = Scintilla_GetWindowDPI(hwnd);
if (bFullVisible) {
diff --git a/src/Edit.c b/src/Edit.c
index 7268373be..dec1faeba 100644
--- a/src/Edit.c
+++ b/src/Edit.c
@@ -1552,7 +1552,7 @@ bool EditSaveFile(
}
// strip trailing blanks
- if (Settings.FixTrailingBlanks) {
+ if (Settings.FixTrailingBlanks && EditHasTrailingBlanks()) {
EditStripLastCharacter(hwnd, true, true);
}
}
@@ -2694,6 +2694,7 @@ void EditTabsToSpaces(int nTabWidth,bool bOnlyIndentingWS)
if (bModified) {
char * const pszText2 = AllocMem((size_t)cchConvW * 3, HEAP_ZERO_MEMORY);
+ if (pszText2) {
ptrdiff_t cchConvM = WideCharToMultiByteEx(Encoding_SciCP,0,pszConvW,cchConvW,
pszText2,SizeOfMem(pszText2),NULL,NULL);
@@ -2711,6 +2712,8 @@ void EditTabsToSpaces(int nTabWidth,bool bOnlyIndentingWS)
Sci_ReplaceTargetTestChgHist(cchConvM, pszText2);
EditSetSelectionEx(iAnchorPos, iCurPos, -1, -1);
EndUndoTransAction();
+
+ } // if pszText2
FreeMem(pszText2);
}
FreeMem(pszConvW);
@@ -2806,6 +2809,7 @@ void EditSpacesToTabs(int nTabWidth,bool bOnlyIndentingWS)
if (bModified || cchConvW != cchTextW) {
char *pszText2 = AllocMem((size_t)cchConvW * 3, HEAP_ZERO_MEMORY);
+ if (pszText2) {
ptrdiff_t cchConvM = WideCharToMultiByteEx(Encoding_SciCP,0,pszConvW,cchConvW,
pszText2,SizeOfMem(pszText2),NULL,NULL);
@@ -2823,6 +2827,8 @@ void EditSpacesToTabs(int nTabWidth,bool bOnlyIndentingWS)
Sci_ReplaceTargetTestChgHist(cchConvM, pszText2);
EditSetSelectionEx(iAnchorPos, iCurPos, -1, -1);
EndUndoTransAction();
+
+ } // if pszText2
FreeMem(pszText2);
}
@@ -3202,7 +3208,7 @@ void EditModifyLines(const PENCLOSESELDATA pEnclData) {
*q = '\0'; // terminate tinyexpr
StringCchCopyA(mszTinyExprPost, COUNTOF(mszTinyExprPost), t);
StringCchCopyA(mszAppend2, COUNTOF(mszAppend2), q + CONSTSTRGLEN(EXPR_END));
- *p = '\0'; // mszPrefix1 terminate
+ *p = '\0'; // mszAppend1 terminate
p = StrStrA(q, EXPR_BEG); // next
}
else {
@@ -3230,7 +3236,7 @@ void EditModifyLines(const PENCLOSESELDATA pEnclData) {
N = I + 1.0;
DocLn vmin = d2ln(te_eval(pTinyExprPre));
DocLn vmax = vmin;
- for (DocLn ln = iStartLine + 2; ln <= iEndLine; ++ln) {
+ for (DocLn ln = iStartLine + 2; ln <= iEndLine + 1; ++ln) {
L = (double)ln;
I += 1.0;
N += 1.0;
@@ -3271,7 +3277,7 @@ void EditModifyLines(const PENCLOSESELDATA pEnclData) {
N = I + 1.0;
DocLn vmin = d2ln(te_eval(pTinyExprPost));
DocLn vmax = vmin;
- for (DocLn ln = iStartLine + 2; ln <= iEndLine; ++ln) {
+ for (DocLn ln = iStartLine + 2; ln <= iEndLine + 1; ++ln) {
L = (double)ln;
I += 1.0;
N += 1.0;
@@ -3379,7 +3385,7 @@ void EditModifyLines(const PENCLOSESELDATA pEnclData) {
DocPos const newPos = SciCall_PositionFromLine(iResetLine) + iResetOffset + prefixInsertLen;
EditSetSelectionEx(newPos, newPos, -1, -1);
}
- else if (iSelStart != iSelEnd) {
+ else {
if (iResetPos < iAnchorPos) {
EditSetSelectionEx(SciCall_PositionFromLine(iEndLine + 1), SciCall_PositionFromLine(iStartLine), -1, -1);
} else {
@@ -3482,9 +3488,9 @@ void EditIndentBlock(HWND hwnd, int cmd, bool bFormatIndentation, bool bForceAll
} else { // on multiline indentation, anchor and current positions are moved to line begin resp. end
if (bFixStart) {
if (iCurPos < iAnchorPos) {
- iDiffCurrent = SciCall_LineLength(iCurLine) - Sci_GetEOLLen();
+ iDiffCurrent = SciCall_GetLineEndPosition(iCurLine) - SciCall_PositionFromLine(iCurLine);
} else {
- iDiffAnchor = SciCall_LineLength(iAnchorLine) - Sci_GetEOLLen();
+ iDiffAnchor = SciCall_GetLineEndPosition(iAnchorLine) - SciCall_PositionFromLine(iAnchorLine);
}
}
EditSetSelectionEx(SciCall_GetLineEndPosition(iAnchorLine) - iDiffAnchor, SciCall_GetLineEndPosition(iCurLine) - iDiffCurrent, -1, -1);
@@ -3535,9 +3541,10 @@ void EditAlignText(int nMode)
if (iLineIndentPos != iLineEndPos) {
int const iIndentCol = SciCall_GetLineIndentation(iLine);
+ DocPos const iLineStartPos = SciCall_PositionFromLine(iLine);
DocPos iTail = iLineEndPos - 1;
char ch = SciCall_GetCharAt(iTail);
- while (iTail >= iLineStart && (ch == ' ' || ch == '\t')) {
+ while (iTail >= iLineStartPos && (ch == ' ' || ch == '\t')) {
--iTail;
ch = SciCall_GetCharAt(iTail);
--iLineEndPos;
@@ -3557,7 +3564,7 @@ void EditAlignText(int nMode)
UndoTransActionBegin();
- if (chNewLineBuf && wchLineBuf && wchNewLineBuf) {
+ if (chNewLineBuf && wchLineBuf && wchNewLineBuf && pWords) {
for (DocLn iLine = iLineStart; iLine <= iLineEnd; iLine++) {
DocPos const iStartPos = SciCall_PositionFromLine(iLine);
@@ -3608,8 +3615,7 @@ void EditAlignText(int nMode)
}
}
- if ((nMode == ALIGN_JUSTIFY || nMode == ALIGN_JUSTIFY_EX) &&
- iWords > 1 && iWordsLength >= 2 &&
+ if (iWords > 1 && iWordsLength >= 2 &&
((nMode != ALIGN_JUSTIFY_EX || !bNextLineIsBlank || iLineStart == iLineEnd) ||
(bNextLineIsBlank && iWordsLength > (iMaxLength - iMinIndent) * 0.75))) {
int iGaps = iWords - 1;
@@ -3704,15 +3710,15 @@ void EditAlignText(int nMode)
}
}
- FreeMem(pWords);
- FreeMem(wchNewLineBuf);
- FreeMem(wchLineBuf);
- FreeMem(chNewLineBuf);
-
} else {
InfoBoxLng(MB_ICONERROR, NULL, IDS_MUI_BUFFERTOOSMALL);
}
+ FreeMem(pWords);
+ FreeMem(wchNewLineBuf);
+ FreeMem(wchLineBuf);
+ FreeMem(chNewLineBuf);
+
if (iAnchorPos > iCurPos) {
iCurPos = SciCall_FindColumn(iLineStart, iCurCol);
iAnchorPos = SciCall_FindColumn(_lnend, iAnchorCol);
@@ -3977,6 +3983,7 @@ void EditToggleLineCommentsExtended(LPCWSTR pwszComment, bool bInsertAtStart)
switch (iAction) {
case 0:
iAction = 2;
+ // fall through
case 2:
SciCall_SetTargetRange(iIndentPos, iSelPos);
Sci_ReplaceTargetTestChgHist(0, "");
@@ -3991,6 +3998,7 @@ void EditToggleLineCommentsExtended(LPCWSTR pwszComment, bool bInsertAtStart)
switch (iAction) {
case 0:
iAction = 1;
+ // fall through
case 1: {
DocPos const iPos = SciCall_FindColumn(iLine, iCommentCol);
SciCall_InsertText(iPos, mszComment);
@@ -4026,7 +4034,7 @@ void EditToggleLineCommentsExtended(LPCWSTR pwszComment, bool bInsertAtStart)
//
// _AppendSpaces()
//
-static DocPos _AppendSpaces(HWND hwnd, DocLn iLineStart, DocLn iLineEnd, DocPos iMaxColumn, bool bSkipEmpty)
+static DocPos _AppendSpaces(HWND hwnd, DocLn iLineStart, DocLn iLineEnd, DocPos iMaxColumn, bool bSkipEmpty)
{
UNREFERENCED_PARAMETER(hwnd);
@@ -4080,7 +4088,7 @@ void EditPadWithSpaces(HWND hwnd, bool bSkipEmpty) {
//~UndoTransActionBegin(); // outside defined
- if (Sci_IsMultiOrRectangleSelection() && !SciCall_IsSelectionEmpty()) {
+ if (Sci_IsMultiOrRectangleSelection()) {
DocPos const selAnchorMainPos = SciCall_GetRectangularSelectionAnchor();
DocPos const selCaretMainPos = SciCall_GetRectangularSelectionCaret();
@@ -4094,52 +4102,55 @@ void EditPadWithSpaces(HWND hwnd, bool bSkipEmpty) {
DocLn const iLineCount = abs_p(iRcCaretLine - iRcAnchorLine) + 1;
// lots of spaces
- DocPos const spBufSize = max_p(iAnchorColumn, selCaretMainPos);
+ DocPos const spBufSize = max_p(iAnchorColumn, iCaretColumn);
char * const pSpaceBuffer = (char *)AllocMem((spBufSize + 1) * sizeof(char), HEAP_ZERO_MEMORY);
- FillMemory(pSpaceBuffer, spBufSize * sizeof(char), ' ');
DocPos * const pVspAVec = (DocPos *)AllocMem(iLineCount * sizeof(DocPos), HEAP_ZERO_MEMORY);
DocPos * const pVspCVec = (DocPos *)AllocMem(iLineCount * sizeof(DocPos), HEAP_ZERO_MEMORY);
- for (DocLn i = 0; i < iLineCount; ++i) {
- pVspAVec[i] = SciCall_GetSelectionNAnchorVirtualSpace(i);
- pVspCVec[i] = SciCall_GetSelectionNCaretVirtualSpace(i);
- }
+ if (pSpaceBuffer && pVspAVec && pVspCVec) {
- DocPos i = 0;
- DocPos iSpcCount = 0;
- DocLn const iLnIncr = (iRcAnchorLine <= iRcCaretLine) ? ((DocLn)+1) : ((DocLn)-1);
- DocLn iLine = iRcAnchorLine - iLnIncr;
- do {
- iLine += iLnIncr;
- DocPos const iInsPos = SciCall_GetLineEndPosition(iLine);
- DocPos const cntVSp = bSelLeft2Right ? pVspCVec[i++] : pVspAVec[i++];
- bool const bSkip = (bSkipEmpty && (iInsPos <= SciCall_PositionFromLine(iLine)));
+ FillMemory(pSpaceBuffer, spBufSize * sizeof(char), ' ');
- if ((cntVSp > 0) && !bSkip) {
- pSpaceBuffer[cntVSp] = '\0';
- SciCall_InsertText(iInsPos, pSpaceBuffer);
- pSpaceBuffer[cntVSp] = ' ';
- iSpcCount += cntVSp;
+ for (DocLn i = 0; i < iLineCount; ++i) {
+ pVspAVec[i] = SciCall_GetSelectionNAnchorVirtualSpace(i);
+ pVspCVec[i] = SciCall_GetSelectionNCaretVirtualSpace(i);
}
- } while ((iLine != iRcCaretLine) && (i < iLineCount));
- FreeMem(pSpaceBuffer);
+ DocPos i = 0;
+ DocPos iSpcCount = 0;
+ DocLn const iLnIncr = (iRcAnchorLine <= iRcCaretLine) ? ((DocLn)+1) : ((DocLn)-1);
+ DocLn iLine = iRcAnchorLine - iLnIncr;
+ do {
+ iLine += iLnIncr;
+ DocPos const iInsPos = SciCall_GetLineEndPosition(iLine);
+ DocPos const cntVSp = bSelLeft2Right ? pVspCVec[i++] : pVspAVec[i++];
+ bool const bSkip = (bSkipEmpty && (iInsPos <= SciCall_PositionFromLine(iLine)));
+
+ if ((cntVSp > 0) && !bSkip) {
+ pSpaceBuffer[cntVSp] = '\0';
+ SciCall_InsertText(iInsPos, pSpaceBuffer);
+ pSpaceBuffer[cntVSp] = ' ';
+ iSpcCount += cntVSp;
+ }
+ } while ((iLine != iRcCaretLine) && (i < iLineCount));
- if (iRcAnchorLine <= iRcCaretLine) {
- if (bSelLeft2Right) {
- EditSetSelectionEx(selAnchorMainPos + pVspAVec[0], selCaretMainPos + iSpcCount, 0, 0);
- } else {
- EditSetSelectionEx(selAnchorMainPos + pVspAVec[0], selCaretMainPos + pVspCVec[iLineCount - 1] + iSpcCount - pVspAVec[iLineCount - 1], 0, 0);
- }
- } else {
- if (bSelLeft2Right) {
- EditSetSelectionEx(selAnchorMainPos + pVspAVec[0] + iSpcCount - pVspCVec[0], selCaretMainPos + pVspCVec[iLineCount - 1], 0, 0);
+ if (iRcAnchorLine <= iRcCaretLine) {
+ if (bSelLeft2Right) {
+ EditSetSelectionEx(selAnchorMainPos + pVspAVec[0], selCaretMainPos + iSpcCount, 0, 0);
+ } else {
+ EditSetSelectionEx(selAnchorMainPos + pVspAVec[0], selCaretMainPos + pVspCVec[iLineCount - 1] + iSpcCount - pVspAVec[iLineCount - 1], 0, 0);
+ }
} else {
- EditSetSelectionEx(selAnchorMainPos + iSpcCount, selCaretMainPos + pVspCVec[iLineCount - 1], 0, 0);
+ if (bSelLeft2Right) {
+ EditSetSelectionEx(selAnchorMainPos + pVspAVec[0] + iSpcCount - pVspCVec[0], selCaretMainPos + pVspCVec[iLineCount - 1], 0, 0);
+ } else {
+ EditSetSelectionEx(selAnchorMainPos + iSpcCount, selCaretMainPos + pVspCVec[iLineCount - 1], 0, 0);
+ }
}
}
+ FreeMem(pSpaceBuffer);
FreeMem(pVspCVec);
FreeMem(pVspAVec);
@@ -4151,15 +4162,10 @@ void EditPadWithSpaces(HWND hwnd, bool bSkipEmpty) {
const DocPos iSelStart = SciCall_GetSelectionStart();
const DocPos iSelEnd = SciCall_GetSelectionEnd();
- DocLn iStartLine = 0;
- DocLn iEndLine = Sci_GetLastDocLineNumber();
-
- if (iSelStart != iSelEnd) {
- iStartLine = SciCall_LineFromPosition(iSelStart);
- iEndLine = SciCall_LineFromPosition(iSelEnd);
- if (iSelEnd < SciCall_GetLineEndPosition(iEndLine)) {
- --iEndLine;
- }
+ DocLn iStartLine = SciCall_LineFromPosition(iSelStart);
+ DocLn iEndLine = SciCall_LineFromPosition(iSelEnd);
+ if (iSelEnd < SciCall_GetLineEndPosition(iEndLine)) {
+ --iEndLine;
}
if (iStartLine < iEndLine) {
DocPos iMaxColumn = 0;
@@ -4193,8 +4199,8 @@ void EditStripFirstCharacter(HWND hwnd)
return;
}
- DocPos const iSelStart = SciCall_IsSelectionEmpty() ? 0 : SciCall_GetSelectionStart();
- DocPos const iSelEnd = SciCall_IsSelectionEmpty() ? Sci_GetDocEndPosition() : SciCall_GetSelectionEnd();
+ DocPos const iSelStart = SciCall_GetSelectionStart();
+ DocPos const iSelEnd = SciCall_GetSelectionEnd();
DocLn const iLineStart = SciCall_LineFromPosition(iSelStart);
DocLn const iLineEnd = SciCall_LineFromPosition(iSelEnd);
@@ -4220,8 +4226,8 @@ void EditStripFirstCharacter(HWND hwnd)
StringCchCopyNA(lineBuffer, SizeOfMem(lineBuffer), SciCall_GetRangePointer(nextPos, len + 1), len);
SciCall_SetTargetRange(selTargetStart, selTargetEnd);
Sci_ReplaceTargetTestChgHist(len, lineBuffer);
+ remCount += (nextPos - selTargetStart);
}
- remCount += (nextPos - selTargetStart);
} // for()
FreeMem(lineBuffer);
}
@@ -4313,8 +4319,10 @@ void EditStripLastCharacter(HWND hwnd, bool bIgnoreSelection, bool bTrailingBlan
lineBuffer[++i] = lineBuffer[end++]; // add "\r\n" if any
}
diff = len - (++i);
- SciCall_SetTargetRange(selTargetStart, selTargetEnd);
- Sci_ReplaceTargetTestChgHist(-1, lineBuffer);
+ if (diff > 0) {
+ SciCall_SetTargetRange(selTargetStart, selTargetEnd);
+ Sci_ReplaceTargetTestChgHist(-1, lineBuffer);
+ }
}
} else {
DocPos const prevPos = SciCall_PositionBefore(selTargetEnd);
@@ -4347,14 +4355,16 @@ void EditStripLastCharacter(HWND hwnd, bool bIgnoreSelection, bool bTrailingBlan
DocPos const iEndPos = SciCall_GetLineEndPosition(iLine);
if (bTrailingBlanksOnly) {
- DocPos i = iEndPos;
- char ch = '\0';
- do {
- ch = SciCall_GetCharAt(--i);
- } while ((i >= iStartPos) && IsBlankCharA(ch));
- if ((++i) < iEndPos) {
- SciCall_SetTargetRange(i, iEndPos);
- Sci_ReplaceTargetTestChgHist(0, "");
+ if (iStartPos < iEndPos) {
+ DocPos i = iEndPos;
+ char ch = '\0';
+ do {
+ ch = SciCall_GetCharAt(--i);
+ } while ((i >= iStartPos) && IsBlankCharA(ch));
+ if ((++i) < iEndPos) {
+ SciCall_SetTargetRange(i, iEndPos);
+ Sci_ReplaceTargetTestChgHist(0, "");
+ }
}
} else { // any char at line end
if (iStartPos < iEndPos) {
@@ -4371,6 +4381,27 @@ void EditStripLastCharacter(HWND hwnd, bool bIgnoreSelection, bool bTrailingBlan
}
+//=============================================================================
+//
+// EditHasTrailingBlanks()
+//
+bool EditHasTrailingBlanks()
+{
+ DocLn const iLineCount = SciCall_GetLineCount();
+ for (DocLn iLine = 0; iLine < iLineCount; ++iLine) {
+ DocPos const iStartPos = SciCall_PositionFromLine(iLine);
+ DocPos const iEndPos = SciCall_GetLineEndPosition(iLine);
+ if (iEndPos > iStartPos) {
+ char const ch = SciCall_GetCharAt(iEndPos - 1);
+ if (IsBlankCharA(ch)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
//=============================================================================
//
// EditCompressBlanks()
diff --git a/src/Edit.h b/src/Edit.h
index 235902f97..0f040b37e 100644
--- a/src/Edit.h
+++ b/src/Edit.h
@@ -80,6 +80,7 @@ void EditToggleLineCommentsExtended(LPCWSTR pwszComment, bool bInsertAtStart);
void EditPadWithSpaces(HWND hwnd, bool bSkipEmpty);
void EditStripFirstCharacter(HWND hwnd);
void EditStripLastCharacter(HWND hwnd, bool bIgnoreSelection, bool bTrailingBlanksOnly);
+bool EditHasTrailingBlanks();
void EditCompressBlanks();
void EditRemoveBlankLines(HWND hwnd, bool bMerge, bool bRemoveWhiteSpace);
void EditUniteDuplicateLines(HWND hwnd, bool bRemoveEmptyLines, bool bRemoveLastDup);
diff --git a/src/Notepad3.c b/src/Notepad3.c
index 91fea3377..f40753008 100644
--- a/src/Notepad3.c
+++ b/src/Notepad3.c
@@ -127,6 +127,9 @@ HPATHL g_tchToolbarBitmapDisabled = NULL;
WCHAR Default_PreferredLanguageLocaleName[LOCALE_NAME_MAX_LENGTH + 1] = { L'\0' };
+// zoom conversion helper (forward declaration)
+static int ZoomPercentToSciLevel(int percent);
+
// ------------------------------------
HPATHL s_hpthRelaunchElevatedFile = NULL;
@@ -639,6 +642,7 @@ static void _InitGlobals()
Globals.iWhiteSpaceSize = 2;
Globals.iCaretOutLineFrameSize = 0;
+ Globals.iZoomPercent = NP3_DEFAULT_ZOOM;
Globals.DOSEncoding = CPI_NONE;
Globals.bZeroBasedColumnIndex = false;
@@ -2192,6 +2196,11 @@ LRESULT CALLBACK MainWndProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
case WM_MOUSEWHEEL:
if (wParam & MK_CONTROL) {
+ if (GET_WHEEL_DELTA_WPARAM(wParam) > 0) {
+ NP3_ZoomIn();
+ } else if (GET_WHEEL_DELTA_WPARAM(wParam) < 0) {
+ NP3_ZoomOut();
+ }
ShowZoomCallTip();
} else if (wParam & MK_RBUTTON) {
// Hold RIGHT MOUSE BUTTON and SCROLL to cycle through UNDO history
@@ -2728,7 +2737,7 @@ LRESULT MsgCreate(HWND hwnd, WPARAM wParam,LPARAM lParam)
Encoding_Current(Settings.DefaultEncoding);
- SciCall_SetZoom(g_IniWinInfo.zoom ? g_IniWinInfo.zoom : 100);
+ NP3_ApplyZoom(g_IniWinInfo.zoom ? g_IniWinInfo.zoom : NP3_DEFAULT_ZOOM);
return 0LL;
}
@@ -6217,19 +6226,19 @@ LRESULT MsgCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
break;
case IDM_VIEW_ZOOMIN: {
- SciCall_ZoomIn();
+ NP3_ZoomIn();
ShowZoomCallTip();
}
break;
case IDM_VIEW_ZOOMOUT: {
- SciCall_ZoomOut();
+ NP3_ZoomOut();
ShowZoomCallTip();
}
break;
case IDM_VIEW_RESETZOOM: {
- SciCall_SetZoom(100);
+ NP3_ApplyZoom(NP3_DEFAULT_ZOOM);
ShowZoomCallTip();
}
break;
@@ -8960,8 +8969,8 @@ static LRESULT _MsgNotifyFromEdit(HWND hwnd, const SCNotification* const scn)
case SCN_ZOOM:
- SciCall_SetWhiteSpaceSize(MulDiv(Globals.iWhiteSpaceSize, SciCall_GetZoom(), 100));
- SciCall_SetCaretLineFrame(MulDiv(Globals.iCaretOutLineFrameSize, SciCall_GetZoom(), 100));
+ SciCall_SetWhiteSpaceSize(MulDiv(Globals.iWhiteSpaceSize, Globals.iZoomPercent, 100));
+ SciCall_SetCaretLineFrame(MulDiv(Globals.iCaretOutLineFrameSize, Globals.iZoomPercent, 100));
UpdateToolbar();
UpdateMargins(true);
break;
@@ -9903,10 +9912,10 @@ static void _UpdateToolbarDelayed()
EnableTool(Globals.hwndToolbar, IDT_VIEW_TOGGLE_VIEW, b2 && IsFocusedViewAllowed());
CheckTool(Globals.hwndToolbar, IDT_VIEW_TOGGLE_VIEW, tv);
- int const zoom = SciCall_GetZoom();
- CheckTool(Globals.hwndToolbar, IDT_VIEW_ZOOMIN, (zoom > 100));
- CheckTool(Globals.hwndToolbar, IDT_VIEW_RESETZOOM, (zoom == 100));
- CheckTool(Globals.hwndToolbar, IDT_VIEW_ZOOMOUT, (zoom < 100));
+ int const zoom = NP3_GetZoomPercent();
+ CheckTool(Globals.hwndToolbar, IDT_VIEW_ZOOMIN, (zoom > NP3_DEFAULT_ZOOM));
+ CheckTool(Globals.hwndToolbar, IDT_VIEW_RESETZOOM, (zoom == NP3_DEFAULT_ZOOM));
+ CheckTool(Globals.hwndToolbar, IDT_VIEW_ZOOMOUT, (zoom < NP3_DEFAULT_ZOOM));
}
@@ -10906,7 +10915,7 @@ bool FileLoad(const HPATHL hfile_pth, const FileLoadFlags fLoadFlags, const DocP
UpdateToolbar();
UpdateMargins(true);
- if (SciCall_GetZoom() != 100) {
+ if (NP3_GetZoomPercent() != NP3_DEFAULT_ZOOM) {
ShowZoomCallTip();
}
@@ -11156,7 +11165,7 @@ bool FileLoad(const HPATHL hfile_pth, const FileLoadFlags fLoadFlags, const DocP
}
UpdateMargins(true);
- if (SciCall_GetZoom() != 100) {
+ if (NP3_GetZoomPercent() != NP3_DEFAULT_ZOOM) {
ShowZoomCallTip();
}
UpdateToolbar_Now(Globals.hwndMain);
@@ -11390,7 +11399,7 @@ bool FileSave(FileSaveFlags fSaveFlags)
}
}
- bool const bSaveNeeded = (IsSaveNeeded() || IsFileChangedFlagSet() || Settings.FixTrailingBlanks) && !bIsEmptyNewFile;
+ bool const bSaveNeeded = (IsSaveNeeded() || IsFileChangedFlagSet() || (Settings.FixTrailingBlanks && EditHasTrailingBlanks())) && !bIsEmptyNewFile;
if (!(fSaveFlags & FSF_SaveAs) && !(fSaveFlags & FSF_SaveAlways) && !bSaveNeeded) {
_MRU_UpdateSession();
@@ -12041,6 +12050,68 @@ void ResetMouseDWellTime()
SciCall_SetMouseDWellTime(500); // needed for "Mouse cursor vanish handling (hide while typing)"
}
+//=============================================================================
+//
+// NP3 Zoom Helpers — percentage-based zoom with Scintilla's additive zoom API
+//
+// Scintilla zoom is additive: sizeZoomed = fontSize + zoomLevel * FontSizeMultiplier
+// NP3 displays percentage (100% = normal). Conversion uses GLOBAL_INITIAL_FONTSIZE.
+//
+
+static int ZoomPercentToSciLevel(int percent)
+{
+ // zoomLevel = baseFontSizeSM * (percent - 100) / 10000
+ // where baseFontSizeSM = GLOBAL_INITIAL_FONTSIZE * 100 (FontSizeMultiplier units)
+ __int64 const raw = (__int64)NP3_ZOOM_BASE_FONT_SIZE * (percent - 100);
+ return (int)((raw >= 0) ? (raw + 5000) / 10000 : (raw - 5000) / 10000);
+}
+
+void NP3_ApplyZoom(int percent)
+{
+ percent = clampi(percent, NP3_MIN_ZOOM_PERCENT, NP3_MAX_ZOOM_PERCENT);
+ Globals.iZoomPercent = percent;
+ SciCall_SetZoom(ZoomPercentToSciLevel(percent));
+}
+
+void NP3_ZoomIn()
+{
+ int const curLevel = SciCall_GetZoom();
+ int percent = Globals.iZoomPercent;
+ if (percent < 200) {
+ percent += 10;
+ } else if (percent < 500) {
+ percent += 25;
+ } else {
+ percent += 50;
+ }
+ percent = min_i(percent, NP3_MAX_ZOOM_PERCENT);
+ int newLevel = ZoomPercentToSciLevel(percent);
+ if (newLevel <= curLevel) {
+ newLevel = curLevel + 1;
+ }
+ Globals.iZoomPercent = percent;
+ SciCall_SetZoom(newLevel);
+}
+
+void NP3_ZoomOut()
+{
+ int const curLevel = SciCall_GetZoom();
+ int percent = Globals.iZoomPercent;
+ percent -= 10;
+ percent = max_i(percent, NP3_MIN_ZOOM_PERCENT);
+ int newLevel = ZoomPercentToSciLevel(percent);
+ if (newLevel >= curLevel) {
+ newLevel = curLevel - 1;
+ }
+ Globals.iZoomPercent = percent;
+ SciCall_SetZoom(newLevel);
+}
+
+int NP3_GetZoomPercent()
+{
+ return Globals.iZoomPercent;
+}
+
//=============================================================================
//
// ShowZoomCallTip()
@@ -12051,7 +12122,7 @@ void ShowZoomCallTip()
int const delayClr = Settings2.ZoomTooltipTimeout;
if (delayClr >= (_MQ_TIMER_CYCLE << 3)) {
- StringCchPrintfA(chToolTip, COUNTOF(chToolTip), "Zoom: %i%%", SciCall_GetZoom());
+ StringCchPrintfA(chToolTip, COUNTOF(chToolTip), "Zoom: %i%%", NP3_GetZoomPercent());
DocPos const iPos = SciCall_PositionFromLine(SciCall_GetFirstVisibleLine());
diff --git a/src/Notepad3.h b/src/Notepad3.h
index 568c79d13..28d6b12a0 100644
--- a/src/Notepad3.h
+++ b/src/Notepad3.h
@@ -95,6 +95,11 @@ bool CheckAutoLoadMostRecent();
void ShowZoomCallTip();
void ShowWrapAroundCallTip(bool forwardSearch);
+void NP3_ZoomIn();
+void NP3_ZoomOut();
+void NP3_ApplyZoom(int percent);
+int NP3_GetZoomPercent();
+
void MarkAllOccurrences(const LONG64 delay, const bool bForceClear);
void UpdateToolbar();
diff --git a/src/Print.cpp b/src/Print.cpp
index 41f404875..5e7e68757 100644
--- a/src/Print.cpp
+++ b/src/Print.cpp
@@ -358,8 +358,9 @@ extern "C" bool EditPrint(HWND hwnd,LPCWSTR pszDocTitle,LPCWSTR pszPageFormat)
SendMessage(hwnd,SCI_SETPRINTCOLOURMODE,printColorModes[Settings.PrintColorMode],0);
//SendMessage(hwnd, SCI_SETPRINTWRAPMODE, SC_WRAP_WORD, 0); // default: SC_WRAP_WORD
- // Set print magnification...
- SendMessage(hwnd, SCI_SETPRINTMAGNIFICATION, (WPARAM)Settings.PrintZoom, 0);
+ // Set print magnification (convert NP3 percent to Scintilla additive points)
+ int const printZoomLevel = (int)(((__int64)NP3_ZOOM_BASE_FONT_SIZE * (Settings.PrintZoom - 100) + 5000) / 10000);
+ SendMessage(hwnd, SCI_SETPRINTMAGNIFICATION, (WPARAM)printZoomLevel, 0);
DocPos const lengthDocMax = SciCall_GetTextLength();
DocPos lengthDoc = lengthDocMax;
@@ -559,7 +560,7 @@ static UINT_PTR CALLBACK _LPSetupHookProc(HWND hwnd, UINT uiMsg, WPARAM wParam,
UDACCEL const acc[1] = { { 0, 10 } };
SendDlgItemMessage(hwnd, 30, EM_LIMITTEXT, 32, 0);
SendDlgItemMessage(hwnd, 31, UDM_SETACCEL, 1, (WPARAM)acc);
- SendDlgItemMessage(hwnd, 31, UDM_SETRANGE32, SC_MIN_ZOOM_LEVEL, SC_MAX_ZOOM_LEVEL);
+ SendDlgItemMessage(hwnd, 31, UDM_SETRANGE32, NP3_MIN_ZOOM_PERCENT, NP3_MAX_ZOOM_PERCENT);
SendDlgItemMessage(hwnd, 31, UDM_SETPOS32, 0, Settings.PrintZoom);
// Set header options
diff --git a/src/Styles.c b/src/Styles.c
index e7624dbae..29a8ec231 100644
--- a/src/Styles.c
+++ b/src/Styles.c
@@ -1570,7 +1570,7 @@ void Style_SetLexer(HWND hwnd, PEDITLEXER pLexNew)
}
Globals.iWhiteSpaceSize = iValue;
//SciCall_SetWhiteSpaceSize(iValue);
- SciCall_SetWhiteSpaceSize(MulDiv(Globals.iWhiteSpaceSize, SciCall_GetZoom(), 100)); // needs update on zoom
+ SciCall_SetWhiteSpaceSize(MulDiv(Globals.iWhiteSpaceSize, NP3_GetZoomPercent(), 100)); // needs update on zoom
// whitespace colors
rgb = RGB(0, 0, 0);
@@ -2087,7 +2087,7 @@ void Style_HighlightCurrentLine(HWND hwnd, int iHiLitCurLn)
iFrameSize = max_i(1, ScaleIntToDPI(hwnd, iFrameSize));
Globals.iCaretOutLineFrameSize = iFrameSize;
// SciCall_SetCaretLineFrame(iFrameSize);
- SciCall_SetCaretLineFrame(MulDiv(Globals.iCaretOutLineFrameSize, SciCall_GetZoom(), 100)); // needs update on zoom
+ SciCall_SetCaretLineFrame(MulDiv(Globals.iCaretOutLineFrameSize, NP3_GetZoomPercent(), 100)); // needs update on zoom
}
else {
SciCall_SetCaretLineFrame(0);
diff --git a/src/TypeDefs.h b/src/TypeDefs.h
index 6d77e0ee7..d95267fd0 100644
--- a/src/TypeDefs.h
+++ b/src/TypeDefs.h
@@ -249,6 +249,13 @@ typedef enum STATUS_SECTOR_T {
#define GLOBAL_INITIAL_FONTSIZE 11.0f
+// NP3 zoom constants (percentage-based, 100 = normal)
+#define NP3_MIN_ZOOM_PERCENT 10
+#define NP3_MAX_ZOOM_PERCENT 1000
+#define NP3_DEFAULT_ZOOM 100
+// Base font size in Scintilla FontSizeMultiplier units (points * 100) for zoom conversion
+#define NP3_ZOOM_BASE_FONT_SIZE ((int)(GLOBAL_INITIAL_FONTSIZE * 100))
+
// --------------------------------------------------------------------------
// |- len -|
@@ -523,6 +530,7 @@ typedef struct GLOBALS_T {
int iWhiteSpaceSize;
int iCaretOutLineFrameSize;
+ int iZoomPercent;
bool bMinimizedToTray;
bool bZeroBasedColumnIndex;