mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-29 08:44:40 +02:00
Update to scintilla 5.5.6 & Lexilla 5.4.4
Release 5.5.6 (https://www.scintilla.org/scintilla556.zip) Released 2 April 2025. * Disallow changing case of protected text. Bug #2463. * Return enumeration type from MarkerSymbolDefined to match MarkerDefine. Bug #2469. * On Win32, use DirectWrite for autocompletion lists when DirectWrite chosen for document text. * On Win32, optimize case-insensitive DBCS search to be around 5 times faster by using 64K memory to cache folding data for each DBCS code page used. * On Win32, fix a crash with bidirectional text. * When using Visual C++ through nmake, fix building for ARM64. Feature #1546. * On Qt, draw clipped UTF-8 text correctly. Bug #2464. * On Qt, avoid a dwell start when the mouse is moved outside the Scintilla widget. Bug #2466. * On Qt, autoCompleteSelection converts from local encoding when not in Unicode mode. Bug #2465. Release 5.4.4 (https://www.scintilla.org/lexilla544.zip) Released 2 April 2025. * Fix building for ARM64. Pull request #308. Close #16373
This commit is contained in:
parent
f127ba02d0
commit
5c1813185a
Binary file not shown.
Binary file not shown.
@ -1429,7 +1429,7 @@ bool NppParameters::load()
|
||||
|
||||
for (const auto& i : udlFiles)
|
||||
{
|
||||
auto udlDoc = new TiXmlDocument(i);
|
||||
TiXmlDocument* udlDoc = new TiXmlDocument(i);
|
||||
loadOkay = udlDoc->LoadFile();
|
||||
if (!loadOkay)
|
||||
{
|
||||
|
17
lexilla/.github/workflows/build-check-win32.yml
vendored
17
lexilla/.github/workflows/build-check-win32.yml
vendored
@ -3,16 +3,24 @@ name: "Build and check Lexilla on Win32 with Visual C++"
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
# Compile for amd64 and cross-compile for arm64. Tests run only for amd64.
|
||||
build:
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
- amd64
|
||||
- amd64_arm64
|
||||
env:
|
||||
TEST: ${{ matrix.arch == 'amd64' && 'test' || '' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Preparing nmake
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: x64
|
||||
arch: ${{ matrix.arch }}
|
||||
- name: Install Scintilla source
|
||||
run: |
|
||||
pwd
|
||||
@ -24,7 +32,7 @@ jobs:
|
||||
- name: Unit Test
|
||||
run: |
|
||||
cd test/unit
|
||||
nmake -f test.mak DEBUG=1 test
|
||||
nmake -f test.mak DEBUG=1 $env:TEST
|
||||
cd ../..
|
||||
- name: Build Lexilla
|
||||
run: |
|
||||
@ -33,14 +41,15 @@ jobs:
|
||||
cd ..
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: lexilla.dll
|
||||
name: lexilla${{ matrix.arch == 'amd64_arm64' && '-arm64' || '' }}.dll
|
||||
path: bin/lexilla.dll
|
||||
- name: Test lexing and folding
|
||||
run: |
|
||||
cd test
|
||||
nmake -f testlexers.mak DEBUG=1 test
|
||||
nmake -f testlexers.mak DEBUG=1 $env:TEST
|
||||
cd ..
|
||||
- name: CheckLexilla C Example
|
||||
if: matrix.arch == 'amd64'
|
||||
run: |
|
||||
cd examples/CheckLexilla
|
||||
cl -MP CheckLexilla.c -I ../../include -Fe: CheckLexilla
|
||||
|
@ -30,12 +30,12 @@
|
||||
namespace {
|
||||
|
||||
#if defined(_WIN32)
|
||||
typedef FARPROC Function;
|
||||
typedef HMODULE Module;
|
||||
using Function = FARPROC;
|
||||
using Module = HMODULE;
|
||||
constexpr const char *pathSeparator = "\\";
|
||||
#else
|
||||
typedef void *Function;
|
||||
typedef void *Module;
|
||||
using Function = void *;
|
||||
using Module = void *;
|
||||
constexpr const char *pathSeparator = "/";
|
||||
#endif
|
||||
|
||||
@ -164,9 +164,10 @@ bool Lexilla::Load(std::string_view sharedLibraryPaths) {
|
||||
if (fnLexerCount && fnLexerName) {
|
||||
const int nLexers = fnLexerCount();
|
||||
for (int i = 0; i < nLexers; i++) {
|
||||
char name[100] = "";
|
||||
constexpr size_t lengthName = 200;
|
||||
char name[lengthName]{};
|
||||
fnLexerName(i, name, sizeof(name));
|
||||
lexers.push_back(name);
|
||||
lexers.emplace_back(name);
|
||||
}
|
||||
}
|
||||
CreateLexerFn fnCL = FunctionPointer<CreateLexerFn>(
|
||||
@ -268,7 +269,7 @@ std::string Lexilla::NameFromID(int identifier) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::string();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::string> Lexilla::LibraryProperties() {
|
||||
|
@ -70,12 +70,14 @@ variableScope:lexilla/lexers/LexCmake.cxx
|
||||
knownConditionTrueFalse:lexilla/lexers/LexCmake.cxx
|
||||
constParameterReference:lexilla/lexers/LexCmake.cxx
|
||||
constParameterReference:lexilla/lexers/LexCOBOL.cxx
|
||||
constVariablePointer:lexilla/lexers/LexCOBOL.cxx
|
||||
constParameterReference:lexilla/lexers/LexCoffeeScript.cxx
|
||||
constParameterPointer:lexilla/lexers/LexCoffeeScript.cxx
|
||||
knownConditionTrueFalse:lexilla/lexers/LexCoffeeScript.cxx
|
||||
constVariableReference:lexilla/lexers/LexConf.cxx
|
||||
constParameterReference:lexilla/lexers/LexCPP.cxx
|
||||
variableScope:lexilla/lexers/LexCSS.cxx
|
||||
constVariablePointer:lexilla/lexers/LexCSS.cxx
|
||||
knownConditionTrueFalse:lexilla/lexers/LexDataflex.cxx
|
||||
constParameterReference:lexilla/lexers/LexDataflex.cxx
|
||||
variableScope:lexilla/lexers/LexDataflex.cxx
|
||||
@ -118,6 +120,7 @@ unreadVariable:lexilla/lexers/LexMatlab.cxx
|
||||
variableScope:lexilla/lexers/LexMatlab.cxx
|
||||
variableScope:lexilla/lexers/LexMetapost.cxx
|
||||
constParameterReference:lexilla/lexers/LexModula.cxx
|
||||
duplicateBreak:lexilla/lexers/LexModula.cxx
|
||||
variableScope:lexilla/lexers/LexModula.cxx
|
||||
constParameterReference:lexilla/lexers/LexMPT.cxx
|
||||
variableScope:lexilla/lexers/LexMSSQL.cxx
|
||||
@ -140,6 +143,7 @@ constVariableReference:lexilla/lexers/LexPerl.cxx
|
||||
knownConditionTrueFalse:lexilla/lexers/LexPerl.cxx
|
||||
constParameterReference:lexilla/lexers/LexPLM.cxx
|
||||
constParameterReference:lexilla/lexers/LexPO.cxx
|
||||
constVariablePointer:lexilla/lexers/LexPOV.cxx
|
||||
constParameterReference:lexilla/lexers/LexPython.cxx
|
||||
shadowVariable:lexilla/lexers/LexPowerPro.cxx
|
||||
knownConditionTrueFalse:lexilla/lexers/LexPowerPro.cxx
|
||||
@ -188,7 +192,6 @@ constVariableReference:lexilla/lexers/LexX12.cxx
|
||||
constParameterPointer:lexilla/lexers/LexX12.cxx
|
||||
uselessCallsSubstr:lexilla/lexers/LexX12.cxx
|
||||
constParameterReference:lexilla/lexers/LexYAML.cxx
|
||||
constParameterPointer:lexilla/lexers/LexYAML.cxx
|
||||
knownConditionTrueFalse:lexilla/lexers/LexYAML.cxx
|
||||
|
||||
// These are due to Accessor::IndentAmount not declaring the callback as taking a const.
|
||||
|
@ -9,7 +9,7 @@
|
||||
<meta name="keywords" content="Scintilla, SciTE, Editing Component, Text Editor" />
|
||||
<meta name="Description"
|
||||
content="www.scintilla.org is the home of the Scintilla editing component and SciTE text editor application." />
|
||||
<meta name="Date.Modified" content="20250225" />
|
||||
<meta name="Date.Modified" content="20250402" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<style type="text/css">
|
||||
.logo {
|
||||
@ -51,6 +51,7 @@
|
||||
<title>
|
||||
Lexilla
|
||||
</title>
|
||||
<link rel="canonical" href="https://scintilla.org/Lexilla.html" />
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
<table bgcolor="#000000" width="100%" cellspacing="0" cellpadding="0" border="0">
|
||||
@ -61,8 +62,8 @@
|
||||
<font color="#FFCC99" size="4"> A library of language lexers for use with Scintilla</font>
|
||||
</td>
|
||||
<td width="40%" align="right">
|
||||
<font color="#FFCC99" size="3">Release version 5.4.3<br />
|
||||
Site last modified February 25 2025</font>
|
||||
<font color="#FFCC99" size="3">Release version 5.4.4<br />
|
||||
Site last modified April 2 2025</font>
|
||||
</td>
|
||||
<td width="20%">
|
||||
|
||||
@ -77,11 +78,11 @@
|
||||
</tr>
|
||||
</table>
|
||||
<ul id="versionlist">
|
||||
<li>Version 5.4.4 fixes a problem when building for ARM654 on Windows.</li>
|
||||
<li>Version 5.4.3 improves C++, Modula 3, Pascal, Python, and Ruby.</li>
|
||||
<li>Version 5.4.2 adds Nix lexer. Improves JavaScript, PHP, Rust, TOML, and Zig.</li>
|
||||
<li>Version 5.4.1 adds Dart, troff, and Zig lexers. Improves C++, F#, HTML, and Smalltalk.</li>
|
||||
<li>Version 5.4.0 adds a TOML lexer.</li>
|
||||
<li>Version 5.3.3 improves HTML, JavaScript, Lua, PHP, and XML.</li>
|
||||
</ul>
|
||||
<ul id="menu">
|
||||
<li id="remote1"><a href="https://www.scintilla.org/SciTEImage.html">Screenshot</a></li>
|
||||
|
@ -10,6 +10,7 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
|
||||
<title>Lexilla Documentation</title>
|
||||
<link rel="canonical" href="https://scintilla.org/LexillaDoc.html" />
|
||||
|
||||
<style type="text/css">
|
||||
<!--
|
||||
|
@ -26,9 +26,9 @@
|
||||
<table bgcolor="#CCCCCC" width="100%" cellspacing="0" cellpadding="8" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
<font size="4"> <a href="https://www.scintilla.org/lexilla543.zip">
|
||||
<font size="4"> <a href="https://www.scintilla.org/lexilla544.zip">
|
||||
Windows</a>
|
||||
<a href="https://www.scintilla.org/lexilla543.tgz">
|
||||
<a href="https://www.scintilla.org/lexilla544.tgz">
|
||||
GTK/Linux</a>
|
||||
</font>
|
||||
</td>
|
||||
@ -42,7 +42,7 @@
|
||||
containing very few restrictions.
|
||||
</p>
|
||||
<h3>
|
||||
Release 5.4.3
|
||||
Release 5.4.4
|
||||
</h3>
|
||||
<h4>
|
||||
Source Code
|
||||
@ -50,8 +50,8 @@
|
||||
The source code package contains all of the source code for Lexilla but no binary
|
||||
executable code and is available in
|
||||
<ul>
|
||||
<li><a href="https://www.scintilla.org/lexilla543.zip">zip format</a> (1.4M) commonly used on Windows</li>
|
||||
<li><a href="https://www.scintilla.org/lexilla543.tgz">tgz format</a> (1.0M) commonly used on Linux and compatible operating systems</li>
|
||||
<li><a href="https://www.scintilla.org/lexilla544.zip">zip format</a> (1.4M) commonly used on Windows</li>
|
||||
<li><a href="https://www.scintilla.org/lexilla544.tgz">tgz format</a> (1.0M) commonly used on Linux and compatible operating systems</li>
|
||||
</ul>
|
||||
Instructions for building on both Windows and Linux are included in the readme file.
|
||||
<h4>
|
||||
|
@ -590,9 +590,22 @@
|
||||
<td>Henrik S. Johansen</td>
|
||||
<td>Ekopalypse</td>
|
||||
<td>HoTschir</td>
|
||||
<td>Ahmet Sait</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2 id="Releases">Releases</h2>
|
||||
<h3>
|
||||
<a href="https://www.scintilla.org/lexilla544.zip">Release 5.4.4</a>
|
||||
</h3>
|
||||
<ul>
|
||||
<li>
|
||||
Released 2 April 2025.
|
||||
</li>
|
||||
<li>
|
||||
Fix building for ARM64.
|
||||
<a href="https://github.com/ScintillaOrg/lexilla/pull/308">Pull request #308</a>.
|
||||
</li>
|
||||
</ul>
|
||||
<h3>
|
||||
<a href="https://www.scintilla.org/lexilla543.zip">Release 5.4.3</a>
|
||||
</h3>
|
||||
|
@ -109,7 +109,7 @@ constexpr int translateBashDigit(int ch) noexcept {
|
||||
return BASH_BASE_ERROR;
|
||||
}
|
||||
|
||||
int getBashNumberBase(char *s) noexcept {
|
||||
int getBashNumberBase(const char *s) noexcept {
|
||||
int i = 0;
|
||||
int base = 0;
|
||||
while (*s) {
|
||||
@ -164,7 +164,7 @@ bool IsCommentLine(Sci_Position line, LexAccessor &styler) {
|
||||
const char ch = styler[i];
|
||||
if (ch == '#')
|
||||
return true;
|
||||
else if (ch != ' ' && ch != '\t')
|
||||
if (ch != ' ' && ch != '\t')
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
@ -698,7 +698,7 @@ void SCI_METHOD LexerBash::Lex(Sci_PositionU startPos, Sci_Position length, int
|
||||
identifierStyle = subStyle | insideCommand;
|
||||
}
|
||||
// allow keywords ending in a whitespace, meta character or command delimiter
|
||||
char s2[10];
|
||||
char s2[10]{};
|
||||
s2[0] = static_cast<char>(sc.ch);
|
||||
s2[1] = '\0';
|
||||
const bool keywordEnds = IsASpace(sc.ch) || setMetaCharacter.Contains(sc.ch) || cmdDelimiter.InList(s2);
|
||||
@ -1140,7 +1140,7 @@ void SCI_METHOD LexerBash::Lex(Sci_PositionU startPos, Sci_Position length, int
|
||||
}
|
||||
// handle command delimiters in command Start|Body|Word state, also Test if 'test' or '[]'
|
||||
if (cmdState < CmdState::DoubleBracket) {
|
||||
char s[10];
|
||||
char s[10]{};
|
||||
s[0] = static_cast<char>(sc.ch);
|
||||
if (setBashOperator.Contains(sc.chNext)) {
|
||||
s[1] = static_cast<char>(sc.chNext);
|
||||
|
@ -48,11 +48,11 @@ constexpr bool IsWhiteSpaceOrEOL(char ch) noexcept {
|
||||
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
|
||||
}
|
||||
|
||||
unsigned int SpaceCount(char* lineBuffer) noexcept {
|
||||
unsigned int SpaceCount(const char* lineBuffer) noexcept {
|
||||
if (lineBuffer == nullptr)
|
||||
return 0;
|
||||
|
||||
char* headBuffer = lineBuffer;
|
||||
const char* headBuffer = lineBuffer;
|
||||
|
||||
while (*headBuffer == ' ')
|
||||
headBuffer++;
|
||||
@ -60,10 +60,10 @@ unsigned int SpaceCount(char* lineBuffer) noexcept {
|
||||
return static_cast<unsigned int>(headBuffer - lineBuffer);
|
||||
}
|
||||
|
||||
bool KeywordAtChar(const char* lineBuffer, char* startComment, const WordList &keywords) noexcept {
|
||||
bool KeywordAtChar(const char* lineBuffer, const char* startComment, const WordList &keywords) noexcept {
|
||||
if (lineBuffer == nullptr || startComment <= lineBuffer)
|
||||
return false;
|
||||
char* endValue = startComment - 1;
|
||||
const char* endValue = startComment - 1;
|
||||
while (endValue >= lineBuffer && *endValue == ' ')
|
||||
endValue--;
|
||||
Sci_PositionU len = static_cast<Sci_PositionU>(endValue - lineBuffer) + 1;
|
||||
|
@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.4.3</string>
|
||||
<string>5.4.4</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
|
@ -876,7 +876,7 @@
|
||||
buildSettings = {
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 5.4.3;
|
||||
CURRENT_PROJECT_VERSION = 5.4.4;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 4F446KW87E;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
@ -904,7 +904,7 @@
|
||||
buildSettings = {
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 5.4.3;
|
||||
CURRENT_PROJECT_VERSION = 5.4.4;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 4F446KW87E;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define VERSION_LEXILLA "5.4.3"
|
||||
#define VERSION_WORDS 5, 4, 3, 0
|
||||
#define VERSION_LEXILLA "5.4.4"
|
||||
#define VERSION_WORDS 5, 4, 4, 0
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VERSION_WORDS
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
.SUFFIXES: .cxx
|
||||
|
||||
DIR_O=.
|
||||
DIR_O=obj
|
||||
DIR_BIN=..\bin
|
||||
|
||||
LEXILLA=$(DIR_BIN)\lexilla.dll
|
||||
@ -23,6 +23,10 @@ LIBLEXILLA=$(DIR_BIN)\liblexilla.lib
|
||||
|
||||
LD=link
|
||||
|
||||
!IF "$(PLATFORM:64=)" == "arm"
|
||||
ARM64=1
|
||||
!ENDIF
|
||||
|
||||
!IFDEF SUPPORT_XP
|
||||
ADD_DEFINE=-D_USING_V110_SDK71_
|
||||
# Different subsystems for 32-bit and 64-bit Windows XP so detect based on Platform
|
||||
@ -33,10 +37,11 @@ SUBSYSTEM=-SUBSYSTEM:WINDOWS,5.02
|
||||
SUBSYSTEM=-SUBSYSTEM:WINDOWS,5.01
|
||||
!ENDIF
|
||||
!ELSE
|
||||
CETCOMPAT=-CETCOMPAT
|
||||
!IFDEF ARM64
|
||||
ADD_DEFINE=-D_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1
|
||||
SUBSYSTEM=-SUBSYSTEM:WINDOWS,10.00
|
||||
!ELSE
|
||||
CETCOMPAT=-CETCOMPAT
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
@ -68,7 +73,10 @@ SCINTILLA_INCLUDE = ../../scintilla/include
|
||||
INCLUDEDIRS=-I../include -I$(SCINTILLA_INCLUDE) -I../lexlib
|
||||
CXXFLAGS=$(CXXFLAGS) $(INCLUDEDIRS)
|
||||
|
||||
all: $(SCINTILLA_INCLUDE) $(LEXILLA) $(LIBLEXILLA)
|
||||
all: $(SCINTILLA_INCLUDE) $(DIR_O) $(LEXILLA) $(LIBLEXILLA)
|
||||
|
||||
$(DIR_O):
|
||||
mkdir "$(DIR_O)" 2>NUL || cd .
|
||||
|
||||
clean:
|
||||
-del /q $(DIR_O)\*.obj $(DIR_O)\*.o $(DIR_O)\*.pdb \
|
||||
|
@ -17,7 +17,7 @@ DEBUG_OPTIONS = -Zi -DEBUG -Od -MTd -DDEBUG $(STATIC_FLAG)
|
||||
DEBUG_OPTIONS = -O2 -MT -DNDEBUG $(STATIC_FLAG) -GL
|
||||
!ENDIF
|
||||
|
||||
CXXFLAGS = /EHsc /std:c++latest $(DEBUG_OPTIONS) $(INCLUDEDIRS)
|
||||
CXXFLAGS = /EHsc /std:c++20 $(DEBUG_OPTIONS) $(INCLUDEDIRS)
|
||||
|
||||
OBJS = TestLexers.obj TestDocument.obj LexillaAccess.obj
|
||||
|
||||
|
@ -1 +1 @@
|
||||
543
|
||||
544
|
@ -2819,8 +2819,8 @@ int ScintillaCall::ExtraDescent() {
|
||||
return static_cast<int>(Call(Message::GetExtraDescent));
|
||||
}
|
||||
|
||||
int ScintillaCall::MarkerSymbolDefined(int markerNumber) {
|
||||
return static_cast<int>(Call(Message::MarkerSymbolDefined, markerNumber));
|
||||
MarkerSymbol ScintillaCall::MarkerSymbolDefined(int markerNumber) {
|
||||
return static_cast<Scintilla::MarkerSymbol>(Call(Message::MarkerSymbolDefined, markerNumber));
|
||||
}
|
||||
|
||||
void ScintillaCall::MarginSetText(Line line, const char *text) {
|
||||
|
@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.5.5</string>
|
||||
<string>5.5.6</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
|
@ -586,7 +586,7 @@
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 5.5.5;
|
||||
CURRENT_PROJECT_VERSION = 5.5.6;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
@ -650,7 +650,7 @@
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 5.5.5;
|
||||
CURRENT_PROJECT_VERSION = 5.5.6;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
@ -682,7 +682,7 @@
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 5.5.5;
|
||||
CURRENT_PROJECT_VERSION = 5.5.6;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
@ -717,7 +717,7 @@
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 5.5.5;
|
||||
CURRENT_PROJECT_VERSION = 5.5.6;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
|
@ -130,7 +130,7 @@
|
||||
|
||||
<h1>Scintilla Documentation</h1>
|
||||
|
||||
<p>Last edited 12 February 2025 NH</p>
|
||||
<p>Last edited 29 March 2025 NH</p>
|
||||
|
||||
<p style="background:#90F0C0">Scintilla 5 has moved the lexers from Scintilla into a new
|
||||
<a href="Lexilla.html">Lexilla</a> project.<br />
|
||||
@ -3583,117 +3583,140 @@ struct Sci_TextToFindFull {
|
||||
<table class="standard" summary="Character Sets supported"><tbody>
|
||||
<tr>
|
||||
<th>Character Set</th>
|
||||
<th>Value</th>
|
||||
<th>Windows</th>
|
||||
<th>GTK</th>
|
||||
<th>Cocoa</th></tr></tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_ANSI</code></td>
|
||||
<tr class="section">
|
||||
<th align="left"><code>SC_CHARSET_ANSI</code></th>
|
||||
<td>0</td>
|
||||
<td>✓</td>
|
||||
<td>✓</td>
|
||||
<td>✓ (8859-1)</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_ARABIC</code></td>
|
||||
<th align="left"><code>SC_CHARSET_ARABIC</code></th>
|
||||
<td>178</td>
|
||||
<td>✓</td>
|
||||
<td></td>
|
||||
<td>✓</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_BALTIC</code></td>
|
||||
<th align="left"><code>SC_CHARSET_BALTIC</code></th>
|
||||
<td>186</td>
|
||||
<td>✓</td>
|
||||
<td></td>
|
||||
<td>✓</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_CHINESEBIG5</code></td>
|
||||
<th align="left"><code>SC_CHARSET_CHINESEBIG5</code></th>
|
||||
<td>136</td>
|
||||
<td>✓</td>
|
||||
<td></td>
|
||||
<td>✓</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_DEFAULT</code></td>
|
||||
<th align="left"><code>SC_CHARSET_DEFAULT</code></th>
|
||||
<td>1</td>
|
||||
<td>✓</td>
|
||||
<td>✓ (8859-1)</td>
|
||||
<td>✓ (8859-1)</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_EASTEUROPE</code></td>
|
||||
<th align="left"><code>SC_CHARSET_EASTEUROPE</code></th>
|
||||
<td>238</td>
|
||||
<td>✓</td>
|
||||
<td>✓</td>
|
||||
<td>✓</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_GB2312</code></td>
|
||||
<th align="left"><code>SC_CHARSET_GB2312</code></th>
|
||||
<td>134</td>
|
||||
<td>✓</td>
|
||||
<td>✓</td>
|
||||
<td>✓</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_GREEK</code></td>
|
||||
<th align="left"><code>SC_CHARSET_GREEK</code></td>
|
||||
<td>161</td>
|
||||
<td>✓</td>
|
||||
<td></td>
|
||||
<td>✓</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_HANGUL</code></td>
|
||||
<th align="left"><code>SC_CHARSET_HANGUL</code></th>
|
||||
<td>129</td>
|
||||
<td>✓</td>
|
||||
<td>✓</td>
|
||||
<td>✓</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_HEBREW</code></td>
|
||||
<th align="left"><code>SC_CHARSET_HEBREW</code></th>
|
||||
<td>177</td>
|
||||
<td>✓</td>
|
||||
<td></td>
|
||||
<td>✓</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_JOHAB</code></td>
|
||||
<th align="left"><code>SC_CHARSET_JOHAB</code></th>
|
||||
<td>130</td>
|
||||
<td>✓</td>
|
||||
<td></td>
|
||||
<td>✓</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_MAC</code></td>
|
||||
<th align="left"><code>SC_CHARSET_MAC</code></th>
|
||||
<td>77</td>
|
||||
<td>✓</td>
|
||||
<td></td>
|
||||
<td>✓</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_OEM</code></td>
|
||||
<th align="left"><code>SC_CHARSET_OEM</code></th>
|
||||
<td>255</td>
|
||||
<td>✓</td>
|
||||
<td></td>
|
||||
<td>✓</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_RUSSIAN</code></td>
|
||||
<th align="left"><code>SC_CHARSET_RUSSIAN</code></th>
|
||||
<td>204</td>
|
||||
<td>✓ (cp1251)</td>
|
||||
<td>✓ (koi8-r)</td>
|
||||
<td>✓ (cp1251)</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_SHIFTJIS</code></td>
|
||||
<th align="left"><code>SC_CHARSET_SHIFTJIS</code></th>
|
||||
<td>128</td>
|
||||
<td>✓</td>
|
||||
<td>✓</td>
|
||||
<td>✓</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_SYMBOL</code></td>
|
||||
<th align="left"><code>SC_CHARSET_SYMBOL</code></th>
|
||||
<td>2</td>
|
||||
<td>✓</td>
|
||||
<td></td>
|
||||
<td>✓</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_THAI</code></td>
|
||||
<th align="left"><code>SC_CHARSET_THAI</code></th>
|
||||
<td>222</td>
|
||||
<td>✓</td>
|
||||
<td></td>
|
||||
<td>✓</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_TURKISH</code></td>
|
||||
<th align="left"><code>SC_CHARSET_TURKISH</code></th>
|
||||
<td>162</td>
|
||||
<td>✓</td>
|
||||
<td></td>
|
||||
<td>✓</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_VIETNAMESE</code></td>
|
||||
<th align="left"><code>SC_CHARSET_VIETNAMESE</code></th>
|
||||
<td>163</td>
|
||||
<td>✓</td>
|
||||
<td></td>
|
||||
<td>✓</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_OEM866</code></td>
|
||||
<th align="left"><code>SC_CHARSET_OEM866</code></th>
|
||||
<td>866</td>
|
||||
<td></td>
|
||||
<td>✓ (cp866)</td>
|
||||
<td></td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_CYRILLIC</code></td>
|
||||
<th align="left"><code>SC_CHARSET_CYRILLIC</code></th>
|
||||
<td>1251</td>
|
||||
<td></td>
|
||||
<td>✓ (cp1251)</td>
|
||||
<td>✓ (cp1251)</td></tr>
|
||||
<tr>
|
||||
<td><code>SC_CHARSET_8859_15</code></td>
|
||||
<th align="left"><code>SC_CHARSET_8859_15</code></th>
|
||||
<td>1000</td>
|
||||
<td></td>
|
||||
<td>✓</td>
|
||||
<td>✓</td></tr>
|
||||
@ -4960,6 +4983,8 @@ struct Sci_TextToFindFull {
|
||||
</table>
|
||||
|
||||
<p>Different shapes available for EOL annotations.
|
||||
Different shapes depend on drawing API so <code>SC_TECHNOLOGY_DEFAULT</code> on Win32
|
||||
only draws a rectangle.
|
||||
Only one shape can currently be used for the whole document - this illustration was produced by trickery.</p>
|
||||
<p><img src="StadiumVariants.png" alt="Different shapes available for EOL annotations" /></p>
|
||||
|
||||
@ -9043,21 +9068,24 @@ struct SCNotification {
|
||||
Sci_Position position;
|
||||
/* SCN_STYLENEEDED, SCN_DOUBLECLICK, SCN_MODIFIED, SCN_MARGINCLICK, */
|
||||
/* SCN_MARGINRIGHTCLICK, SCN_NEEDSHOWN, SCN_DWELLSTART, SCN_DWELLEND, */
|
||||
/* SCN_CALLTIPCLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */
|
||||
/* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
||||
/* SCN_USERLISTSELECTION, SCN_AUTOCSELECTION, SCN_AUTOCSELECTIONCHANGE */
|
||||
/* SCN_CALLTIPCLICK, */
|
||||
/* SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, SCN_HOTSPOTRELEASECLICK, */
|
||||
/* SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
||||
/* SCN_USERLISTSELECTION, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */
|
||||
/* SCN_AUTOCSELECTIONCHANGE */
|
||||
|
||||
int ch;
|
||||
/* SCN_CHARADDED, SCN_KEY, SCN_AUTOCCOMPLETE, SCN_AUTOCSELECTION, */
|
||||
/* SCN_CHARADDED, SCN_KEY, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */
|
||||
/* SCN_USERLISTSELECTION */
|
||||
int modifiers;
|
||||
/* SCN_KEY, SCN_DOUBLECLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */
|
||||
/* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
||||
/* SCN_MARGINCLICK, SCN_MARGINRIGHTCLICK */
|
||||
|
||||
int modificationType; /* SCN_MODIFIED */
|
||||
const char *text;
|
||||
/* SCN_MODIFIED, SCN_USERLISTSELECTION, SCN_AUTOCSELECTION, SCN_URIDROPPED, */
|
||||
/* SCN_AUTOCSELECTIONCHANGE */
|
||||
/* SCN_MODIFIED, SCN_USERLISTSELECTION, SCN_URIDROPPED, */
|
||||
/* SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, SCN_AUTOCSELECTIONCHANGE */
|
||||
|
||||
Sci_Position length; /* SCN_MODIFIED */
|
||||
Sci_Position linesAdded; /* SCN_MODIFIED */
|
||||
|
@ -26,9 +26,9 @@
|
||||
<table bgcolor="#CCCCCC" width="100%" cellspacing="0" cellpadding="8" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
<font size="4"> <a href="https://www.scintilla.org/scintilla555.zip">
|
||||
<font size="4"> <a href="https://www.scintilla.org/scintilla556.zip">
|
||||
Windows</a>
|
||||
<a href="https://www.scintilla.org/scintilla555.tgz">
|
||||
<a href="https://www.scintilla.org/scintilla556.tgz">
|
||||
GTK/Linux</a>
|
||||
</font>
|
||||
</td>
|
||||
@ -42,7 +42,7 @@
|
||||
containing very few restrictions.
|
||||
</p>
|
||||
<h3>
|
||||
Release 5.5.5
|
||||
Release 5.5.6
|
||||
</h3>
|
||||
<h4>
|
||||
Source Code
|
||||
@ -50,8 +50,8 @@
|
||||
The source code package contains all of the source code for Scintilla but no binary
|
||||
executable code and is available in
|
||||
<ul>
|
||||
<li><a href="https://www.scintilla.org/scintilla555.zip">zip format</a> (1.8M) commonly used on Windows</li>
|
||||
<li><a href="https://www.scintilla.org/scintilla555.tgz">tgz format</a> (1.7M) commonly used on Linux and compatible operating systems</li>
|
||||
<li><a href="https://www.scintilla.org/scintilla556.zip">zip format</a> (1.8M) commonly used on Windows</li>
|
||||
<li><a href="https://www.scintilla.org/scintilla556.tgz">tgz format</a> (1.7M) commonly used on Linux and compatible operating systems</li>
|
||||
</ul>
|
||||
Instructions for building on both Windows and Linux are included in the readme file.
|
||||
<h4>
|
||||
|
@ -585,9 +585,56 @@
|
||||
<td>Martijn Laan</td>
|
||||
</tr><tr>
|
||||
<td>Pawel Z Wronek</td>
|
||||
<td>Joachim Mairboeck</td>
|
||||
<td>Gianluca Vaccari</td>
|
||||
<td>8day</td>
|
||||
</tr><tr>
|
||||
<td>Ahmet Sait</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2 id="Releases">Releases</h2>
|
||||
<h3>
|
||||
<a href="https://www.scintilla.org/scintilla556.zip">Release 5.5.6</a>
|
||||
</h3>
|
||||
<ul>
|
||||
<li>
|
||||
Released 2 April 2025.
|
||||
</li>
|
||||
<li>
|
||||
Disallow changing case of protected text.
|
||||
<a href="https://sourceforge.net/p/scintilla/bugs/2463/">Bug #2463</a>.
|
||||
</li>
|
||||
<li>
|
||||
Return enumeration type from MarkerSymbolDefined to match MarkerDefine.
|
||||
<a href="https://sourceforge.net/p/scintilla/bugs/2469/">Bug #2469</a>.
|
||||
</li>
|
||||
<li>
|
||||
On Win32, use DirectWrite for autocompletion lists when DirectWrite chosen for document text.
|
||||
</li>
|
||||
<li>
|
||||
On Win32, optimize case-insensitive DBCS search to be around 5 times faster
|
||||
by using 64K memory to cache folding data for each DBCS code page used.
|
||||
</li>
|
||||
<li>
|
||||
On Win32, fix a crash with bidirectional text.
|
||||
</li>
|
||||
<li>
|
||||
When using Visual C++ through nmake, fix building for ARM64.
|
||||
<a href="https://sourceforge.net/p/scintilla/feature-requests/1546/">Feature #1546</a>.
|
||||
</li>
|
||||
<li>
|
||||
On Qt, draw clipped UTF-8 text correctly.
|
||||
<a href="https://sourceforge.net/p/scintilla/bugs/2464/">Bug #2464</a>.
|
||||
</li>
|
||||
<li>
|
||||
On Qt, avoid a dwell start when the mouse is moved outside the Scintilla widget.
|
||||
<a href="https://sourceforge.net/p/scintilla/bugs/2466/">Bug #2466</a>.
|
||||
</li>
|
||||
<li>
|
||||
On Qt, autoCompleteSelection converts from local encoding when not in Unicode mode.
|
||||
<a href="https://sourceforge.net/p/scintilla/bugs/2465/">Bug #2465</a>.
|
||||
</li>
|
||||
</ul>
|
||||
<h3>
|
||||
<a href="https://www.scintilla.org/scintilla555.zip">Release 5.5.5</a>
|
||||
</h3>
|
||||
|
@ -10,6 +10,7 @@
|
||||
<title>
|
||||
Scintilla Usage Notes
|
||||
</title>
|
||||
<link rel="canonical" href="https://scintilla.org/ScintillaUsage.html" />
|
||||
<style type="text/css">
|
||||
SPAN {
|
||||
font-family: Verdana, Arial, Helvetica;
|
||||
|
@ -9,7 +9,7 @@
|
||||
<meta name="keywords" content="Scintilla, SciTE, Editing Component, Text Editor" />
|
||||
<meta name="Description"
|
||||
content="www.scintilla.org is the home of the Scintilla editing component and SciTE text editor application." />
|
||||
<meta name="Date.Modified" content="20250225" />
|
||||
<meta name="Date.Modified" content="20250402" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<style type="text/css">
|
||||
.logo {
|
||||
@ -61,8 +61,8 @@
|
||||
GTK, and macOS</font>
|
||||
</td>
|
||||
<td width="40%" align="right">
|
||||
<font color="#FFCC99" size="3"> Release version 5.5.5<br />
|
||||
Site last modified February 25 2025</font>
|
||||
<font color="#FFCC99" size="3"> Release version 5.5.6<br />
|
||||
Site last modified April 2 2025</font>
|
||||
</td>
|
||||
<td width="20%">
|
||||
|
||||
@ -77,11 +77,11 @@
|
||||
</tr>
|
||||
</table>
|
||||
<ul id="versionlist">
|
||||
<li>Version 5.5.6 improves DBCS and autocompletion drawing on Win32 and improves dwell, encoding and text clipping on Qt.</li>
|
||||
<li>Version 5.5.5 can remember selection with undo and redo. Update to use DirectWrite 1.1.</li>
|
||||
<li>Version 5.5.4 fixes wrapping of removed lines and edge cases for moving lines. On GTK, middle click can be repeated with one value.</li>
|
||||
<li>Version 5.5.3 fixes horizontal scrolling with a touchpad on Win32.</li>
|
||||
<li>Version 5.5.2 adds multiple selection copy with separator, a font stretch setting, and access to whether an undo sequence is active.</li>
|
||||
<li>Version 5.5.1 adds SCI_CUTALLOWLINE and fixes a Win32 bug that caused the cursor to flicker.</li>
|
||||
</ul>
|
||||
<ul id="menu">
|
||||
<li id="remote1"><a href="https://www.scintilla.org/SciTEImage.html">Screenshot</a></li>
|
||||
|
@ -1424,10 +1424,12 @@ struct SCNotification {
|
||||
Sci_NotifyHeader nmhdr;
|
||||
Sci_Position position;
|
||||
/* SCN_STYLENEEDED, SCN_DOUBLECLICK, SCN_MODIFIED, SCN_MARGINCLICK, */
|
||||
/* SCN_NEEDSHOWN, SCN_DWELLSTART, SCN_DWELLEND, SCN_CALLTIPCLICK, */
|
||||
/* SCN_MARGINRIGHTCLICK, SCN_NEEDSHOWN, SCN_DWELLSTART, SCN_DWELLEND, */
|
||||
/* SCN_CALLTIPCLICK, */
|
||||
/* SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, SCN_HOTSPOTRELEASECLICK, */
|
||||
/* SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
||||
/* SCN_USERLISTSELECTION, SCN_AUTOCSELECTION */
|
||||
/* SCN_USERLISTSELECTION, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */
|
||||
/* SCN_AUTOCSELECTIONCHANGE */
|
||||
|
||||
int ch;
|
||||
/* SCN_CHARADDED, SCN_KEY, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */
|
||||
@ -1435,10 +1437,12 @@ struct SCNotification {
|
||||
int modifiers;
|
||||
/* SCN_KEY, SCN_DOUBLECLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */
|
||||
/* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
||||
/* SCN_MARGINCLICK, SCN_MARGINRIGHTCLICK */
|
||||
|
||||
int modificationType; /* SCN_MODIFIED */
|
||||
const char *text;
|
||||
/* SCN_MODIFIED, SCN_USERLISTSELECTION, SCN_AUTOCSELECTION, SCN_URIDROPPED */
|
||||
/* SCN_MODIFIED, SCN_USERLISTSELECTION, SCN_URIDROPPED, */
|
||||
/* SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, SCN_AUTOCSELECTIONCHANGE */
|
||||
|
||||
Sci_Position length; /* SCN_MODIFIED */
|
||||
Sci_Position linesAdded; /* SCN_MODIFIED */
|
||||
@ -1448,15 +1452,15 @@ struct SCNotification {
|
||||
Sci_Position line; /* SCN_MODIFIED */
|
||||
int foldLevelNow; /* SCN_MODIFIED */
|
||||
int foldLevelPrev; /* SCN_MODIFIED */
|
||||
int margin; /* SCN_MARGINCLICK */
|
||||
int listType; /* SCN_USERLISTSELECTION */
|
||||
int margin; /* SCN_MARGINCLICK, SCN_MARGINRIGHTCLICK */
|
||||
int listType; /* SCN_USERLISTSELECTION, SCN_AUTOCSELECTIONCHANGE */
|
||||
int x; /* SCN_DWELLSTART, SCN_DWELLEND */
|
||||
int y; /* SCN_DWELLSTART, SCN_DWELLEND */
|
||||
int token; /* SCN_MODIFIED with SC_MOD_CONTAINER */
|
||||
Sci_Position annotationLinesAdded; /* SCN_MODIFIED with SC_MOD_CHANGEANNOTATION */
|
||||
int updated; /* SCN_UPDATEUI */
|
||||
int listCompletionMethod;
|
||||
/* SCN_AUTOCSELECTION, SCN_AUTOCCOMPLETED, SCN_USERLISTSELECTION, */
|
||||
/* SCN_AUTOCSELECTION, SCN_AUTOCCOMPLETED, SCN_USERLISTSELECTION */
|
||||
int characterSource; /* SCN_CHARADDED */
|
||||
};
|
||||
|
||||
|
@ -2755,7 +2755,7 @@ set void SetExtraDescent=2527(int extraDescent,)
|
||||
get int GetExtraDescent=2528(,)
|
||||
|
||||
# Which symbol was defined for markerNumber with MarkerDefine
|
||||
fun int MarkerSymbolDefined=2529(int markerNumber,)
|
||||
fun MarkerSymbol MarkerSymbolDefined=2529(int markerNumber,)
|
||||
|
||||
# Set the text in the text margin for a line
|
||||
set void MarginSetText=2530(line line, string text)
|
||||
|
@ -750,7 +750,7 @@ public:
|
||||
int ExtraAscent();
|
||||
void SetExtraDescent(int extraDescent);
|
||||
int ExtraDescent();
|
||||
int MarkerSymbolDefined(int markerNumber);
|
||||
Scintilla::MarkerSymbol MarkerSymbolDefined(int markerNumber);
|
||||
void MarginSetText(Line line, const char *text);
|
||||
int MarginGetText(Line line, char *text);
|
||||
std::string MarginGetText(Line line);
|
||||
|
@ -88,10 +88,12 @@ struct NotificationData {
|
||||
NotifyHeader nmhdr;
|
||||
Position position;
|
||||
/* SCN_STYLENEEDED, SCN_DOUBLECLICK, SCN_MODIFIED, SCN_MARGINCLICK, */
|
||||
/* SCN_NEEDSHOWN, SCN_DWELLSTART, SCN_DWELLEND, SCN_CALLTIPCLICK, */
|
||||
/* SCN_MARGINRIGHTCLICK, SCN_NEEDSHOWN, SCN_DWELLSTART, SCN_DWELLEND, */
|
||||
/* SCN_CALLTIPCLICK, */
|
||||
/* SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, SCN_HOTSPOTRELEASECLICK, */
|
||||
/* SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
||||
/* SCN_USERLISTSELECTION, SCN_AUTOCSELECTION */
|
||||
/* SCN_USERLISTSELECTION, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */
|
||||
/* SCN_AUTOCSELECTIONCHANGE */
|
||||
|
||||
int ch;
|
||||
/* SCN_CHARADDED, SCN_KEY, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */
|
||||
@ -99,10 +101,12 @@ struct NotificationData {
|
||||
KeyMod modifiers;
|
||||
/* SCN_KEY, SCN_DOUBLECLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */
|
||||
/* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
||||
/* SCN_MARGINCLICK, SCN_MARGINRIGHTCLICK */
|
||||
|
||||
ModificationFlags modificationType; /* SCN_MODIFIED */
|
||||
const char *text;
|
||||
/* SCN_MODIFIED, SCN_USERLISTSELECTION, SCN_AUTOCSELECTION, SCN_URIDROPPED */
|
||||
/* SCN_MODIFIED, SCN_USERLISTSELECTION, SCN_URIDROPPED, */
|
||||
/* SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, SCN_AUTOCSELECTIONCHANGE */
|
||||
|
||||
Position length; /* SCN_MODIFIED */
|
||||
Position linesAdded; /* SCN_MODIFIED */
|
||||
@ -112,15 +116,15 @@ struct NotificationData {
|
||||
Position line; /* SCN_MODIFIED */
|
||||
FoldLevel foldLevelNow; /* SCN_MODIFIED */
|
||||
FoldLevel foldLevelPrev; /* SCN_MODIFIED */
|
||||
int margin; /* SCN_MARGINCLICK */
|
||||
int listType; /* SCN_USERLISTSELECTION */
|
||||
int margin; /* SCN_MARGINCLICK, SCN_MARGINRIGHTCLICK */
|
||||
int listType; /* SCN_USERLISTSELECTION, SCN_AUTOCSELECTIONCHANGE */
|
||||
int x; /* SCN_DWELLSTART, SCN_DWELLEND */
|
||||
int y; /* SCN_DWELLSTART, SCN_DWELLEND */
|
||||
int token; /* SCN_MODIFIED with SC_MOD_CONTAINER */
|
||||
Position annotationLinesAdded; /* SCN_MODIFIED with SC_MOD_CHANGEANNOTATION */
|
||||
Update updated; /* SCN_UPDATEUI */
|
||||
CompletionMethods listCompletionMethod;
|
||||
/* SCN_AUTOCSELECTION, SCN_AUTOCCOMPLETED, SCN_USERLISTSELECTION, */
|
||||
/* SCN_AUTOCSELECTION, SCN_AUTOCCOMPLETED, SCN_USERLISTSELECTION */
|
||||
CharacterSource characterSource; /* SCN_CHARADDED */
|
||||
};
|
||||
|
||||
|
@ -13,7 +13,7 @@ TEMPLATE = lib
|
||||
CONFIG += lib_bundle
|
||||
CONFIG += c++1z
|
||||
|
||||
VERSION = 5.5.5
|
||||
VERSION = 5.5.6
|
||||
|
||||
SOURCES += \
|
||||
ScintillaEdit.cpp \
|
||||
|
@ -667,7 +667,7 @@ void SurfaceImpl::DrawTextClippedUTF8(PRectangle rc,
|
||||
ColourRGBA back)
|
||||
{
|
||||
SetClip(rc);
|
||||
DrawTextNoClip(rc, font, ybase, text, fore, back);
|
||||
DrawTextNoClipUTF8(rc, font, ybase, text, fore, back);
|
||||
PopClip();
|
||||
}
|
||||
|
||||
|
@ -373,6 +373,12 @@ void ScintillaEditBase::mouseMoveEvent(QMouseEvent *event)
|
||||
sqt->ButtonMoveWithModifiers(pos, TimeOfEvent(time), modifiers);
|
||||
}
|
||||
|
||||
void ScintillaEditBase::leaveEvent(QEvent *event)
|
||||
{
|
||||
QWidget::leaveEvent(event);
|
||||
sqt->MouseLeave();
|
||||
}
|
||||
|
||||
void ScintillaEditBase::contextMenuEvent(QContextMenuEvent *event)
|
||||
{
|
||||
const Point pos = PointFromQPoint(event->globalPos());
|
||||
@ -810,7 +816,7 @@ void ScintillaEditBase::notifyParent(NotificationData scn)
|
||||
break;
|
||||
|
||||
case Notification::AutoCSelection:
|
||||
emit autoCompleteSelection(scn.lParam, QString::fromUtf8(scn.text));
|
||||
emit autoCompleteSelection(scn.lParam, sqt->IsUnicodeMode() ? QString::fromUtf8(scn.text) : QString::fromLocal8Bit(scn.text));
|
||||
break;
|
||||
|
||||
case Notification::AutoCCancelled:
|
||||
|
@ -141,6 +141,7 @@ protected:
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
void contextMenuEvent(QContextMenuEvent *event) override;
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void dragLeaveEvent(QDragLeaveEvent *event) override;
|
||||
|
@ -13,7 +13,7 @@ TEMPLATE = lib
|
||||
CONFIG += lib_bundle
|
||||
CONFIG += c++1z
|
||||
|
||||
VERSION = 5.5.5
|
||||
VERSION = 5.5.6
|
||||
|
||||
SOURCES += \
|
||||
PlatQt.cpp \
|
||||
|
@ -158,6 +158,9 @@
|
||||
// win32
|
||||
#include "WinTypes.h"
|
||||
#include "PlatWin.h"
|
||||
#include "ListBox.h"
|
||||
#include "SurfaceGDI.h"
|
||||
#include "SurfaceD2D.h"
|
||||
#include "HanjaDic.h"
|
||||
#include "ScintillaWin.h"
|
||||
|
||||
|
@ -605,7 +605,7 @@ class CaseConverter final : public ICaseConverter {
|
||||
return character < other.character;
|
||||
}
|
||||
};
|
||||
typedef std::vector<CharacterConversion> CharacterToConversion;
|
||||
using CharacterToConversion = std::vector<CharacterConversion>;
|
||||
CharacterToConversion characterToConversion;
|
||||
// The parallel arrays
|
||||
std::vector<int> characters;
|
||||
@ -613,7 +613,7 @@ class CaseConverter final : public ICaseConverter {
|
||||
|
||||
public:
|
||||
CaseConverter() noexcept = default;
|
||||
bool Initialised() const noexcept {
|
||||
[[nodiscard]] bool Initialised() const noexcept {
|
||||
return !characters.empty();
|
||||
}
|
||||
void Add(int character, std::string_view conversion_) {
|
||||
@ -787,7 +787,7 @@ size_t CaseConvertString(char *converted, size_t sizeConverted, const char *mixe
|
||||
|
||||
std::string CaseConvertString(const std::string &s, CaseConversion conversion) {
|
||||
std::string retMapped(s.length() * maxExpansionCaseConversion, 0);
|
||||
const size_t lenMapped = CaseConvertString(&retMapped[0], retMapped.length(), s.c_str(), s.length(),
|
||||
const size_t lenMapped = CaseConvertString(retMapped.data(), retMapped.length(), s.c_str(), s.length(),
|
||||
conversion);
|
||||
retMapped.resize(lenMapped);
|
||||
return retMapped;
|
||||
|
@ -5,6 +5,11 @@
|
||||
// Copyright 2017 by Neil Hodgson <neilh@scintilla.org>
|
||||
// The License.txt file describes the conditions under which this software may be distributed.
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
#include "DBCS.h"
|
||||
|
||||
using namespace Scintilla::Internal;
|
||||
@ -15,33 +20,68 @@ bool DBCSIsLeadByte(int codePage, char ch) noexcept {
|
||||
// Byte ranges found in Wikipedia articles with relevant search strings in each case
|
||||
const unsigned char uch = ch;
|
||||
switch (codePage) {
|
||||
case 932:
|
||||
case cp932:
|
||||
// Shift_jis
|
||||
return ((uch >= 0x81) && (uch <= 0x9F)) ||
|
||||
((uch >= 0xE0) && (uch <= 0xFC));
|
||||
// Lead bytes F0 to FC may be a Microsoft addition.
|
||||
case 936:
|
||||
case cp936:
|
||||
// GBK
|
||||
return (uch >= 0x81) && (uch <= 0xFE);
|
||||
case 949:
|
||||
case cp949:
|
||||
// Korean Wansung KS C-5601-1987
|
||||
return (uch >= 0x81) && (uch <= 0xFE);
|
||||
case 950:
|
||||
case cp950:
|
||||
// Big5
|
||||
return (uch >= 0x81) && (uch <= 0xFE);
|
||||
case 1361:
|
||||
case cp1361:
|
||||
// Korean Johab KS C-5601-1992
|
||||
return
|
||||
((uch >= 0x84) && (uch <= 0xD3)) ||
|
||||
((uch >= 0xD8) && (uch <= 0xDE)) ||
|
||||
((uch >= 0xE0) && (uch <= 0xF9));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DBCSIsTrailByte(int codePage, char ch) noexcept {
|
||||
const unsigned char trail = ch;
|
||||
switch (codePage) {
|
||||
case cp932:
|
||||
// Shift_jis
|
||||
return (trail != 0x7F) &&
|
||||
((trail >= 0x40) && (trail <= 0xFC));
|
||||
case cp936:
|
||||
// GBK
|
||||
return (trail != 0x7F) &&
|
||||
((trail >= 0x40) && (trail <= 0xFE));
|
||||
case cp949:
|
||||
// Korean Wansung KS C-5601-1987
|
||||
return
|
||||
((trail >= 0x41) && (trail <= 0x5A)) ||
|
||||
((trail >= 0x61) && (trail <= 0x7A)) ||
|
||||
((trail >= 0x81) && (trail <= 0xFE));
|
||||
case cp950:
|
||||
// Big5
|
||||
return
|
||||
((trail >= 0x40) && (trail <= 0x7E)) ||
|
||||
((trail >= 0xA1) && (trail <= 0xFE));
|
||||
case cp1361:
|
||||
// Korean Johab KS C-5601-1992
|
||||
return
|
||||
((trail >= 0x31) && (trail <= 0x7E)) ||
|
||||
((trail >= 0x81) && (trail <= 0xFE));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsDBCSValidSingleByte(int codePage, int ch) noexcept {
|
||||
switch (codePage) {
|
||||
case 932:
|
||||
case cp932:
|
||||
return ch == 0x80
|
||||
|| (ch >= 0xA0 && ch <= 0xDF)
|
||||
|| (ch >= 0xFD);
|
||||
@ -51,4 +91,25 @@ bool IsDBCSValidSingleByte(int codePage, int ch) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
using CodePageToFoldMap = std::map<int, FoldMap>;
|
||||
CodePageToFoldMap cpToFoldMap;
|
||||
|
||||
bool DBCSHasFoldMap(int codePage) {
|
||||
const CodePageToFoldMap::const_iterator it = cpToFoldMap.find(codePage);
|
||||
return it != cpToFoldMap.end();
|
||||
}
|
||||
|
||||
void DBCSSetFoldMap(int codePage, const FoldMap &foldMap) {
|
||||
cpToFoldMap[codePage] = foldMap;
|
||||
}
|
||||
|
||||
FoldMap *DBCSGetMutableFoldMap(int codePage) {
|
||||
// Constructs if needed
|
||||
return &cpToFoldMap[codePage];
|
||||
}
|
||||
|
||||
const FoldMap *DBCSGetFoldMap(int codePage) {
|
||||
return &cpToFoldMap[codePage];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,17 +10,44 @@
|
||||
|
||||
namespace Scintilla::Internal {
|
||||
|
||||
constexpr int cp932 = 932;
|
||||
constexpr int cp936 = 936;
|
||||
constexpr int cp949 = 949;
|
||||
constexpr int cp950 = 950;
|
||||
constexpr int cp1361 = 1361;
|
||||
|
||||
constexpr bool IsDBCSCodePage(int codePage) noexcept {
|
||||
return codePage == 932
|
||||
|| codePage == 936
|
||||
|| codePage == 949
|
||||
|| codePage == 950
|
||||
|| codePage == 1361;
|
||||
return codePage == cp932
|
||||
|| codePage == cp936
|
||||
|| codePage == cp949
|
||||
|| codePage == cp950
|
||||
|| codePage == cp1361;
|
||||
}
|
||||
|
||||
bool DBCSIsLeadByte(int codePage, char ch) noexcept;
|
||||
bool DBCSIsTrailByte(int codePage, char ch) noexcept;
|
||||
bool IsDBCSValidSingleByte(int codePage, int ch) noexcept;
|
||||
|
||||
// Calculate a number from a DBCS byte pair that can be used to index into an array or map.
|
||||
// Should only be called with genuine DBCS character pairs which means that ch1 has top bit set.
|
||||
constexpr uint16_t DBCSIndex(char ch1, char ch2) noexcept {
|
||||
constexpr unsigned int highStart = 0x80U;
|
||||
constexpr unsigned int byteMultiply = 0x100U;
|
||||
const unsigned char uch1 = ch1;
|
||||
const unsigned char uch2 = ch2;
|
||||
return ((uch1 - highStart) * byteMultiply) + uch2;
|
||||
}
|
||||
|
||||
struct DBCSPair {
|
||||
char chars[2];
|
||||
};
|
||||
using FoldMap = std::array<DBCSPair, 0x8000>;
|
||||
|
||||
bool DBCSHasFoldMap(int codePage);
|
||||
void DBCSSetFoldMap(int codePage, const FoldMap &foldMap);
|
||||
FoldMap *DBCSGetMutableFoldMap(int codePage);
|
||||
const FoldMap *DBCSGetFoldMap(int codePage);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -620,11 +620,14 @@ void Document::ClearLevels() {
|
||||
Levels()->ClearLevels();
|
||||
}
|
||||
|
||||
static bool IsSubordinate(FoldLevel levelStart, FoldLevel levelTry) noexcept {
|
||||
namespace {
|
||||
|
||||
constexpr bool IsSubordinate(FoldLevel levelStart, FoldLevel levelTry) noexcept {
|
||||
if (LevelIsWhitespace(levelTry))
|
||||
return true;
|
||||
else
|
||||
return LevelNumber(levelStart) < LevelNumber(levelTry);
|
||||
return LevelNumber(levelStart) < LevelNumber(levelTry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Sci::Line Document::GetLastChild(Sci::Line lineParent, std::optional<FoldLevel> level, Sci::Line lastLine) {
|
||||
@ -1229,8 +1232,8 @@ void DiscardEndFragment(std::string_view &text) noexcept {
|
||||
}
|
||||
|
||||
constexpr bool IsBaseOfGrapheme(CharacterCategory cc) {
|
||||
// \p{L}\p{N}\p{P}\p{Sm}\p{Sc}\p{So}\p{Zs}
|
||||
switch (cc) {
|
||||
// \p{L}\p{N}\p{P}\p{Sm}\p{Sc}\p{So}\p{Zs}
|
||||
case ccLu:
|
||||
case ccLl:
|
||||
case ccLt:
|
||||
@ -1250,12 +1253,16 @@ constexpr bool IsBaseOfGrapheme(CharacterCategory cc) {
|
||||
case ccSc:
|
||||
case ccSo:
|
||||
case ccZs:
|
||||
// Control
|
||||
case ccCc:
|
||||
case ccCs:
|
||||
case ccCo:
|
||||
return true;
|
||||
default:
|
||||
// ccMn, ccMc, ccMe,
|
||||
// ccSk,
|
||||
// ccZl, ccZp,
|
||||
// ccCc, ccCf, ccCs, ccCo, ccCn
|
||||
// ccCf, ccCn
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1276,6 +1283,25 @@ CharacterExtracted LastCharacter(std::string_view text) noexcept {
|
||||
static_cast<unsigned int>(utf8status & UTF8MaskWidth) };
|
||||
}
|
||||
|
||||
constexpr Sci::Position NextTab(Sci::Position pos, Sci::Position tabSize) noexcept {
|
||||
return ((pos / tabSize) + 1) * tabSize;
|
||||
}
|
||||
|
||||
std::string CreateIndentation(Sci::Position indent, int tabSize, bool insertSpaces) {
|
||||
std::string indentation;
|
||||
if (!insertSpaces) {
|
||||
while (indent >= tabSize) {
|
||||
indentation += '\t';
|
||||
indent -= tabSize;
|
||||
}
|
||||
}
|
||||
while (indent > 0) {
|
||||
indentation += ' ';
|
||||
indent--;
|
||||
}
|
||||
return indentation;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool Scintilla::Internal::DiscardLastCombinedCharacter(std::string_view &text) noexcept {
|
||||
@ -1287,6 +1313,8 @@ bool Scintilla::Internal::DiscardLastCombinedCharacter(std::string_view &text) n
|
||||
// ccs-base := [\p{L}\p{N}\p{P}\p{S}\p{Zs}]
|
||||
// ccs-extend := [\p{M}\p{Join_Control}]
|
||||
// Modified to move Sk (Symbol Modifier) from ccs-base to ccs-extend to preserve modified emoji
|
||||
// May break before and after Control which is defined as most of ccC? but not some of ccCf and ccCn
|
||||
// so treat ccCc, ccCs, ccCo as base for now.
|
||||
|
||||
std::string_view truncated = text;
|
||||
while (truncated.length() > UTF8MaxBytes) {
|
||||
@ -1702,25 +1730,6 @@ void Document::DelCharBack(Sci::Position pos) {
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr Sci::Position NextTab(Sci::Position pos, Sci::Position tabSize) noexcept {
|
||||
return ((pos / tabSize) + 1) * tabSize;
|
||||
}
|
||||
|
||||
static std::string CreateIndentation(Sci::Position indent, int tabSize, bool insertSpaces) {
|
||||
std::string indentation;
|
||||
if (!insertSpaces) {
|
||||
while (indent >= tabSize) {
|
||||
indentation += '\t';
|
||||
indent -= tabSize;
|
||||
}
|
||||
}
|
||||
while (indent > 0) {
|
||||
indentation += ' ';
|
||||
indent--;
|
||||
}
|
||||
return indentation;
|
||||
}
|
||||
|
||||
int SCI_METHOD Document::GetLineIndentation(Sci_Position line) {
|
||||
int indent = 0;
|
||||
if ((line >= 0) && (line < LinesTotal())) {
|
||||
@ -2364,7 +2373,7 @@ Sci::Position Document::FindText(Sci::Position minPos, Sci::Position maxPos, con
|
||||
constexpr size_t maxFoldingExpansion = 4;
|
||||
std::vector<char> searchThing((lengthFind+1) * UTF8MaxBytes * maxFoldingExpansion + 1);
|
||||
const size_t lenSearch =
|
||||
pcf->Fold(&searchThing[0], searchThing.size(), search, lengthFind);
|
||||
pcf->Fold(searchThing.data(), searchThing.size(), search, lengthFind);
|
||||
while (forward ? (pos < endPos) : (pos >= endPos)) {
|
||||
int widthFirstCharacter = 1;
|
||||
Sci::Position posIndexDocument = pos;
|
||||
@ -2397,7 +2406,7 @@ Sci::Position Document::FindText(Sci::Position minPos, Sci::Position maxPos, con
|
||||
// memcmp may examine lenFlat bytes in both arguments so assert it doesn't read past end of searchThing
|
||||
assert((indexSearch + lenFlat) <= searchThing.size());
|
||||
// Does folded match the buffer
|
||||
characterMatches = 0 == memcmp(folded, &searchThing[0] + indexSearch, lenFlat);
|
||||
characterMatches = 0 == memcmp(folded, searchThing.data() + indexSearch, lenFlat);
|
||||
}
|
||||
if (!characterMatches) {
|
||||
break;
|
||||
@ -2423,7 +2432,7 @@ Sci::Position Document::FindText(Sci::Position minPos, Sci::Position maxPos, con
|
||||
constexpr size_t maxBytesCharacter = 2;
|
||||
constexpr size_t maxFoldingExpansion = 4;
|
||||
std::vector<char> searchThing((lengthFind+1) * maxBytesCharacter * maxFoldingExpansion + 1);
|
||||
const size_t lenSearch = pcf->Fold(&searchThing[0], searchThing.size(), search, lengthFind);
|
||||
const size_t lenSearch = pcf->Fold(searchThing.data(), searchThing.size(), search, lengthFind);
|
||||
while (forward ? (pos < endPos) : (pos >= endPos)) {
|
||||
int widthFirstCharacter = 0;
|
||||
Sci::Position indexDocument = 0;
|
||||
@ -2452,7 +2461,7 @@ Sci::Position Document::FindText(Sci::Position minPos, Sci::Position maxPos, con
|
||||
// memcmp may examine lenFlat bytes in both arguments so assert it doesn't read past end of searchThing
|
||||
assert((indexSearch + lenFlat) <= searchThing.size());
|
||||
// Does folded match the buffer
|
||||
characterMatches = 0 == memcmp(folded, &searchThing[0] + indexSearch, lenFlat);
|
||||
characterMatches = 0 == memcmp(folded, searchThing.data() + indexSearch, lenFlat);
|
||||
}
|
||||
if (!characterMatches) {
|
||||
break;
|
||||
@ -2477,7 +2486,7 @@ Sci::Position Document::FindText(Sci::Position minPos, Sci::Position maxPos, con
|
||||
} else {
|
||||
const Sci::Position endSearch = (startPos <= endPos) ? endPos - lengthFind + 1 : endPos;
|
||||
std::vector<char> searchThing(lengthFind + 1);
|
||||
pcf->Fold(&searchThing[0], searchThing.size(), search, lengthFind);
|
||||
pcf->Fold(searchThing.data(), searchThing.size(), search, lengthFind);
|
||||
while (forward ? (pos < endSearch) : (pos >= endSearch)) {
|
||||
bool found = (pos + lengthFind) <= limitPos;
|
||||
for (int indexSearch = 0; (indexSearch < lengthFind) && found; indexSearch++) {
|
||||
@ -2975,7 +2984,9 @@ Sci::Position Document::ExtendStyleRange(Sci::Position pos, int delta, bool sing
|
||||
return pos;
|
||||
}
|
||||
|
||||
static char BraceOpposite(char ch) noexcept {
|
||||
namespace {
|
||||
|
||||
constexpr char BraceOpposite(char ch) noexcept {
|
||||
switch (ch) {
|
||||
case '(':
|
||||
return ')';
|
||||
@ -2998,6 +3009,8 @@ static char BraceOpposite(char ch) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO: should be able to extend styled region to find matching brace
|
||||
Sci::Position Document::BraceMatch(Sci::Position position, Sci::Position /*maxReStyle*/, Sci::Position startPos, bool useStartPos) noexcept {
|
||||
const unsigned char chBrace = CharAt(position);
|
||||
@ -3075,7 +3088,7 @@ public:
|
||||
lineRangeEnd = doc->SciLineFromPosition(endPos);
|
||||
lineRangeBreak = lineRangeEnd + increment;
|
||||
}
|
||||
Range LineRange(Sci::Line line, Sci::Position lineStartPos, Sci::Position lineEndPos) const noexcept {
|
||||
[[nodiscard]] Range LineRange(Sci::Line line, Sci::Position lineStartPos, Sci::Position lineEndPos) const noexcept {
|
||||
Range range(lineStartPos, lineEndPos);
|
||||
if (increment == 1) {
|
||||
if (line == lineRangeStart)
|
||||
@ -3101,13 +3114,13 @@ public:
|
||||
pdoc(pdoc_), end(end_) {
|
||||
}
|
||||
|
||||
char CharAt(Sci::Position index) const noexcept override {
|
||||
[[nodiscard]] char CharAt(Sci::Position index) const noexcept override {
|
||||
if (index < 0 || index >= end)
|
||||
return 0;
|
||||
else
|
||||
return pdoc->CharAt(index);
|
||||
}
|
||||
Sci::Position MovePositionOutsideChar(Sci::Position pos, Sci::Position moveDir) const noexcept override {
|
||||
[[nodiscard]] Sci::Position MovePositionOutsideChar(Sci::Position pos, Sci::Position moveDir) const noexcept override {
|
||||
return pdoc->MovePositionOutsideChar(pos, moveDir, false);
|
||||
}
|
||||
};
|
||||
@ -3150,10 +3163,10 @@ public:
|
||||
bool operator!=(const ByteIterator &other) const noexcept {
|
||||
return doc != other.doc || position != other.position;
|
||||
}
|
||||
Sci::Position Pos() const noexcept {
|
||||
[[nodiscard]] Sci::Position Pos() const noexcept {
|
||||
return position;
|
||||
}
|
||||
Sci::Position PosRoundUp() const noexcept {
|
||||
[[nodiscard]] Sci::Position PosRoundUp() const noexcept {
|
||||
return position;
|
||||
}
|
||||
};
|
||||
@ -3178,11 +3191,11 @@ class UTF8Iterator {
|
||||
// These 3 fields determine the iterator position and are used for comparisons
|
||||
const Document *doc;
|
||||
Sci::Position position;
|
||||
size_t characterIndex;
|
||||
size_t characterIndex = 0;
|
||||
// Remaining fields are derived from the determining fields so are excluded in comparisons
|
||||
unsigned int lenBytes;
|
||||
size_t lenCharacters;
|
||||
wchar_t buffered[2];
|
||||
unsigned int lenBytes = 0;
|
||||
size_t lenCharacters = 0;
|
||||
wchar_t buffered[2]{};
|
||||
public:
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type = wchar_t;
|
||||
@ -3191,9 +3204,7 @@ public:
|
||||
using reference = wchar_t&;
|
||||
|
||||
explicit UTF8Iterator(const Document *doc_=nullptr, Sci::Position position_=0) noexcept :
|
||||
doc(doc_), position(position_), characterIndex(0), lenBytes(0), lenCharacters(0), buffered{} {
|
||||
buffered[0] = 0;
|
||||
buffered[1] = 0;
|
||||
doc(doc_), position(position_) {
|
||||
if (doc) {
|
||||
ReadCharacter();
|
||||
}
|
||||
@ -3245,10 +3256,10 @@ public:
|
||||
position != other.position ||
|
||||
characterIndex != other.characterIndex;
|
||||
}
|
||||
Sci::Position Pos() const noexcept {
|
||||
[[nodiscard]] Sci::Position Pos() const noexcept {
|
||||
return position;
|
||||
}
|
||||
Sci::Position PosRoundUp() const noexcept {
|
||||
[[nodiscard]] Sci::Position PosRoundUp() const noexcept {
|
||||
if (characterIndex)
|
||||
return position + lenBytes; // Force to end of character
|
||||
else
|
||||
|
@ -106,15 +106,7 @@ constexpr bool IsLastStep(const DocModification &mh) noexcept {
|
||||
&& ((mh.modificationType & finalMask) == finalMask);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Timer::Timer() noexcept :
|
||||
ticking(false), ticksToWait(0), tickerID{} {}
|
||||
|
||||
Idler::Idler() noexcept :
|
||||
state(false), idlerID(nullptr) {}
|
||||
|
||||
static constexpr bool IsAllSpacesOrTabs(std::string_view sv) noexcept {
|
||||
constexpr bool IsAllSpacesOrTabs(std::string_view sv) noexcept {
|
||||
for (const char ch : sv) {
|
||||
// This is safe because IsSpaceOrTab() will return false for null terminators
|
||||
if (!IsSpaceOrTab(ch))
|
||||
@ -123,6 +115,14 @@ static constexpr bool IsAllSpacesOrTabs(std::string_view sv) noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Timer::Timer() noexcept :
|
||||
ticking(false), ticksToWait(0), tickerID{} {}
|
||||
|
||||
Idler::Idler() noexcept :
|
||||
state(false), idlerID(nullptr) {}
|
||||
|
||||
Editor::Editor() : durationWrapOneByte(0.000001, 0.00000001, 0.00001) {
|
||||
ctrlID = 0;
|
||||
|
||||
@ -3143,7 +3143,7 @@ void Editor::ChangeCaseOfSelection(CaseMapping caseMapping) {
|
||||
SelectionRange currentNoVS = current;
|
||||
currentNoVS.ClearVirtualSpace();
|
||||
const size_t rangeBytes = currentNoVS.Length();
|
||||
if (rangeBytes > 0) {
|
||||
if (rangeBytes > 0 && !RangeContainsProtected(currentNoVS)) {
|
||||
std::string sText = RangeText(currentNoVS.Start().Position(), currentNoVS.End().Position());
|
||||
|
||||
std::string sMapped = CaseMapString(sText, caseMapping);
|
||||
@ -4402,7 +4402,9 @@ void Editor::GoToLine(Sci::Line lineNo) {
|
||||
EnsureCaretVisible();
|
||||
}
|
||||
|
||||
static bool Close(Point pt1, Point pt2, Point threshold) noexcept {
|
||||
namespace {
|
||||
|
||||
bool Close(Point pt1, Point pt2, Point threshold) noexcept {
|
||||
const Point ptDifference = pt2 - pt1;
|
||||
if (std::abs(ptDifference.x) > threshold.x)
|
||||
return false;
|
||||
@ -4411,6 +4413,12 @@ static bool Close(Point pt1, Point pt2, Point threshold) noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool AllowVirtualSpace(VirtualSpace virtualSpaceOptions, bool rectangular) noexcept {
|
||||
return FlagSet(virtualSpaceOptions, (rectangular ? VirtualSpace::RectangularSelection : VirtualSpace::UserAccessible));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::string Editor::RangeText(Sci::Position start, Sci::Position end) const {
|
||||
if (start < end) {
|
||||
const Sci::Position len = end - start;
|
||||
@ -4756,10 +4764,6 @@ void Editor::MouseLeave() {
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr bool AllowVirtualSpace(VirtualSpace virtualSpaceOptions, bool rectangular) noexcept {
|
||||
return FlagSet(virtualSpaceOptions, (rectangular ? VirtualSpace::RectangularSelection : VirtualSpace::UserAccessible));
|
||||
}
|
||||
|
||||
void Editor::ButtonDownWithModifiers(Point pt, unsigned int curTime, KeyMod modifiers) {
|
||||
SetHoverIndicatorPoint(pt);
|
||||
//Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
|
||||
|
@ -15,16 +15,83 @@
|
||||
|
||||
namespace Scintilla::Internal {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int first2Byte = 0x80;
|
||||
constexpr int first3Byte = 0x800;
|
||||
|
||||
constexpr unsigned int maskSurrogate = 0x3FF;
|
||||
constexpr unsigned int shiftSurrogate = 10;
|
||||
|
||||
// The top 2 bits are 0b10 to indicate a trail byte.
|
||||
// The lower 6 bits contain the value.
|
||||
constexpr unsigned int trailByteFlag = 0b1000'0000;
|
||||
constexpr unsigned int trailByteMask = 0b0011'1111;
|
||||
|
||||
// With each UTF-8 length the bits are divided into length indicator
|
||||
// bits and value bits separated by a 0 bit.
|
||||
constexpr unsigned int leadByte2 = 0b1100'0000;
|
||||
constexpr unsigned int leadBits2 = 0b0001'1111;
|
||||
|
||||
constexpr unsigned int leadByte3 = 0b1110'0000;
|
||||
constexpr unsigned int leadBits3 = 0b0000'1111;
|
||||
|
||||
constexpr unsigned int leadByte4 = 0b1111'0000;
|
||||
constexpr unsigned int leadBits4 = 0b0000'0111;
|
||||
|
||||
constexpr unsigned int shiftByte2 = 6;
|
||||
constexpr unsigned int shiftByte3 = 12;
|
||||
constexpr unsigned int shiftByte4 = 18;
|
||||
|
||||
constexpr char LeadByte(unsigned int lengthValue, unsigned int uch) noexcept {
|
||||
return static_cast<unsigned char>(lengthValue | uch);
|
||||
}
|
||||
|
||||
constexpr char TrailByte(unsigned int uch) noexcept {
|
||||
return trailByteFlag | (uch & trailByteMask);
|
||||
}
|
||||
|
||||
constexpr unsigned char TrailByteValue(unsigned char c) noexcept {
|
||||
return c & trailByteMask;
|
||||
}
|
||||
|
||||
constexpr wchar_t SurrogateLead(int val) noexcept {
|
||||
return static_cast<wchar_t>(((val - SUPPLEMENTAL_PLANE_FIRST) >> shiftSurrogate) + SURROGATE_LEAD_FIRST);
|
||||
}
|
||||
|
||||
constexpr wchar_t SurrogateTrail(int val) noexcept {
|
||||
return (val & maskSurrogate) + SURROGATE_TRAIL_FIRST;
|
||||
}
|
||||
|
||||
void UTF8AppendCharacter(int uch, char *putf, size_t &k) noexcept {
|
||||
if (uch < first2Byte) {
|
||||
putf[k++] = LeadByte(0, uch);
|
||||
} else if (uch < first3Byte) {
|
||||
putf[k++] = LeadByte(leadByte2, uch >> shiftByte2);
|
||||
putf[k++] = TrailByte(uch);
|
||||
} else if (uch < SUPPLEMENTAL_PLANE_FIRST) {
|
||||
putf[k++] = LeadByte(leadByte3, uch >> shiftByte3);
|
||||
putf[k++] = TrailByte(uch >> shiftByte2);
|
||||
putf[k++] = TrailByte(uch);
|
||||
} else {
|
||||
putf[k++] = LeadByte(leadByte4, uch >> shiftByte4);
|
||||
putf[k++] = TrailByte(uch >> shiftByte3);
|
||||
putf[k++] = TrailByte(uch >> shiftByte2);
|
||||
putf[k++] = TrailByte(uch);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
size_t UTF8Length(std::wstring_view wsv) noexcept {
|
||||
size_t len = 0;
|
||||
for (size_t i = 0; i < wsv.length() && wsv[i];) {
|
||||
const unsigned int uch = wsv[i];
|
||||
if (uch < 0x80) {
|
||||
const wchar_t uch = wsv[i];
|
||||
if (uch < first2Byte) {
|
||||
len++;
|
||||
} else if (uch < 0x800) {
|
||||
} else if (uch < first3Byte) {
|
||||
len += 2;
|
||||
} else if ((uch >= SURROGATE_LEAD_FIRST) &&
|
||||
(uch <= SURROGATE_TRAIL_LAST)) {
|
||||
} else if (IsSurrogate(uch)) {
|
||||
len += 4;
|
||||
i++;
|
||||
} else {
|
||||
@ -50,26 +117,13 @@ size_t UTF8PositionFromUTF16Position(std::string_view u8Text, size_t positionUTF
|
||||
void UTF8FromUTF16(std::wstring_view wsv, char *putf, size_t len) noexcept {
|
||||
size_t k = 0;
|
||||
for (size_t i = 0; i < wsv.length() && wsv[i];) {
|
||||
const unsigned int uch = wsv[i];
|
||||
if (uch < 0x80) {
|
||||
putf[k++] = static_cast<char>(uch);
|
||||
} else if (uch < 0x800) {
|
||||
putf[k++] = static_cast<char>(0xC0 | (uch >> 6));
|
||||
putf[k++] = static_cast<char>(0x80 | (uch & 0x3f));
|
||||
} else if ((uch >= SURROGATE_LEAD_FIRST) &&
|
||||
(uch <= SURROGATE_TRAIL_LAST)) {
|
||||
unsigned int uch = wsv[i];
|
||||
if (IsSurrogate(wsv[i])) {
|
||||
// Half a surrogate pair
|
||||
i++;
|
||||
const unsigned int xch = 0x10000 + ((uch & 0x3ff) << 10) + (wsv[i] & 0x3ff);
|
||||
putf[k++] = static_cast<char>(0xF0 | (xch >> 18));
|
||||
putf[k++] = static_cast<char>(0x80 | ((xch >> 12) & 0x3f));
|
||||
putf[k++] = static_cast<char>(0x80 | ((xch >> 6) & 0x3f));
|
||||
putf[k++] = static_cast<char>(0x80 | (xch & 0x3f));
|
||||
} else {
|
||||
putf[k++] = static_cast<char>(0xE0 | (uch >> 12));
|
||||
putf[k++] = static_cast<char>(0x80 | ((uch >> 6) & 0x3f));
|
||||
putf[k++] = static_cast<char>(0x80 | (uch & 0x3f));
|
||||
uch = SUPPLEMENTAL_PLANE_FIRST + ((uch & maskSurrogate) << shiftSurrogate) + (wsv[i] & maskSurrogate);
|
||||
}
|
||||
UTF8AppendCharacter(uch, putf, k);
|
||||
i++;
|
||||
}
|
||||
if (k < len)
|
||||
@ -78,21 +132,7 @@ void UTF8FromUTF16(std::wstring_view wsv, char *putf, size_t len) noexcept {
|
||||
|
||||
void UTF8FromUTF32Character(int uch, char *putf) noexcept {
|
||||
size_t k = 0;
|
||||
if (uch < 0x80) {
|
||||
putf[k++] = static_cast<char>(uch);
|
||||
} else if (uch < 0x800) {
|
||||
putf[k++] = static_cast<char>(0xC0 | (uch >> 6));
|
||||
putf[k++] = static_cast<char>(0x80 | (uch & 0x3f));
|
||||
} else if (uch < 0x10000) {
|
||||
putf[k++] = static_cast<char>(0xE0 | (uch >> 12));
|
||||
putf[k++] = static_cast<char>(0x80 | ((uch >> 6) & 0x3f));
|
||||
putf[k++] = static_cast<char>(0x80 | (uch & 0x3f));
|
||||
} else {
|
||||
putf[k++] = static_cast<char>(0xF0 | (uch >> 18));
|
||||
putf[k++] = static_cast<char>(0x80 | ((uch >> 12) & 0x3f));
|
||||
putf[k++] = static_cast<char>(0x80 | ((uch >> 6) & 0x3f));
|
||||
putf[k++] = static_cast<char>(0x80 | (uch & 0x3f));
|
||||
}
|
||||
UTF8AppendCharacter(uch, putf, k);
|
||||
putf[k] = '\0';
|
||||
}
|
||||
|
||||
@ -108,18 +148,12 @@ size_t UTF16Length(std::string_view svu8) noexcept {
|
||||
return ulen;
|
||||
}
|
||||
|
||||
constexpr unsigned char TrailByteValue(unsigned char c) {
|
||||
// The top 2 bits are 0b10 to indicate a trail byte.
|
||||
// The lower 6 bits contain the value.
|
||||
return c & 0b0011'1111;
|
||||
}
|
||||
|
||||
size_t UTF16FromUTF8(std::string_view svu8, wchar_t *tbuf, size_t tlen) {
|
||||
size_t ui = 0;
|
||||
for (size_t i = 0; i < svu8.length();) {
|
||||
unsigned char ch = svu8[i];
|
||||
const unsigned int byteCount = UTF8BytesOfLead[ch];
|
||||
unsigned int value;
|
||||
unsigned int value = 0;
|
||||
|
||||
if (i + byteCount > svu8.length()) {
|
||||
// Trying to read past end but still have space to write
|
||||
@ -141,31 +175,31 @@ size_t UTF16FromUTF8(std::string_view svu8, wchar_t *tbuf, size_t tlen) {
|
||||
tbuf[ui] = ch;
|
||||
break;
|
||||
case 2:
|
||||
value = (ch & 0x1F) << 6;
|
||||
value = (ch & leadBits2) << shiftByte2;
|
||||
ch = svu8[i++];
|
||||
value += TrailByteValue(ch);
|
||||
tbuf[ui] = static_cast<wchar_t>(value);
|
||||
break;
|
||||
case 3:
|
||||
value = (ch & 0xF) << 12;
|
||||
value = (ch & leadBits3) << shiftByte3;
|
||||
ch = svu8[i++];
|
||||
value += (TrailByteValue(ch) << 6);
|
||||
value += (TrailByteValue(ch) << shiftByte2);
|
||||
ch = svu8[i++];
|
||||
value += TrailByteValue(ch);
|
||||
tbuf[ui] = static_cast<wchar_t>(value);
|
||||
break;
|
||||
default:
|
||||
// Outside the BMP so need two surrogates
|
||||
value = (ch & 0x7) << 18;
|
||||
value = (ch & leadBits4) << shiftByte4;
|
||||
ch = svu8[i++];
|
||||
value += TrailByteValue(ch) << 12;
|
||||
value += TrailByteValue(ch) << shiftByte3;
|
||||
ch = svu8[i++];
|
||||
value += TrailByteValue(ch) << 6;
|
||||
value += TrailByteValue(ch) << shiftByte2;
|
||||
ch = svu8[i++];
|
||||
value += TrailByteValue(ch);
|
||||
tbuf[ui] = static_cast<wchar_t>(((value - 0x10000) >> 10) + SURROGATE_LEAD_FIRST);
|
||||
tbuf[ui] = SurrogateLead(value);
|
||||
ui++;
|
||||
tbuf[ui] = static_cast<wchar_t>((value & 0x3ff) + SURROGATE_TRAIL_FIRST);
|
||||
tbuf[ui] = SurrogateTrail(value);
|
||||
break;
|
||||
}
|
||||
ui++;
|
||||
@ -189,7 +223,7 @@ size_t UTF32FromUTF8(std::string_view svu8, unsigned int *tbuf, size_t tlen) {
|
||||
for (size_t i = 0; i < svu8.length();) {
|
||||
unsigned char ch = svu8[i];
|
||||
const unsigned int byteCount = UTF8BytesOfLead[ch];
|
||||
unsigned int value;
|
||||
unsigned int value = 0;
|
||||
|
||||
if (i + byteCount > svu8.length()) {
|
||||
// Trying to read past end but still have space to write
|
||||
@ -210,23 +244,23 @@ size_t UTF32FromUTF8(std::string_view svu8, unsigned int *tbuf, size_t tlen) {
|
||||
value = ch;
|
||||
break;
|
||||
case 2:
|
||||
value = (ch & 0x1F) << 6;
|
||||
value = (ch & leadBits2) << shiftByte2;
|
||||
ch = svu8[i++];
|
||||
value += TrailByteValue(ch);
|
||||
break;
|
||||
case 3:
|
||||
value = (ch & 0xF) << 12;
|
||||
value = (ch & leadBits3) << shiftByte3;
|
||||
ch = svu8[i++];
|
||||
value += TrailByteValue(ch) << 6;
|
||||
value += TrailByteValue(ch) << shiftByte2;
|
||||
ch = svu8[i++];
|
||||
value += TrailByteValue(ch);
|
||||
break;
|
||||
default:
|
||||
value = (ch & 0x7) << 18;
|
||||
value = (ch & leadBits4) << shiftByte4;
|
||||
ch = svu8[i++];
|
||||
value += TrailByteValue(ch) << 12;
|
||||
value += TrailByteValue(ch) << shiftByte3;
|
||||
ch = svu8[i++];
|
||||
value += TrailByteValue(ch) << 6;
|
||||
value += TrailByteValue(ch) << shiftByte2;
|
||||
ch = svu8[i++];
|
||||
value += TrailByteValue(ch);
|
||||
break;
|
||||
@ -256,8 +290,8 @@ unsigned int UTF16FromUTF32Character(unsigned int val, wchar_t *tbuf) noexcept {
|
||||
tbuf[0] = static_cast<wchar_t>(val);
|
||||
return 1;
|
||||
}
|
||||
tbuf[0] = static_cast<wchar_t>(((val - SUPPLEMENTAL_PLANE_FIRST) >> 10) + SURROGATE_LEAD_FIRST);
|
||||
tbuf[1] = static_cast<wchar_t>((val & 0x3ff) + SURROGATE_TRAIL_FIRST);
|
||||
tbuf[0] = SurrogateLead(val);
|
||||
tbuf[1] = SurrogateTrail(val);
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
@ -99,8 +99,12 @@ enum { SURROGATE_TRAIL_FIRST = 0xDC00 };
|
||||
enum { SURROGATE_TRAIL_LAST = 0xDFFF };
|
||||
enum { SUPPLEMENTAL_PLANE_FIRST = 0x10000 };
|
||||
|
||||
constexpr bool IsSurrogate(wchar_t uch) noexcept {
|
||||
return (uch >= SURROGATE_LEAD_FIRST) && (uch <= SURROGATE_TRAIL_LAST);
|
||||
}
|
||||
|
||||
constexpr unsigned int UTF16CharLength(wchar_t uch) noexcept {
|
||||
return ((uch >= SURROGATE_LEAD_FIRST) && (uch <= SURROGATE_LEAD_LAST)) ? 2 : 1;
|
||||
return IsSurrogate(uch) ? 2 : 1;
|
||||
}
|
||||
|
||||
constexpr unsigned int UTF16LengthFromUTF8ByteCount(unsigned int byteCount) noexcept {
|
||||
|
@ -145,5 +145,27 @@ class TestPerformance(unittest.TestCase):
|
||||
print("%6.3f testUTF8AsciiSearches" % duration)
|
||||
self.xite.DoEvents()
|
||||
|
||||
def testShiftJISSearches(self):
|
||||
self.ed.SetCodePage(932)
|
||||
self.ed.StyleSetCharacterSet(32, 128)
|
||||
oneLine = "Fold Margin=折りたたみ表示用の余白(&F)\n".encode('cp932')
|
||||
manyLines = oneLine * 100000
|
||||
manyLines = manyLines + "φ\n".encode('cp932')
|
||||
#~ with open("932.txt", "wb") as fp:
|
||||
#~ fp.write(manyLines)
|
||||
self.ed.AddText(len(manyLines), manyLines)
|
||||
searchString = "φ".encode('cp932')
|
||||
start = timer()
|
||||
for i in range(20):
|
||||
self.ed.TargetStart = 0
|
||||
self.ed.TargetEnd = self.ed.Length-1
|
||||
self.ed.SearchFlags = 0
|
||||
pos = self.ed.SearchInTarget(len(searchString), searchString)
|
||||
self.assertTrue(pos > 0)
|
||||
end = timer()
|
||||
duration = end - start
|
||||
print("%6.3f testShiftJISSearches" % duration)
|
||||
self.xite.DoEvents()
|
||||
|
||||
if __name__ == '__main__':
|
||||
Xite.main("performanceTests")
|
||||
|
@ -1042,6 +1042,137 @@ TEST_CASE("SafeSegment") {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("DiscardLastCombinedCharacter") {
|
||||
SECTION("Short") {
|
||||
const std::string_view base = "12345";
|
||||
// Short strings (up to 4 bytes) aren't changed to avoid null and problematic results
|
||||
for (size_t len = 0; len < 5; len++) {
|
||||
std::string_view text = base.substr(0, len);
|
||||
REQUIRE(text.length() == len);
|
||||
const bool changed = DiscardLastCombinedCharacter(text);
|
||||
REQUIRE(!changed);
|
||||
REQUIRE(text.length() == len);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("ASCII") {
|
||||
std::string_view text = "12345";
|
||||
REQUIRE(text.length() == 5);
|
||||
const bool changed = DiscardLastCombinedCharacter(text);
|
||||
REQUIRE(changed);
|
||||
REQUIRE(text.length() == 4);
|
||||
}
|
||||
|
||||
SECTION("Control") {
|
||||
{
|
||||
std::string_view text = "12345\007";
|
||||
REQUIRE(text.length() == 6);
|
||||
const bool changed = DiscardLastCombinedCharacter(text);
|
||||
REQUIRE(changed);
|
||||
REQUIRE(text.length() == 5);
|
||||
}
|
||||
{
|
||||
std::string_view text = "12345\007Z";
|
||||
REQUIRE(text.length() == 7);
|
||||
const bool changed = DiscardLastCombinedCharacter(text);
|
||||
REQUIRE(changed);
|
||||
REQUIRE(text.length() == 6);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Japanese") {
|
||||
std::string_view text = "Japanese\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
|
||||
REQUIRE(text.length() == 17);
|
||||
const bool changed = DiscardLastCombinedCharacter(text);
|
||||
REQUIRE(changed);
|
||||
REQUIRE(text.length() == 14);
|
||||
}
|
||||
|
||||
SECTION("Thai Combining") {
|
||||
// Ends with two combined characters
|
||||
// 7 characters, 5 base characters and 2 combining
|
||||
// HO HIP, SARA AA, KHO KHAI, MAI THO, O ANG, MO MA, SARA UU
|
||||
std::string_view text = "\xe0\xb8\xab\xe0\xb8\xb2\xe0\xb8\x82\xe0\xb9\x89\xe0\xb8\xad\xe0\xb8\xa1\xe0\xb8\xb9";
|
||||
REQUIRE(text.length() == 21);
|
||||
const bool changed = DiscardLastCombinedCharacter(text);
|
||||
REQUIRE(changed);
|
||||
// Discarded 2 x 3-byte characters
|
||||
REQUIRE(text.length() == 15);
|
||||
}
|
||||
|
||||
SECTION("Invalid UTF-8") {
|
||||
{
|
||||
// Ends with isolated lead byte
|
||||
std::string_view text = "1234\xe0";
|
||||
REQUIRE(text.length() == 5);
|
||||
const bool changed = DiscardLastCombinedCharacter(text);
|
||||
REQUIRE(changed);
|
||||
// Discarded final invalid byte
|
||||
REQUIRE(text.length() == 4);
|
||||
}
|
||||
{
|
||||
// Ends with isolated trail byte
|
||||
std::string_view text = "1234\xb8";
|
||||
REQUIRE(text.length() == 5);
|
||||
const bool changed = DiscardLastCombinedCharacter(text);
|
||||
REQUIRE(changed);
|
||||
// Discarded final invalid byte
|
||||
REQUIRE(text.length() == 4);
|
||||
}
|
||||
{
|
||||
// Ends with lead byte and only one of two required trail bytes
|
||||
std::string_view text = "1234\xe0\xb8";
|
||||
REQUIRE(text.length() == 6);
|
||||
const bool changed = DiscardLastCombinedCharacter(text);
|
||||
REQUIRE(changed);
|
||||
// Discarded final invalid byte
|
||||
REQUIRE(text.length() == 5);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Private Use UTF-8") {
|
||||
{
|
||||
// Ends with private use area U+F8FF - Apple uses for apple symbol.
|
||||
std::string_view text = "1234\xEF\xA3\xBF";
|
||||
REQUIRE(text.length() == 7);
|
||||
const bool changed = DiscardLastCombinedCharacter(text);
|
||||
REQUIRE(changed);
|
||||
// Discarded whole final character
|
||||
REQUIRE(text.length() == 4);
|
||||
}
|
||||
{
|
||||
// At end: PUA + letter: PUA acts as base
|
||||
std::string_view text = "1234\xEF\xA3\xBFZ";
|
||||
REQUIRE(text.length() == 8);
|
||||
const bool changed = DiscardLastCombinedCharacter(text);
|
||||
REQUIRE(changed);
|
||||
// Discarded just final character
|
||||
REQUIRE(text.length() == 7);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Surrogates") {
|
||||
{
|
||||
// Ends with surrogate U+D800.
|
||||
std::string_view text = "1234\xED\xA0\x80";
|
||||
REQUIRE(text.length() == 7);
|
||||
const bool changed = DiscardLastCombinedCharacter(text);
|
||||
REQUIRE(changed);
|
||||
// Discarded final invalid byte
|
||||
REQUIRE(text.length() == 6);
|
||||
}
|
||||
{
|
||||
// Ends with surrogate U+DC00.
|
||||
std::string_view text = "1234\xED\xB0\x80";
|
||||
REQUIRE(text.length() == 7);
|
||||
const bool changed = DiscardLastCombinedCharacter(text);
|
||||
REQUIRE(changed);
|
||||
// Discarded final invalid byte
|
||||
REQUIRE(text.length() == 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("PerLine") {
|
||||
SECTION("LineMarkers") {
|
||||
DocPlus doc("1\n2\n", CpUtf8);
|
||||
|
@ -121,6 +121,9 @@ TEST_CASE("UniConversion") {
|
||||
const size_t tlen = UTF16FromUTF8(s, tbuf, 1);
|
||||
REQUIRE(tlen == 1U);
|
||||
REQUIRE(tbuf[0] == 'a');
|
||||
char back[4]{};
|
||||
UTF8FromUTF16(std::wstring_view(tbuf, tlen), back, sizeof(back));
|
||||
REQUIRE(strcmp(s, back) == 0);
|
||||
}
|
||||
|
||||
SECTION("UTF16FromUTF8 Example1") {
|
||||
@ -129,6 +132,9 @@ TEST_CASE("UniConversion") {
|
||||
const size_t tlen = UTF16FromUTF8(s, tbuf, 1);
|
||||
REQUIRE(tlen == 1U);
|
||||
REQUIRE(tbuf[0] == 0x24);
|
||||
char back[4]{};
|
||||
UTF8FromUTF16(std::wstring_view(tbuf, tlen), back, sizeof(back));
|
||||
REQUIRE(strcmp(s, back) == 0);
|
||||
}
|
||||
|
||||
SECTION("UTF16FromUTF8 Example2") {
|
||||
@ -137,6 +143,9 @@ TEST_CASE("UniConversion") {
|
||||
const size_t tlen = UTF16FromUTF8(s, tbuf, 1);
|
||||
REQUIRE(tlen == 1U);
|
||||
REQUIRE(tbuf[0] == 0xA2);
|
||||
char back[4]{};
|
||||
UTF8FromUTF16(std::wstring_view(tbuf, tlen), back, sizeof(back));
|
||||
REQUIRE(strcmp(s, back) == 0);
|
||||
}
|
||||
|
||||
SECTION("UTF16FromUTF8 Example3") {
|
||||
@ -145,6 +154,9 @@ TEST_CASE("UniConversion") {
|
||||
const size_t tlen = UTF16FromUTF8(s, tbuf, 1);;
|
||||
REQUIRE(tlen == 1U);
|
||||
REQUIRE(tbuf[0] == 0x20AC);
|
||||
char back[4]{};
|
||||
UTF8FromUTF16(std::wstring_view(tbuf, tlen), back, sizeof(back));
|
||||
REQUIRE(strcmp(s, back) == 0);
|
||||
}
|
||||
|
||||
SECTION("UTF16FromUTF8 Example4") {
|
||||
@ -154,6 +166,9 @@ TEST_CASE("UniConversion") {
|
||||
REQUIRE(tlen == 2U);
|
||||
REQUIRE(tbuf[0] == 0xD800);
|
||||
REQUIRE(tbuf[1] == 0xDF48);
|
||||
char back[5]{};
|
||||
UTF8FromUTF16(std::wstring_view(tbuf, tlen), back, sizeof(back));
|
||||
REQUIRE(strcmp(s, back) == 0);
|
||||
}
|
||||
|
||||
SECTION("UTF16FromUTF8 Invalid Trail byte in lead position") {
|
||||
@ -165,6 +180,7 @@ TEST_CASE("UniConversion") {
|
||||
REQUIRE(tbuf[1] == 0xB5);
|
||||
REQUIRE(tbuf[2] == 'y');
|
||||
REQUIRE(tbuf[3] == 'z');
|
||||
// Invalid so can't round trip
|
||||
}
|
||||
|
||||
SECTION("UTF16FromUTF8 Invalid Lead byte at end") {
|
||||
@ -174,6 +190,7 @@ TEST_CASE("UniConversion") {
|
||||
REQUIRE(tlen == 2U);
|
||||
REQUIRE(tbuf[0] == 'a');
|
||||
REQUIRE(tbuf[1] == 0xC2);
|
||||
// Invalid so can't round trip
|
||||
}
|
||||
|
||||
SECTION("UTF16FromUTF8 Invalid Lead byte implies 3 trails but only 2") {
|
||||
@ -183,6 +200,7 @@ TEST_CASE("UniConversion") {
|
||||
REQUIRE(tlen == 2U);
|
||||
REQUIRE(tbuf[0] == 'a');
|
||||
REQUIRE(tbuf[1] == 0xF1);
|
||||
// Invalid so can't round trip
|
||||
}
|
||||
|
||||
// UTF32FromUTF8
|
||||
@ -193,6 +211,9 @@ TEST_CASE("UniConversion") {
|
||||
const size_t tlen = UTF32FromUTF8(s, tbuf, 1);
|
||||
REQUIRE(tlen == 1U);
|
||||
REQUIRE(tbuf[0] == static_cast<unsigned int>('a'));
|
||||
char back[5]{};
|
||||
UTF8FromUTF32Character(tbuf[0], back);
|
||||
REQUIRE(strcmp(s, back) == 0);
|
||||
}
|
||||
|
||||
SECTION("UTF32FromUTF8 Example1") {
|
||||
@ -201,6 +222,9 @@ TEST_CASE("UniConversion") {
|
||||
const size_t tlen = UTF32FromUTF8(s, tbuf, 1);
|
||||
REQUIRE(tlen == 1U);
|
||||
REQUIRE(tbuf[0] == 0x24);
|
||||
char back[5]{};
|
||||
UTF8FromUTF32Character(tbuf[0], back);
|
||||
REQUIRE(strcmp(s, back) == 0);
|
||||
}
|
||||
|
||||
SECTION("UTF32FromUTF8 Example2") {
|
||||
@ -209,6 +233,9 @@ TEST_CASE("UniConversion") {
|
||||
const size_t tlen = UTF32FromUTF8(s, tbuf, 1);
|
||||
REQUIRE(tlen == 1U);
|
||||
REQUIRE(tbuf[0] == 0xA2);
|
||||
char back[5]{};
|
||||
UTF8FromUTF32Character(tbuf[0], back);
|
||||
REQUIRE(strcmp(s, back) == 0);
|
||||
}
|
||||
|
||||
SECTION("UTF32FromUTF8 Example3") {
|
||||
@ -217,6 +244,9 @@ TEST_CASE("UniConversion") {
|
||||
const size_t tlen = UTF32FromUTF8(s, tbuf, 1);
|
||||
REQUIRE(tlen == 1U);
|
||||
REQUIRE(tbuf[0] == 0x20AC);
|
||||
char back[5]{};
|
||||
UTF8FromUTF32Character(tbuf[0], back);
|
||||
REQUIRE(strcmp(s, back) == 0);
|
||||
}
|
||||
|
||||
SECTION("UTF32FromUTF8 Example4") {
|
||||
@ -225,6 +255,9 @@ TEST_CASE("UniConversion") {
|
||||
const size_t tlen = UTF32FromUTF8(s, tbuf, 1);
|
||||
REQUIRE(tlen == 1U);
|
||||
REQUIRE(tbuf[0] == 0x10348);
|
||||
char back[5]{};
|
||||
UTF8FromUTF32Character(tbuf[0], back);
|
||||
REQUIRE(strcmp(s, back) == 0);
|
||||
}
|
||||
|
||||
SECTION("UTF32FromUTF8 Invalid Trail byte in lead position") {
|
||||
|
@ -1 +1 @@
|
||||
555
|
||||
556
|
||||
|
988
scintilla/win32/ListBox.cxx
Normal file
988
scintilla/win32/ListBox.cxx
Normal file
@ -0,0 +1,988 @@
|
||||
// Scintilla source code edit control
|
||||
/** @file ListBox.cxx
|
||||
** Implementation of list box on Windows.
|
||||
**/
|
||||
// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
|
||||
// The License.txt file describes the conditions under which this software may be distributed.
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <ctime>
|
||||
#include <cmath>
|
||||
#include <climits>
|
||||
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
// Want to use std::min and std::max so don't want Windows.h version of min and max
|
||||
#if !defined(NOMINMAX)
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0A00
|
||||
#undef WINVER
|
||||
#define WINVER 0x0A00
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include <richedit.h>
|
||||
#include <windowsx.h>
|
||||
#include <shellscalingapi.h>
|
||||
|
||||
#include <wrl.h>
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
#if !defined(DISABLE_D2D)
|
||||
#define USE_D2D 1
|
||||
#endif
|
||||
|
||||
#if defined(USE_D2D)
|
||||
#include <d2d1_1.h>
|
||||
#include <d3d11_1.h>
|
||||
#include <dwrite_1.h>
|
||||
#endif
|
||||
|
||||
#include "ScintillaTypes.h"
|
||||
|
||||
#include "Debugging.h"
|
||||
#include "Geometry.h"
|
||||
#include "Platform.h"
|
||||
#include "XPM.h"
|
||||
#include "UniConversion.h"
|
||||
#include "DBCS.h"
|
||||
|
||||
#include "WinTypes.h"
|
||||
#include "PlatWin.h"
|
||||
#include "ListBox.h"
|
||||
#if defined(USE_D2D)
|
||||
#include "SurfaceD2D.h"
|
||||
#endif
|
||||
|
||||
using namespace Scintilla;
|
||||
using namespace Scintilla::Internal;
|
||||
|
||||
namespace {
|
||||
|
||||
struct ListItemData {
|
||||
const char *text;
|
||||
int pixId;
|
||||
};
|
||||
|
||||
class LineToItem {
|
||||
std::vector<char> words;
|
||||
|
||||
std::vector<ListItemData> data;
|
||||
|
||||
public:
|
||||
void Clear() noexcept {
|
||||
words.clear();
|
||||
data.clear();
|
||||
}
|
||||
|
||||
[[nodiscard]] ListItemData Get(size_t index) const noexcept {
|
||||
if (index < data.size()) {
|
||||
return data[index];
|
||||
}
|
||||
ListItemData missing = {"", -1};
|
||||
return missing;
|
||||
}
|
||||
[[nodiscard]] int Count() const noexcept {
|
||||
return static_cast<int>(data.size());
|
||||
}
|
||||
|
||||
void AllocItem(const char *text, int pixId) {
|
||||
const ListItemData lid = { text, pixId };
|
||||
data.push_back(lid);
|
||||
}
|
||||
|
||||
char *SetWords(const char *s) {
|
||||
words = std::vector<char>(s, s+strlen(s)+1);
|
||||
return words.data();
|
||||
}
|
||||
};
|
||||
|
||||
const TCHAR ListBoxX_ClassName[] = TEXT("ListBoxX");
|
||||
|
||||
ColourRGBA ColourElement(std::optional<ColourRGBA> colour, int nIndex) {
|
||||
if (colour.has_value()) {
|
||||
return colour.value();
|
||||
}
|
||||
return ColourFromSys(nIndex);
|
||||
}
|
||||
|
||||
struct LBGraphics {
|
||||
GDIBitMap bm;
|
||||
std::unique_ptr<Surface> pixmapLine;
|
||||
#if defined(USE_D2D)
|
||||
DCRenderTarget pBMDCTarget;
|
||||
#endif
|
||||
|
||||
void Release() noexcept {
|
||||
pixmapLine.reset();
|
||||
#if defined(USE_D2D)
|
||||
pBMDCTarget = nullptr;
|
||||
#endif
|
||||
bm.Release();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class ListBoxX : public ListBox {
|
||||
int lineHeight = 10;
|
||||
HFONT fontCopy {};
|
||||
std::unique_ptr<FontWin> fontWin;
|
||||
Technology technology = Technology::Default;
|
||||
RGBAImageSet images;
|
||||
LineToItem lti;
|
||||
HWND lb {};
|
||||
bool unicodeMode = false;
|
||||
int codePage = 0;
|
||||
int desiredVisibleRows = 9;
|
||||
int maxItemCharacters = 0;
|
||||
unsigned int aveCharWidth = 8;
|
||||
Window *parent = nullptr;
|
||||
int ctrlID = 0;
|
||||
UINT dpi = USER_DEFAULT_SCREEN_DPI;
|
||||
IListBoxDelegate *delegate = nullptr;
|
||||
unsigned int maxCharWidth = 1;
|
||||
WPARAM resizeHit = 0;
|
||||
PRectangle rcPreSize;
|
||||
Point dragOffset;
|
||||
Point location; // Caret location at which the list is opened
|
||||
MouseWheelDelta wheelDelta;
|
||||
ListOptions options;
|
||||
DWORD frameStyle = WS_THICKFRAME;
|
||||
|
||||
LBGraphics graphics;
|
||||
|
||||
HWND GetHWND() const noexcept;
|
||||
void AppendListItem(const char *text, const char *numword);
|
||||
void AdjustWindowRect(PRectangle *rc, UINT dpiAdjust) const noexcept;
|
||||
int ItemHeight() const noexcept;
|
||||
int MinClientWidth() const noexcept;
|
||||
int TextOffset() const noexcept;
|
||||
POINT GetClientExtent() const noexcept;
|
||||
POINT MinTrackSize() const noexcept;
|
||||
POINT MaxTrackSize() const noexcept;
|
||||
void SetRedraw(bool on) noexcept;
|
||||
void OnDoubleClick();
|
||||
void OnSelChange();
|
||||
void ResizeToCursor();
|
||||
void StartResize(WPARAM);
|
||||
LRESULT NcHitTest(WPARAM, LPARAM) const;
|
||||
void CentreItem(int n);
|
||||
void AllocateBitMap();
|
||||
static LRESULT PASCAL ControlWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
static constexpr POINT ItemInset {0, 0}; // Padding around whole item
|
||||
static constexpr POINT TextInset {2, 0}; // Padding around text
|
||||
static constexpr POINT ImageInset {1, 0}; // Padding around image
|
||||
|
||||
public:
|
||||
ListBoxX() = default;
|
||||
ListBoxX(const ListBoxX &) = delete;
|
||||
ListBoxX(ListBoxX &&) = delete;
|
||||
ListBoxX &operator=(const ListBoxX &) = delete;
|
||||
ListBoxX &operator=(ListBoxX &&) = delete;
|
||||
~ListBoxX() noexcept override {
|
||||
if (fontCopy) {
|
||||
::DeleteObject(fontCopy);
|
||||
fontCopy = {};
|
||||
}
|
||||
graphics.Release();
|
||||
}
|
||||
void SetFont(const Font *font) override;
|
||||
void Create(Window &parent_, int ctrlID_, Point location_, int lineHeight_, bool unicodeMode_, Technology technology_) override;
|
||||
void SetAverageCharWidth(int width) override;
|
||||
void SetVisibleRows(int rows) override;
|
||||
int GetVisibleRows() const override;
|
||||
PRectangle GetDesiredRect() override;
|
||||
int CaretFromEdge() override;
|
||||
void Clear() noexcept override;
|
||||
void Append(char *s, int type) override;
|
||||
int Length() override;
|
||||
void Select(int n) override;
|
||||
int GetSelection() override;
|
||||
int Find(const char *prefix) override;
|
||||
std::string GetValue(int n) override;
|
||||
void RegisterImage(int type, const char *xpm_data) override;
|
||||
void RegisterRGBAImage(int type, int width, int height, const unsigned char *pixelsImage) override;
|
||||
void ClearRegisteredImages() override;
|
||||
void SetDelegate(IListBoxDelegate *lbDelegate) override;
|
||||
void SetList(const char *list, char separator, char typesep) override;
|
||||
void SetOptions(ListOptions options_) override;
|
||||
void Draw(DRAWITEMSTRUCT *pDrawItem);
|
||||
LRESULT WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
|
||||
static LRESULT PASCAL StaticWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
|
||||
};
|
||||
|
||||
std::unique_ptr<ListBox> ListBox::Allocate() {
|
||||
return std::make_unique<ListBoxX>();
|
||||
}
|
||||
|
||||
void ListBoxX::Create(Window &parent_, int ctrlID_, Point location_, int lineHeight_, bool unicodeMode_, Technology technology_) {
|
||||
parent = &parent_;
|
||||
ctrlID = ctrlID_;
|
||||
location = location_;
|
||||
lineHeight = lineHeight_;
|
||||
unicodeMode = unicodeMode_;
|
||||
codePage = unicodeMode ? CpUtf8 : 0;
|
||||
technology = technology_;
|
||||
HWND hwndParent = HwndFromWindow(*parent);
|
||||
HINSTANCE hinstanceParent = GetWindowInstance(hwndParent);
|
||||
// Window created as popup so not clipped within parent client area
|
||||
wid = ::CreateWindowEx(
|
||||
WS_EX_WINDOWEDGE, ListBoxX_ClassName, TEXT(""),
|
||||
WS_POPUP | frameStyle,
|
||||
100,100, 150,80, hwndParent,
|
||||
{},
|
||||
hinstanceParent,
|
||||
this);
|
||||
|
||||
dpi = DpiForWindow(hwndParent);
|
||||
POINT locationw = POINTFromPoint(location);
|
||||
::MapWindowPoints(hwndParent, {}, &locationw, 1);
|
||||
location = PointFromPOINT(locationw);
|
||||
}
|
||||
|
||||
void ListBoxX::SetFont(const Font *font) {
|
||||
const FontWin *pfm = dynamic_cast<const FontWin *>(font);
|
||||
if (pfm) {
|
||||
if (fontCopy) {
|
||||
::DeleteObject(fontCopy);
|
||||
fontCopy = {};
|
||||
}
|
||||
fontCopy = pfm->HFont();
|
||||
SetWindowFont(lb, fontCopy, 0);
|
||||
fontWin = pfm->Duplicate();
|
||||
codePage = unicodeMode ? CpUtf8 : CodePageFromCharSet(fontWin->GetCharacterSet(), 1252);
|
||||
graphics.Release();
|
||||
}
|
||||
}
|
||||
|
||||
void ListBoxX::SetAverageCharWidth(int width) {
|
||||
aveCharWidth = width;
|
||||
}
|
||||
|
||||
void ListBoxX::SetVisibleRows(int rows) {
|
||||
desiredVisibleRows = rows;
|
||||
}
|
||||
|
||||
int ListBoxX::GetVisibleRows() const {
|
||||
return desiredVisibleRows;
|
||||
}
|
||||
|
||||
HWND ListBoxX::GetHWND() const noexcept {
|
||||
return HwndFromWindowID(GetID());
|
||||
}
|
||||
|
||||
PRectangle ListBoxX::GetDesiredRect() {
|
||||
PRectangle rcDesired = GetPosition();
|
||||
|
||||
int rows = Length();
|
||||
if ((rows == 0) || (rows > desiredVisibleRows))
|
||||
rows = desiredVisibleRows;
|
||||
rcDesired.bottom = rcDesired.top + ItemHeight() * rows;
|
||||
|
||||
int width = MinClientWidth();
|
||||
int textSize = 0;
|
||||
int averageCharWidth = 8;
|
||||
|
||||
// Make a measuring surface
|
||||
std::unique_ptr<Surface> surfaceItem(Surface::Allocate(technology));
|
||||
surfaceItem->Init(GetID());
|
||||
surfaceItem->SetMode(SurfaceMode(codePage, false));
|
||||
|
||||
// Find the widest item in pixels
|
||||
const int items = lti.Count();
|
||||
for (int i = 0; i < items; i++) {
|
||||
const ListItemData item = lti.Get(i);
|
||||
const int itemTextSize = static_cast<int>(std::ceil(
|
||||
surfaceItem->WidthText(fontWin.get(), item.text)));
|
||||
textSize = std::max(textSize, itemTextSize);
|
||||
}
|
||||
|
||||
maxCharWidth = static_cast<int>(std::ceil(surfaceItem->WidthText(fontWin.get(), "W")));
|
||||
averageCharWidth = static_cast<int>(surfaceItem->AverageCharWidth(fontWin.get()));
|
||||
|
||||
width = std::max({ width, textSize, (maxItemCharacters + 1) * averageCharWidth });
|
||||
|
||||
rcDesired.right = rcDesired.left + TextOffset() + width + (TextInset.x * 2);
|
||||
if (Length() > rows)
|
||||
rcDesired.right += SystemMetricsForDpi(SM_CXVSCROLL, dpi);
|
||||
|
||||
AdjustWindowRect(&rcDesired, dpi);
|
||||
return rcDesired;
|
||||
}
|
||||
|
||||
int ListBoxX::TextOffset() const noexcept {
|
||||
const int pixWidth = images.GetWidth();
|
||||
return pixWidth == 0 ? ItemInset.x : ItemInset.x + pixWidth + (ImageInset.x * 2);
|
||||
}
|
||||
|
||||
int ListBoxX::CaretFromEdge() {
|
||||
PRectangle rc;
|
||||
AdjustWindowRect(&rc, dpi);
|
||||
return TextOffset() + static_cast<int>(TextInset.x + (0 - rc.left) - 1);
|
||||
}
|
||||
|
||||
void ListBoxX::Clear() noexcept {
|
||||
ListBox_ResetContent(lb);
|
||||
maxItemCharacters = 0;
|
||||
lti.Clear();
|
||||
}
|
||||
|
||||
void ListBoxX::Append(char *, int) {
|
||||
// This method is no longer called in Scintilla
|
||||
PLATFORM_ASSERT(false);
|
||||
}
|
||||
|
||||
int ListBoxX::Length() {
|
||||
return lti.Count();
|
||||
}
|
||||
|
||||
void ListBoxX::Select(int n) {
|
||||
// We are going to scroll to centre on the new selection and then select it, so disable
|
||||
// redraw to avoid flicker caused by a painting new selection twice in unselected and then
|
||||
// selected states
|
||||
SetRedraw(false);
|
||||
CentreItem(n);
|
||||
ListBox_SetCurSel(lb, n);
|
||||
OnSelChange();
|
||||
SetRedraw(true);
|
||||
}
|
||||
|
||||
int ListBoxX::GetSelection() {
|
||||
return ListBox_GetCurSel(lb);
|
||||
}
|
||||
|
||||
// This is not actually called at present
|
||||
int ListBoxX::Find(const char *) {
|
||||
return LB_ERR;
|
||||
}
|
||||
|
||||
std::string ListBoxX::GetValue(int n) {
|
||||
const ListItemData item = lti.Get(n);
|
||||
return item.text;
|
||||
}
|
||||
|
||||
void ListBoxX::RegisterImage(int type, const char *xpm_data) {
|
||||
XPM xpmImage(xpm_data);
|
||||
images.AddImage(type, std::make_unique<RGBAImage>(xpmImage));
|
||||
}
|
||||
|
||||
void ListBoxX::RegisterRGBAImage(int type, int width, int height, const unsigned char *pixelsImage) {
|
||||
images.AddImage(type, std::make_unique<RGBAImage>(width, height, 1.0f, pixelsImage));
|
||||
}
|
||||
|
||||
void ListBoxX::ClearRegisteredImages() {
|
||||
images.Clear();
|
||||
}
|
||||
|
||||
void ListBoxX::Draw(DRAWITEMSTRUCT *pDrawItem) {
|
||||
if ((pDrawItem->itemAction != ODA_SELECT) && (pDrawItem->itemAction != ODA_DRAWENTIRE)) {
|
||||
return;
|
||||
}
|
||||
if (!graphics.pixmapLine) {
|
||||
AllocateBitMap();
|
||||
if (!graphics.pixmapLine) {
|
||||
// Failed to allocate, so release fully and give up
|
||||
graphics.Release();
|
||||
return;
|
||||
}
|
||||
}
|
||||
#if defined(USE_D2D)
|
||||
if (graphics.pBMDCTarget) {
|
||||
graphics.pBMDCTarget->BeginDraw();
|
||||
}
|
||||
#endif
|
||||
|
||||
const PRectangle rcItemBase = PRectangleFromRECT(pDrawItem->rcItem);
|
||||
const PRectangle rcItem(0, 0, rcItemBase.Width(), rcItemBase.Height());
|
||||
PRectangle rcBox = rcItem;
|
||||
rcBox.left += TextOffset();
|
||||
ColourRGBA colourFore;
|
||||
ColourRGBA colourBack;
|
||||
if (pDrawItem->itemState & ODS_SELECTED) {
|
||||
PRectangle rcImage = rcItem;
|
||||
rcImage.right = rcBox.left;
|
||||
// The image is not highlighted
|
||||
graphics.pixmapLine->FillRectangle(rcImage, ColourElement(options.back, COLOR_WINDOW));
|
||||
colourBack = ColourElement(options.backSelected, COLOR_HIGHLIGHT);
|
||||
graphics.pixmapLine->FillRectangle(rcBox, colourBack);
|
||||
colourFore = ColourElement(options.foreSelected, COLOR_HIGHLIGHTTEXT);
|
||||
} else {
|
||||
colourBack = ColourElement(options.back, COLOR_WINDOW);
|
||||
graphics.pixmapLine->FillRectangle(rcItem, colourBack);
|
||||
colourFore = ColourElement(options.fore, COLOR_WINDOWTEXT);
|
||||
}
|
||||
|
||||
const ListItemData item = lti.Get(pDrawItem->itemID);
|
||||
const int pixId = item.pixId;
|
||||
const char *text = item.text;
|
||||
|
||||
const PRectangle rcText = rcBox.Inset(Point(TextInset.x, TextInset.y));
|
||||
|
||||
const double ascent = graphics.pixmapLine->Ascent(fontWin.get());
|
||||
graphics.pixmapLine->DrawTextClipped(rcText, fontWin.get(), rcText.top + ascent, text, colourFore, colourBack);
|
||||
|
||||
// Draw the image, if any
|
||||
const RGBAImage *pimage = images.Get(pixId);
|
||||
if (pimage) {
|
||||
const XYPOSITION left = rcItem.left + ItemInset.x + ImageInset.x;
|
||||
PRectangle rcImage = rcItem;
|
||||
rcImage.left = left;
|
||||
rcImage.right = rcImage.left + images.GetWidth();
|
||||
graphics.pixmapLine->DrawRGBAImage(rcImage,
|
||||
pimage->GetWidth(), pimage->GetHeight(), pimage->Pixels());
|
||||
}
|
||||
|
||||
#if defined(USE_D2D)
|
||||
if (graphics.pBMDCTarget) {
|
||||
const HRESULT hrEnd = graphics.pBMDCTarget->EndDraw();
|
||||
if (FAILED(hrEnd)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Blit from hMemDC to hDC
|
||||
const SIZE extent = SizeOfRect(pDrawItem->rcItem);
|
||||
::BitBlt(pDrawItem->hDC, pDrawItem->rcItem.left, pDrawItem->rcItem.top, extent.cx, extent.cy, graphics.bm.DC(), 0, 0, SRCCOPY);
|
||||
}
|
||||
|
||||
void ListBoxX::AppendListItem(const char *text, const char *numword) {
|
||||
int pixId = -1;
|
||||
if (numword) {
|
||||
pixId = 0;
|
||||
char ch;
|
||||
while ((ch = *++numword) != '\0') {
|
||||
pixId = 10 * pixId + (ch - '0');
|
||||
}
|
||||
}
|
||||
|
||||
lti.AllocItem(text, pixId);
|
||||
maxItemCharacters = std::max(maxItemCharacters, static_cast<int>(strlen(text)));
|
||||
}
|
||||
|
||||
void ListBoxX::SetDelegate(IListBoxDelegate *lbDelegate) {
|
||||
delegate = lbDelegate;
|
||||
}
|
||||
|
||||
void ListBoxX::SetList(const char *list, char separator, char typesep) {
|
||||
// Turn off redraw while populating the list - this has a significant effect, even if
|
||||
// the listbox is not visible.
|
||||
SetRedraw(false);
|
||||
Clear();
|
||||
const size_t size = strlen(list);
|
||||
char *words = lti.SetWords(list);
|
||||
const char *startword = words;
|
||||
char *numword = nullptr;
|
||||
for (size_t i=0; i < size; i++) {
|
||||
if (words[i] == separator) {
|
||||
words[i] = '\0';
|
||||
if (numword)
|
||||
*numword = '\0';
|
||||
AppendListItem(startword, numword);
|
||||
startword = words + i + 1;
|
||||
numword = nullptr;
|
||||
} else if (words[i] == typesep) {
|
||||
numword = words + i;
|
||||
}
|
||||
}
|
||||
if (startword) {
|
||||
if (numword)
|
||||
*numword = '\0';
|
||||
AppendListItem(startword, numword);
|
||||
}
|
||||
|
||||
// Finally populate the listbox itself with the correct number of items
|
||||
const int count = lti.Count();
|
||||
::SendMessage(lb, LB_INITSTORAGE, count, 0);
|
||||
for (intptr_t j=0; j<count; j++) {
|
||||
ListBox_AddItemData(lb, j+1);
|
||||
}
|
||||
SetRedraw(true);
|
||||
}
|
||||
|
||||
void ListBoxX::SetOptions(ListOptions options_) {
|
||||
options = options_;
|
||||
frameStyle = FlagSet(options.options, AutoCompleteOption::FixedSize) ? WS_BORDER : WS_THICKFRAME;
|
||||
}
|
||||
|
||||
void ListBoxX::AdjustWindowRect(PRectangle *rc, UINT dpiAdjust) const noexcept {
|
||||
RECT rcw = RectFromPRectangle(*rc);
|
||||
AdjustWindowRectForDpi(&rcw, frameStyle, dpiAdjust);
|
||||
*rc = PRectangleFromRECT(rcw);
|
||||
}
|
||||
|
||||
int ListBoxX::ItemHeight() const noexcept {
|
||||
int itemHeight = lineHeight + (TextInset.y * 2);
|
||||
const int pixHeight = images.GetHeight() + (ImageInset.y * 2);
|
||||
if (itemHeight < pixHeight) {
|
||||
itemHeight = pixHeight;
|
||||
}
|
||||
return itemHeight;
|
||||
}
|
||||
|
||||
int ListBoxX::MinClientWidth() const noexcept {
|
||||
return 12 * (aveCharWidth+aveCharWidth/3);
|
||||
}
|
||||
|
||||
POINT ListBoxX::MinTrackSize() const noexcept {
|
||||
PRectangle rc = PRectangle::FromInts(0, 0, MinClientWidth(), ItemHeight());
|
||||
AdjustWindowRect(&rc, dpi);
|
||||
POINT ret = {static_cast<LONG>(rc.Width()), static_cast<LONG>(rc.Height())};
|
||||
return ret;
|
||||
}
|
||||
|
||||
POINT ListBoxX::MaxTrackSize() const noexcept {
|
||||
PRectangle rc = PRectangle::FromInts(0, 0,
|
||||
std::max<int>(static_cast<unsigned int>(MinClientWidth()),
|
||||
maxCharWidth * maxItemCharacters + TextInset.x * 2 +
|
||||
TextOffset() + SystemMetricsForDpi(SM_CXVSCROLL, dpi)),
|
||||
ItemHeight() * lti.Count());
|
||||
AdjustWindowRect(&rc, dpi);
|
||||
POINT ret = {static_cast<LONG>(rc.Width()), static_cast<LONG>(rc.Height())};
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ListBoxX::SetRedraw(bool on) noexcept {
|
||||
::SendMessage(lb, WM_SETREDRAW, on, 0);
|
||||
if (on) {
|
||||
::RedrawWindow(lb, {}, {}, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
|
||||
}
|
||||
}
|
||||
|
||||
void ListBoxX::ResizeToCursor() {
|
||||
PRectangle rc = GetPosition();
|
||||
POINT ptw;
|
||||
::GetCursorPos(&ptw);
|
||||
const Point pt = PointFromPOINT(ptw) + dragOffset;
|
||||
|
||||
switch (resizeHit) {
|
||||
case HTLEFT:
|
||||
rc.left = pt.x;
|
||||
break;
|
||||
case HTRIGHT:
|
||||
rc.right = pt.x;
|
||||
break;
|
||||
case HTTOP:
|
||||
rc.top = pt.y;
|
||||
break;
|
||||
case HTTOPLEFT:
|
||||
rc.top = pt.y;
|
||||
rc.left = pt.x;
|
||||
break;
|
||||
case HTTOPRIGHT:
|
||||
rc.top = pt.y;
|
||||
rc.right = pt.x;
|
||||
break;
|
||||
case HTBOTTOM:
|
||||
rc.bottom = pt.y;
|
||||
break;
|
||||
case HTBOTTOMLEFT:
|
||||
rc.bottom = pt.y;
|
||||
rc.left = pt.x;
|
||||
break;
|
||||
case HTBOTTOMRIGHT:
|
||||
rc.bottom = pt.y;
|
||||
rc.right = pt.x;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const POINT ptMin = MinTrackSize();
|
||||
const POINT ptMax = MaxTrackSize();
|
||||
// We don't allow the left edge to move at present, but just in case
|
||||
rc.left = std::clamp(rc.left, rcPreSize.right - ptMax.x, rcPreSize.right - ptMin.x);
|
||||
rc.top = std::clamp(rc.top, rcPreSize.bottom - ptMax.y, rcPreSize.bottom - ptMin.y);
|
||||
rc.right = std::clamp(rc.right, rcPreSize.left + ptMin.x, rcPreSize.left + ptMax.x);
|
||||
rc.bottom = std::clamp(rc.bottom, rcPreSize.top + ptMin.y, rcPreSize.top + ptMax.y);
|
||||
|
||||
SetPosition(rc);
|
||||
}
|
||||
|
||||
void ListBoxX::StartResize(WPARAM hitCode) {
|
||||
rcPreSize = GetPosition();
|
||||
POINT cursorPos;
|
||||
::GetCursorPos(&cursorPos);
|
||||
|
||||
switch (hitCode) {
|
||||
case HTRIGHT:
|
||||
case HTBOTTOM:
|
||||
case HTBOTTOMRIGHT:
|
||||
dragOffset.x = rcPreSize.right - cursorPos.x;
|
||||
dragOffset.y = rcPreSize.bottom - cursorPos.y;
|
||||
break;
|
||||
|
||||
case HTTOPRIGHT:
|
||||
dragOffset.x = rcPreSize.right - cursorPos.x;
|
||||
dragOffset.y = rcPreSize.top - cursorPos.y;
|
||||
break;
|
||||
|
||||
// Note that the current hit test code prevents the left edge cases ever firing
|
||||
// as we don't want the left edge to be movable
|
||||
case HTLEFT:
|
||||
case HTTOP:
|
||||
case HTTOPLEFT:
|
||||
dragOffset.x = rcPreSize.left - cursorPos.x;
|
||||
dragOffset.y = rcPreSize.top - cursorPos.y;
|
||||
break;
|
||||
case HTBOTTOMLEFT:
|
||||
dragOffset.x = rcPreSize.left - cursorPos.x;
|
||||
dragOffset.y = rcPreSize.bottom - cursorPos.y;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
::SetCapture(GetHWND());
|
||||
resizeHit = hitCode;
|
||||
}
|
||||
|
||||
LRESULT ListBoxX::NcHitTest(WPARAM wParam, LPARAM lParam) const {
|
||||
const PRectangle rc = GetPosition();
|
||||
|
||||
LRESULT hit = ::DefWindowProc(GetHWND(), WM_NCHITTEST, wParam, lParam);
|
||||
// There is an apparent bug in the DefWindowProc hit test code whereby it will
|
||||
// return HTTOPXXX if the window in question is shorter than the default
|
||||
// window caption height + frame, even if one is hovering over the bottom edge of
|
||||
// the frame, so workaround that here
|
||||
if (hit >= HTTOP && hit <= HTTOPRIGHT) {
|
||||
const int minHeight = SystemMetricsForDpi(SM_CYMINTRACK, dpi);
|
||||
const int yPos = GET_Y_LPARAM(lParam);
|
||||
if ((rc.Height() < minHeight) && (yPos > ((rc.top + rc.bottom)/2))) {
|
||||
hit += HTBOTTOM - HTTOP;
|
||||
}
|
||||
}
|
||||
|
||||
// Never permit resizing that moves the left edge. Allow movement of top or bottom edge
|
||||
// depending on whether the list is above or below the caret
|
||||
switch (hit) {
|
||||
case HTLEFT:
|
||||
case HTTOPLEFT:
|
||||
case HTBOTTOMLEFT:
|
||||
hit = HTERROR;
|
||||
break;
|
||||
|
||||
case HTTOP:
|
||||
case HTTOPRIGHT: {
|
||||
// Valid only if caret below list
|
||||
if (location.y < rc.top)
|
||||
hit = HTERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case HTBOTTOM:
|
||||
case HTBOTTOMRIGHT: {
|
||||
// Valid only if caret above list
|
||||
if (rc.bottom <= location.y)
|
||||
hit = HTERROR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
void ListBoxX::OnDoubleClick() {
|
||||
if (delegate) {
|
||||
ListBoxEvent event(ListBoxEvent::EventType::doubleClick);
|
||||
delegate->ListNotify(&event);
|
||||
}
|
||||
}
|
||||
|
||||
void ListBoxX::OnSelChange() {
|
||||
if (delegate) {
|
||||
ListBoxEvent event(ListBoxEvent::EventType::selectionChange);
|
||||
delegate->ListNotify(&event);
|
||||
}
|
||||
}
|
||||
|
||||
POINT ListBoxX::GetClientExtent() const noexcept {
|
||||
RECT rc;
|
||||
::GetWindowRect(HwndFromWindowID(wid), &rc);
|
||||
POINT ret { rc.right - rc.left, rc.bottom - rc.top };
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ListBoxX::CentreItem(int n) {
|
||||
// If below mid point, scroll up to centre, but with more items below if uneven
|
||||
if (n >= 0) {
|
||||
const POINT extent = GetClientExtent();
|
||||
const int visible = extent.y/ItemHeight();
|
||||
if (visible < Length()) {
|
||||
const int top = ListBox_GetTopIndex(lb);
|
||||
const int half = (visible - 1) / 2;
|
||||
if (n > (top + half))
|
||||
ListBox_SetTopIndex(lb, n - half);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ListBoxX::AllocateBitMap() {
|
||||
const SIZE extent { GetClientExtent().x, lineHeight };
|
||||
|
||||
graphics.bm.Create({}, extent.cx, -extent.cy, nullptr);
|
||||
if (!graphics.bm) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make a surface
|
||||
graphics.pixmapLine = Surface::Allocate(technology);
|
||||
graphics.pixmapLine->SetMode(SurfaceMode(codePage, false));
|
||||
|
||||
#if defined(USE_D2D)
|
||||
if (technology != Technology::Default) {
|
||||
if (!LoadD2D()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const D2D1_RENDER_TARGET_PROPERTIES drtp = D2D1::RenderTargetProperties(
|
||||
D2D1_RENDER_TARGET_TYPE_DEFAULT,
|
||||
{ DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED });
|
||||
|
||||
HRESULT hr = CreateDCRenderTarget(&drtp, graphics.pBMDCTarget);
|
||||
if (FAILED(hr) || !graphics.pBMDCTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
const RECT rcExtent = { 0, 0, extent.cx, extent.cy };
|
||||
hr = graphics.pBMDCTarget->BindDC(graphics.bm.DC(), &rcExtent);
|
||||
if (SUCCEEDED(hr)) {
|
||||
graphics.pixmapLine->Init(graphics.pBMDCTarget.Get(), GetID());
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Either technology == Technology::Default or USE_D2D turned off
|
||||
graphics.pixmapLine->Init(graphics.bm.DC(), GetID());
|
||||
}
|
||||
|
||||
LRESULT PASCAL ListBoxX::ControlWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) {
|
||||
try {
|
||||
ListBoxX *lbx = static_cast<ListBoxX *>(PointerFromWindow(::GetParent(hWnd)));
|
||||
switch (iMessage) {
|
||||
case WM_ERASEBKGND:
|
||||
return TRUE;
|
||||
|
||||
case WM_MOUSEACTIVATE:
|
||||
// This prevents the view activating when the scrollbar is clicked
|
||||
return MA_NOACTIVATE;
|
||||
|
||||
case WM_LBUTTONDOWN: {
|
||||
// We must take control of selection to prevent the ListBox activating
|
||||
// the popup
|
||||
const LRESULT lResult = ::SendMessage(hWnd, LB_ITEMFROMPOINT, 0, lParam);
|
||||
if (HIWORD(lResult) == 0) {
|
||||
ListBox_SetCurSel(hWnd, LOWORD(lResult));
|
||||
if (lbx) {
|
||||
lbx->OnSelChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
return 0;
|
||||
|
||||
case WM_LBUTTONDBLCLK: {
|
||||
if (lbx) {
|
||||
lbx->OnDoubleClick();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_MBUTTONDOWN:
|
||||
// disable the scroll wheel button click action
|
||||
return 0;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
WNDPROC prevWndProc = reinterpret_cast<WNDPROC>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
|
||||
if (prevWndProc) {
|
||||
return ::CallWindowProc(prevWndProc, hWnd, iMessage, wParam, lParam);
|
||||
}
|
||||
return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
|
||||
} catch (...) {
|
||||
}
|
||||
return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
|
||||
}
|
||||
|
||||
LRESULT ListBoxX::WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) {
|
||||
switch (iMessage) {
|
||||
case WM_CREATE: {
|
||||
HINSTANCE hinstanceParent = GetWindowInstance(HwndFromWindow(*parent));
|
||||
// Note that LBS_NOINTEGRALHEIGHT is specified to fix cosmetic issue when resizing the list
|
||||
// but has useful side effect of speeding up list population significantly
|
||||
lb = ::CreateWindowEx(
|
||||
0, TEXT("listbox"), TEXT(""),
|
||||
WS_CHILD | WS_VSCROLL | WS_VISIBLE |
|
||||
LBS_OWNERDRAWFIXED | LBS_NODATA | LBS_NOINTEGRALHEIGHT,
|
||||
0, 0, 150,80, hWnd,
|
||||
reinterpret_cast<HMENU>(static_cast<ptrdiff_t>(ctrlID)),
|
||||
hinstanceParent,
|
||||
nullptr);
|
||||
WNDPROC prevWndProc = SubclassWindow(lb, ControlWndProc);
|
||||
::SetWindowLongPtr(lb, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(prevWndProc));
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_SIZE:
|
||||
if (lb) {
|
||||
graphics.Release(); // Bitmap must be reallocated to new size.
|
||||
SetRedraw(false);
|
||||
::SetWindowPos(lb, {}, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
|
||||
// Ensure the selection remains visible
|
||||
CentreItem(GetSelection());
|
||||
SetRedraw(true);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_PAINT: {
|
||||
Painter painter(hWnd);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_COMMAND:
|
||||
// This is not actually needed now - the registered double click action is used
|
||||
// directly to action a choice from the list.
|
||||
::SendMessage(HwndFromWindow(*parent), iMessage, wParam, lParam);
|
||||
break;
|
||||
|
||||
case WM_MEASUREITEM: {
|
||||
MEASUREITEMSTRUCT *pMeasureItem = reinterpret_cast<MEASUREITEMSTRUCT *>(lParam);
|
||||
pMeasureItem->itemHeight = ItemHeight();
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_DRAWITEM:
|
||||
Draw(reinterpret_cast<DRAWITEMSTRUCT *>(lParam));
|
||||
break;
|
||||
|
||||
case WM_DESTROY:
|
||||
lb = {};
|
||||
SetWindowPointer(hWnd, nullptr);
|
||||
return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
|
||||
|
||||
case WM_ERASEBKGND:
|
||||
// To reduce flicker we can elide background erasure since this window is
|
||||
// completely covered by its child.
|
||||
return TRUE;
|
||||
|
||||
case WM_GETMINMAXINFO: {
|
||||
MINMAXINFO *minMax = reinterpret_cast<MINMAXINFO*>(lParam);
|
||||
minMax->ptMaxTrackSize = MaxTrackSize();
|
||||
minMax->ptMinTrackSize = MinTrackSize();
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_MOUSEACTIVATE:
|
||||
return MA_NOACTIVATE;
|
||||
|
||||
case WM_NCHITTEST:
|
||||
return NcHitTest(wParam, lParam);
|
||||
|
||||
case WM_NCLBUTTONDOWN:
|
||||
// We have to implement our own window resizing because the DefWindowProc
|
||||
// implementation insists on activating the resized window
|
||||
StartResize(wParam);
|
||||
return 0;
|
||||
|
||||
case WM_MOUSEMOVE: {
|
||||
if (resizeHit == 0) {
|
||||
return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
|
||||
}
|
||||
ResizeToCursor();
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
case WM_CANCELMODE:
|
||||
if (resizeHit != 0) {
|
||||
resizeHit = 0;
|
||||
::ReleaseCapture();
|
||||
}
|
||||
return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
|
||||
case WM_MOUSEWHEEL:
|
||||
if (wheelDelta.Accumulate(wParam)) {
|
||||
const int nRows = GetVisibleRows();
|
||||
int linesToScroll = std::clamp(nRows - 1, 1, 3);
|
||||
linesToScroll *= wheelDelta.Actions();
|
||||
int top = ListBox_GetTopIndex(lb) + linesToScroll;
|
||||
if (top < 0) {
|
||||
top = 0;
|
||||
}
|
||||
ListBox_SetTopIndex(lb, top);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT PASCAL ListBoxX::StaticWndProc(
|
||||
HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) {
|
||||
if (iMessage == WM_CREATE) {
|
||||
CREATESTRUCT *pCreate = reinterpret_cast<CREATESTRUCT *>(lParam);
|
||||
SetWindowPointer(hWnd, pCreate->lpCreateParams);
|
||||
}
|
||||
// Find C++ object associated with window.
|
||||
ListBoxX *lbx = static_cast<ListBoxX *>(PointerFromWindow(hWnd));
|
||||
if (lbx) {
|
||||
return lbx->WndProc(hWnd, iMessage, wParam, lParam);
|
||||
}
|
||||
return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
|
||||
}
|
||||
|
||||
namespace Scintilla::Internal {
|
||||
|
||||
bool ListBoxX_Register() noexcept {
|
||||
WNDCLASSEX wndclassc {};
|
||||
wndclassc.cbSize = sizeof(wndclassc);
|
||||
// We need CS_HREDRAW and CS_VREDRAW because of the ellipsis that might be drawn for
|
||||
// truncated items in the list and the appearance/disappearance of the vertical scroll bar.
|
||||
// The list repaint is double-buffered to avoid the flicker this would otherwise cause.
|
||||
wndclassc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
|
||||
wndclassc.cbWndExtra = sizeof(ListBoxX *);
|
||||
wndclassc.hInstance = hinstPlatformRes;
|
||||
wndclassc.lpfnWndProc = ListBoxX::StaticWndProc;
|
||||
wndclassc.hCursor = ::LoadCursor({}, IDC_ARROW);
|
||||
wndclassc.lpszClassName = ListBoxX_ClassName;
|
||||
|
||||
return ::RegisterClassEx(&wndclassc) != 0;
|
||||
}
|
||||
|
||||
void ListBoxX_Unregister() noexcept {
|
||||
if (hinstPlatformRes) {
|
||||
::UnregisterClass(ListBoxX_ClassName, hinstPlatformRes);
|
||||
}
|
||||
}
|
||||
|
||||
ListBox::ListBox() noexcept = default;
|
||||
|
||||
ListBox::~ListBox() noexcept = default;
|
||||
|
||||
}
|
18
scintilla/win32/ListBox.h
Normal file
18
scintilla/win32/ListBox.h
Normal file
@ -0,0 +1,18 @@
|
||||
// Scintilla source code edit control
|
||||
/** @file ListBox.h
|
||||
** Definitions for list box on Windows.
|
||||
**/
|
||||
// Copyright 2025 by Neil Hodgson <neilh@scintilla.org>
|
||||
// The License.txt file describes the conditions under which this software may be distributed.
|
||||
|
||||
#ifndef LISTBOX_H
|
||||
#define LISTBOX_H
|
||||
|
||||
namespace Scintilla::Internal {
|
||||
|
||||
bool ListBoxX_Register() noexcept;
|
||||
void ListBoxX_Unregister() noexcept;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -13,6 +13,10 @@ namespace Scintilla::Internal {
|
||||
#ifndef USER_DEFAULT_SCREEN_DPI
|
||||
#define USER_DEFAULT_SCREEN_DPI 96
|
||||
#endif
|
||||
constexpr FLOAT dpiDefault = USER_DEFAULT_SCREEN_DPI;
|
||||
|
||||
// Used for defining font size with LOGFONT
|
||||
constexpr int pointsPerInch = 72;
|
||||
|
||||
extern void Platform_Initialise(void *hInstance) noexcept;
|
||||
|
||||
@ -24,6 +28,10 @@ constexpr RECT RectFromPRectangle(PRectangle prc) noexcept {
|
||||
return rc;
|
||||
}
|
||||
|
||||
constexpr PRectangle PRectangleFromRECT(RECT rc) noexcept {
|
||||
return PRectangle::FromInts(rc.left, rc.top, rc.right, rc.bottom);
|
||||
}
|
||||
|
||||
constexpr POINT POINTFromPoint(Point pt) noexcept {
|
||||
return POINT{ static_cast<LONG>(pt.x), static_cast<LONG>(pt.y) };
|
||||
}
|
||||
@ -36,6 +44,8 @@ constexpr SIZE SizeOfRect(RECT rc) noexcept {
|
||||
return { rc.right - rc.left, rc.bottom - rc.top };
|
||||
}
|
||||
|
||||
ColourRGBA ColourFromSys(int nIndex) noexcept;
|
||||
|
||||
constexpr HWND HwndFromWindowID(WindowID wid) noexcept {
|
||||
return static_cast<HWND>(wid);
|
||||
}
|
||||
@ -44,6 +54,10 @@ inline HWND HwndFromWindow(const Window &w) noexcept {
|
||||
return HwndFromWindowID(w.GetID());
|
||||
}
|
||||
|
||||
extern HINSTANCE hinstPlatformRes;
|
||||
|
||||
UINT CodePageFromCharSet(CharacterSet characterSet, UINT documentCodePage) noexcept;
|
||||
|
||||
void *PointerFromWindow(HWND hWnd) noexcept;
|
||||
void SetWindowPointer(HWND hWnd, void *ptr) noexcept;
|
||||
|
||||
@ -54,8 +68,22 @@ float GetDeviceScaleFactorWhenGdiScalingActive(HWND hWnd) noexcept;
|
||||
|
||||
int SystemMetricsForDpi(int nIndex, UINT dpi) noexcept;
|
||||
|
||||
void AdjustWindowRectForDpi(LPRECT lpRect, DWORD dwStyle, UINT dpi) noexcept;
|
||||
|
||||
HCURSOR LoadReverseArrowCursor(UINT dpi) noexcept;
|
||||
|
||||
// Encapsulate WM_PAINT handling so that EndPaint is always called even with unexpected returns or exceptions.
|
||||
struct Painter {
|
||||
HWND hWnd{};
|
||||
PAINTSTRUCT ps{};
|
||||
explicit Painter(HWND hWnd_) noexcept : hWnd(hWnd_) {
|
||||
::BeginPaint(hWnd, &ps);
|
||||
}
|
||||
~Painter() {
|
||||
::EndPaint(hWnd, &ps);
|
||||
}
|
||||
};
|
||||
|
||||
class MouseWheelDelta {
|
||||
int wheelDelta = 0;
|
||||
public:
|
||||
@ -70,29 +98,89 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(USE_D2D)
|
||||
extern bool LoadD2D() noexcept;
|
||||
extern ID2D1Factory1 *pD2DFactory;
|
||||
extern IDWriteFactory1 *pIDWriteFactory;
|
||||
|
||||
using DCRenderTarget = ComPtr<ID2D1DCRenderTarget>;
|
||||
|
||||
using D3D11Device = ComPtr<ID3D11Device1>;
|
||||
|
||||
HRESULT CreateDCRenderTarget(const D2D1_RENDER_TARGET_PROPERTIES *renderTargetProperties, DCRenderTarget &dcRT) noexcept;
|
||||
extern HRESULT CreateD3D(D3D11Device &device) noexcept;
|
||||
|
||||
using WriteRenderingParams = ComPtr<IDWriteRenderingParams1>;
|
||||
|
||||
struct RenderingParams {
|
||||
WriteRenderingParams defaultRenderingParams;
|
||||
WriteRenderingParams customRenderingParams;
|
||||
// Both GDI and DirectWrite can produce a HFONT for use in list boxes
|
||||
struct FontWin : public Font {
|
||||
[[nodiscard]] virtual HFONT HFont() const noexcept = 0;
|
||||
[[nodiscard]] virtual std::unique_ptr<FontWin> Duplicate() const = 0;
|
||||
[[nodiscard]] virtual CharacterSet GetCharacterSet() const noexcept = 0;
|
||||
};
|
||||
|
||||
struct ISetRenderingParams {
|
||||
virtual void SetRenderingParams(std::shared_ptr<RenderingParams> renderingParams_) = 0;
|
||||
// Buffer to hold strings and string position arrays without always allocating on heap.
|
||||
// May sometimes have string too long to allocate on stack. So use a fixed stack-allocated buffer
|
||||
// when less than safe size otherwise allocate on heap and free automatically.
|
||||
template<typename T, int lengthStandard>
|
||||
class VarBuffer {
|
||||
T bufferStandard[lengthStandard];
|
||||
public:
|
||||
T *buffer;
|
||||
explicit VarBuffer(size_t length) : buffer(nullptr) {
|
||||
if (length > lengthStandard) {
|
||||
buffer = new T[length];
|
||||
} else {
|
||||
buffer = bufferStandard;
|
||||
}
|
||||
}
|
||||
// Deleted so VarBuffer objects can not be copied.
|
||||
VarBuffer(const VarBuffer &) = delete;
|
||||
VarBuffer(VarBuffer &&) = delete;
|
||||
VarBuffer &operator=(const VarBuffer &) = delete;
|
||||
VarBuffer &operator=(VarBuffer &&) = delete;
|
||||
|
||||
~VarBuffer() noexcept {
|
||||
if (buffer != bufferStandard) {
|
||||
delete[]buffer;
|
||||
buffer = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
constexpr int stackBufferLength = 400;
|
||||
class TextWide : public VarBuffer<wchar_t, stackBufferLength> {
|
||||
public:
|
||||
int tlen; // Using int instead of size_t as most Win32 APIs take int.
|
||||
TextWide(std::string_view text, int codePage) :
|
||||
VarBuffer<wchar_t, stackBufferLength>(text.length()) {
|
||||
if (codePage == CpUtf8) {
|
||||
tlen = static_cast<int>(UTF16FromUTF8(text, buffer, text.length()));
|
||||
} else {
|
||||
// Support Asian string display in 9x English
|
||||
tlen = ::MultiByteToWideChar(codePage, 0, text.data(), static_cast<int>(text.length()),
|
||||
buffer, static_cast<int>(text.length()));
|
||||
}
|
||||
}
|
||||
[[nodiscard]] std::wstring_view AsView() const noexcept {
|
||||
return std::wstring_view(buffer, tlen);
|
||||
}
|
||||
};
|
||||
using TextPositions = VarBuffer<XYPOSITION, stackBufferLength>;
|
||||
|
||||
// Manage the lifetime of a memory HBITMAP and its HDC so there are no leaks.
|
||||
class GDIBitMap {
|
||||
HDC hdc{};
|
||||
HBITMAP hbm{};
|
||||
HBITMAP hbmOriginal{};
|
||||
|
||||
public:
|
||||
GDIBitMap() noexcept = default;
|
||||
// Deleted so GDIBitMap objects can not be copied.
|
||||
GDIBitMap(const GDIBitMap &) = delete;
|
||||
GDIBitMap(GDIBitMap &&) = delete;
|
||||
// Move would be OK but not needed yet
|
||||
GDIBitMap &operator=(const GDIBitMap &) = delete;
|
||||
GDIBitMap &operator=(GDIBitMap &&) = delete;
|
||||
~GDIBitMap() noexcept;
|
||||
|
||||
void Create(HDC hdcBase, int width, int height, DWORD **pixels) noexcept;
|
||||
void Release() noexcept;
|
||||
HBITMAP Extract() noexcept;
|
||||
|
||||
[[nodiscard]] HDC DC() const noexcept {
|
||||
return hdc;
|
||||
}
|
||||
[[nodiscard]] explicit operator bool() const noexcept {
|
||||
return hdc && hbm;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define VERSION_SCINTILLA "5.5.5"
|
||||
#define VERSION_WORDS 5, 5, 5, 0
|
||||
#define VERSION_SCINTILLA "5.5.6"
|
||||
#define VERSION_WORDS 5, 5, 6, 0
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VERSION_WORDS
|
||||
|
@ -195,6 +195,9 @@
|
||||
<ClCompile Include="..\..\boostregex\*.cxx" />
|
||||
<ClCompile Include="..\win32\HanjaDic.cxx" />
|
||||
<ClCompile Include="..\win32\PlatWin.cxx" />
|
||||
<ClCompile Include="..\win32\ListBox.cxx" />
|
||||
<ClCompile Include="..\win32\SurfaceGDI.cxx" />
|
||||
<ClCompile Include="..\win32\SurfaceD2D.cxx" />
|
||||
<ClCompile Include="..\win32\ScintillaWin.cxx" />
|
||||
<ClCompile Include="..\win32\ScintillaDLL.cxx" />
|
||||
</ItemGroup>
|
||||
|
File diff suppressed because it is too large
Load Diff
1742
scintilla/win32/SurfaceD2D.cxx
Normal file
1742
scintilla/win32/SurfaceD2D.cxx
Normal file
File diff suppressed because it is too large
Load Diff
50
scintilla/win32/SurfaceD2D.h
Normal file
50
scintilla/win32/SurfaceD2D.h
Normal file
@ -0,0 +1,50 @@
|
||||
// Scintilla source code edit control
|
||||
/** @file SurfaceD2D.h
|
||||
** Definitions for drawing to Direct2D on Windows.
|
||||
**/
|
||||
// Copyright 1998-2011 by Neil Hodgson <neilh@scintilla.org>
|
||||
// The License.txt file describes the conditions under which this software may be distributed.
|
||||
|
||||
#ifndef SURFACED2D_H
|
||||
#define SURFACED2D_H
|
||||
|
||||
namespace Scintilla::Internal {
|
||||
|
||||
extern bool LoadD2D() noexcept;
|
||||
extern void ReleaseD2D() noexcept;
|
||||
extern ID2D1Factory1 *pD2DFactory;
|
||||
extern IDWriteFactory1 *pIDWriteFactory;
|
||||
|
||||
using DCRenderTarget = ComPtr<ID2D1DCRenderTarget>;
|
||||
|
||||
using D3D11Device = ComPtr<ID3D11Device1>;
|
||||
|
||||
HRESULT CreateDCRenderTarget(const D2D1_RENDER_TARGET_PROPERTIES *renderTargetProperties, DCRenderTarget &dcRT) noexcept;
|
||||
extern HRESULT CreateD3D(D3D11Device &device) noexcept;
|
||||
|
||||
using WriteRenderingParams = ComPtr<IDWriteRenderingParams1>;
|
||||
|
||||
struct RenderingParams {
|
||||
WriteRenderingParams defaultRenderingParams;
|
||||
WriteRenderingParams customRenderingParams;
|
||||
};
|
||||
|
||||
struct ISetRenderingParams {
|
||||
virtual void SetRenderingParams(std::shared_ptr<RenderingParams> renderingParams_) = 0;
|
||||
};
|
||||
|
||||
using BrushSolid = ComPtr<ID2D1SolidColorBrush>;
|
||||
using Geometry = ComPtr<ID2D1PathGeometry>;
|
||||
using GeometrySink = ComPtr<ID2D1GeometrySink>;
|
||||
using StrokeStyle = ComPtr<ID2D1StrokeStyle>;
|
||||
using TextLayout = ComPtr<IDWriteTextLayout>;
|
||||
|
||||
BrushSolid BrushSolidCreate(ID2D1RenderTarget *pTarget, COLORREF colour) noexcept;
|
||||
Geometry GeometryCreate() noexcept;
|
||||
GeometrySink GeometrySinkCreate(ID2D1PathGeometry *geometry) noexcept;
|
||||
StrokeStyle StrokeStyleCreate(const D2D1_STROKE_STYLE_PROPERTIES &strokeStyleProperties) noexcept;
|
||||
TextLayout LayoutCreate(std::wstring_view wsv, IDWriteTextFormat *pTextFormat, FLOAT maxWidth=10000.0F, FLOAT maxHeight=1000.0F) noexcept;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
889
scintilla/win32/SurfaceGDI.cxx
Normal file
889
scintilla/win32/SurfaceGDI.cxx
Normal file
@ -0,0 +1,889 @@
|
||||
// Scintilla source code edit control
|
||||
/** @file SurfaceGDI.cxx
|
||||
** Implementation of drawing to GDI on Windows.
|
||||
**/
|
||||
// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
|
||||
// The License.txt file describes the conditions under which this software may be distributed.
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <ctime>
|
||||
#include <cmath>
|
||||
#include <climits>
|
||||
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
// Want to use std::min and std::max so don't want Windows.h version of min and max
|
||||
#if !defined(NOMINMAX)
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0A00
|
||||
#undef WINVER
|
||||
#define WINVER 0x0A00
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include <richedit.h>
|
||||
#include <windowsx.h>
|
||||
#include <shellscalingapi.h>
|
||||
|
||||
#include "ScintillaTypes.h"
|
||||
|
||||
#include "Debugging.h"
|
||||
#include "Geometry.h"
|
||||
#include "Platform.h"
|
||||
#include "XPM.h"
|
||||
#include "UniConversion.h"
|
||||
#include "DBCS.h"
|
||||
|
||||
#include "WinTypes.h"
|
||||
#include "PlatWin.h"
|
||||
#include "SurfaceGDI.h"
|
||||
|
||||
using namespace Scintilla;
|
||||
using namespace Scintilla::Internal;
|
||||
|
||||
// All file hidden in unnamed namespace except for FontGDI_Allocate and SurfaceGDI_Allocate
|
||||
namespace {
|
||||
|
||||
constexpr Supports SupportsGDI[] = {
|
||||
Supports::PixelModification,
|
||||
};
|
||||
|
||||
constexpr BYTE Win32MapFontQuality(FontQuality extraFontFlag) noexcept {
|
||||
switch (extraFontFlag & FontQuality::QualityMask) {
|
||||
|
||||
case FontQuality::QualityNonAntialiased:
|
||||
return NONANTIALIASED_QUALITY;
|
||||
|
||||
case FontQuality::QualityAntialiased:
|
||||
return ANTIALIASED_QUALITY;
|
||||
|
||||
case FontQuality::QualityLcdOptimized:
|
||||
return CLEARTYPE_QUALITY;
|
||||
|
||||
default:
|
||||
return DEFAULT_QUALITY;
|
||||
}
|
||||
}
|
||||
|
||||
void SetLogFont(LOGFONTW &lf, const char *faceName, CharacterSet characterSet, XYPOSITION size, FontWeight weight, bool italic, FontQuality extraFontFlag) {
|
||||
lf = LOGFONTW();
|
||||
// The negative is to allow for leading
|
||||
lf.lfHeight = -(std::abs(std::lround(size)));
|
||||
lf.lfWeight = static_cast<LONG>(weight);
|
||||
lf.lfItalic = italic ? 1 : 0;
|
||||
lf.lfCharSet = static_cast<BYTE>(characterSet);
|
||||
lf.lfQuality = Win32MapFontQuality(extraFontFlag);
|
||||
UTF16FromUTF8(faceName, lf.lfFaceName, LF_FACESIZE);
|
||||
}
|
||||
|
||||
struct FontGDI : public FontWin {
|
||||
HFONT hfont = {};
|
||||
CharacterSet characterSet = CharacterSet::Ansi;
|
||||
FontGDI(HFONT hfont_, CharacterSet characterSet_) noexcept : hfont(hfont_), characterSet(characterSet_) {
|
||||
// Takes ownership and deletes the font
|
||||
}
|
||||
explicit FontGDI(const FontParameters &fp) : characterSet(fp.characterSet) {
|
||||
LOGFONTW lf;
|
||||
SetLogFont(lf, fp.faceName, fp.characterSet, fp.size, fp.weight, fp.italic, fp.extraFontFlag);
|
||||
hfont = ::CreateFontIndirectW(&lf);
|
||||
}
|
||||
// Deleted so FontGDI objects can not be copied.
|
||||
FontGDI(const FontGDI &) = delete;
|
||||
FontGDI(FontGDI &&) = delete;
|
||||
FontGDI &operator=(const FontGDI &) = delete;
|
||||
FontGDI &operator=(FontGDI &&) = delete;
|
||||
~FontGDI() noexcept override {
|
||||
if (hfont)
|
||||
::DeleteObject(hfont);
|
||||
}
|
||||
[[nodiscard]] HFONT HFont() const noexcept override {
|
||||
// Duplicating hfont
|
||||
LOGFONTW lf = {};
|
||||
if (0 == ::GetObjectW(hfont, sizeof(lf), &lf)) {
|
||||
return {};
|
||||
}
|
||||
return ::CreateFontIndirectW(&lf);
|
||||
}
|
||||
[[nodiscard]] std::unique_ptr<FontWin> Duplicate() const override {
|
||||
HFONT hfontCopy = HFont();
|
||||
return std::make_unique<FontGDI>(hfontCopy, characterSet);
|
||||
}
|
||||
[[nodiscard]] CharacterSet GetCharacterSet() const noexcept override {
|
||||
return characterSet;
|
||||
}
|
||||
};
|
||||
|
||||
class SurfaceGDI : public Surface {
|
||||
SurfaceMode mode;
|
||||
HDC hdc{};
|
||||
bool hdcOwned = false;
|
||||
HPEN pen{};
|
||||
HPEN penOld{};
|
||||
HBRUSH brush{};
|
||||
HBRUSH brushOld{};
|
||||
HFONT fontOld{};
|
||||
HBITMAP bitmap{};
|
||||
HBITMAP bitmapOld{};
|
||||
|
||||
int logPixelsY = USER_DEFAULT_SCREEN_DPI;
|
||||
|
||||
static constexpr int maxWidthMeasure = INT_MAX;
|
||||
// There appears to be a 16 bit string length limit in GDI on NT.
|
||||
static constexpr int maxLenText = 65535;
|
||||
|
||||
void PenColour(ColourRGBA fore, XYPOSITION widthStroke) noexcept;
|
||||
|
||||
void BrushColour(ColourRGBA back) noexcept;
|
||||
void SetFont(const Font *font_);
|
||||
void Clear() noexcept;
|
||||
|
||||
public:
|
||||
SurfaceGDI() noexcept = default;
|
||||
SurfaceGDI(HDC hdcCompatible, int width, int height, SurfaceMode mode_, int logPixelsY_) noexcept;
|
||||
// Deleted so SurfaceGDI objects can not be copied.
|
||||
SurfaceGDI(const SurfaceGDI &) = delete;
|
||||
SurfaceGDI(SurfaceGDI &&) = delete;
|
||||
SurfaceGDI &operator=(const SurfaceGDI &) = delete;
|
||||
SurfaceGDI &operator=(SurfaceGDI &&) = delete;
|
||||
|
||||
~SurfaceGDI() noexcept override;
|
||||
|
||||
void Init(WindowID wid) override;
|
||||
void Init(SurfaceID sid, WindowID wid) override;
|
||||
std::unique_ptr<Surface> AllocatePixMap(int width, int height) override;
|
||||
|
||||
void SetMode(SurfaceMode mode_) override;
|
||||
|
||||
void Release() noexcept override;
|
||||
int SupportsFeature(Supports feature) noexcept override;
|
||||
bool Initialised() override;
|
||||
int LogPixelsY() override;
|
||||
int PixelDivisions() override;
|
||||
int DeviceHeightFont(int points) override;
|
||||
void LineDraw(Point start, Point end, Stroke stroke) override;
|
||||
void PolyLine(const Point *pts, size_t npts, Stroke stroke) override;
|
||||
void Polygon(const Point *pts, size_t npts, FillStroke fillStroke) override;
|
||||
void RectangleDraw(PRectangle rc, FillStroke fillStroke) override;
|
||||
void RectangleFrame(PRectangle rc, Stroke stroke) override;
|
||||
void FillRectangle(PRectangle rc, Fill fill) override;
|
||||
void FillRectangleAligned(PRectangle rc, Fill fill) override;
|
||||
void FillRectangle(PRectangle rc, Surface &surfacePattern) override;
|
||||
void RoundedRectangle(PRectangle rc, FillStroke fillStroke) override;
|
||||
void AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) override;
|
||||
void GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) override;
|
||||
void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) override;
|
||||
void Ellipse(PRectangle rc, FillStroke fillStroke) override;
|
||||
void Stadium(PRectangle rc, FillStroke fillStroke, Ends ends) override;
|
||||
void Copy(PRectangle rc, Point from, Surface &surfaceSource) override;
|
||||
|
||||
std::unique_ptr<IScreenLineLayout> Layout(const IScreenLine *screenLine) override;
|
||||
|
||||
void DrawTextCommon(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, UINT fuOptions);
|
||||
void DrawTextNoClip(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourRGBA fore, ColourRGBA back) override;
|
||||
void DrawTextClipped(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourRGBA fore, ColourRGBA back) override;
|
||||
void DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourRGBA fore) override;
|
||||
void MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) override;
|
||||
XYPOSITION WidthText(const Font *font_, std::string_view text) override;
|
||||
|
||||
void DrawTextCommonUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, UINT fuOptions);
|
||||
void DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourRGBA fore, ColourRGBA back) override;
|
||||
void DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourRGBA fore, ColourRGBA back) override;
|
||||
void DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourRGBA fore) override;
|
||||
void MeasureWidthsUTF8(const Font *font_, std::string_view text, XYPOSITION *positions) override;
|
||||
XYPOSITION WidthTextUTF8(const Font *font_, std::string_view text) override;
|
||||
|
||||
XYPOSITION Ascent(const Font *font_) override;
|
||||
XYPOSITION Descent(const Font *font_) override;
|
||||
XYPOSITION InternalLeading(const Font *font_) override;
|
||||
XYPOSITION Height(const Font *font_) override;
|
||||
XYPOSITION AverageCharWidth(const Font *font_) override;
|
||||
|
||||
void SetClip(PRectangle rc) override;
|
||||
void PopClip() override;
|
||||
void FlushCachedState() override;
|
||||
void FlushDrawing() override;
|
||||
};
|
||||
|
||||
SurfaceGDI::SurfaceGDI(HDC hdcCompatible, int width, int height, SurfaceMode mode_, int logPixelsY_) noexcept {
|
||||
hdc = ::CreateCompatibleDC(hdcCompatible);
|
||||
hdcOwned = true;
|
||||
bitmap = ::CreateCompatibleBitmap(hdcCompatible, width, height);
|
||||
bitmapOld = SelectBitmap(hdc, bitmap);
|
||||
::SetTextAlign(hdc, TA_BASELINE);
|
||||
mode = mode_;
|
||||
logPixelsY = logPixelsY_;
|
||||
}
|
||||
|
||||
SurfaceGDI::~SurfaceGDI() noexcept {
|
||||
Clear();
|
||||
}
|
||||
|
||||
void SurfaceGDI::Clear() noexcept {
|
||||
if (penOld) {
|
||||
::SelectObject(hdc, penOld);
|
||||
::DeleteObject(pen);
|
||||
penOld = {};
|
||||
}
|
||||
pen = {};
|
||||
if (brushOld) {
|
||||
::SelectObject(hdc, brushOld);
|
||||
::DeleteObject(brush);
|
||||
brushOld = {};
|
||||
}
|
||||
brush = {};
|
||||
if (fontOld) {
|
||||
// Fonts are not deleted as they are owned by a Font object
|
||||
::SelectObject(hdc, fontOld);
|
||||
fontOld = {};
|
||||
}
|
||||
if (bitmapOld) {
|
||||
::SelectObject(hdc, bitmapOld);
|
||||
::DeleteObject(bitmap);
|
||||
bitmapOld = {};
|
||||
}
|
||||
bitmap = {};
|
||||
if (hdcOwned) {
|
||||
::DeleteDC(hdc);
|
||||
hdc = {};
|
||||
hdcOwned = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SurfaceGDI::Release() noexcept {
|
||||
Clear();
|
||||
}
|
||||
|
||||
int SurfaceGDI::SupportsFeature(Supports feature) noexcept {
|
||||
for (const Supports f : SupportsGDI) {
|
||||
if (f == feature)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SurfaceGDI::Initialised() {
|
||||
return hdc;
|
||||
}
|
||||
|
||||
void SurfaceGDI::Init(WindowID wid) {
|
||||
Release();
|
||||
hdc = ::CreateCompatibleDC({});
|
||||
hdcOwned = true;
|
||||
::SetTextAlign(hdc, TA_BASELINE);
|
||||
logPixelsY = DpiForWindow(wid);
|
||||
}
|
||||
|
||||
void SurfaceGDI::Init(SurfaceID sid, WindowID wid) {
|
||||
Release();
|
||||
hdc = static_cast<HDC>(sid);
|
||||
::SetTextAlign(hdc, TA_BASELINE);
|
||||
// Windows on screen are scaled but printers are not.
|
||||
const bool printing = ::GetDeviceCaps(hdc, TECHNOLOGY) != DT_RASDISPLAY;
|
||||
logPixelsY = printing ? ::GetDeviceCaps(hdc, LOGPIXELSY) : DpiForWindow(wid);
|
||||
}
|
||||
|
||||
std::unique_ptr<Surface> SurfaceGDI::AllocatePixMap(int width, int height) {
|
||||
return std::make_unique<SurfaceGDI>(hdc, width, height, mode, logPixelsY);
|
||||
}
|
||||
|
||||
void SurfaceGDI::SetMode(SurfaceMode mode_) {
|
||||
mode = mode_;
|
||||
}
|
||||
|
||||
void SurfaceGDI::PenColour(ColourRGBA fore, XYPOSITION widthStroke) noexcept {
|
||||
if (pen) {
|
||||
::SelectObject(hdc, penOld);
|
||||
::DeleteObject(pen);
|
||||
pen = {};
|
||||
penOld = {};
|
||||
}
|
||||
const DWORD penWidth = std::lround(widthStroke);
|
||||
const COLORREF penColour = fore.OpaqueRGB();
|
||||
if (widthStroke > 1) {
|
||||
const LOGBRUSH brushParameters{ BS_SOLID, penColour, 0 };
|
||||
pen = ::ExtCreatePen(PS_GEOMETRIC | PS_ENDCAP_ROUND | PS_JOIN_MITER,
|
||||
penWidth,
|
||||
&brushParameters,
|
||||
0,
|
||||
nullptr);
|
||||
} else {
|
||||
pen = ::CreatePen(PS_INSIDEFRAME, penWidth, penColour);
|
||||
}
|
||||
penOld = SelectPen(hdc, pen);
|
||||
}
|
||||
|
||||
void SurfaceGDI::BrushColour(ColourRGBA back) noexcept {
|
||||
if (brush) {
|
||||
::SelectObject(hdc, brushOld);
|
||||
::DeleteObject(brush);
|
||||
brush = {};
|
||||
brushOld = {};
|
||||
}
|
||||
brush = ::CreateSolidBrush(back.OpaqueRGB());
|
||||
brushOld = SelectBrush(hdc, brush);
|
||||
}
|
||||
|
||||
void SurfaceGDI::SetFont(const Font *font_) {
|
||||
const FontGDI *pfm = dynamic_cast<const FontGDI *>(font_);
|
||||
PLATFORM_ASSERT(pfm);
|
||||
if (!pfm) {
|
||||
throw std::runtime_error("SurfaceGDI::SetFont: wrong Font type.");
|
||||
}
|
||||
if (fontOld) {
|
||||
SelectFont(hdc, pfm->hfont);
|
||||
} else {
|
||||
fontOld = SelectFont(hdc, pfm->hfont);
|
||||
}
|
||||
}
|
||||
|
||||
int SurfaceGDI::LogPixelsY() {
|
||||
return logPixelsY;
|
||||
}
|
||||
|
||||
int SurfaceGDI::PixelDivisions() {
|
||||
// Win32 uses device pixels.
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SurfaceGDI::DeviceHeightFont(int points) {
|
||||
return ::MulDiv(points, LogPixelsY(), pointsPerInch);
|
||||
}
|
||||
|
||||
void SurfaceGDI::LineDraw(Point start, Point end, Stroke stroke) {
|
||||
PenColour(stroke.colour, stroke.width);
|
||||
::MoveToEx(hdc, std::lround(std::floor(start.x)), std::lround(std::floor(start.y)), nullptr);
|
||||
::LineTo(hdc, std::lround(std::floor(end.x)), std::lround(std::floor(end.y)));
|
||||
}
|
||||
|
||||
void SurfaceGDI::PolyLine(const Point *pts, size_t npts, Stroke stroke) {
|
||||
PLATFORM_ASSERT(npts > 1);
|
||||
if (npts <= 1) {
|
||||
return;
|
||||
}
|
||||
PenColour(stroke.colour, stroke.width);
|
||||
std::vector<POINT> outline;
|
||||
std::transform(pts, pts + npts, std::back_inserter(outline), POINTFromPoint);
|
||||
::Polyline(hdc, outline.data(), static_cast<int>(npts));
|
||||
}
|
||||
|
||||
void SurfaceGDI::Polygon(const Point *pts, size_t npts, FillStroke fillStroke) {
|
||||
PenColour(fillStroke.stroke.colour.WithoutAlpha(), fillStroke.stroke.width);
|
||||
BrushColour(fillStroke.fill.colour.WithoutAlpha());
|
||||
std::vector<POINT> outline;
|
||||
std::transform(pts, pts + npts, std::back_inserter(outline), POINTFromPoint);
|
||||
::Polygon(hdc, outline.data(), static_cast<int>(npts));
|
||||
}
|
||||
|
||||
void SurfaceGDI::RectangleDraw(PRectangle rc, FillStroke fillStroke) {
|
||||
RectangleFrame(rc, fillStroke.stroke);
|
||||
FillRectangle(rc.Inset(fillStroke.stroke.width), fillStroke.fill.colour);
|
||||
}
|
||||
|
||||
void SurfaceGDI::RectangleFrame(PRectangle rc, Stroke stroke) {
|
||||
BrushColour(stroke.colour);
|
||||
const RECT rcw = RectFromPRectangle(rc);
|
||||
::FrameRect(hdc, &rcw, brush);
|
||||
}
|
||||
|
||||
void SurfaceGDI::FillRectangle(PRectangle rc, Fill fill) {
|
||||
if (fill.colour.IsOpaque()) {
|
||||
// Using ExtTextOut rather than a FillRect ensures that no dithering occurs.
|
||||
// There is no need to allocate a brush either.
|
||||
const RECT rcw = RectFromPRectangle(rc);
|
||||
::SetBkColor(hdc, fill.colour.OpaqueRGB());
|
||||
::ExtTextOut(hdc, rcw.left, rcw.top, ETO_OPAQUE, &rcw, TEXT(""), 0, nullptr);
|
||||
} else {
|
||||
AlphaRectangle(rc, 0, FillStroke(fill.colour));
|
||||
}
|
||||
}
|
||||
|
||||
void SurfaceGDI::FillRectangleAligned(PRectangle rc, Fill fill) {
|
||||
FillRectangle(PixelAlign(rc, 1), fill);
|
||||
}
|
||||
|
||||
void SurfaceGDI::FillRectangle(PRectangle rc, Surface &surfacePattern) {
|
||||
HBRUSH br{};
|
||||
if (SurfaceGDI *psgdi = dynamic_cast<SurfaceGDI *>(&surfacePattern); psgdi && psgdi->bitmap) {
|
||||
br = ::CreatePatternBrush(psgdi->bitmap);
|
||||
} else { // Something is wrong so display in red
|
||||
br = ::CreateSolidBrush(RGB(0xff, 0, 0));
|
||||
}
|
||||
const RECT rcw = RectFromPRectangle(rc);
|
||||
::FillRect(hdc, &rcw, br);
|
||||
::DeleteObject(br);
|
||||
}
|
||||
|
||||
void SurfaceGDI::RoundedRectangle(PRectangle rc, FillStroke fillStroke) {
|
||||
PenColour(fillStroke.stroke.colour, fillStroke.stroke.width);
|
||||
BrushColour(fillStroke.fill.colour);
|
||||
const RECT rcw = RectFromPRectangle(rc);
|
||||
constexpr int cornerSize = 8;
|
||||
::RoundRect(hdc,
|
||||
rcw.left + 1, rcw.top,
|
||||
rcw.right - 1, rcw.bottom,
|
||||
cornerSize, cornerSize);
|
||||
}
|
||||
|
||||
// DIBSection is bitmap with some drawing operations used by SurfaceGDI.
|
||||
class DIBSection {
|
||||
GDIBitMap bm;
|
||||
SIZE size{};
|
||||
DWORD *pixels = nullptr;
|
||||
public:
|
||||
DIBSection(HDC hdc, SIZE size_) noexcept;
|
||||
explicit operator bool() const noexcept {
|
||||
return bm && pixels;
|
||||
}
|
||||
[[nodiscard]] DWORD *Pixels() const noexcept {
|
||||
return pixels;
|
||||
}
|
||||
[[nodiscard]] unsigned char *Bytes() const noexcept {
|
||||
return reinterpret_cast<unsigned char *>(pixels);
|
||||
}
|
||||
[[nodiscard]] HDC DC() const noexcept {
|
||||
return bm.DC();
|
||||
}
|
||||
void SetPixel(LONG x, LONG y, DWORD value) noexcept {
|
||||
PLATFORM_ASSERT(x >= 0);
|
||||
PLATFORM_ASSERT(y >= 0);
|
||||
PLATFORM_ASSERT(x < size.cx);
|
||||
PLATFORM_ASSERT(y < size.cy);
|
||||
pixels[(y * size.cx) + x] = value;
|
||||
}
|
||||
void SetSymmetric(LONG x, LONG y, DWORD value) noexcept;
|
||||
};
|
||||
|
||||
DIBSection::DIBSection(HDC hdc, SIZE size_) noexcept : size(size_) {
|
||||
// -size.y makes bitmap start from top
|
||||
bm.Create(hdc, size.cx, -size.cy, &pixels);
|
||||
}
|
||||
|
||||
void DIBSection::SetSymmetric(LONG x, LONG y, DWORD value) noexcept {
|
||||
// Plot a point symmetrically to all 4 quadrants
|
||||
const LONG xSymmetric = size.cx - 1 - x;
|
||||
const LONG ySymmetric = size.cy - 1 - y;
|
||||
SetPixel(x, y, value);
|
||||
SetPixel(xSymmetric, y, value);
|
||||
SetPixel(x, ySymmetric, value);
|
||||
SetPixel(xSymmetric, ySymmetric, value);
|
||||
}
|
||||
|
||||
ColourRGBA GradientValue(const std::vector<ColourStop> &stops, XYPOSITION proportion) noexcept {
|
||||
for (size_t stop = 0; stop < stops.size() - 1; stop++) {
|
||||
// Loop through each pair of stops
|
||||
const XYPOSITION positionStart = stops[stop].position;
|
||||
const XYPOSITION positionEnd = stops[stop + 1].position;
|
||||
if ((proportion >= positionStart) && (proportion <= positionEnd)) {
|
||||
const XYPOSITION proportionInPair = (proportion - positionStart) /
|
||||
(positionEnd - positionStart);
|
||||
return stops[stop].colour.MixedWith(stops[stop + 1].colour, proportionInPair);
|
||||
}
|
||||
}
|
||||
// Loop should always find a value
|
||||
return ColourRGBA();
|
||||
}
|
||||
|
||||
constexpr DWORD dwordFromBGRA(byte b, byte g, byte r, byte a) noexcept {
|
||||
constexpr int aShift = 24;
|
||||
constexpr int rShift = 16;
|
||||
constexpr int gShift = 8;
|
||||
return (a << aShift) | (r << rShift) | (g << gShift) | b;
|
||||
}
|
||||
|
||||
constexpr byte AlphaScaled(unsigned char component, unsigned int alpha) noexcept {
|
||||
constexpr byte maxByte = 0xFFU;
|
||||
return (component * alpha / maxByte) & maxByte;
|
||||
}
|
||||
|
||||
constexpr DWORD dwordMultiplied(ColourRGBA colour) noexcept {
|
||||
return dwordFromBGRA(
|
||||
AlphaScaled(colour.GetBlue(), colour.GetAlpha()),
|
||||
AlphaScaled(colour.GetGreen(), colour.GetAlpha()),
|
||||
AlphaScaled(colour.GetRed(), colour.GetAlpha()),
|
||||
colour.GetAlpha());
|
||||
}
|
||||
|
||||
constexpr BLENDFUNCTION mergeAlpha = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
|
||||
|
||||
void SurfaceGDI::AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) {
|
||||
// TODO: Implement strokeWidth
|
||||
const RECT rcw = RectFromPRectangle(rc);
|
||||
const SIZE size = SizeOfRect(rcw);
|
||||
|
||||
if (size.cx > 0) {
|
||||
|
||||
DIBSection section(hdc, size);
|
||||
|
||||
if (section) {
|
||||
|
||||
// Ensure not distorted too much by corners when small
|
||||
const LONG corner = std::min(static_cast<LONG>(cornerSize), (std::min(size.cx, size.cy) / 2) - 2);
|
||||
|
||||
constexpr DWORD valEmpty = dwordFromBGRA(0, 0, 0, 0);
|
||||
const DWORD valFill = dwordMultiplied(fillStroke.fill.colour);
|
||||
const DWORD valOutline = dwordMultiplied(fillStroke.stroke.colour);
|
||||
|
||||
// Draw a framed rectangle
|
||||
for (int y = 0; y < size.cy; y++) {
|
||||
for (int x = 0; x < size.cx; x++) {
|
||||
if ((x == 0) || (x == size.cx - 1) || (y == 0) || (y == size.cy - 1)) {
|
||||
section.SetPixel(x, y, valOutline);
|
||||
} else {
|
||||
section.SetPixel(x, y, valFill);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make the corners transparent
|
||||
for (LONG c = 0; c < corner; c++) {
|
||||
for (LONG x = 0; x < c + 1; x++) {
|
||||
section.SetSymmetric(x, c - x, valEmpty);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the corner frame pieces
|
||||
for (LONG x = 1; x < corner; x++) {
|
||||
section.SetSymmetric(x, corner - x, valOutline);
|
||||
}
|
||||
|
||||
GdiAlphaBlend(hdc, rcw.left, rcw.top, size.cx, size.cy, section.DC(), 0, 0, size.cx, size.cy, mergeAlpha);
|
||||
}
|
||||
} else {
|
||||
BrushColour(fillStroke.stroke.colour);
|
||||
FrameRect(hdc, &rcw, brush);
|
||||
}
|
||||
}
|
||||
|
||||
void SurfaceGDI::GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) {
|
||||
|
||||
const RECT rcw = RectFromPRectangle(rc);
|
||||
const SIZE size = SizeOfRect(rcw);
|
||||
|
||||
DIBSection section(hdc, size);
|
||||
|
||||
if (section) {
|
||||
|
||||
if (options == GradientOptions::topToBottom) {
|
||||
for (LONG y = 0; y < size.cy; y++) {
|
||||
// Find y/height proportional colour
|
||||
const XYPOSITION proportion = y / (rc.Height() - 1.0f);
|
||||
const ColourRGBA mixed = GradientValue(stops, proportion);
|
||||
const DWORD valFill = dwordMultiplied(mixed);
|
||||
for (LONG x = 0; x < size.cx; x++) {
|
||||
section.SetPixel(x, y, valFill);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (LONG x = 0; x < size.cx; x++) {
|
||||
// Find x/width proportional colour
|
||||
const XYPOSITION proportion = x / (rc.Width() - 1.0f);
|
||||
const ColourRGBA mixed = GradientValue(stops, proportion);
|
||||
const DWORD valFill = dwordMultiplied(mixed);
|
||||
for (LONG y = 0; y < size.cy; y++) {
|
||||
section.SetPixel(x, y, valFill);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GdiAlphaBlend(hdc, rcw.left, rcw.top, size.cx, size.cy, section.DC(), 0, 0, size.cx, size.cy, mergeAlpha);
|
||||
}
|
||||
}
|
||||
|
||||
void SurfaceGDI::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) {
|
||||
if (rc.Width() > 0) {
|
||||
if (rc.Width() > width)
|
||||
rc.left += std::floor((rc.Width() - width) / 2);
|
||||
rc.right = rc.left + width;
|
||||
if (rc.Height() > height)
|
||||
rc.top += std::floor((rc.Height() - height) / 2);
|
||||
rc.bottom = rc.top + height;
|
||||
|
||||
const SIZE size{ width, height };
|
||||
DIBSection section(hdc, size);
|
||||
if (section) {
|
||||
RGBAImage::BGRAFromRGBA(section.Bytes(), pixelsImage, static_cast<size_t>(width) * height);
|
||||
GdiAlphaBlend(hdc, static_cast<int>(rc.left), static_cast<int>(rc.top),
|
||||
static_cast<int>(rc.Width()), static_cast<int>(rc.Height()), section.DC(),
|
||||
0, 0, width, height, mergeAlpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SurfaceGDI::Ellipse(PRectangle rc, FillStroke fillStroke) {
|
||||
PenColour(fillStroke.stroke.colour, fillStroke.stroke.width);
|
||||
BrushColour(fillStroke.fill.colour);
|
||||
const RECT rcw = RectFromPRectangle(rc);
|
||||
::Ellipse(hdc, rcw.left, rcw.top, rcw.right, rcw.bottom);
|
||||
}
|
||||
|
||||
void SurfaceGDI::Stadium(PRectangle rc, FillStroke fillStroke, [[maybe_unused]] Ends ends) {
|
||||
// TODO: Implement properly - the rectangle is just a placeholder
|
||||
RectangleDraw(rc, fillStroke);
|
||||
}
|
||||
|
||||
void SurfaceGDI::Copy(PRectangle rc, Point from, Surface &surfaceSource) {
|
||||
::BitBlt(hdc,
|
||||
static_cast<int>(rc.left), static_cast<int>(rc.top),
|
||||
static_cast<int>(rc.Width()), static_cast<int>(rc.Height()),
|
||||
dynamic_cast<SurfaceGDI &>(surfaceSource).hdc,
|
||||
static_cast<int>(from.x), static_cast<int>(from.y), SRCCOPY);
|
||||
}
|
||||
|
||||
std::unique_ptr<IScreenLineLayout> SurfaceGDI::Layout(const IScreenLine *) {
|
||||
return {};
|
||||
}
|
||||
|
||||
using TextPositionsI = VarBuffer<int, stackBufferLength>;
|
||||
|
||||
void SurfaceGDI::DrawTextCommon(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, UINT fuOptions) {
|
||||
SetFont(font_);
|
||||
const RECT rcw = RectFromPRectangle(rc);
|
||||
const int x = static_cast<int>(rc.left);
|
||||
const int yBaseInt = static_cast<int>(ybase);
|
||||
|
||||
if (mode.codePage == CpUtf8) {
|
||||
const TextWide tbuf(text, mode.codePage);
|
||||
::ExtTextOutW(hdc, x, yBaseInt, fuOptions, &rcw, tbuf.buffer, tbuf.tlen, nullptr);
|
||||
} else {
|
||||
::ExtTextOutA(hdc, x, yBaseInt, fuOptions, &rcw, text.data(), static_cast<UINT>(text.length()), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void SurfaceGDI::DrawTextNoClip(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
|
||||
ColourRGBA fore, ColourRGBA back) {
|
||||
::SetTextColor(hdc, fore.OpaqueRGB());
|
||||
::SetBkColor(hdc, back.OpaqueRGB());
|
||||
DrawTextCommon(rc, font_, ybase, text, ETO_OPAQUE);
|
||||
}
|
||||
|
||||
void SurfaceGDI::DrawTextClipped(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
|
||||
ColourRGBA fore, ColourRGBA back) {
|
||||
::SetTextColor(hdc, fore.OpaqueRGB());
|
||||
::SetBkColor(hdc, back.OpaqueRGB());
|
||||
DrawTextCommon(rc, font_, ybase, text, ETO_OPAQUE | ETO_CLIPPED);
|
||||
}
|
||||
|
||||
void SurfaceGDI::DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
|
||||
ColourRGBA fore) {
|
||||
// Avoid drawing spaces in transparent mode
|
||||
for (const char ch : text) {
|
||||
if (ch != ' ') {
|
||||
::SetTextColor(hdc, fore.OpaqueRGB());
|
||||
::SetBkMode(hdc, TRANSPARENT);
|
||||
DrawTextCommon(rc, font_, ybase, text, 0);
|
||||
::SetBkMode(hdc, OPAQUE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SurfaceGDI::MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) {
|
||||
// Zero positions to avoid random behaviour on failure.
|
||||
std::fill(positions, positions + text.length(), 0.0f);
|
||||
SetFont(font_);
|
||||
SIZE sz = { 0,0 };
|
||||
int fit = 0;
|
||||
int i = 0;
|
||||
const int len = static_cast<int>(text.length());
|
||||
if (mode.codePage == CpUtf8) {
|
||||
const TextWide tbuf(text, mode.codePage);
|
||||
TextPositionsI poses(tbuf.tlen);
|
||||
if (!::GetTextExtentExPointW(hdc, tbuf.buffer, tbuf.tlen, maxWidthMeasure, &fit, poses.buffer, &sz)) {
|
||||
// Failure
|
||||
return;
|
||||
}
|
||||
// Map the widths given for UTF-16 characters back onto the UTF-8 input string
|
||||
for (int ui = 0; ui < fit; ui++) {
|
||||
const unsigned char uch = text[i];
|
||||
const unsigned int byteCount = UTF8BytesOfLead[uch];
|
||||
if (byteCount == 4) { // Non-BMP
|
||||
ui++;
|
||||
}
|
||||
for (unsigned int bytePos = 0; (bytePos < byteCount) && (i < len); bytePos++) {
|
||||
positions[i++] = static_cast<XYPOSITION>(poses.buffer[ui]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TextPositionsI poses(len);
|
||||
if (!::GetTextExtentExPointA(hdc, text.data(), len, maxWidthMeasure, &fit, poses.buffer, &sz)) {
|
||||
// Eeek - a NULL DC or other foolishness could cause this.
|
||||
return;
|
||||
}
|
||||
while (i < fit) {
|
||||
positions[i] = static_cast<XYPOSITION>(poses.buffer[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
// If any positions not filled in then use the last position for them
|
||||
const XYPOSITION lastPos = (fit > 0) ? positions[fit - 1] : 0.0f;
|
||||
std::fill(positions + i, positions + text.length(), lastPos);
|
||||
}
|
||||
|
||||
XYPOSITION SurfaceGDI::WidthText(const Font *font_, std::string_view text) {
|
||||
SetFont(font_);
|
||||
SIZE sz = { 0,0 };
|
||||
if (!(mode.codePage == CpUtf8)) {
|
||||
::GetTextExtentPoint32A(hdc, text.data(), std::min(static_cast<int>(text.length()), maxLenText), &sz);
|
||||
} else {
|
||||
const TextWide tbuf(text, mode.codePage);
|
||||
::GetTextExtentPoint32W(hdc, tbuf.buffer, tbuf.tlen, &sz);
|
||||
}
|
||||
return static_cast<XYPOSITION>(sz.cx);
|
||||
}
|
||||
|
||||
void SurfaceGDI::DrawTextCommonUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, UINT fuOptions) {
|
||||
SetFont(font_);
|
||||
const RECT rcw = RectFromPRectangle(rc);
|
||||
const int x = static_cast<int>(rc.left);
|
||||
const int yBaseInt = static_cast<int>(ybase);
|
||||
|
||||
const TextWide tbuf(text, CpUtf8);
|
||||
::ExtTextOutW(hdc, x, yBaseInt, fuOptions, &rcw, tbuf.buffer, tbuf.tlen, nullptr);
|
||||
}
|
||||
|
||||
void SurfaceGDI::DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
|
||||
ColourRGBA fore, ColourRGBA back) {
|
||||
::SetTextColor(hdc, fore.OpaqueRGB());
|
||||
::SetBkColor(hdc, back.OpaqueRGB());
|
||||
DrawTextCommonUTF8(rc, font_, ybase, text, ETO_OPAQUE);
|
||||
}
|
||||
|
||||
void SurfaceGDI::DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
|
||||
ColourRGBA fore, ColourRGBA back) {
|
||||
::SetTextColor(hdc, fore.OpaqueRGB());
|
||||
::SetBkColor(hdc, back.OpaqueRGB());
|
||||
DrawTextCommonUTF8(rc, font_, ybase, text, ETO_OPAQUE | ETO_CLIPPED);
|
||||
}
|
||||
|
||||
void SurfaceGDI::DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
|
||||
ColourRGBA fore) {
|
||||
// Avoid drawing spaces in transparent mode
|
||||
for (const char ch : text) {
|
||||
if (ch != ' ') {
|
||||
::SetTextColor(hdc, fore.OpaqueRGB());
|
||||
::SetBkMode(hdc, TRANSPARENT);
|
||||
DrawTextCommonUTF8(rc, font_, ybase, text, 0);
|
||||
::SetBkMode(hdc, OPAQUE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SurfaceGDI::MeasureWidthsUTF8(const Font *font_, std::string_view text, XYPOSITION *positions) {
|
||||
// Zero positions to avoid random behaviour on failure.
|
||||
std::fill(positions, positions + text.length(), 0.0f);
|
||||
SetFont(font_);
|
||||
SIZE sz = { 0,0 };
|
||||
int fit = 0;
|
||||
int i = 0;
|
||||
const int len = static_cast<int>(text.length());
|
||||
const TextWide tbuf(text, CpUtf8);
|
||||
TextPositionsI poses(tbuf.tlen);
|
||||
if (!::GetTextExtentExPointW(hdc, tbuf.buffer, tbuf.tlen, maxWidthMeasure, &fit, poses.buffer, &sz)) {
|
||||
// Failure
|
||||
return;
|
||||
}
|
||||
// Map the widths given for UTF-16 characters back onto the UTF-8 input string
|
||||
for (int ui = 0; ui < fit; ui++) {
|
||||
const unsigned char uch = text[i];
|
||||
const unsigned int byteCount = UTF8BytesOfLead[uch];
|
||||
if (byteCount == 4) { // Non-BMP
|
||||
ui++;
|
||||
}
|
||||
for (unsigned int bytePos = 0; (bytePos < byteCount) && (i < len); bytePos++) {
|
||||
positions[i++] = static_cast<XYPOSITION>(poses.buffer[ui]);
|
||||
}
|
||||
}
|
||||
// If any positions not filled in then use the last position for them
|
||||
const XYPOSITION lastPos = (fit > 0) ? positions[fit - 1] : 0.0f;
|
||||
std::fill(positions + i, positions + text.length(), lastPos);
|
||||
}
|
||||
|
||||
XYPOSITION SurfaceGDI::WidthTextUTF8(const Font *font_, std::string_view text) {
|
||||
SetFont(font_);
|
||||
SIZE sz = { 0,0 };
|
||||
const TextWide tbuf(text, CpUtf8);
|
||||
::GetTextExtentPoint32W(hdc, tbuf.buffer, tbuf.tlen, &sz);
|
||||
return static_cast<XYPOSITION>(sz.cx);
|
||||
}
|
||||
|
||||
XYPOSITION SurfaceGDI::Ascent(const Font *font_) {
|
||||
SetFont(font_);
|
||||
TEXTMETRIC tm;
|
||||
::GetTextMetrics(hdc, &tm);
|
||||
return static_cast<XYPOSITION>(tm.tmAscent);
|
||||
}
|
||||
|
||||
XYPOSITION SurfaceGDI::Descent(const Font *font_) {
|
||||
SetFont(font_);
|
||||
TEXTMETRIC tm;
|
||||
::GetTextMetrics(hdc, &tm);
|
||||
return static_cast<XYPOSITION>(tm.tmDescent);
|
||||
}
|
||||
|
||||
XYPOSITION SurfaceGDI::InternalLeading(const Font *font_) {
|
||||
SetFont(font_);
|
||||
TEXTMETRIC tm;
|
||||
::GetTextMetrics(hdc, &tm);
|
||||
return static_cast<XYPOSITION>(tm.tmInternalLeading);
|
||||
}
|
||||
|
||||
XYPOSITION SurfaceGDI::Height(const Font *font_) {
|
||||
SetFont(font_);
|
||||
TEXTMETRIC tm;
|
||||
::GetTextMetrics(hdc, &tm);
|
||||
return static_cast<XYPOSITION>(tm.tmHeight);
|
||||
}
|
||||
|
||||
XYPOSITION SurfaceGDI::AverageCharWidth(const Font *font_) {
|
||||
SetFont(font_);
|
||||
TEXTMETRIC tm;
|
||||
::GetTextMetrics(hdc, &tm);
|
||||
return static_cast<XYPOSITION>(tm.tmAveCharWidth);
|
||||
}
|
||||
|
||||
void SurfaceGDI::SetClip(PRectangle rc) {
|
||||
::SaveDC(hdc);
|
||||
::IntersectClipRect(hdc, static_cast<int>(rc.left), static_cast<int>(rc.top),
|
||||
static_cast<int>(rc.right), static_cast<int>(rc.bottom));
|
||||
}
|
||||
|
||||
void SurfaceGDI::PopClip() {
|
||||
::RestoreDC(hdc, -1);
|
||||
}
|
||||
|
||||
void SurfaceGDI::FlushCachedState() {
|
||||
pen = {};
|
||||
brush = {};
|
||||
}
|
||||
|
||||
void SurfaceGDI::FlushDrawing() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Scintilla::Internal {
|
||||
|
||||
std::shared_ptr<Font> FontGDI_Allocate(const FontParameters &fp) {
|
||||
return std::make_shared<FontGDI>(fp);
|
||||
}
|
||||
|
||||
std::unique_ptr<Surface> SurfaceGDI_Allocate() {
|
||||
return std::make_unique<SurfaceGDI>();
|
||||
}
|
||||
|
||||
}
|
18
scintilla/win32/SurfaceGDI.h
Normal file
18
scintilla/win32/SurfaceGDI.h
Normal file
@ -0,0 +1,18 @@
|
||||
// Scintilla source code edit control
|
||||
/** @file SurfaceGDI.h
|
||||
** Definitions for drawing to GDI on Windows.
|
||||
**/
|
||||
// Copyright 2025 by Neil Hodgson <neilh@scintilla.org>
|
||||
// The License.txt file describes the conditions under which this software may be distributed.
|
||||
|
||||
#ifndef SURFACEGDI_H
|
||||
#define SURFACEGDI_H
|
||||
|
||||
namespace Scintilla::Internal {
|
||||
|
||||
std::shared_ptr<Font> FontGDI_Allocate(const FontParameters &fp);
|
||||
std::unique_ptr<Surface> SurfaceGDI_Allocate();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -52,6 +52,13 @@ inline T DLLFunction(HMODULE hModule, LPCSTR lpProcName) noexcept {
|
||||
return fp;
|
||||
}
|
||||
|
||||
inline void ReleaseLibrary(HMODULE &hLib) noexcept {
|
||||
if (hLib) {
|
||||
FreeLibrary(hLib);
|
||||
hLib = {};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -3,6 +3,19 @@ $(DIR_O)/HanjaDic.o: \
|
||||
HanjaDic.cxx \
|
||||
WinTypes.h \
|
||||
HanjaDic.h
|
||||
$(DIR_O)/ListBox.o: \
|
||||
ListBox.cxx \
|
||||
../include/ScintillaTypes.h \
|
||||
../src/Debugging.h \
|
||||
../src/Geometry.h \
|
||||
../src/Platform.h \
|
||||
../src/XPM.h \
|
||||
../src/UniConversion.h \
|
||||
../src/DBCS.h \
|
||||
WinTypes.h \
|
||||
PlatWin.h \
|
||||
ListBox.h \
|
||||
SurfaceD2D.h
|
||||
$(DIR_O)/PlatWin.o: \
|
||||
PlatWin.cxx \
|
||||
../include/ScintillaTypes.h \
|
||||
@ -13,7 +26,9 @@ $(DIR_O)/PlatWin.o: \
|
||||
../src/UniConversion.h \
|
||||
../src/DBCS.h \
|
||||
WinTypes.h \
|
||||
PlatWin.h
|
||||
PlatWin.h \
|
||||
ListBox.h \
|
||||
SurfaceD2D.h
|
||||
$(DIR_O)/ScintillaDLL.o: \
|
||||
ScintillaDLL.cxx \
|
||||
../include/ScintillaTypes.h \
|
||||
@ -29,6 +44,7 @@ $(DIR_O)/ScintillaWin.o: \
|
||||
../src/Debugging.h \
|
||||
../src/Geometry.h \
|
||||
../src/Platform.h \
|
||||
../src/CharacterType.h \
|
||||
../src/CharacterCategoryMap.h \
|
||||
../src/Position.h \
|
||||
../src/UniqueString.h \
|
||||
@ -49,6 +65,7 @@ $(DIR_O)/ScintillaWin.o: \
|
||||
../src/Document.h \
|
||||
../src/CaseConvert.h \
|
||||
../src/UniConversion.h \
|
||||
../src/DBCS.h \
|
||||
../src/Selection.h \
|
||||
../src/PositionCache.h \
|
||||
../src/EditModel.h \
|
||||
@ -60,8 +77,34 @@ $(DIR_O)/ScintillaWin.o: \
|
||||
../src/ScintillaBase.h \
|
||||
WinTypes.h \
|
||||
PlatWin.h \
|
||||
SurfaceD2D.h \
|
||||
HanjaDic.h \
|
||||
ScintillaWin.h
|
||||
$(DIR_O)/SurfaceD2D.o: \
|
||||
SurfaceD2D.cxx \
|
||||
../include/ScintillaTypes.h \
|
||||
../src/Debugging.h \
|
||||
../src/Geometry.h \
|
||||
../src/Platform.h \
|
||||
../src/XPM.h \
|
||||
../src/UniConversion.h \
|
||||
../src/DBCS.h \
|
||||
WinTypes.h \
|
||||
PlatWin.h \
|
||||
SurfaceGDI.h \
|
||||
SurfaceD2D.h
|
||||
$(DIR_O)/SurfaceGDI.o: \
|
||||
SurfaceGDI.cxx \
|
||||
../include/ScintillaTypes.h \
|
||||
../src/Debugging.h \
|
||||
../src/Geometry.h \
|
||||
../src/Platform.h \
|
||||
../src/XPM.h \
|
||||
../src/UniConversion.h \
|
||||
../src/DBCS.h \
|
||||
WinTypes.h \
|
||||
PlatWin.h \
|
||||
SurfaceGDI.h
|
||||
$(DIR_O)/AutoComplete.o: \
|
||||
../src/AutoComplete.cxx \
|
||||
../include/ScintillaTypes.h \
|
||||
|
@ -118,6 +118,9 @@ COMPONENT_OBJS = \
|
||||
$(SRC_OBJS) \
|
||||
$(DIR_O)/HanjaDic.o \
|
||||
$(DIR_O)/PlatWin.o \
|
||||
$(DIR_O)/ListBox.o \
|
||||
$(DIR_O)/SurfaceGDI.o \
|
||||
$(DIR_O)/SurfaceD2D.o \
|
||||
$(DIR_O)/ScintillaBase.o \
|
||||
$(DIR_O)/ScintillaWin.o
|
||||
|
||||
|
@ -3,6 +3,19 @@ $(DIR_O)/HanjaDic.obj: \
|
||||
HanjaDic.cxx \
|
||||
WinTypes.h \
|
||||
HanjaDic.h
|
||||
$(DIR_O)/ListBox.obj: \
|
||||
ListBox.cxx \
|
||||
../include/ScintillaTypes.h \
|
||||
../src/Debugging.h \
|
||||
../src/Geometry.h \
|
||||
../src/Platform.h \
|
||||
../src/XPM.h \
|
||||
../src/UniConversion.h \
|
||||
../src/DBCS.h \
|
||||
WinTypes.h \
|
||||
PlatWin.h \
|
||||
ListBox.h \
|
||||
SurfaceD2D.h
|
||||
$(DIR_O)/PlatWin.obj: \
|
||||
PlatWin.cxx \
|
||||
../include/ScintillaTypes.h \
|
||||
@ -13,7 +26,9 @@ $(DIR_O)/PlatWin.obj: \
|
||||
../src/UniConversion.h \
|
||||
../src/DBCS.h \
|
||||
WinTypes.h \
|
||||
PlatWin.h
|
||||
PlatWin.h \
|
||||
ListBox.h \
|
||||
SurfaceD2D.h
|
||||
$(DIR_O)/ScintillaDLL.obj: \
|
||||
ScintillaDLL.cxx \
|
||||
../include/ScintillaTypes.h \
|
||||
@ -29,6 +44,7 @@ $(DIR_O)/ScintillaWin.obj: \
|
||||
../src/Debugging.h \
|
||||
../src/Geometry.h \
|
||||
../src/Platform.h \
|
||||
../src/CharacterType.h \
|
||||
../src/CharacterCategoryMap.h \
|
||||
../src/Position.h \
|
||||
../src/UniqueString.h \
|
||||
@ -49,6 +65,7 @@ $(DIR_O)/ScintillaWin.obj: \
|
||||
../src/Document.h \
|
||||
../src/CaseConvert.h \
|
||||
../src/UniConversion.h \
|
||||
../src/DBCS.h \
|
||||
../src/Selection.h \
|
||||
../src/PositionCache.h \
|
||||
../src/EditModel.h \
|
||||
@ -60,8 +77,34 @@ $(DIR_O)/ScintillaWin.obj: \
|
||||
../src/ScintillaBase.h \
|
||||
WinTypes.h \
|
||||
PlatWin.h \
|
||||
SurfaceD2D.h \
|
||||
HanjaDic.h \
|
||||
ScintillaWin.h
|
||||
$(DIR_O)/SurfaceD2D.obj: \
|
||||
SurfaceD2D.cxx \
|
||||
../include/ScintillaTypes.h \
|
||||
../src/Debugging.h \
|
||||
../src/Geometry.h \
|
||||
../src/Platform.h \
|
||||
../src/XPM.h \
|
||||
../src/UniConversion.h \
|
||||
../src/DBCS.h \
|
||||
WinTypes.h \
|
||||
PlatWin.h \
|
||||
SurfaceGDI.h \
|
||||
SurfaceD2D.h
|
||||
$(DIR_O)/SurfaceGDI.obj: \
|
||||
SurfaceGDI.cxx \
|
||||
../include/ScintillaTypes.h \
|
||||
../src/Debugging.h \
|
||||
../src/Geometry.h \
|
||||
../src/Platform.h \
|
||||
../src/XPM.h \
|
||||
../src/UniConversion.h \
|
||||
../src/DBCS.h \
|
||||
WinTypes.h \
|
||||
PlatWin.h \
|
||||
SurfaceGDI.h
|
||||
$(DIR_O)/AutoComplete.obj: \
|
||||
../src/AutoComplete.cxx \
|
||||
../include/ScintillaTypes.h \
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
.SUFFIXES: .cxx
|
||||
|
||||
DIR_O=.
|
||||
DIR_O=obj
|
||||
DIR_BIN=..\bin
|
||||
|
||||
COMPONENT=$(DIR_BIN)\Scintilla.dll
|
||||
@ -18,6 +18,10 @@ LIBSCI=$(DIR_BIN)\libscintilla.lib
|
||||
|
||||
LD=link
|
||||
|
||||
!IF "$(PLATFORM:64=)" == "arm"
|
||||
ARM64=1
|
||||
!ENDIF
|
||||
|
||||
!IFDEF SUPPORT_XP
|
||||
ADD_DEFINE=-D_USING_V110_SDK71_
|
||||
# Different subsystems for 32-bit and 64-bit Windows XP so detect based on Platform
|
||||
@ -28,10 +32,11 @@ SUBSYSTEM=-SUBSYSTEM:WINDOWS,5.02
|
||||
SUBSYSTEM=-SUBSYSTEM:WINDOWS,5.01
|
||||
!ENDIF
|
||||
!ELSE
|
||||
CETCOMPAT=-CETCOMPAT
|
||||
!IFDEF ARM64
|
||||
ADD_DEFINE=-D_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1
|
||||
SUBSYSTEM=-SUBSYSTEM:WINDOWS,10.00
|
||||
!ELSE
|
||||
CETCOMPAT=-CETCOMPAT
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
@ -65,7 +70,10 @@ CXXFLAGS=$(CXXFLAGS) $(CXXNDEBUG)
|
||||
INCLUDES=-I../include -I../src
|
||||
CXXFLAGS=$(CXXFLAGS) $(INCLUDES)
|
||||
|
||||
all: $(COMPONENT) $(LIBSCI)
|
||||
all: $(DIR_O) $(COMPONENT) $(LIBSCI)
|
||||
|
||||
$(DIR_O):
|
||||
mkdir "$(DIR_O)" 2>NUL || cd .
|
||||
|
||||
clean:
|
||||
-del /q $(DIR_O)\*.obj $(DIR_O)\*.pdb $(DIR_O)\*.asm $(COMPONENT) \
|
||||
@ -117,6 +125,9 @@ SRC_OBJS=\
|
||||
COMPONENT_OBJS = \
|
||||
$(DIR_O)\HanjaDic.obj \
|
||||
$(DIR_O)\PlatWin.obj \
|
||||
$(DIR_O)\ListBox.obj \
|
||||
$(DIR_O)\SurfaceGDI.obj \
|
||||
$(DIR_O)\SurfaceD2D.obj \
|
||||
$(DIR_O)\ScintillaBase.obj \
|
||||
$(DIR_O)\ScintillaWin.obj \
|
||||
$(SRC_OBJS)
|
||||
|
Loading…
x
Reference in New Issue
Block a user