mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-30 17:24:54 +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)
|
for (const auto& i : udlFiles)
|
||||||
{
|
{
|
||||||
auto udlDoc = new TiXmlDocument(i);
|
TiXmlDocument* udlDoc = new TiXmlDocument(i);
|
||||||
loadOkay = udlDoc->LoadFile();
|
loadOkay = udlDoc->LoadFile();
|
||||||
if (!loadOkay)
|
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]
|
on: [push]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
# Compile for amd64 and cross-compile for arm64. Tests run only for amd64.
|
||||||
build:
|
build:
|
||||||
|
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
arch:
|
||||||
|
- amd64
|
||||||
|
- amd64_arm64
|
||||||
|
env:
|
||||||
|
TEST: ${{ matrix.arch == 'amd64' && 'test' || '' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Preparing nmake
|
- name: Preparing nmake
|
||||||
uses: ilammy/msvc-dev-cmd@v1
|
uses: ilammy/msvc-dev-cmd@v1
|
||||||
with:
|
with:
|
||||||
arch: x64
|
arch: ${{ matrix.arch }}
|
||||||
- name: Install Scintilla source
|
- name: Install Scintilla source
|
||||||
run: |
|
run: |
|
||||||
pwd
|
pwd
|
||||||
@ -24,7 +32,7 @@ jobs:
|
|||||||
- name: Unit Test
|
- name: Unit Test
|
||||||
run: |
|
run: |
|
||||||
cd test/unit
|
cd test/unit
|
||||||
nmake -f test.mak DEBUG=1 test
|
nmake -f test.mak DEBUG=1 $env:TEST
|
||||||
cd ../..
|
cd ../..
|
||||||
- name: Build Lexilla
|
- name: Build Lexilla
|
||||||
run: |
|
run: |
|
||||||
@ -33,14 +41,15 @@ jobs:
|
|||||||
cd ..
|
cd ..
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: lexilla.dll
|
name: lexilla${{ matrix.arch == 'amd64_arm64' && '-arm64' || '' }}.dll
|
||||||
path: bin/lexilla.dll
|
path: bin/lexilla.dll
|
||||||
- name: Test lexing and folding
|
- name: Test lexing and folding
|
||||||
run: |
|
run: |
|
||||||
cd test
|
cd test
|
||||||
nmake -f testlexers.mak DEBUG=1 test
|
nmake -f testlexers.mak DEBUG=1 $env:TEST
|
||||||
cd ..
|
cd ..
|
||||||
- name: CheckLexilla C Example
|
- name: CheckLexilla C Example
|
||||||
|
if: matrix.arch == 'amd64'
|
||||||
run: |
|
run: |
|
||||||
cd examples/CheckLexilla
|
cd examples/CheckLexilla
|
||||||
cl -MP CheckLexilla.c -I ../../include -Fe: CheckLexilla
|
cl -MP CheckLexilla.c -I ../../include -Fe: CheckLexilla
|
||||||
|
@ -30,12 +30,12 @@
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
typedef FARPROC Function;
|
using Function = FARPROC;
|
||||||
typedef HMODULE Module;
|
using Module = HMODULE;
|
||||||
constexpr const char *pathSeparator = "\\";
|
constexpr const char *pathSeparator = "\\";
|
||||||
#else
|
#else
|
||||||
typedef void *Function;
|
using Function = void *;
|
||||||
typedef void *Module;
|
using Module = void *;
|
||||||
constexpr const char *pathSeparator = "/";
|
constexpr const char *pathSeparator = "/";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -164,9 +164,10 @@ bool Lexilla::Load(std::string_view sharedLibraryPaths) {
|
|||||||
if (fnLexerCount && fnLexerName) {
|
if (fnLexerCount && fnLexerName) {
|
||||||
const int nLexers = fnLexerCount();
|
const int nLexers = fnLexerCount();
|
||||||
for (int i = 0; i < nLexers; i++) {
|
for (int i = 0; i < nLexers; i++) {
|
||||||
char name[100] = "";
|
constexpr size_t lengthName = 200;
|
||||||
|
char name[lengthName]{};
|
||||||
fnLexerName(i, name, sizeof(name));
|
fnLexerName(i, name, sizeof(name));
|
||||||
lexers.push_back(name);
|
lexers.emplace_back(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CreateLexerFn fnCL = FunctionPointer<CreateLexerFn>(
|
CreateLexerFn fnCL = FunctionPointer<CreateLexerFn>(
|
||||||
@ -268,7 +269,7 @@ std::string Lexilla::NameFromID(int identifier) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::string();
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> Lexilla::LibraryProperties() {
|
std::vector<std::string> Lexilla::LibraryProperties() {
|
||||||
|
@ -70,12 +70,14 @@ variableScope:lexilla/lexers/LexCmake.cxx
|
|||||||
knownConditionTrueFalse:lexilla/lexers/LexCmake.cxx
|
knownConditionTrueFalse:lexilla/lexers/LexCmake.cxx
|
||||||
constParameterReference:lexilla/lexers/LexCmake.cxx
|
constParameterReference:lexilla/lexers/LexCmake.cxx
|
||||||
constParameterReference:lexilla/lexers/LexCOBOL.cxx
|
constParameterReference:lexilla/lexers/LexCOBOL.cxx
|
||||||
|
constVariablePointer:lexilla/lexers/LexCOBOL.cxx
|
||||||
constParameterReference:lexilla/lexers/LexCoffeeScript.cxx
|
constParameterReference:lexilla/lexers/LexCoffeeScript.cxx
|
||||||
constParameterPointer:lexilla/lexers/LexCoffeeScript.cxx
|
constParameterPointer:lexilla/lexers/LexCoffeeScript.cxx
|
||||||
knownConditionTrueFalse:lexilla/lexers/LexCoffeeScript.cxx
|
knownConditionTrueFalse:lexilla/lexers/LexCoffeeScript.cxx
|
||||||
constVariableReference:lexilla/lexers/LexConf.cxx
|
constVariableReference:lexilla/lexers/LexConf.cxx
|
||||||
constParameterReference:lexilla/lexers/LexCPP.cxx
|
constParameterReference:lexilla/lexers/LexCPP.cxx
|
||||||
variableScope:lexilla/lexers/LexCSS.cxx
|
variableScope:lexilla/lexers/LexCSS.cxx
|
||||||
|
constVariablePointer:lexilla/lexers/LexCSS.cxx
|
||||||
knownConditionTrueFalse:lexilla/lexers/LexDataflex.cxx
|
knownConditionTrueFalse:lexilla/lexers/LexDataflex.cxx
|
||||||
constParameterReference:lexilla/lexers/LexDataflex.cxx
|
constParameterReference:lexilla/lexers/LexDataflex.cxx
|
||||||
variableScope: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/LexMatlab.cxx
|
||||||
variableScope:lexilla/lexers/LexMetapost.cxx
|
variableScope:lexilla/lexers/LexMetapost.cxx
|
||||||
constParameterReference:lexilla/lexers/LexModula.cxx
|
constParameterReference:lexilla/lexers/LexModula.cxx
|
||||||
|
duplicateBreak:lexilla/lexers/LexModula.cxx
|
||||||
variableScope:lexilla/lexers/LexModula.cxx
|
variableScope:lexilla/lexers/LexModula.cxx
|
||||||
constParameterReference:lexilla/lexers/LexMPT.cxx
|
constParameterReference:lexilla/lexers/LexMPT.cxx
|
||||||
variableScope:lexilla/lexers/LexMSSQL.cxx
|
variableScope:lexilla/lexers/LexMSSQL.cxx
|
||||||
@ -140,6 +143,7 @@ constVariableReference:lexilla/lexers/LexPerl.cxx
|
|||||||
knownConditionTrueFalse:lexilla/lexers/LexPerl.cxx
|
knownConditionTrueFalse:lexilla/lexers/LexPerl.cxx
|
||||||
constParameterReference:lexilla/lexers/LexPLM.cxx
|
constParameterReference:lexilla/lexers/LexPLM.cxx
|
||||||
constParameterReference:lexilla/lexers/LexPO.cxx
|
constParameterReference:lexilla/lexers/LexPO.cxx
|
||||||
|
constVariablePointer:lexilla/lexers/LexPOV.cxx
|
||||||
constParameterReference:lexilla/lexers/LexPython.cxx
|
constParameterReference:lexilla/lexers/LexPython.cxx
|
||||||
shadowVariable:lexilla/lexers/LexPowerPro.cxx
|
shadowVariable:lexilla/lexers/LexPowerPro.cxx
|
||||||
knownConditionTrueFalse:lexilla/lexers/LexPowerPro.cxx
|
knownConditionTrueFalse:lexilla/lexers/LexPowerPro.cxx
|
||||||
@ -188,7 +192,6 @@ constVariableReference:lexilla/lexers/LexX12.cxx
|
|||||||
constParameterPointer:lexilla/lexers/LexX12.cxx
|
constParameterPointer:lexilla/lexers/LexX12.cxx
|
||||||
uselessCallsSubstr:lexilla/lexers/LexX12.cxx
|
uselessCallsSubstr:lexilla/lexers/LexX12.cxx
|
||||||
constParameterReference:lexilla/lexers/LexYAML.cxx
|
constParameterReference:lexilla/lexers/LexYAML.cxx
|
||||||
constParameterPointer:lexilla/lexers/LexYAML.cxx
|
|
||||||
knownConditionTrueFalse:lexilla/lexers/LexYAML.cxx
|
knownConditionTrueFalse:lexilla/lexers/LexYAML.cxx
|
||||||
|
|
||||||
// These are due to Accessor::IndentAmount not declaring the callback as taking a const.
|
// 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="keywords" content="Scintilla, SciTE, Editing Component, Text Editor" />
|
||||||
<meta name="Description"
|
<meta name="Description"
|
||||||
content="www.scintilla.org is the home of the Scintilla editing component and SciTE text editor application." />
|
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" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
.logo {
|
.logo {
|
||||||
@ -51,6 +51,7 @@
|
|||||||
<title>
|
<title>
|
||||||
Lexilla
|
Lexilla
|
||||||
</title>
|
</title>
|
||||||
|
<link rel="canonical" href="https://scintilla.org/Lexilla.html" />
|
||||||
</head>
|
</head>
|
||||||
<body bgcolor="#FFFFFF" text="#000000">
|
<body bgcolor="#FFFFFF" text="#000000">
|
||||||
<table bgcolor="#000000" width="100%" cellspacing="0" cellpadding="0" border="0">
|
<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>
|
<font color="#FFCC99" size="4"> A library of language lexers for use with Scintilla</font>
|
||||||
</td>
|
</td>
|
||||||
<td width="40%" align="right">
|
<td width="40%" align="right">
|
||||||
<font color="#FFCC99" size="3">Release version 5.4.3<br />
|
<font color="#FFCC99" size="3">Release version 5.4.4<br />
|
||||||
Site last modified February 25 2025</font>
|
Site last modified April 2 2025</font>
|
||||||
</td>
|
</td>
|
||||||
<td width="20%">
|
<td width="20%">
|
||||||
|
|
||||||
@ -77,11 +78,11 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<ul id="versionlist">
|
<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.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.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.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.4.0 adds a TOML lexer.</li>
|
||||||
<li>Version 5.3.3 improves HTML, JavaScript, Lua, PHP, and XML.</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
<ul id="menu">
|
<ul id="menu">
|
||||||
<li id="remote1"><a href="https://www.scintilla.org/SciTEImage.html">Screenshot</a></li>
|
<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" />
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||||
|
|
||||||
<title>Lexilla Documentation</title>
|
<title>Lexilla Documentation</title>
|
||||||
|
<link rel="canonical" href="https://scintilla.org/LexillaDoc.html" />
|
||||||
|
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
<!--
|
<!--
|
||||||
|
@ -26,9 +26,9 @@
|
|||||||
<table bgcolor="#CCCCCC" width="100%" cellspacing="0" cellpadding="8" border="0">
|
<table bgcolor="#CCCCCC" width="100%" cellspacing="0" cellpadding="8" border="0">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<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>
|
Windows</a>
|
||||||
<a href="https://www.scintilla.org/lexilla543.tgz">
|
<a href="https://www.scintilla.org/lexilla544.tgz">
|
||||||
GTK/Linux</a>
|
GTK/Linux</a>
|
||||||
</font>
|
</font>
|
||||||
</td>
|
</td>
|
||||||
@ -42,7 +42,7 @@
|
|||||||
containing very few restrictions.
|
containing very few restrictions.
|
||||||
</p>
|
</p>
|
||||||
<h3>
|
<h3>
|
||||||
Release 5.4.3
|
Release 5.4.4
|
||||||
</h3>
|
</h3>
|
||||||
<h4>
|
<h4>
|
||||||
Source Code
|
Source Code
|
||||||
@ -50,8 +50,8 @@
|
|||||||
The source code package contains all of the source code for Lexilla but no binary
|
The source code package contains all of the source code for Lexilla but no binary
|
||||||
executable code and is available in
|
executable code and is available in
|
||||||
<ul>
|
<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/lexilla544.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.tgz">tgz format</a> (1.0M) commonly used on Linux and compatible operating systems</li>
|
||||||
</ul>
|
</ul>
|
||||||
Instructions for building on both Windows and Linux are included in the readme file.
|
Instructions for building on both Windows and Linux are included in the readme file.
|
||||||
<h4>
|
<h4>
|
||||||
|
@ -590,9 +590,22 @@
|
|||||||
<td>Henrik S. Johansen</td>
|
<td>Henrik S. Johansen</td>
|
||||||
<td>Ekopalypse</td>
|
<td>Ekopalypse</td>
|
||||||
<td>HoTschir</td>
|
<td>HoTschir</td>
|
||||||
|
<td>Ahmet Sait</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<h2 id="Releases">Releases</h2>
|
<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>
|
<h3>
|
||||||
<a href="https://www.scintilla.org/lexilla543.zip">Release 5.4.3</a>
|
<a href="https://www.scintilla.org/lexilla543.zip">Release 5.4.3</a>
|
||||||
</h3>
|
</h3>
|
||||||
|
@ -109,7 +109,7 @@ constexpr int translateBashDigit(int ch) noexcept {
|
|||||||
return BASH_BASE_ERROR;
|
return BASH_BASE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getBashNumberBase(char *s) noexcept {
|
int getBashNumberBase(const char *s) noexcept {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int base = 0;
|
int base = 0;
|
||||||
while (*s) {
|
while (*s) {
|
||||||
@ -164,7 +164,7 @@ bool IsCommentLine(Sci_Position line, LexAccessor &styler) {
|
|||||||
const char ch = styler[i];
|
const char ch = styler[i];
|
||||||
if (ch == '#')
|
if (ch == '#')
|
||||||
return true;
|
return true;
|
||||||
else if (ch != ' ' && ch != '\t')
|
if (ch != ' ' && ch != '\t')
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -698,7 +698,7 @@ void SCI_METHOD LexerBash::Lex(Sci_PositionU startPos, Sci_Position length, int
|
|||||||
identifierStyle = subStyle | insideCommand;
|
identifierStyle = subStyle | insideCommand;
|
||||||
}
|
}
|
||||||
// allow keywords ending in a whitespace, meta character or command delimiter
|
// 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[0] = static_cast<char>(sc.ch);
|
||||||
s2[1] = '\0';
|
s2[1] = '\0';
|
||||||
const bool keywordEnds = IsASpace(sc.ch) || setMetaCharacter.Contains(sc.ch) || cmdDelimiter.InList(s2);
|
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 '[]'
|
// handle command delimiters in command Start|Body|Word state, also Test if 'test' or '[]'
|
||||||
if (cmdState < CmdState::DoubleBracket) {
|
if (cmdState < CmdState::DoubleBracket) {
|
||||||
char s[10];
|
char s[10]{};
|
||||||
s[0] = static_cast<char>(sc.ch);
|
s[0] = static_cast<char>(sc.ch);
|
||||||
if (setBashOperator.Contains(sc.chNext)) {
|
if (setBashOperator.Contains(sc.chNext)) {
|
||||||
s[1] = static_cast<char>(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';
|
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int SpaceCount(char* lineBuffer) noexcept {
|
unsigned int SpaceCount(const char* lineBuffer) noexcept {
|
||||||
if (lineBuffer == nullptr)
|
if (lineBuffer == nullptr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
char* headBuffer = lineBuffer;
|
const char* headBuffer = lineBuffer;
|
||||||
|
|
||||||
while (*headBuffer == ' ')
|
while (*headBuffer == ' ')
|
||||||
headBuffer++;
|
headBuffer++;
|
||||||
@ -60,10 +60,10 @@ unsigned int SpaceCount(char* lineBuffer) noexcept {
|
|||||||
return static_cast<unsigned int>(headBuffer - lineBuffer);
|
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)
|
if (lineBuffer == nullptr || startComment <= lineBuffer)
|
||||||
return false;
|
return false;
|
||||||
char* endValue = startComment - 1;
|
const char* endValue = startComment - 1;
|
||||||
while (endValue >= lineBuffer && *endValue == ' ')
|
while (endValue >= lineBuffer && *endValue == ' ')
|
||||||
endValue--;
|
endValue--;
|
||||||
Sci_PositionU len = static_cast<Sci_PositionU>(endValue - lineBuffer) + 1;
|
Sci_PositionU len = static_cast<Sci_PositionU>(endValue - lineBuffer) + 1;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>5.4.3</string>
|
<string>5.4.4</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
@ -876,7 +876,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 5.4.3;
|
CURRENT_PROJECT_VERSION = 5.4.4;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEVELOPMENT_TEAM = 4F446KW87E;
|
DEVELOPMENT_TEAM = 4F446KW87E;
|
||||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
@ -904,7 +904,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 5.4.3;
|
CURRENT_PROJECT_VERSION = 5.4.4;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEVELOPMENT_TEAM = 4F446KW87E;
|
DEVELOPMENT_TEAM = 4F446KW87E;
|
||||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#define VERSION_LEXILLA "5.4.3"
|
#define VERSION_LEXILLA "5.4.4"
|
||||||
#define VERSION_WORDS 5, 4, 3, 0
|
#define VERSION_WORDS 5, 4, 4, 0
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION VERSION_WORDS
|
FILEVERSION VERSION_WORDS
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
.SUFFIXES: .cxx
|
.SUFFIXES: .cxx
|
||||||
|
|
||||||
DIR_O=.
|
DIR_O=obj
|
||||||
DIR_BIN=..\bin
|
DIR_BIN=..\bin
|
||||||
|
|
||||||
LEXILLA=$(DIR_BIN)\lexilla.dll
|
LEXILLA=$(DIR_BIN)\lexilla.dll
|
||||||
@ -23,6 +23,10 @@ LIBLEXILLA=$(DIR_BIN)\liblexilla.lib
|
|||||||
|
|
||||||
LD=link
|
LD=link
|
||||||
|
|
||||||
|
!IF "$(PLATFORM:64=)" == "arm"
|
||||||
|
ARM64=1
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
!IFDEF SUPPORT_XP
|
!IFDEF SUPPORT_XP
|
||||||
ADD_DEFINE=-D_USING_V110_SDK71_
|
ADD_DEFINE=-D_USING_V110_SDK71_
|
||||||
# Different subsystems for 32-bit and 64-bit Windows XP so detect based on Platform
|
# 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
|
SUBSYSTEM=-SUBSYSTEM:WINDOWS,5.01
|
||||||
!ENDIF
|
!ENDIF
|
||||||
!ELSE
|
!ELSE
|
||||||
CETCOMPAT=-CETCOMPAT
|
|
||||||
!IFDEF ARM64
|
!IFDEF ARM64
|
||||||
ADD_DEFINE=-D_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1
|
ADD_DEFINE=-D_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1
|
||||||
SUBSYSTEM=-SUBSYSTEM:WINDOWS,10.00
|
SUBSYSTEM=-SUBSYSTEM:WINDOWS,10.00
|
||||||
|
!ELSE
|
||||||
|
CETCOMPAT=-CETCOMPAT
|
||||||
!ENDIF
|
!ENDIF
|
||||||
!ENDIF
|
!ENDIF
|
||||||
|
|
||||||
@ -68,7 +73,10 @@ SCINTILLA_INCLUDE = ../../scintilla/include
|
|||||||
INCLUDEDIRS=-I../include -I$(SCINTILLA_INCLUDE) -I../lexlib
|
INCLUDEDIRS=-I../include -I$(SCINTILLA_INCLUDE) -I../lexlib
|
||||||
CXXFLAGS=$(CXXFLAGS) $(INCLUDEDIRS)
|
CXXFLAGS=$(CXXFLAGS) $(INCLUDEDIRS)
|
||||||
|
|
||||||
all: $(SCINTILLA_INCLUDE) $(LEXILLA) $(LIBLEXILLA)
|
all: $(SCINTILLA_INCLUDE) $(DIR_O) $(LEXILLA) $(LIBLEXILLA)
|
||||||
|
|
||||||
|
$(DIR_O):
|
||||||
|
mkdir "$(DIR_O)" 2>NUL || cd .
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
-del /q $(DIR_O)\*.obj $(DIR_O)\*.o $(DIR_O)\*.pdb \
|
-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
|
DEBUG_OPTIONS = -O2 -MT -DNDEBUG $(STATIC_FLAG) -GL
|
||||||
!ENDIF
|
!ENDIF
|
||||||
|
|
||||||
CXXFLAGS = /EHsc /std:c++latest $(DEBUG_OPTIONS) $(INCLUDEDIRS)
|
CXXFLAGS = /EHsc /std:c++20 $(DEBUG_OPTIONS) $(INCLUDEDIRS)
|
||||||
|
|
||||||
OBJS = TestLexers.obj TestDocument.obj LexillaAccess.obj
|
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));
|
return static_cast<int>(Call(Message::GetExtraDescent));
|
||||||
}
|
}
|
||||||
|
|
||||||
int ScintillaCall::MarkerSymbolDefined(int markerNumber) {
|
MarkerSymbol ScintillaCall::MarkerSymbolDefined(int markerNumber) {
|
||||||
return static_cast<int>(Call(Message::MarkerSymbolDefined, markerNumber));
|
return static_cast<Scintilla::MarkerSymbol>(Call(Message::MarkerSymbolDefined, markerNumber));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScintillaCall::MarginSetText(Line line, const char *text) {
|
void ScintillaCall::MarginSetText(Line line, const char *text) {
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>5.5.5</string>
|
<string>5.5.6</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
@ -586,7 +586,7 @@
|
|||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
CURRENT_PROJECT_VERSION = 5.5.5;
|
CURRENT_PROJECT_VERSION = 5.5.6;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
@ -650,7 +650,7 @@
|
|||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
CURRENT_PROJECT_VERSION = 5.5.5;
|
CURRENT_PROJECT_VERSION = 5.5.6;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
@ -682,7 +682,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "-";
|
CODE_SIGN_IDENTITY = "-";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 5.5.5;
|
CURRENT_PROJECT_VERSION = 5.5.6;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEFINES_MODULE = YES;
|
DEFINES_MODULE = YES;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
@ -717,7 +717,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "-";
|
CODE_SIGN_IDENTITY = "-";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 5.5.5;
|
CURRENT_PROJECT_VERSION = 5.5.6;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEFINES_MODULE = YES;
|
DEFINES_MODULE = YES;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
|
@ -130,7 +130,7 @@
|
|||||||
|
|
||||||
<h1>Scintilla Documentation</h1>
|
<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
|
<p style="background:#90F0C0">Scintilla 5 has moved the lexers from Scintilla into a new
|
||||||
<a href="Lexilla.html">Lexilla</a> project.<br />
|
<a href="Lexilla.html">Lexilla</a> project.<br />
|
||||||
@ -3583,117 +3583,140 @@ struct Sci_TextToFindFull {
|
|||||||
<table class="standard" summary="Character Sets supported"><tbody>
|
<table class="standard" summary="Character Sets supported"><tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Character Set</th>
|
<th>Character Set</th>
|
||||||
|
<th>Value</th>
|
||||||
<th>Windows</th>
|
<th>Windows</th>
|
||||||
<th>GTK</th>
|
<th>GTK</th>
|
||||||
<th>Cocoa</th></tr></tbody>
|
<th>Cocoa</th></tr></tbody>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr class="section">
|
||||||
<td><code>SC_CHARSET_ANSI</code></td>
|
<th align="left"><code>SC_CHARSET_ANSI</code></th>
|
||||||
|
<td>0</td>
|
||||||
<td>✓</td>
|
<td>✓</td>
|
||||||
<td>✓</td>
|
<td>✓</td>
|
||||||
<td>✓ (8859-1)</td></tr>
|
<td>✓ (8859-1)</td></tr>
|
||||||
<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>
|
<td></td>
|
||||||
<td>✓</td></tr>
|
<td>✓</td></tr>
|
||||||
<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>
|
<td></td>
|
||||||
<td>✓</td></tr>
|
<td>✓</td></tr>
|
||||||
<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>
|
<td></td>
|
||||||
<td>✓</td></tr>
|
<td>✓</td></tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>SC_CHARSET_DEFAULT</code></td>
|
<th align="left"><code>SC_CHARSET_DEFAULT</code></th>
|
||||||
|
<td>1</td>
|
||||||
<td>✓</td>
|
<td>✓</td>
|
||||||
<td>✓ (8859-1)</td>
|
<td>✓ (8859-1)</td>
|
||||||
<td>✓ (8859-1)</td></tr>
|
<td>✓ (8859-1)</td></tr>
|
||||||
<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>
|
<td>✓</td>
|
||||||
<td>✓</td></tr>
|
<td>✓</td></tr>
|
||||||
<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>
|
<td>✓</td>
|
||||||
<td>✓</td></tr>
|
<td>✓</td></tr>
|
||||||
<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>
|
<td></td>
|
||||||
<td>✓</td></tr>
|
<td>✓</td></tr>
|
||||||
<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>
|
<td>✓</td>
|
||||||
<td>✓</td></tr>
|
<td>✓</td></tr>
|
||||||
<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>
|
<td></td>
|
||||||
<td>✓</td></tr>
|
<td>✓</td></tr>
|
||||||
<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>
|
<td></td>
|
||||||
<td>✓</td></tr>
|
<td>✓</td></tr>
|
||||||
<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>
|
<td></td>
|
||||||
<td>✓</td></tr>
|
<td>✓</td></tr>
|
||||||
<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>
|
<td></td>
|
||||||
<td>✓</td></tr>
|
<td>✓</td></tr>
|
||||||
<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>✓ (cp1251)</td>
|
||||||
<td>✓ (koi8-r)</td>
|
<td>✓ (koi8-r)</td>
|
||||||
<td>✓ (cp1251)</td></tr>
|
<td>✓ (cp1251)</td></tr>
|
||||||
<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>
|
<td>✓</td>
|
||||||
<td>✓</td></tr>
|
<td>✓</td></tr>
|
||||||
<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>
|
<td></td>
|
||||||
<td>✓</td></tr>
|
<td>✓</td></tr>
|
||||||
<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>
|
<td></td>
|
||||||
<td>✓</td></tr>
|
<td>✓</td></tr>
|
||||||
<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>
|
<td></td>
|
||||||
<td>✓</td></tr>
|
<td>✓</td></tr>
|
||||||
<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>
|
<td></td>
|
||||||
<td>✓</td></tr>
|
<td>✓</td></tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>SC_CHARSET_OEM866</code></td>
|
<th align="left"><code>SC_CHARSET_OEM866</code></th>
|
||||||
|
<td>866</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>✓ (cp866)</td>
|
<td>✓ (cp866)</td>
|
||||||
<td></td></tr>
|
<td></td></tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>SC_CHARSET_CYRILLIC</code></td>
|
<th align="left"><code>SC_CHARSET_CYRILLIC</code></th>
|
||||||
|
<td>1251</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>✓ (cp1251)</td>
|
<td>✓ (cp1251)</td>
|
||||||
<td>✓ (cp1251)</td></tr>
|
<td>✓ (cp1251)</td></tr>
|
||||||
<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>
|
<td>✓</td>
|
||||||
<td>✓</td></tr>
|
<td>✓</td></tr>
|
||||||
@ -4960,6 +4983,8 @@ struct Sci_TextToFindFull {
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<p>Different shapes available for EOL annotations.
|
<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>
|
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>
|
<p><img src="StadiumVariants.png" alt="Different shapes available for EOL annotations" /></p>
|
||||||
|
|
||||||
@ -9043,21 +9068,24 @@ struct SCNotification {
|
|||||||
Sci_Position position;
|
Sci_Position position;
|
||||||
/* SCN_STYLENEEDED, SCN_DOUBLECLICK, SCN_MODIFIED, SCN_MARGINCLICK, */
|
/* SCN_STYLENEEDED, SCN_DOUBLECLICK, SCN_MODIFIED, SCN_MARGINCLICK, */
|
||||||
/* SCN_MARGINRIGHTCLICK, SCN_NEEDSHOWN, SCN_DWELLSTART, SCN_DWELLEND, */
|
/* SCN_MARGINRIGHTCLICK, SCN_NEEDSHOWN, SCN_DWELLSTART, SCN_DWELLEND, */
|
||||||
/* SCN_CALLTIPCLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */
|
/* SCN_CALLTIPCLICK, */
|
||||||
/* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
/* SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, SCN_HOTSPOTRELEASECLICK, */
|
||||||
/* SCN_USERLISTSELECTION, SCN_AUTOCSELECTION, SCN_AUTOCSELECTIONCHANGE */
|
/* SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
||||||
|
/* SCN_USERLISTSELECTION, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */
|
||||||
|
/* SCN_AUTOCSELECTIONCHANGE */
|
||||||
|
|
||||||
int ch;
|
int ch;
|
||||||
/* SCN_CHARADDED, SCN_KEY, SCN_AUTOCCOMPLETE, SCN_AUTOCSELECTION, */
|
/* SCN_CHARADDED, SCN_KEY, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */
|
||||||
/* SCN_USERLISTSELECTION */
|
/* SCN_USERLISTSELECTION */
|
||||||
int modifiers;
|
int modifiers;
|
||||||
/* SCN_KEY, SCN_DOUBLECLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */
|
/* SCN_KEY, SCN_DOUBLECLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */
|
||||||
/* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
/* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
||||||
|
/* SCN_MARGINCLICK, SCN_MARGINRIGHTCLICK */
|
||||||
|
|
||||||
int modificationType; /* SCN_MODIFIED */
|
int modificationType; /* SCN_MODIFIED */
|
||||||
const char *text;
|
const char *text;
|
||||||
/* SCN_MODIFIED, SCN_USERLISTSELECTION, SCN_AUTOCSELECTION, SCN_URIDROPPED, */
|
/* SCN_MODIFIED, SCN_USERLISTSELECTION, SCN_URIDROPPED, */
|
||||||
/* SCN_AUTOCSELECTIONCHANGE */
|
/* SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, SCN_AUTOCSELECTIONCHANGE */
|
||||||
|
|
||||||
Sci_Position length; /* SCN_MODIFIED */
|
Sci_Position length; /* SCN_MODIFIED */
|
||||||
Sci_Position linesAdded; /* SCN_MODIFIED */
|
Sci_Position linesAdded; /* SCN_MODIFIED */
|
||||||
|
@ -26,9 +26,9 @@
|
|||||||
<table bgcolor="#CCCCCC" width="100%" cellspacing="0" cellpadding="8" border="0">
|
<table bgcolor="#CCCCCC" width="100%" cellspacing="0" cellpadding="8" border="0">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<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>
|
Windows</a>
|
||||||
<a href="https://www.scintilla.org/scintilla555.tgz">
|
<a href="https://www.scintilla.org/scintilla556.tgz">
|
||||||
GTK/Linux</a>
|
GTK/Linux</a>
|
||||||
</font>
|
</font>
|
||||||
</td>
|
</td>
|
||||||
@ -42,7 +42,7 @@
|
|||||||
containing very few restrictions.
|
containing very few restrictions.
|
||||||
</p>
|
</p>
|
||||||
<h3>
|
<h3>
|
||||||
Release 5.5.5
|
Release 5.5.6
|
||||||
</h3>
|
</h3>
|
||||||
<h4>
|
<h4>
|
||||||
Source Code
|
Source Code
|
||||||
@ -50,8 +50,8 @@
|
|||||||
The source code package contains all of the source code for Scintilla but no binary
|
The source code package contains all of the source code for Scintilla but no binary
|
||||||
executable code and is available in
|
executable code and is available in
|
||||||
<ul>
|
<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/scintilla556.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.tgz">tgz format</a> (1.7M) commonly used on Linux and compatible operating systems</li>
|
||||||
</ul>
|
</ul>
|
||||||
Instructions for building on both Windows and Linux are included in the readme file.
|
Instructions for building on both Windows and Linux are included in the readme file.
|
||||||
<h4>
|
<h4>
|
||||||
|
@ -585,9 +585,56 @@
|
|||||||
<td>Martijn Laan</td>
|
<td>Martijn Laan</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td>Pawel Z Wronek</td>
|
<td>Pawel Z Wronek</td>
|
||||||
|
<td>Joachim Mairboeck</td>
|
||||||
|
<td>Gianluca Vaccari</td>
|
||||||
|
<td>8day</td>
|
||||||
|
</tr><tr>
|
||||||
|
<td>Ahmet Sait</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<h2 id="Releases">Releases</h2>
|
<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>
|
<h3>
|
||||||
<a href="https://www.scintilla.org/scintilla555.zip">Release 5.5.5</a>
|
<a href="https://www.scintilla.org/scintilla555.zip">Release 5.5.5</a>
|
||||||
</h3>
|
</h3>
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
<title>
|
<title>
|
||||||
Scintilla Usage Notes
|
Scintilla Usage Notes
|
||||||
</title>
|
</title>
|
||||||
|
<link rel="canonical" href="https://scintilla.org/ScintillaUsage.html" />
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
SPAN {
|
SPAN {
|
||||||
font-family: Verdana, Arial, Helvetica;
|
font-family: Verdana, Arial, Helvetica;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<meta name="keywords" content="Scintilla, SciTE, Editing Component, Text Editor" />
|
<meta name="keywords" content="Scintilla, SciTE, Editing Component, Text Editor" />
|
||||||
<meta name="Description"
|
<meta name="Description"
|
||||||
content="www.scintilla.org is the home of the Scintilla editing component and SciTE text editor application." />
|
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" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
.logo {
|
.logo {
|
||||||
@ -61,8 +61,8 @@
|
|||||||
GTK, and macOS</font>
|
GTK, and macOS</font>
|
||||||
</td>
|
</td>
|
||||||
<td width="40%" align="right">
|
<td width="40%" align="right">
|
||||||
<font color="#FFCC99" size="3"> Release version 5.5.5<br />
|
<font color="#FFCC99" size="3"> Release version 5.5.6<br />
|
||||||
Site last modified February 25 2025</font>
|
Site last modified April 2 2025</font>
|
||||||
</td>
|
</td>
|
||||||
<td width="20%">
|
<td width="20%">
|
||||||
|
|
||||||
@ -77,11 +77,11 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<ul id="versionlist">
|
<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.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.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.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.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>
|
||||||
<ul id="menu">
|
<ul id="menu">
|
||||||
<li id="remote1"><a href="https://www.scintilla.org/SciTEImage.html">Screenshot</a></li>
|
<li id="remote1"><a href="https://www.scintilla.org/SciTEImage.html">Screenshot</a></li>
|
||||||
|
@ -1424,10 +1424,12 @@ struct SCNotification {
|
|||||||
Sci_NotifyHeader nmhdr;
|
Sci_NotifyHeader nmhdr;
|
||||||
Sci_Position position;
|
Sci_Position position;
|
||||||
/* SCN_STYLENEEDED, SCN_DOUBLECLICK, SCN_MODIFIED, SCN_MARGINCLICK, */
|
/* 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_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, SCN_HOTSPOTRELEASECLICK, */
|
||||||
/* SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
/* SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
||||||
/* SCN_USERLISTSELECTION, SCN_AUTOCSELECTION */
|
/* SCN_USERLISTSELECTION, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */
|
||||||
|
/* SCN_AUTOCSELECTIONCHANGE */
|
||||||
|
|
||||||
int ch;
|
int ch;
|
||||||
/* SCN_CHARADDED, SCN_KEY, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */
|
/* SCN_CHARADDED, SCN_KEY, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */
|
||||||
@ -1435,10 +1437,12 @@ struct SCNotification {
|
|||||||
int modifiers;
|
int modifiers;
|
||||||
/* SCN_KEY, SCN_DOUBLECLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */
|
/* SCN_KEY, SCN_DOUBLECLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */
|
||||||
/* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
/* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
||||||
|
/* SCN_MARGINCLICK, SCN_MARGINRIGHTCLICK */
|
||||||
|
|
||||||
int modificationType; /* SCN_MODIFIED */
|
int modificationType; /* SCN_MODIFIED */
|
||||||
const char *text;
|
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 length; /* SCN_MODIFIED */
|
||||||
Sci_Position linesAdded; /* SCN_MODIFIED */
|
Sci_Position linesAdded; /* SCN_MODIFIED */
|
||||||
@ -1448,15 +1452,15 @@ struct SCNotification {
|
|||||||
Sci_Position line; /* SCN_MODIFIED */
|
Sci_Position line; /* SCN_MODIFIED */
|
||||||
int foldLevelNow; /* SCN_MODIFIED */
|
int foldLevelNow; /* SCN_MODIFIED */
|
||||||
int foldLevelPrev; /* SCN_MODIFIED */
|
int foldLevelPrev; /* SCN_MODIFIED */
|
||||||
int margin; /* SCN_MARGINCLICK */
|
int margin; /* SCN_MARGINCLICK, SCN_MARGINRIGHTCLICK */
|
||||||
int listType; /* SCN_USERLISTSELECTION */
|
int listType; /* SCN_USERLISTSELECTION, SCN_AUTOCSELECTIONCHANGE */
|
||||||
int x; /* SCN_DWELLSTART, SCN_DWELLEND */
|
int x; /* SCN_DWELLSTART, SCN_DWELLEND */
|
||||||
int y; /* SCN_DWELLSTART, SCN_DWELLEND */
|
int y; /* SCN_DWELLSTART, SCN_DWELLEND */
|
||||||
int token; /* SCN_MODIFIED with SC_MOD_CONTAINER */
|
int token; /* SCN_MODIFIED with SC_MOD_CONTAINER */
|
||||||
Sci_Position annotationLinesAdded; /* SCN_MODIFIED with SC_MOD_CHANGEANNOTATION */
|
Sci_Position annotationLinesAdded; /* SCN_MODIFIED with SC_MOD_CHANGEANNOTATION */
|
||||||
int updated; /* SCN_UPDATEUI */
|
int updated; /* SCN_UPDATEUI */
|
||||||
int listCompletionMethod;
|
int listCompletionMethod;
|
||||||
/* SCN_AUTOCSELECTION, SCN_AUTOCCOMPLETED, SCN_USERLISTSELECTION, */
|
/* SCN_AUTOCSELECTION, SCN_AUTOCCOMPLETED, SCN_USERLISTSELECTION */
|
||||||
int characterSource; /* SCN_CHARADDED */
|
int characterSource; /* SCN_CHARADDED */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2755,7 +2755,7 @@ set void SetExtraDescent=2527(int extraDescent,)
|
|||||||
get int GetExtraDescent=2528(,)
|
get int GetExtraDescent=2528(,)
|
||||||
|
|
||||||
# Which symbol was defined for markerNumber with MarkerDefine
|
# 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 the text in the text margin for a line
|
||||||
set void MarginSetText=2530(line line, string text)
|
set void MarginSetText=2530(line line, string text)
|
||||||
|
@ -750,7 +750,7 @@ public:
|
|||||||
int ExtraAscent();
|
int ExtraAscent();
|
||||||
void SetExtraDescent(int extraDescent);
|
void SetExtraDescent(int extraDescent);
|
||||||
int ExtraDescent();
|
int ExtraDescent();
|
||||||
int MarkerSymbolDefined(int markerNumber);
|
Scintilla::MarkerSymbol MarkerSymbolDefined(int markerNumber);
|
||||||
void MarginSetText(Line line, const char *text);
|
void MarginSetText(Line line, const char *text);
|
||||||
int MarginGetText(Line line, char *text);
|
int MarginGetText(Line line, char *text);
|
||||||
std::string MarginGetText(Line line);
|
std::string MarginGetText(Line line);
|
||||||
|
@ -88,10 +88,12 @@ struct NotificationData {
|
|||||||
NotifyHeader nmhdr;
|
NotifyHeader nmhdr;
|
||||||
Position position;
|
Position position;
|
||||||
/* SCN_STYLENEEDED, SCN_DOUBLECLICK, SCN_MODIFIED, SCN_MARGINCLICK, */
|
/* 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_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, SCN_HOTSPOTRELEASECLICK, */
|
||||||
/* SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
/* SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
||||||
/* SCN_USERLISTSELECTION, SCN_AUTOCSELECTION */
|
/* SCN_USERLISTSELECTION, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */
|
||||||
|
/* SCN_AUTOCSELECTIONCHANGE */
|
||||||
|
|
||||||
int ch;
|
int ch;
|
||||||
/* SCN_CHARADDED, SCN_KEY, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */
|
/* SCN_CHARADDED, SCN_KEY, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */
|
||||||
@ -99,10 +101,12 @@ struct NotificationData {
|
|||||||
KeyMod modifiers;
|
KeyMod modifiers;
|
||||||
/* SCN_KEY, SCN_DOUBLECLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */
|
/* SCN_KEY, SCN_DOUBLECLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */
|
||||||
/* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
/* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
|
||||||
|
/* SCN_MARGINCLICK, SCN_MARGINRIGHTCLICK */
|
||||||
|
|
||||||
ModificationFlags modificationType; /* SCN_MODIFIED */
|
ModificationFlags modificationType; /* SCN_MODIFIED */
|
||||||
const char *text;
|
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 length; /* SCN_MODIFIED */
|
||||||
Position linesAdded; /* SCN_MODIFIED */
|
Position linesAdded; /* SCN_MODIFIED */
|
||||||
@ -112,15 +116,15 @@ struct NotificationData {
|
|||||||
Position line; /* SCN_MODIFIED */
|
Position line; /* SCN_MODIFIED */
|
||||||
FoldLevel foldLevelNow; /* SCN_MODIFIED */
|
FoldLevel foldLevelNow; /* SCN_MODIFIED */
|
||||||
FoldLevel foldLevelPrev; /* SCN_MODIFIED */
|
FoldLevel foldLevelPrev; /* SCN_MODIFIED */
|
||||||
int margin; /* SCN_MARGINCLICK */
|
int margin; /* SCN_MARGINCLICK, SCN_MARGINRIGHTCLICK */
|
||||||
int listType; /* SCN_USERLISTSELECTION */
|
int listType; /* SCN_USERLISTSELECTION, SCN_AUTOCSELECTIONCHANGE */
|
||||||
int x; /* SCN_DWELLSTART, SCN_DWELLEND */
|
int x; /* SCN_DWELLSTART, SCN_DWELLEND */
|
||||||
int y; /* SCN_DWELLSTART, SCN_DWELLEND */
|
int y; /* SCN_DWELLSTART, SCN_DWELLEND */
|
||||||
int token; /* SCN_MODIFIED with SC_MOD_CONTAINER */
|
int token; /* SCN_MODIFIED with SC_MOD_CONTAINER */
|
||||||
Position annotationLinesAdded; /* SCN_MODIFIED with SC_MOD_CHANGEANNOTATION */
|
Position annotationLinesAdded; /* SCN_MODIFIED with SC_MOD_CHANGEANNOTATION */
|
||||||
Update updated; /* SCN_UPDATEUI */
|
Update updated; /* SCN_UPDATEUI */
|
||||||
CompletionMethods listCompletionMethod;
|
CompletionMethods listCompletionMethod;
|
||||||
/* SCN_AUTOCSELECTION, SCN_AUTOCCOMPLETED, SCN_USERLISTSELECTION, */
|
/* SCN_AUTOCSELECTION, SCN_AUTOCCOMPLETED, SCN_USERLISTSELECTION */
|
||||||
CharacterSource characterSource; /* SCN_CHARADDED */
|
CharacterSource characterSource; /* SCN_CHARADDED */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ TEMPLATE = lib
|
|||||||
CONFIG += lib_bundle
|
CONFIG += lib_bundle
|
||||||
CONFIG += c++1z
|
CONFIG += c++1z
|
||||||
|
|
||||||
VERSION = 5.5.5
|
VERSION = 5.5.6
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
ScintillaEdit.cpp \
|
ScintillaEdit.cpp \
|
||||||
|
@ -667,7 +667,7 @@ void SurfaceImpl::DrawTextClippedUTF8(PRectangle rc,
|
|||||||
ColourRGBA back)
|
ColourRGBA back)
|
||||||
{
|
{
|
||||||
SetClip(rc);
|
SetClip(rc);
|
||||||
DrawTextNoClip(rc, font, ybase, text, fore, back);
|
DrawTextNoClipUTF8(rc, font, ybase, text, fore, back);
|
||||||
PopClip();
|
PopClip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,6 +373,12 @@ void ScintillaEditBase::mouseMoveEvent(QMouseEvent *event)
|
|||||||
sqt->ButtonMoveWithModifiers(pos, TimeOfEvent(time), modifiers);
|
sqt->ButtonMoveWithModifiers(pos, TimeOfEvent(time), modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScintillaEditBase::leaveEvent(QEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::leaveEvent(event);
|
||||||
|
sqt->MouseLeave();
|
||||||
|
}
|
||||||
|
|
||||||
void ScintillaEditBase::contextMenuEvent(QContextMenuEvent *event)
|
void ScintillaEditBase::contextMenuEvent(QContextMenuEvent *event)
|
||||||
{
|
{
|
||||||
const Point pos = PointFromQPoint(event->globalPos());
|
const Point pos = PointFromQPoint(event->globalPos());
|
||||||
@ -810,7 +816,7 @@ void ScintillaEditBase::notifyParent(NotificationData scn)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Notification::AutoCSelection:
|
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;
|
break;
|
||||||
|
|
||||||
case Notification::AutoCCancelled:
|
case Notification::AutoCCancelled:
|
||||||
|
@ -141,6 +141,7 @@ protected:
|
|||||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||||
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||||
void mouseMoveEvent(QMouseEvent *event) override;
|
void mouseMoveEvent(QMouseEvent *event) override;
|
||||||
|
void leaveEvent(QEvent *event) override;
|
||||||
void contextMenuEvent(QContextMenuEvent *event) override;
|
void contextMenuEvent(QContextMenuEvent *event) override;
|
||||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||||
void dragLeaveEvent(QDragLeaveEvent *event) override;
|
void dragLeaveEvent(QDragLeaveEvent *event) override;
|
||||||
|
@ -13,7 +13,7 @@ TEMPLATE = lib
|
|||||||
CONFIG += lib_bundle
|
CONFIG += lib_bundle
|
||||||
CONFIG += c++1z
|
CONFIG += c++1z
|
||||||
|
|
||||||
VERSION = 5.5.5
|
VERSION = 5.5.6
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
PlatQt.cpp \
|
PlatQt.cpp \
|
||||||
|
@ -158,6 +158,9 @@
|
|||||||
// win32
|
// win32
|
||||||
#include "WinTypes.h"
|
#include "WinTypes.h"
|
||||||
#include "PlatWin.h"
|
#include "PlatWin.h"
|
||||||
|
#include "ListBox.h"
|
||||||
|
#include "SurfaceGDI.h"
|
||||||
|
#include "SurfaceD2D.h"
|
||||||
#include "HanjaDic.h"
|
#include "HanjaDic.h"
|
||||||
#include "ScintillaWin.h"
|
#include "ScintillaWin.h"
|
||||||
|
|
||||||
|
@ -605,7 +605,7 @@ class CaseConverter final : public ICaseConverter {
|
|||||||
return character < other.character;
|
return character < other.character;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
typedef std::vector<CharacterConversion> CharacterToConversion;
|
using CharacterToConversion = std::vector<CharacterConversion>;
|
||||||
CharacterToConversion characterToConversion;
|
CharacterToConversion characterToConversion;
|
||||||
// The parallel arrays
|
// The parallel arrays
|
||||||
std::vector<int> characters;
|
std::vector<int> characters;
|
||||||
@ -613,7 +613,7 @@ class CaseConverter final : public ICaseConverter {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
CaseConverter() noexcept = default;
|
CaseConverter() noexcept = default;
|
||||||
bool Initialised() const noexcept {
|
[[nodiscard]] bool Initialised() const noexcept {
|
||||||
return !characters.empty();
|
return !characters.empty();
|
||||||
}
|
}
|
||||||
void Add(int character, std::string_view conversion_) {
|
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 CaseConvertString(const std::string &s, CaseConversion conversion) {
|
||||||
std::string retMapped(s.length() * maxExpansionCaseConversion, 0);
|
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);
|
conversion);
|
||||||
retMapped.resize(lenMapped);
|
retMapped.resize(lenMapped);
|
||||||
return retMapped;
|
return retMapped;
|
||||||
|
@ -5,6 +5,11 @@
|
|||||||
// Copyright 2017 by Neil Hodgson <neilh@scintilla.org>
|
// Copyright 2017 by Neil Hodgson <neilh@scintilla.org>
|
||||||
// The License.txt file describes the conditions under which this software may be distributed.
|
// The License.txt file describes the conditions under which this software may be distributed.
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "DBCS.h"
|
#include "DBCS.h"
|
||||||
|
|
||||||
using namespace Scintilla::Internal;
|
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
|
// Byte ranges found in Wikipedia articles with relevant search strings in each case
|
||||||
const unsigned char uch = ch;
|
const unsigned char uch = ch;
|
||||||
switch (codePage) {
|
switch (codePage) {
|
||||||
case 932:
|
case cp932:
|
||||||
// Shift_jis
|
// Shift_jis
|
||||||
return ((uch >= 0x81) && (uch <= 0x9F)) ||
|
return ((uch >= 0x81) && (uch <= 0x9F)) ||
|
||||||
((uch >= 0xE0) && (uch <= 0xFC));
|
((uch >= 0xE0) && (uch <= 0xFC));
|
||||||
// Lead bytes F0 to FC may be a Microsoft addition.
|
// Lead bytes F0 to FC may be a Microsoft addition.
|
||||||
case 936:
|
case cp936:
|
||||||
// GBK
|
// GBK
|
||||||
return (uch >= 0x81) && (uch <= 0xFE);
|
return (uch >= 0x81) && (uch <= 0xFE);
|
||||||
case 949:
|
case cp949:
|
||||||
// Korean Wansung KS C-5601-1987
|
// Korean Wansung KS C-5601-1987
|
||||||
return (uch >= 0x81) && (uch <= 0xFE);
|
return (uch >= 0x81) && (uch <= 0xFE);
|
||||||
case 950:
|
case cp950:
|
||||||
// Big5
|
// Big5
|
||||||
return (uch >= 0x81) && (uch <= 0xFE);
|
return (uch >= 0x81) && (uch <= 0xFE);
|
||||||
case 1361:
|
case cp1361:
|
||||||
// Korean Johab KS C-5601-1992
|
// Korean Johab KS C-5601-1992
|
||||||
return
|
return
|
||||||
((uch >= 0x84) && (uch <= 0xD3)) ||
|
((uch >= 0x84) && (uch <= 0xD3)) ||
|
||||||
((uch >= 0xD8) && (uch <= 0xDE)) ||
|
((uch >= 0xD8) && (uch <= 0xDE)) ||
|
||||||
((uch >= 0xE0) && (uch <= 0xF9));
|
((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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsDBCSValidSingleByte(int codePage, int ch) noexcept {
|
bool IsDBCSValidSingleByte(int codePage, int ch) noexcept {
|
||||||
switch (codePage) {
|
switch (codePage) {
|
||||||
case 932:
|
case cp932:
|
||||||
return ch == 0x80
|
return ch == 0x80
|
||||||
|| (ch >= 0xA0 && ch <= 0xDF)
|
|| (ch >= 0xA0 && ch <= 0xDF)
|
||||||
|| (ch >= 0xFD);
|
|| (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 {
|
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 {
|
constexpr bool IsDBCSCodePage(int codePage) noexcept {
|
||||||
return codePage == 932
|
return codePage == cp932
|
||||||
|| codePage == 936
|
|| codePage == cp936
|
||||||
|| codePage == 949
|
|| codePage == cp949
|
||||||
|| codePage == 950
|
|| codePage == cp950
|
||||||
|| codePage == 1361;
|
|| codePage == cp1361;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DBCSIsLeadByte(int codePage, char ch) noexcept;
|
bool DBCSIsLeadByte(int codePage, char ch) noexcept;
|
||||||
|
bool DBCSIsTrailByte(int codePage, char ch) noexcept;
|
||||||
bool IsDBCSValidSingleByte(int codePage, int 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
|
#endif
|
||||||
|
@ -620,11 +620,14 @@ void Document::ClearLevels() {
|
|||||||
Levels()->ClearLevels();
|
Levels()->ClearLevels();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsSubordinate(FoldLevel levelStart, FoldLevel levelTry) noexcept {
|
namespace {
|
||||||
|
|
||||||
|
constexpr bool IsSubordinate(FoldLevel levelStart, FoldLevel levelTry) noexcept {
|
||||||
if (LevelIsWhitespace(levelTry))
|
if (LevelIsWhitespace(levelTry))
|
||||||
return true;
|
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) {
|
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) {
|
constexpr bool IsBaseOfGrapheme(CharacterCategory cc) {
|
||||||
// \p{L}\p{N}\p{P}\p{Sm}\p{Sc}\p{So}\p{Zs}
|
|
||||||
switch (cc) {
|
switch (cc) {
|
||||||
|
// \p{L}\p{N}\p{P}\p{Sm}\p{Sc}\p{So}\p{Zs}
|
||||||
case ccLu:
|
case ccLu:
|
||||||
case ccLl:
|
case ccLl:
|
||||||
case ccLt:
|
case ccLt:
|
||||||
@ -1250,12 +1253,16 @@ constexpr bool IsBaseOfGrapheme(CharacterCategory cc) {
|
|||||||
case ccSc:
|
case ccSc:
|
||||||
case ccSo:
|
case ccSo:
|
||||||
case ccZs:
|
case ccZs:
|
||||||
|
// Control
|
||||||
|
case ccCc:
|
||||||
|
case ccCs:
|
||||||
|
case ccCo:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
// ccMn, ccMc, ccMe,
|
// ccMn, ccMc, ccMe,
|
||||||
// ccSk,
|
// ccSk,
|
||||||
// ccZl, ccZp,
|
// ccZl, ccZp,
|
||||||
// ccCc, ccCf, ccCs, ccCo, ccCn
|
// ccCf, ccCn
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1276,6 +1283,25 @@ CharacterExtracted LastCharacter(std::string_view text) noexcept {
|
|||||||
static_cast<unsigned int>(utf8status & UTF8MaskWidth) };
|
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 {
|
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-base := [\p{L}\p{N}\p{P}\p{S}\p{Zs}]
|
||||||
// ccs-extend := [\p{M}\p{Join_Control}]
|
// ccs-extend := [\p{M}\p{Join_Control}]
|
||||||
// Modified to move Sk (Symbol Modifier) from ccs-base to ccs-extend to preserve modified emoji
|
// 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;
|
std::string_view truncated = text;
|
||||||
while (truncated.length() > UTF8MaxBytes) {
|
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 SCI_METHOD Document::GetLineIndentation(Sci_Position line) {
|
||||||
int indent = 0;
|
int indent = 0;
|
||||||
if ((line >= 0) && (line < LinesTotal())) {
|
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;
|
constexpr size_t maxFoldingExpansion = 4;
|
||||||
std::vector<char> searchThing((lengthFind+1) * UTF8MaxBytes * maxFoldingExpansion + 1);
|
std::vector<char> searchThing((lengthFind+1) * UTF8MaxBytes * maxFoldingExpansion + 1);
|
||||||
const size_t lenSearch =
|
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)) {
|
while (forward ? (pos < endPos) : (pos >= endPos)) {
|
||||||
int widthFirstCharacter = 1;
|
int widthFirstCharacter = 1;
|
||||||
Sci::Position posIndexDocument = pos;
|
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
|
// memcmp may examine lenFlat bytes in both arguments so assert it doesn't read past end of searchThing
|
||||||
assert((indexSearch + lenFlat) <= searchThing.size());
|
assert((indexSearch + lenFlat) <= searchThing.size());
|
||||||
// Does folded match the buffer
|
// Does folded match the buffer
|
||||||
characterMatches = 0 == memcmp(folded, &searchThing[0] + indexSearch, lenFlat);
|
characterMatches = 0 == memcmp(folded, searchThing.data() + indexSearch, lenFlat);
|
||||||
}
|
}
|
||||||
if (!characterMatches) {
|
if (!characterMatches) {
|
||||||
break;
|
break;
|
||||||
@ -2423,7 +2432,7 @@ Sci::Position Document::FindText(Sci::Position minPos, Sci::Position maxPos, con
|
|||||||
constexpr size_t maxBytesCharacter = 2;
|
constexpr size_t maxBytesCharacter = 2;
|
||||||
constexpr size_t maxFoldingExpansion = 4;
|
constexpr size_t maxFoldingExpansion = 4;
|
||||||
std::vector<char> searchThing((lengthFind+1) * maxBytesCharacter * maxFoldingExpansion + 1);
|
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)) {
|
while (forward ? (pos < endPos) : (pos >= endPos)) {
|
||||||
int widthFirstCharacter = 0;
|
int widthFirstCharacter = 0;
|
||||||
Sci::Position indexDocument = 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
|
// memcmp may examine lenFlat bytes in both arguments so assert it doesn't read past end of searchThing
|
||||||
assert((indexSearch + lenFlat) <= searchThing.size());
|
assert((indexSearch + lenFlat) <= searchThing.size());
|
||||||
// Does folded match the buffer
|
// Does folded match the buffer
|
||||||
characterMatches = 0 == memcmp(folded, &searchThing[0] + indexSearch, lenFlat);
|
characterMatches = 0 == memcmp(folded, searchThing.data() + indexSearch, lenFlat);
|
||||||
}
|
}
|
||||||
if (!characterMatches) {
|
if (!characterMatches) {
|
||||||
break;
|
break;
|
||||||
@ -2477,7 +2486,7 @@ Sci::Position Document::FindText(Sci::Position minPos, Sci::Position maxPos, con
|
|||||||
} else {
|
} else {
|
||||||
const Sci::Position endSearch = (startPos <= endPos) ? endPos - lengthFind + 1 : endPos;
|
const Sci::Position endSearch = (startPos <= endPos) ? endPos - lengthFind + 1 : endPos;
|
||||||
std::vector<char> searchThing(lengthFind + 1);
|
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)) {
|
while (forward ? (pos < endSearch) : (pos >= endSearch)) {
|
||||||
bool found = (pos + lengthFind) <= limitPos;
|
bool found = (pos + lengthFind) <= limitPos;
|
||||||
for (int indexSearch = 0; (indexSearch < lengthFind) && found; indexSearch++) {
|
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;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char BraceOpposite(char ch) noexcept {
|
namespace {
|
||||||
|
|
||||||
|
constexpr char BraceOpposite(char ch) noexcept {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case '(':
|
case '(':
|
||||||
return ')';
|
return ')';
|
||||||
@ -2998,6 +3009,8 @@ static char BraceOpposite(char ch) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: should be able to extend styled region to find matching brace
|
// 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 {
|
Sci::Position Document::BraceMatch(Sci::Position position, Sci::Position /*maxReStyle*/, Sci::Position startPos, bool useStartPos) noexcept {
|
||||||
const unsigned char chBrace = CharAt(position);
|
const unsigned char chBrace = CharAt(position);
|
||||||
@ -3075,7 +3088,7 @@ public:
|
|||||||
lineRangeEnd = doc->SciLineFromPosition(endPos);
|
lineRangeEnd = doc->SciLineFromPosition(endPos);
|
||||||
lineRangeBreak = lineRangeEnd + increment;
|
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);
|
Range range(lineStartPos, lineEndPos);
|
||||||
if (increment == 1) {
|
if (increment == 1) {
|
||||||
if (line == lineRangeStart)
|
if (line == lineRangeStart)
|
||||||
@ -3101,13 +3114,13 @@ public:
|
|||||||
pdoc(pdoc_), end(end_) {
|
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)
|
if (index < 0 || index >= end)
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
return pdoc->CharAt(index);
|
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);
|
return pdoc->MovePositionOutsideChar(pos, moveDir, false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -3150,10 +3163,10 @@ public:
|
|||||||
bool operator!=(const ByteIterator &other) const noexcept {
|
bool operator!=(const ByteIterator &other) const noexcept {
|
||||||
return doc != other.doc || position != other.position;
|
return doc != other.doc || position != other.position;
|
||||||
}
|
}
|
||||||
Sci::Position Pos() const noexcept {
|
[[nodiscard]] Sci::Position Pos() const noexcept {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
Sci::Position PosRoundUp() const noexcept {
|
[[nodiscard]] Sci::Position PosRoundUp() const noexcept {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -3178,11 +3191,11 @@ class UTF8Iterator {
|
|||||||
// These 3 fields determine the iterator position and are used for comparisons
|
// These 3 fields determine the iterator position and are used for comparisons
|
||||||
const Document *doc;
|
const Document *doc;
|
||||||
Sci::Position position;
|
Sci::Position position;
|
||||||
size_t characterIndex;
|
size_t characterIndex = 0;
|
||||||
// Remaining fields are derived from the determining fields so are excluded in comparisons
|
// Remaining fields are derived from the determining fields so are excluded in comparisons
|
||||||
unsigned int lenBytes;
|
unsigned int lenBytes = 0;
|
||||||
size_t lenCharacters;
|
size_t lenCharacters = 0;
|
||||||
wchar_t buffered[2];
|
wchar_t buffered[2]{};
|
||||||
public:
|
public:
|
||||||
using iterator_category = std::bidirectional_iterator_tag;
|
using iterator_category = std::bidirectional_iterator_tag;
|
||||||
using value_type = wchar_t;
|
using value_type = wchar_t;
|
||||||
@ -3191,9 +3204,7 @@ public:
|
|||||||
using reference = wchar_t&;
|
using reference = wchar_t&;
|
||||||
|
|
||||||
explicit UTF8Iterator(const Document *doc_=nullptr, Sci::Position position_=0) noexcept :
|
explicit UTF8Iterator(const Document *doc_=nullptr, Sci::Position position_=0) noexcept :
|
||||||
doc(doc_), position(position_), characterIndex(0), lenBytes(0), lenCharacters(0), buffered{} {
|
doc(doc_), position(position_) {
|
||||||
buffered[0] = 0;
|
|
||||||
buffered[1] = 0;
|
|
||||||
if (doc) {
|
if (doc) {
|
||||||
ReadCharacter();
|
ReadCharacter();
|
||||||
}
|
}
|
||||||
@ -3245,10 +3256,10 @@ public:
|
|||||||
position != other.position ||
|
position != other.position ||
|
||||||
characterIndex != other.characterIndex;
|
characterIndex != other.characterIndex;
|
||||||
}
|
}
|
||||||
Sci::Position Pos() const noexcept {
|
[[nodiscard]] Sci::Position Pos() const noexcept {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
Sci::Position PosRoundUp() const noexcept {
|
[[nodiscard]] Sci::Position PosRoundUp() const noexcept {
|
||||||
if (characterIndex)
|
if (characterIndex)
|
||||||
return position + lenBytes; // Force to end of character
|
return position + lenBytes; // Force to end of character
|
||||||
else
|
else
|
||||||
|
@ -106,15 +106,7 @@ constexpr bool IsLastStep(const DocModification &mh) noexcept {
|
|||||||
&& ((mh.modificationType & finalMask) == finalMask);
|
&& ((mh.modificationType & finalMask) == finalMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
constexpr bool IsAllSpacesOrTabs(std::string_view sv) noexcept {
|
||||||
|
|
||||||
Timer::Timer() noexcept :
|
|
||||||
ticking(false), ticksToWait(0), tickerID{} {}
|
|
||||||
|
|
||||||
Idler::Idler() noexcept :
|
|
||||||
state(false), idlerID(nullptr) {}
|
|
||||||
|
|
||||||
static constexpr bool IsAllSpacesOrTabs(std::string_view sv) noexcept {
|
|
||||||
for (const char ch : sv) {
|
for (const char ch : sv) {
|
||||||
// This is safe because IsSpaceOrTab() will return false for null terminators
|
// This is safe because IsSpaceOrTab() will return false for null terminators
|
||||||
if (!IsSpaceOrTab(ch))
|
if (!IsSpaceOrTab(ch))
|
||||||
@ -123,6 +115,14 @@ static constexpr bool IsAllSpacesOrTabs(std::string_view sv) noexcept {
|
|||||||
return true;
|
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) {
|
Editor::Editor() : durationWrapOneByte(0.000001, 0.00000001, 0.00001) {
|
||||||
ctrlID = 0;
|
ctrlID = 0;
|
||||||
|
|
||||||
@ -3143,7 +3143,7 @@ void Editor::ChangeCaseOfSelection(CaseMapping caseMapping) {
|
|||||||
SelectionRange currentNoVS = current;
|
SelectionRange currentNoVS = current;
|
||||||
currentNoVS.ClearVirtualSpace();
|
currentNoVS.ClearVirtualSpace();
|
||||||
const size_t rangeBytes = currentNoVS.Length();
|
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 sText = RangeText(currentNoVS.Start().Position(), currentNoVS.End().Position());
|
||||||
|
|
||||||
std::string sMapped = CaseMapString(sText, caseMapping);
|
std::string sMapped = CaseMapString(sText, caseMapping);
|
||||||
@ -4402,7 +4402,9 @@ void Editor::GoToLine(Sci::Line lineNo) {
|
|||||||
EnsureCaretVisible();
|
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;
|
const Point ptDifference = pt2 - pt1;
|
||||||
if (std::abs(ptDifference.x) > threshold.x)
|
if (std::abs(ptDifference.x) > threshold.x)
|
||||||
return false;
|
return false;
|
||||||
@ -4411,6 +4413,12 @@ static bool Close(Point pt1, Point pt2, Point threshold) noexcept {
|
|||||||
return true;
|
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 {
|
std::string Editor::RangeText(Sci::Position start, Sci::Position end) const {
|
||||||
if (start < end) {
|
if (start < end) {
|
||||||
const Sci::Position len = end - start;
|
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) {
|
void Editor::ButtonDownWithModifiers(Point pt, unsigned int curTime, KeyMod modifiers) {
|
||||||
SetHoverIndicatorPoint(pt);
|
SetHoverIndicatorPoint(pt);
|
||||||
//Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
|
//Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
|
||||||
|
@ -15,16 +15,83 @@
|
|||||||
|
|
||||||
namespace Scintilla::Internal {
|
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 UTF8Length(std::wstring_view wsv) noexcept {
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
for (size_t i = 0; i < wsv.length() && wsv[i];) {
|
for (size_t i = 0; i < wsv.length() && wsv[i];) {
|
||||||
const unsigned int uch = wsv[i];
|
const wchar_t uch = wsv[i];
|
||||||
if (uch < 0x80) {
|
if (uch < first2Byte) {
|
||||||
len++;
|
len++;
|
||||||
} else if (uch < 0x800) {
|
} else if (uch < first3Byte) {
|
||||||
len += 2;
|
len += 2;
|
||||||
} else if ((uch >= SURROGATE_LEAD_FIRST) &&
|
} else if (IsSurrogate(uch)) {
|
||||||
(uch <= SURROGATE_TRAIL_LAST)) {
|
|
||||||
len += 4;
|
len += 4;
|
||||||
i++;
|
i++;
|
||||||
} else {
|
} 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 {
|
void UTF8FromUTF16(std::wstring_view wsv, char *putf, size_t len) noexcept {
|
||||||
size_t k = 0;
|
size_t k = 0;
|
||||||
for (size_t i = 0; i < wsv.length() && wsv[i];) {
|
for (size_t i = 0; i < wsv.length() && wsv[i];) {
|
||||||
const unsigned int uch = wsv[i];
|
unsigned int uch = wsv[i];
|
||||||
if (uch < 0x80) {
|
if (IsSurrogate(wsv[i])) {
|
||||||
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)) {
|
|
||||||
// Half a surrogate pair
|
// Half a surrogate pair
|
||||||
i++;
|
i++;
|
||||||
const unsigned int xch = 0x10000 + ((uch & 0x3ff) << 10) + (wsv[i] & 0x3ff);
|
uch = SUPPLEMENTAL_PLANE_FIRST + ((uch & maskSurrogate) << shiftSurrogate) + (wsv[i] & maskSurrogate);
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
UTF8AppendCharacter(uch, putf, k);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (k < len)
|
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 {
|
void UTF8FromUTF32Character(int uch, char *putf) noexcept {
|
||||||
size_t k = 0;
|
size_t k = 0;
|
||||||
if (uch < 0x80) {
|
UTF8AppendCharacter(uch, putf, k);
|
||||||
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));
|
|
||||||
}
|
|
||||||
putf[k] = '\0';
|
putf[k] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,18 +148,12 @@ size_t UTF16Length(std::string_view svu8) noexcept {
|
|||||||
return ulen;
|
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 UTF16FromUTF8(std::string_view svu8, wchar_t *tbuf, size_t tlen) {
|
||||||
size_t ui = 0;
|
size_t ui = 0;
|
||||||
for (size_t i = 0; i < svu8.length();) {
|
for (size_t i = 0; i < svu8.length();) {
|
||||||
unsigned char ch = svu8[i];
|
unsigned char ch = svu8[i];
|
||||||
const unsigned int byteCount = UTF8BytesOfLead[ch];
|
const unsigned int byteCount = UTF8BytesOfLead[ch];
|
||||||
unsigned int value;
|
unsigned int value = 0;
|
||||||
|
|
||||||
if (i + byteCount > svu8.length()) {
|
if (i + byteCount > svu8.length()) {
|
||||||
// Trying to read past end but still have space to write
|
// 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;
|
tbuf[ui] = ch;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
value = (ch & 0x1F) << 6;
|
value = (ch & leadBits2) << shiftByte2;
|
||||||
ch = svu8[i++];
|
ch = svu8[i++];
|
||||||
value += TrailByteValue(ch);
|
value += TrailByteValue(ch);
|
||||||
tbuf[ui] = static_cast<wchar_t>(value);
|
tbuf[ui] = static_cast<wchar_t>(value);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
value = (ch & 0xF) << 12;
|
value = (ch & leadBits3) << shiftByte3;
|
||||||
ch = svu8[i++];
|
ch = svu8[i++];
|
||||||
value += (TrailByteValue(ch) << 6);
|
value += (TrailByteValue(ch) << shiftByte2);
|
||||||
ch = svu8[i++];
|
ch = svu8[i++];
|
||||||
value += TrailByteValue(ch);
|
value += TrailByteValue(ch);
|
||||||
tbuf[ui] = static_cast<wchar_t>(value);
|
tbuf[ui] = static_cast<wchar_t>(value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Outside the BMP so need two surrogates
|
// Outside the BMP so need two surrogates
|
||||||
value = (ch & 0x7) << 18;
|
value = (ch & leadBits4) << shiftByte4;
|
||||||
ch = svu8[i++];
|
ch = svu8[i++];
|
||||||
value += TrailByteValue(ch) << 12;
|
value += TrailByteValue(ch) << shiftByte3;
|
||||||
ch = svu8[i++];
|
ch = svu8[i++];
|
||||||
value += TrailByteValue(ch) << 6;
|
value += TrailByteValue(ch) << shiftByte2;
|
||||||
ch = svu8[i++];
|
ch = svu8[i++];
|
||||||
value += TrailByteValue(ch);
|
value += TrailByteValue(ch);
|
||||||
tbuf[ui] = static_cast<wchar_t>(((value - 0x10000) >> 10) + SURROGATE_LEAD_FIRST);
|
tbuf[ui] = SurrogateLead(value);
|
||||||
ui++;
|
ui++;
|
||||||
tbuf[ui] = static_cast<wchar_t>((value & 0x3ff) + SURROGATE_TRAIL_FIRST);
|
tbuf[ui] = SurrogateTrail(value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ui++;
|
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();) {
|
for (size_t i = 0; i < svu8.length();) {
|
||||||
unsigned char ch = svu8[i];
|
unsigned char ch = svu8[i];
|
||||||
const unsigned int byteCount = UTF8BytesOfLead[ch];
|
const unsigned int byteCount = UTF8BytesOfLead[ch];
|
||||||
unsigned int value;
|
unsigned int value = 0;
|
||||||
|
|
||||||
if (i + byteCount > svu8.length()) {
|
if (i + byteCount > svu8.length()) {
|
||||||
// Trying to read past end but still have space to write
|
// 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;
|
value = ch;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
value = (ch & 0x1F) << 6;
|
value = (ch & leadBits2) << shiftByte2;
|
||||||
ch = svu8[i++];
|
ch = svu8[i++];
|
||||||
value += TrailByteValue(ch);
|
value += TrailByteValue(ch);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
value = (ch & 0xF) << 12;
|
value = (ch & leadBits3) << shiftByte3;
|
||||||
ch = svu8[i++];
|
ch = svu8[i++];
|
||||||
value += TrailByteValue(ch) << 6;
|
value += TrailByteValue(ch) << shiftByte2;
|
||||||
ch = svu8[i++];
|
ch = svu8[i++];
|
||||||
value += TrailByteValue(ch);
|
value += TrailByteValue(ch);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
value = (ch & 0x7) << 18;
|
value = (ch & leadBits4) << shiftByte4;
|
||||||
ch = svu8[i++];
|
ch = svu8[i++];
|
||||||
value += TrailByteValue(ch) << 12;
|
value += TrailByteValue(ch) << shiftByte3;
|
||||||
ch = svu8[i++];
|
ch = svu8[i++];
|
||||||
value += TrailByteValue(ch) << 6;
|
value += TrailByteValue(ch) << shiftByte2;
|
||||||
ch = svu8[i++];
|
ch = svu8[i++];
|
||||||
value += TrailByteValue(ch);
|
value += TrailByteValue(ch);
|
||||||
break;
|
break;
|
||||||
@ -256,8 +290,8 @@ unsigned int UTF16FromUTF32Character(unsigned int val, wchar_t *tbuf) noexcept {
|
|||||||
tbuf[0] = static_cast<wchar_t>(val);
|
tbuf[0] = static_cast<wchar_t>(val);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
tbuf[0] = static_cast<wchar_t>(((val - SUPPLEMENTAL_PLANE_FIRST) >> 10) + SURROGATE_LEAD_FIRST);
|
tbuf[0] = SurrogateLead(val);
|
||||||
tbuf[1] = static_cast<wchar_t>((val & 0x3ff) + SURROGATE_TRAIL_FIRST);
|
tbuf[1] = SurrogateTrail(val);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,8 +99,12 @@ enum { SURROGATE_TRAIL_FIRST = 0xDC00 };
|
|||||||
enum { SURROGATE_TRAIL_LAST = 0xDFFF };
|
enum { SURROGATE_TRAIL_LAST = 0xDFFF };
|
||||||
enum { SUPPLEMENTAL_PLANE_FIRST = 0x10000 };
|
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 {
|
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 {
|
constexpr unsigned int UTF16LengthFromUTF8ByteCount(unsigned int byteCount) noexcept {
|
||||||
|
@ -145,5 +145,27 @@ class TestPerformance(unittest.TestCase):
|
|||||||
print("%6.3f testUTF8AsciiSearches" % duration)
|
print("%6.3f testUTF8AsciiSearches" % duration)
|
||||||
self.xite.DoEvents()
|
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__':
|
if __name__ == '__main__':
|
||||||
Xite.main("performanceTests")
|
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") {
|
TEST_CASE("PerLine") {
|
||||||
SECTION("LineMarkers") {
|
SECTION("LineMarkers") {
|
||||||
DocPlus doc("1\n2\n", CpUtf8);
|
DocPlus doc("1\n2\n", CpUtf8);
|
||||||
|
@ -121,6 +121,9 @@ TEST_CASE("UniConversion") {
|
|||||||
const size_t tlen = UTF16FromUTF8(s, tbuf, 1);
|
const size_t tlen = UTF16FromUTF8(s, tbuf, 1);
|
||||||
REQUIRE(tlen == 1U);
|
REQUIRE(tlen == 1U);
|
||||||
REQUIRE(tbuf[0] == 'a');
|
REQUIRE(tbuf[0] == 'a');
|
||||||
|
char back[4]{};
|
||||||
|
UTF8FromUTF16(std::wstring_view(tbuf, tlen), back, sizeof(back));
|
||||||
|
REQUIRE(strcmp(s, back) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("UTF16FromUTF8 Example1") {
|
SECTION("UTF16FromUTF8 Example1") {
|
||||||
@ -129,6 +132,9 @@ TEST_CASE("UniConversion") {
|
|||||||
const size_t tlen = UTF16FromUTF8(s, tbuf, 1);
|
const size_t tlen = UTF16FromUTF8(s, tbuf, 1);
|
||||||
REQUIRE(tlen == 1U);
|
REQUIRE(tlen == 1U);
|
||||||
REQUIRE(tbuf[0] == 0x24);
|
REQUIRE(tbuf[0] == 0x24);
|
||||||
|
char back[4]{};
|
||||||
|
UTF8FromUTF16(std::wstring_view(tbuf, tlen), back, sizeof(back));
|
||||||
|
REQUIRE(strcmp(s, back) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("UTF16FromUTF8 Example2") {
|
SECTION("UTF16FromUTF8 Example2") {
|
||||||
@ -137,6 +143,9 @@ TEST_CASE("UniConversion") {
|
|||||||
const size_t tlen = UTF16FromUTF8(s, tbuf, 1);
|
const size_t tlen = UTF16FromUTF8(s, tbuf, 1);
|
||||||
REQUIRE(tlen == 1U);
|
REQUIRE(tlen == 1U);
|
||||||
REQUIRE(tbuf[0] == 0xA2);
|
REQUIRE(tbuf[0] == 0xA2);
|
||||||
|
char back[4]{};
|
||||||
|
UTF8FromUTF16(std::wstring_view(tbuf, tlen), back, sizeof(back));
|
||||||
|
REQUIRE(strcmp(s, back) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("UTF16FromUTF8 Example3") {
|
SECTION("UTF16FromUTF8 Example3") {
|
||||||
@ -145,6 +154,9 @@ TEST_CASE("UniConversion") {
|
|||||||
const size_t tlen = UTF16FromUTF8(s, tbuf, 1);;
|
const size_t tlen = UTF16FromUTF8(s, tbuf, 1);;
|
||||||
REQUIRE(tlen == 1U);
|
REQUIRE(tlen == 1U);
|
||||||
REQUIRE(tbuf[0] == 0x20AC);
|
REQUIRE(tbuf[0] == 0x20AC);
|
||||||
|
char back[4]{};
|
||||||
|
UTF8FromUTF16(std::wstring_view(tbuf, tlen), back, sizeof(back));
|
||||||
|
REQUIRE(strcmp(s, back) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("UTF16FromUTF8 Example4") {
|
SECTION("UTF16FromUTF8 Example4") {
|
||||||
@ -154,6 +166,9 @@ TEST_CASE("UniConversion") {
|
|||||||
REQUIRE(tlen == 2U);
|
REQUIRE(tlen == 2U);
|
||||||
REQUIRE(tbuf[0] == 0xD800);
|
REQUIRE(tbuf[0] == 0xD800);
|
||||||
REQUIRE(tbuf[1] == 0xDF48);
|
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") {
|
SECTION("UTF16FromUTF8 Invalid Trail byte in lead position") {
|
||||||
@ -165,6 +180,7 @@ TEST_CASE("UniConversion") {
|
|||||||
REQUIRE(tbuf[1] == 0xB5);
|
REQUIRE(tbuf[1] == 0xB5);
|
||||||
REQUIRE(tbuf[2] == 'y');
|
REQUIRE(tbuf[2] == 'y');
|
||||||
REQUIRE(tbuf[3] == 'z');
|
REQUIRE(tbuf[3] == 'z');
|
||||||
|
// Invalid so can't round trip
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("UTF16FromUTF8 Invalid Lead byte at end") {
|
SECTION("UTF16FromUTF8 Invalid Lead byte at end") {
|
||||||
@ -174,6 +190,7 @@ TEST_CASE("UniConversion") {
|
|||||||
REQUIRE(tlen == 2U);
|
REQUIRE(tlen == 2U);
|
||||||
REQUIRE(tbuf[0] == 'a');
|
REQUIRE(tbuf[0] == 'a');
|
||||||
REQUIRE(tbuf[1] == 0xC2);
|
REQUIRE(tbuf[1] == 0xC2);
|
||||||
|
// Invalid so can't round trip
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("UTF16FromUTF8 Invalid Lead byte implies 3 trails but only 2") {
|
SECTION("UTF16FromUTF8 Invalid Lead byte implies 3 trails but only 2") {
|
||||||
@ -183,6 +200,7 @@ TEST_CASE("UniConversion") {
|
|||||||
REQUIRE(tlen == 2U);
|
REQUIRE(tlen == 2U);
|
||||||
REQUIRE(tbuf[0] == 'a');
|
REQUIRE(tbuf[0] == 'a');
|
||||||
REQUIRE(tbuf[1] == 0xF1);
|
REQUIRE(tbuf[1] == 0xF1);
|
||||||
|
// Invalid so can't round trip
|
||||||
}
|
}
|
||||||
|
|
||||||
// UTF32FromUTF8
|
// UTF32FromUTF8
|
||||||
@ -193,6 +211,9 @@ TEST_CASE("UniConversion") {
|
|||||||
const size_t tlen = UTF32FromUTF8(s, tbuf, 1);
|
const size_t tlen = UTF32FromUTF8(s, tbuf, 1);
|
||||||
REQUIRE(tlen == 1U);
|
REQUIRE(tlen == 1U);
|
||||||
REQUIRE(tbuf[0] == static_cast<unsigned int>('a'));
|
REQUIRE(tbuf[0] == static_cast<unsigned int>('a'));
|
||||||
|
char back[5]{};
|
||||||
|
UTF8FromUTF32Character(tbuf[0], back);
|
||||||
|
REQUIRE(strcmp(s, back) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("UTF32FromUTF8 Example1") {
|
SECTION("UTF32FromUTF8 Example1") {
|
||||||
@ -201,6 +222,9 @@ TEST_CASE("UniConversion") {
|
|||||||
const size_t tlen = UTF32FromUTF8(s, tbuf, 1);
|
const size_t tlen = UTF32FromUTF8(s, tbuf, 1);
|
||||||
REQUIRE(tlen == 1U);
|
REQUIRE(tlen == 1U);
|
||||||
REQUIRE(tbuf[0] == 0x24);
|
REQUIRE(tbuf[0] == 0x24);
|
||||||
|
char back[5]{};
|
||||||
|
UTF8FromUTF32Character(tbuf[0], back);
|
||||||
|
REQUIRE(strcmp(s, back) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("UTF32FromUTF8 Example2") {
|
SECTION("UTF32FromUTF8 Example2") {
|
||||||
@ -209,6 +233,9 @@ TEST_CASE("UniConversion") {
|
|||||||
const size_t tlen = UTF32FromUTF8(s, tbuf, 1);
|
const size_t tlen = UTF32FromUTF8(s, tbuf, 1);
|
||||||
REQUIRE(tlen == 1U);
|
REQUIRE(tlen == 1U);
|
||||||
REQUIRE(tbuf[0] == 0xA2);
|
REQUIRE(tbuf[0] == 0xA2);
|
||||||
|
char back[5]{};
|
||||||
|
UTF8FromUTF32Character(tbuf[0], back);
|
||||||
|
REQUIRE(strcmp(s, back) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("UTF32FromUTF8 Example3") {
|
SECTION("UTF32FromUTF8 Example3") {
|
||||||
@ -217,6 +244,9 @@ TEST_CASE("UniConversion") {
|
|||||||
const size_t tlen = UTF32FromUTF8(s, tbuf, 1);
|
const size_t tlen = UTF32FromUTF8(s, tbuf, 1);
|
||||||
REQUIRE(tlen == 1U);
|
REQUIRE(tlen == 1U);
|
||||||
REQUIRE(tbuf[0] == 0x20AC);
|
REQUIRE(tbuf[0] == 0x20AC);
|
||||||
|
char back[5]{};
|
||||||
|
UTF8FromUTF32Character(tbuf[0], back);
|
||||||
|
REQUIRE(strcmp(s, back) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("UTF32FromUTF8 Example4") {
|
SECTION("UTF32FromUTF8 Example4") {
|
||||||
@ -225,6 +255,9 @@ TEST_CASE("UniConversion") {
|
|||||||
const size_t tlen = UTF32FromUTF8(s, tbuf, 1);
|
const size_t tlen = UTF32FromUTF8(s, tbuf, 1);
|
||||||
REQUIRE(tlen == 1U);
|
REQUIRE(tlen == 1U);
|
||||||
REQUIRE(tbuf[0] == 0x10348);
|
REQUIRE(tbuf[0] == 0x10348);
|
||||||
|
char back[5]{};
|
||||||
|
UTF8FromUTF32Character(tbuf[0], back);
|
||||||
|
REQUIRE(strcmp(s, back) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("UTF32FromUTF8 Invalid Trail byte in lead position") {
|
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
|
#ifndef USER_DEFAULT_SCREEN_DPI
|
||||||
#define USER_DEFAULT_SCREEN_DPI 96
|
#define USER_DEFAULT_SCREEN_DPI 96
|
||||||
#endif
|
#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;
|
extern void Platform_Initialise(void *hInstance) noexcept;
|
||||||
|
|
||||||
@ -24,6 +28,10 @@ constexpr RECT RectFromPRectangle(PRectangle prc) noexcept {
|
|||||||
return rc;
|
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 {
|
constexpr POINT POINTFromPoint(Point pt) noexcept {
|
||||||
return POINT{ static_cast<LONG>(pt.x), static_cast<LONG>(pt.y) };
|
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 };
|
return { rc.right - rc.left, rc.bottom - rc.top };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ColourRGBA ColourFromSys(int nIndex) noexcept;
|
||||||
|
|
||||||
constexpr HWND HwndFromWindowID(WindowID wid) noexcept {
|
constexpr HWND HwndFromWindowID(WindowID wid) noexcept {
|
||||||
return static_cast<HWND>(wid);
|
return static_cast<HWND>(wid);
|
||||||
}
|
}
|
||||||
@ -44,6 +54,10 @@ inline HWND HwndFromWindow(const Window &w) noexcept {
|
|||||||
return HwndFromWindowID(w.GetID());
|
return HwndFromWindowID(w.GetID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern HINSTANCE hinstPlatformRes;
|
||||||
|
|
||||||
|
UINT CodePageFromCharSet(CharacterSet characterSet, UINT documentCodePage) noexcept;
|
||||||
|
|
||||||
void *PointerFromWindow(HWND hWnd) noexcept;
|
void *PointerFromWindow(HWND hWnd) noexcept;
|
||||||
void SetWindowPointer(HWND hWnd, void *ptr) noexcept;
|
void SetWindowPointer(HWND hWnd, void *ptr) noexcept;
|
||||||
|
|
||||||
@ -54,8 +68,22 @@ float GetDeviceScaleFactorWhenGdiScalingActive(HWND hWnd) noexcept;
|
|||||||
|
|
||||||
int SystemMetricsForDpi(int nIndex, UINT dpi) noexcept;
|
int SystemMetricsForDpi(int nIndex, UINT dpi) noexcept;
|
||||||
|
|
||||||
|
void AdjustWindowRectForDpi(LPRECT lpRect, DWORD dwStyle, UINT dpi) noexcept;
|
||||||
|
|
||||||
HCURSOR LoadReverseArrowCursor(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 {
|
class MouseWheelDelta {
|
||||||
int wheelDelta = 0;
|
int wheelDelta = 0;
|
||||||
public:
|
public:
|
||||||
@ -70,29 +98,89 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(USE_D2D)
|
// Both GDI and DirectWrite can produce a HFONT for use in list boxes
|
||||||
extern bool LoadD2D() noexcept;
|
struct FontWin : public Font {
|
||||||
extern ID2D1Factory1 *pD2DFactory;
|
[[nodiscard]] virtual HFONT HFont() const noexcept = 0;
|
||||||
extern IDWriteFactory1 *pIDWriteFactory;
|
[[nodiscard]] virtual std::unique_ptr<FontWin> Duplicate() const = 0;
|
||||||
|
[[nodiscard]] virtual CharacterSet GetCharacterSet() const noexcept = 0;
|
||||||
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 {
|
// Buffer to hold strings and string position arrays without always allocating on heap.
|
||||||
virtual void SetRenderingParams(std::shared_ptr<RenderingParams> renderingParams_) = 0;
|
// 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>
|
#include <windows.h>
|
||||||
|
|
||||||
#define VERSION_SCINTILLA "5.5.5"
|
#define VERSION_SCINTILLA "5.5.6"
|
||||||
#define VERSION_WORDS 5, 5, 5, 0
|
#define VERSION_WORDS 5, 5, 6, 0
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION VERSION_WORDS
|
FILEVERSION VERSION_WORDS
|
||||||
|
@ -195,6 +195,9 @@
|
|||||||
<ClCompile Include="..\..\boostregex\*.cxx" />
|
<ClCompile Include="..\..\boostregex\*.cxx" />
|
||||||
<ClCompile Include="..\win32\HanjaDic.cxx" />
|
<ClCompile Include="..\win32\HanjaDic.cxx" />
|
||||||
<ClCompile Include="..\win32\PlatWin.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\ScintillaWin.cxx" />
|
||||||
<ClCompile Include="..\win32\ScintillaDLL.cxx" />
|
<ClCompile Include="..\win32\ScintillaDLL.cxx" />
|
||||||
</ItemGroup>
|
</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;
|
return fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void ReleaseLibrary(HMODULE &hLib) noexcept {
|
||||||
|
if (hLib) {
|
||||||
|
FreeLibrary(hLib);
|
||||||
|
hLib = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -3,6 +3,19 @@ $(DIR_O)/HanjaDic.o: \
|
|||||||
HanjaDic.cxx \
|
HanjaDic.cxx \
|
||||||
WinTypes.h \
|
WinTypes.h \
|
||||||
HanjaDic.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: \
|
$(DIR_O)/PlatWin.o: \
|
||||||
PlatWin.cxx \
|
PlatWin.cxx \
|
||||||
../include/ScintillaTypes.h \
|
../include/ScintillaTypes.h \
|
||||||
@ -13,7 +26,9 @@ $(DIR_O)/PlatWin.o: \
|
|||||||
../src/UniConversion.h \
|
../src/UniConversion.h \
|
||||||
../src/DBCS.h \
|
../src/DBCS.h \
|
||||||
WinTypes.h \
|
WinTypes.h \
|
||||||
PlatWin.h
|
PlatWin.h \
|
||||||
|
ListBox.h \
|
||||||
|
SurfaceD2D.h
|
||||||
$(DIR_O)/ScintillaDLL.o: \
|
$(DIR_O)/ScintillaDLL.o: \
|
||||||
ScintillaDLL.cxx \
|
ScintillaDLL.cxx \
|
||||||
../include/ScintillaTypes.h \
|
../include/ScintillaTypes.h \
|
||||||
@ -29,6 +44,7 @@ $(DIR_O)/ScintillaWin.o: \
|
|||||||
../src/Debugging.h \
|
../src/Debugging.h \
|
||||||
../src/Geometry.h \
|
../src/Geometry.h \
|
||||||
../src/Platform.h \
|
../src/Platform.h \
|
||||||
|
../src/CharacterType.h \
|
||||||
../src/CharacterCategoryMap.h \
|
../src/CharacterCategoryMap.h \
|
||||||
../src/Position.h \
|
../src/Position.h \
|
||||||
../src/UniqueString.h \
|
../src/UniqueString.h \
|
||||||
@ -49,6 +65,7 @@ $(DIR_O)/ScintillaWin.o: \
|
|||||||
../src/Document.h \
|
../src/Document.h \
|
||||||
../src/CaseConvert.h \
|
../src/CaseConvert.h \
|
||||||
../src/UniConversion.h \
|
../src/UniConversion.h \
|
||||||
|
../src/DBCS.h \
|
||||||
../src/Selection.h \
|
../src/Selection.h \
|
||||||
../src/PositionCache.h \
|
../src/PositionCache.h \
|
||||||
../src/EditModel.h \
|
../src/EditModel.h \
|
||||||
@ -60,8 +77,34 @@ $(DIR_O)/ScintillaWin.o: \
|
|||||||
../src/ScintillaBase.h \
|
../src/ScintillaBase.h \
|
||||||
WinTypes.h \
|
WinTypes.h \
|
||||||
PlatWin.h \
|
PlatWin.h \
|
||||||
|
SurfaceD2D.h \
|
||||||
HanjaDic.h \
|
HanjaDic.h \
|
||||||
ScintillaWin.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: \
|
$(DIR_O)/AutoComplete.o: \
|
||||||
../src/AutoComplete.cxx \
|
../src/AutoComplete.cxx \
|
||||||
../include/ScintillaTypes.h \
|
../include/ScintillaTypes.h \
|
||||||
|
@ -118,6 +118,9 @@ COMPONENT_OBJS = \
|
|||||||
$(SRC_OBJS) \
|
$(SRC_OBJS) \
|
||||||
$(DIR_O)/HanjaDic.o \
|
$(DIR_O)/HanjaDic.o \
|
||||||
$(DIR_O)/PlatWin.o \
|
$(DIR_O)/PlatWin.o \
|
||||||
|
$(DIR_O)/ListBox.o \
|
||||||
|
$(DIR_O)/SurfaceGDI.o \
|
||||||
|
$(DIR_O)/SurfaceD2D.o \
|
||||||
$(DIR_O)/ScintillaBase.o \
|
$(DIR_O)/ScintillaBase.o \
|
||||||
$(DIR_O)/ScintillaWin.o
|
$(DIR_O)/ScintillaWin.o
|
||||||
|
|
||||||
|
@ -3,6 +3,19 @@ $(DIR_O)/HanjaDic.obj: \
|
|||||||
HanjaDic.cxx \
|
HanjaDic.cxx \
|
||||||
WinTypes.h \
|
WinTypes.h \
|
||||||
HanjaDic.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: \
|
$(DIR_O)/PlatWin.obj: \
|
||||||
PlatWin.cxx \
|
PlatWin.cxx \
|
||||||
../include/ScintillaTypes.h \
|
../include/ScintillaTypes.h \
|
||||||
@ -13,7 +26,9 @@ $(DIR_O)/PlatWin.obj: \
|
|||||||
../src/UniConversion.h \
|
../src/UniConversion.h \
|
||||||
../src/DBCS.h \
|
../src/DBCS.h \
|
||||||
WinTypes.h \
|
WinTypes.h \
|
||||||
PlatWin.h
|
PlatWin.h \
|
||||||
|
ListBox.h \
|
||||||
|
SurfaceD2D.h
|
||||||
$(DIR_O)/ScintillaDLL.obj: \
|
$(DIR_O)/ScintillaDLL.obj: \
|
||||||
ScintillaDLL.cxx \
|
ScintillaDLL.cxx \
|
||||||
../include/ScintillaTypes.h \
|
../include/ScintillaTypes.h \
|
||||||
@ -29,6 +44,7 @@ $(DIR_O)/ScintillaWin.obj: \
|
|||||||
../src/Debugging.h \
|
../src/Debugging.h \
|
||||||
../src/Geometry.h \
|
../src/Geometry.h \
|
||||||
../src/Platform.h \
|
../src/Platform.h \
|
||||||
|
../src/CharacterType.h \
|
||||||
../src/CharacterCategoryMap.h \
|
../src/CharacterCategoryMap.h \
|
||||||
../src/Position.h \
|
../src/Position.h \
|
||||||
../src/UniqueString.h \
|
../src/UniqueString.h \
|
||||||
@ -49,6 +65,7 @@ $(DIR_O)/ScintillaWin.obj: \
|
|||||||
../src/Document.h \
|
../src/Document.h \
|
||||||
../src/CaseConvert.h \
|
../src/CaseConvert.h \
|
||||||
../src/UniConversion.h \
|
../src/UniConversion.h \
|
||||||
|
../src/DBCS.h \
|
||||||
../src/Selection.h \
|
../src/Selection.h \
|
||||||
../src/PositionCache.h \
|
../src/PositionCache.h \
|
||||||
../src/EditModel.h \
|
../src/EditModel.h \
|
||||||
@ -60,8 +77,34 @@ $(DIR_O)/ScintillaWin.obj: \
|
|||||||
../src/ScintillaBase.h \
|
../src/ScintillaBase.h \
|
||||||
WinTypes.h \
|
WinTypes.h \
|
||||||
PlatWin.h \
|
PlatWin.h \
|
||||||
|
SurfaceD2D.h \
|
||||||
HanjaDic.h \
|
HanjaDic.h \
|
||||||
ScintillaWin.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: \
|
$(DIR_O)/AutoComplete.obj: \
|
||||||
../src/AutoComplete.cxx \
|
../src/AutoComplete.cxx \
|
||||||
../include/ScintillaTypes.h \
|
../include/ScintillaTypes.h \
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
.SUFFIXES: .cxx
|
.SUFFIXES: .cxx
|
||||||
|
|
||||||
DIR_O=.
|
DIR_O=obj
|
||||||
DIR_BIN=..\bin
|
DIR_BIN=..\bin
|
||||||
|
|
||||||
COMPONENT=$(DIR_BIN)\Scintilla.dll
|
COMPONENT=$(DIR_BIN)\Scintilla.dll
|
||||||
@ -18,6 +18,10 @@ LIBSCI=$(DIR_BIN)\libscintilla.lib
|
|||||||
|
|
||||||
LD=link
|
LD=link
|
||||||
|
|
||||||
|
!IF "$(PLATFORM:64=)" == "arm"
|
||||||
|
ARM64=1
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
!IFDEF SUPPORT_XP
|
!IFDEF SUPPORT_XP
|
||||||
ADD_DEFINE=-D_USING_V110_SDK71_
|
ADD_DEFINE=-D_USING_V110_SDK71_
|
||||||
# Different subsystems for 32-bit and 64-bit Windows XP so detect based on Platform
|
# 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
|
SUBSYSTEM=-SUBSYSTEM:WINDOWS,5.01
|
||||||
!ENDIF
|
!ENDIF
|
||||||
!ELSE
|
!ELSE
|
||||||
CETCOMPAT=-CETCOMPAT
|
|
||||||
!IFDEF ARM64
|
!IFDEF ARM64
|
||||||
ADD_DEFINE=-D_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1
|
ADD_DEFINE=-D_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1
|
||||||
SUBSYSTEM=-SUBSYSTEM:WINDOWS,10.00
|
SUBSYSTEM=-SUBSYSTEM:WINDOWS,10.00
|
||||||
|
!ELSE
|
||||||
|
CETCOMPAT=-CETCOMPAT
|
||||||
!ENDIF
|
!ENDIF
|
||||||
!ENDIF
|
!ENDIF
|
||||||
|
|
||||||
@ -65,7 +70,10 @@ CXXFLAGS=$(CXXFLAGS) $(CXXNDEBUG)
|
|||||||
INCLUDES=-I../include -I../src
|
INCLUDES=-I../include -I../src
|
||||||
CXXFLAGS=$(CXXFLAGS) $(INCLUDES)
|
CXXFLAGS=$(CXXFLAGS) $(INCLUDES)
|
||||||
|
|
||||||
all: $(COMPONENT) $(LIBSCI)
|
all: $(DIR_O) $(COMPONENT) $(LIBSCI)
|
||||||
|
|
||||||
|
$(DIR_O):
|
||||||
|
mkdir "$(DIR_O)" 2>NUL || cd .
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
-del /q $(DIR_O)\*.obj $(DIR_O)\*.pdb $(DIR_O)\*.asm $(COMPONENT) \
|
-del /q $(DIR_O)\*.obj $(DIR_O)\*.pdb $(DIR_O)\*.asm $(COMPONENT) \
|
||||||
@ -117,6 +125,9 @@ SRC_OBJS=\
|
|||||||
COMPONENT_OBJS = \
|
COMPONENT_OBJS = \
|
||||||
$(DIR_O)\HanjaDic.obj \
|
$(DIR_O)\HanjaDic.obj \
|
||||||
$(DIR_O)\PlatWin.obj \
|
$(DIR_O)\PlatWin.obj \
|
||||||
|
$(DIR_O)\ListBox.obj \
|
||||||
|
$(DIR_O)\SurfaceGDI.obj \
|
||||||
|
$(DIR_O)\SurfaceD2D.obj \
|
||||||
$(DIR_O)\ScintillaBase.obj \
|
$(DIR_O)\ScintillaBase.obj \
|
||||||
$(DIR_O)\ScintillaWin.obj \
|
$(DIR_O)\ScintillaWin.obj \
|
||||||
$(SRC_OBJS)
|
$(SRC_OBJS)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user