diff options
author | Neil <nyamatongwe@gmail.com> | 2021-03-19 13:43:32 +1100 |
---|---|---|
committer | Neil <nyamatongwe@gmail.com> | 2021-03-19 13:43:32 +1100 |
commit | 9659ea34246320bd9872740d1ee6a5c9ae9066c6 (patch) | |
tree | cf185d19f133dd40a7faed0bd24c1a04fb12a1be | |
parent | 63fbfcb7c05dc7035ebf80805be70b0109def792 (diff) | |
download | scintilla-mirror-9659ea34246320bd9872740d1ee6a5c9ae9066c6.tar.gz |
Add Geometry.cxx for geometric and colour operations too complex for headers.
Add FillStroke to hold parameters for drawing shapes.
-rw-r--r-- | cocoa/Scintilla/Scintilla.xcodeproj/project.pbxproj | 12 | ||||
-rw-r--r-- | gtk/deps.mak | 3 | ||||
-rw-r--r-- | gtk/makefile | 1 | ||||
-rw-r--r-- | qt/ScintillaEdit/ScintillaEdit.pro | 1 | ||||
-rw-r--r-- | qt/ScintillaEditBase/ScintillaEditBase.pro | 1 | ||||
-rw-r--r-- | src/Geometry.cxx | 97 | ||||
-rw-r--r-- | src/Geometry.h | 101 | ||||
-rw-r--r-- | win32/deps.mak | 3 | ||||
-rw-r--r-- | win32/makefile | 1 | ||||
-rw-r--r-- | win32/nmdeps.mak | 3 | ||||
-rw-r--r-- | win32/scintilla.mak | 1 |
11 files changed, 217 insertions, 7 deletions
diff --git a/cocoa/Scintilla/Scintilla.xcodeproj/project.pbxproj b/cocoa/Scintilla/Scintilla.xcodeproj/project.pbxproj index 5ae456664..d0e7a0c8d 100644 --- a/cocoa/Scintilla/Scintilla.xcodeproj/project.pbxproj +++ b/cocoa/Scintilla/Scintilla.xcodeproj/project.pbxproj @@ -87,6 +87,9 @@ 286F8E6425F84F7400EC8D60 /* ILexer.h in Headers */ = {isa = PBXBuildFile; fileRef = 286F8E6025F84F7400EC8D60 /* ILexer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 286F8E6525F84F7400EC8D60 /* ILoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 286F8E6125F84F7400EC8D60 /* ILoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; 286F8E6625F84F7400EC8D60 /* Scintilla.h in Headers */ = {isa = PBXBuildFile; fileRef = 286F8E6225F84F7400EC8D60 /* Scintilla.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 286F8EDE260448C300EC8D60 /* Platform.h in Headers */ = {isa = PBXBuildFile; fileRef = 286F8EDB260448C300EC8D60 /* Platform.h */; }; + 286F8EDF260448C300EC8D60 /* Geometry.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 286F8EDC260448C300EC8D60 /* Geometry.cxx */; }; + 286F8EE0260448C300EC8D60 /* Geometry.h in Headers */ = {isa = PBXBuildFile; fileRef = 286F8EDD260448C300EC8D60 /* Geometry.h */; }; 287F3C6A246F90240040E76F /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 287F3C69246F90240040E76F /* Cocoa.framework */; }; 287F3C6C246F90300040E76F /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 287F3C6B246F90300040E76F /* QuartzCore.framework */; }; 28EA9CAE255894B4007710C4 /* CharacterCategory.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 28EA9CAA255894B4007710C4 /* CharacterCategory.cxx */; }; @@ -177,6 +180,9 @@ 286F8E6025F84F7400EC8D60 /* ILexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ILexer.h; path = ../../include/ILexer.h; sourceTree = "<group>"; }; 286F8E6125F84F7400EC8D60 /* ILoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ILoader.h; path = ../../include/ILoader.h; sourceTree = "<group>"; }; 286F8E6225F84F7400EC8D60 /* Scintilla.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Scintilla.h; path = ../../include/Scintilla.h; sourceTree = "<group>"; }; + 286F8EDB260448C300EC8D60 /* Platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Platform.h; path = ../../src/Platform.h; sourceTree = "<group>"; }; + 286F8EDC260448C300EC8D60 /* Geometry.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Geometry.cxx; path = ../../src/Geometry.cxx; sourceTree = "<group>"; }; + 286F8EDD260448C300EC8D60 /* Geometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Geometry.h; path = ../../src/Geometry.h; sourceTree = "<group>"; }; 287F3C41246F8DC70040E76F /* Scintilla.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Scintilla.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 287F3C69246F90240040E76F /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 287F3C6B246F90300040E76F /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; @@ -254,6 +260,8 @@ 2829371324E2D58600C84BA2 /* EditView.h */, 282936EC24E2D58400C84BA2 /* ElapsedPeriod.h */, 2829372024E2D58700C84BA2 /* FontQuality.h */, + 286F8EDC260448C300EC8D60 /* Geometry.cxx */, + 286F8EDD260448C300EC8D60 /* Geometry.h */, 286F8E6025F84F7400EC8D60 /* ILexer.h */, 286F8E6125F84F7400EC8D60 /* ILoader.h */, 282936F624E2D58400C84BA2 /* Indicator.cxx */, @@ -268,6 +276,7 @@ 2829371F24E2D58700C84BA2 /* Partitioning.h */, 2829371024E2D58500C84BA2 /* PerLine.cxx */, 282936FA24E2D58400C84BA2 /* PerLine.h */, + 286F8EDB260448C300EC8D60 /* Platform.h */, 282936F824E2D58400C84BA2 /* Position.h */, 2829370224E2D58500C84BA2 /* PositionCache.cxx */, 282936EE24E2D58400C84BA2 /* PositionCache.h */, @@ -351,6 +360,7 @@ 2829373224E2D58800C84BA2 /* KeyMap.h in Headers */, 2829376324E2D58800C84BA2 /* FontQuality.h in Headers */, 2829373E24E2D58800C84BA2 /* Indicator.h in Headers */, + 286F8EDE260448C300EC8D60 /* Platform.h in Headers */, 2829375C24E2D58800C84BA2 /* CellBuffer.h in Headers */, 2829373F24E2D58800C84BA2 /* UniConversion.h in Headers */, 2829373D24E2D58800C84BA2 /* PerLine.h in Headers */, @@ -391,6 +401,7 @@ 2829374D24E2D58800C84BA2 /* AutoComplete.h in Headers */, 2829374124E2D58800C84BA2 /* CharClassify.h in Headers */, 2829373124E2D58800C84BA2 /* PositionCache.h in Headers */, + 286F8EE0260448C300EC8D60 /* Geometry.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -493,6 +504,7 @@ 28EA9CAE255894B4007710C4 /* CharacterCategory.cxx in Sources */, 2829374024E2D58800C84BA2 /* XPM.cxx in Sources */, 2829374B24E2D58800C84BA2 /* Decoration.cxx in Sources */, + 286F8EDF260448C300EC8D60 /* Geometry.cxx in Sources */, 2829373624E2D58800C84BA2 /* UniqueString.cxx in Sources */, 282936E824E2D55D00C84BA2 /* ScintillaView.mm in Sources */, 2829376924E2D58800C84BA2 /* CellBuffer.cxx in Sources */, diff --git a/gtk/deps.mak b/gtk/deps.mak index f446b6dd1..749a3a0d1 100644 --- a/gtk/deps.mak +++ b/gtk/deps.mak @@ -288,6 +288,9 @@ EditView.o: \ ../src/MarginView.h \ ../src/EditView.h \ ../src/ElapsedPeriod.h +Geometry.o: \ + ../src/Geometry.cxx \ + ../src/Geometry.h Indicator.o: \ ../src/Indicator.cxx \ ../src/Debugging.h \ diff --git a/gtk/makefile b/gtk/makefile index 862276097..a820e1476 100644 --- a/gtk/makefile +++ b/gtk/makefile @@ -138,6 +138,7 @@ SRC_OBJS = \ EditModel.o \ Editor.o \ EditView.o \ + Geometry.o \ Indicator.o \ KeyMap.o \ LineMarker.o \ diff --git a/qt/ScintillaEdit/ScintillaEdit.pro b/qt/ScintillaEdit/ScintillaEdit.pro index 244352d2d..36ffdd017 100644 --- a/qt/ScintillaEdit/ScintillaEdit.pro +++ b/qt/ScintillaEdit/ScintillaEdit.pro @@ -35,6 +35,7 @@ SOURCES += \ ../../src/LineMarker.cxx \ ../../src/KeyMap.cxx \ ../../src/Indicator.cxx \ + ../../src/Geometry.cxx \ ../../src/EditView.cxx \ ../../src/Editor.cxx \ ../../src/EditModel.cxx \ diff --git a/qt/ScintillaEditBase/ScintillaEditBase.pro b/qt/ScintillaEditBase/ScintillaEditBase.pro index c39b0f1f6..e867418f9 100644 --- a/qt/ScintillaEditBase/ScintillaEditBase.pro +++ b/qt/ScintillaEditBase/ScintillaEditBase.pro @@ -33,6 +33,7 @@ SOURCES += \ ../../src/LineMarker.cxx \ ../../src/KeyMap.cxx \ ../../src/Indicator.cxx \ + ../../src/Geometry.cxx \ ../../src/EditView.cxx \ ../../src/Editor.cxx \ ../../src/EditModel.cxx \ diff --git a/src/Geometry.cxx b/src/Geometry.cxx new file mode 100644 index 000000000..68ce1f628 --- /dev/null +++ b/src/Geometry.cxx @@ -0,0 +1,97 @@ +// Scintilla source code edit control +/** @file Geometry.cxx + ** Helper functions for geometric calculations. + **/ +// Copyright 2020 by Neil Hodgson <neilh@scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +#include <cmath> + +#include <algorithm> + +#include "Geometry.h" + +namespace Scintilla { + +PRectangle Clamp(PRectangle rc, Edge edge, XYPOSITION position) noexcept { + switch (edge) { + case Edge::left: + return PRectangle(std::clamp(position, rc.left, rc.right), rc.top, rc.right, rc.bottom); + case Edge::top: + return PRectangle(rc.left, std::clamp(position, rc.top, rc.bottom), rc.right, rc.bottom); + case Edge::right: + return PRectangle(rc.left, rc.top, std::clamp(position, rc.left, rc.right), rc.bottom); + case Edge::bottom: + default: + return PRectangle(rc.left, rc.top, rc.right, std::clamp(position, rc.top, rc.bottom)); + } +} + +PRectangle Side(PRectangle rc, Edge edge, XYPOSITION size) noexcept { + switch (edge) { + case Edge::left: + return PRectangle(rc.left, rc.top, std::min(rc.left + size, rc.right), rc.bottom); + case Edge::top: + return PRectangle(rc.left, rc.top, rc.right, std::min(rc.top + size, rc.bottom)); + case Edge::right: + return PRectangle(std::max(rc.left, rc.right - size), rc.top, rc.right, rc.bottom); + case Edge::bottom: + default: + return PRectangle(rc.left, std::max(rc.top, rc.bottom - size), rc.right, rc.bottom); + } +} + +Interval Intersection(Interval a, Interval b) noexcept { + const XYPOSITION leftMax = std::max(a.left, b.left); + const XYPOSITION rightMin = std::min(a.right, b.right); + // If the result would have a negative width. make empty instead. + const XYPOSITION rightResult = (rightMin >= leftMax) ? rightMin : leftMax; + return { leftMax, rightResult }; +} + +PRectangle Intersection(PRectangle rc, Interval horizontalBounds) noexcept { + const Interval intersection = Intersection(HorizontalBounds(rc), horizontalBounds); + return PRectangle(intersection.left, rc.top, intersection.right, rc.bottom); +} + +Interval HorizontalBounds(PRectangle rc) noexcept { + return { rc.left, rc.right }; +} + +XYPOSITION PixelAlign(XYPOSITION xy, int pixelDivisions) noexcept { + return std::round(xy * pixelDivisions) / pixelDivisions; +} + +XYPOSITION PixelAlignFloor(XYPOSITION xy, int pixelDivisions) noexcept { + return std::floor(xy * pixelDivisions) / pixelDivisions; +} + +Point PixelAlign(const Point &pt, int pixelDivisions) noexcept { + return Point( + std::round(pt.x * pixelDivisions) / pixelDivisions, + std::round(pt.y * pixelDivisions) / pixelDivisions); +} + +PRectangle PixelAlign(const PRectangle &rc, int pixelDivisions) noexcept { + // Move left and right side to nearest pixel to avoid blurry visuals. + // The top and bottom should be integers but floor them to make sure. + // `pixelDivisions` is commonly 1 except for 'retina' displays where it is 2. + // On retina displays, the positions should be moved to the nearest device + // pixel which is the nearest half logical pixel. + return PRectangle( + std::round(rc.left * pixelDivisions) / pixelDivisions, + PixelAlignFloor(rc.top, pixelDivisions), + std::round(rc.right * pixelDivisions) / pixelDivisions, + PixelAlignFloor(rc.bottom, pixelDivisions)); +} + +PRectangle PixelAlignOutside(const PRectangle &rc, int pixelDivisions) noexcept { + // Move left and right side to extremes (floor(left) ceil(right)) to avoid blurry visuals. + return PRectangle( + std::floor(rc.left * pixelDivisions) / pixelDivisions, + std::floor(rc.top * pixelDivisions) / pixelDivisions, + std::ceil(rc.right * pixelDivisions) / pixelDivisions, + std::floor(rc.bottom * pixelDivisions) / pixelDivisions); +} + +} diff --git a/src/Geometry.h b/src/Geometry.h index 35702a468..bab50d502 100644 --- a/src/Geometry.h +++ b/src/Geometry.h @@ -35,6 +35,10 @@ public: return Point(static_cast<XYPOSITION>(x_), static_cast<XYPOSITION>(y_)); } + constexpr bool operator==(Point other) const noexcept { + return (x == other.x) && (y == other.y); + } + constexpr bool operator!=(Point other) const noexcept { return (x != other.x) || (y != other.y); } @@ -50,9 +54,24 @@ public: // Other automatically defined methods (assignment, copy constructor, destructor) are fine }; -struct Interval { + +/** + * A geometric interval class. + */ +class Interval { +public: XYPOSITION left; XYPOSITION right; + constexpr bool operator==(const Interval &other) const noexcept { + return (left == other.left) && (right == other.right); + } + constexpr XYPOSITION Width() const noexcept { return right - left; } + constexpr bool Empty() const noexcept { + return Width() <= 0; + } + constexpr bool Intersects(Interval other) const noexcept { + return (right > other.left) && (left < other.right); + } }; /** @@ -105,6 +124,15 @@ public: right += xDelta; bottom += yDelta; } + + constexpr PRectangle Inset(XYPOSITION delta) const noexcept { + return PRectangle(left + delta, top + delta, right - delta, bottom - delta); + } + + constexpr Point Centre() const noexcept { + return Point((left + right) / 2, (top + bottom) / 2); + } + constexpr XYPOSITION Width() const noexcept { return right - left; } constexpr XYPOSITION Height() const noexcept { return bottom - top; } constexpr bool Empty() const noexcept { @@ -112,6 +140,23 @@ public: } }; +enum class Edge { left, top, bottom, right }; + +PRectangle Clamp(PRectangle rc, Edge edge, XYPOSITION position) noexcept; +PRectangle Side(PRectangle rc, Edge edge, XYPOSITION size) noexcept; + +Interval Intersection(Interval a, Interval b) noexcept; +PRectangle Intersection(PRectangle rc, Interval horizontalBounds) noexcept; +Interval HorizontalBounds(PRectangle rc) noexcept; + +XYPOSITION PixelAlign(XYPOSITION xy, int pixelDivisions) noexcept; +XYPOSITION PixelAlignFloor(XYPOSITION xy, int pixelDivisions) noexcept; + +Point PixelAlign(const Point &pt, int pixelDivisions) noexcept; + +PRectangle PixelAlign(const PRectangle &rc, int pixelDivisions) noexcept; +PRectangle PixelAlignOutside(const PRectangle &rc, int pixelDivisions) noexcept; + /** * Holds an RGB colour with 8 bits for each component. */ @@ -165,11 +210,7 @@ public: constexpr explicit ColourAlpha(int co_ = 0) noexcept : ColourDesired(co_) { } - constexpr ColourAlpha(unsigned int red, unsigned int green, unsigned int blue) noexcept : - ColourDesired(red | (green << 8) | (blue << 16)) { - } - - constexpr ColourAlpha(unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha) noexcept : + constexpr ColourAlpha(unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha=0xff) noexcept : ColourDesired(red | (green << 8) | (blue << 16) | (alpha << 24)) { } @@ -177,6 +218,10 @@ public: ColourDesired(cd.AsInteger() | (alpha << 24)) { } + constexpr ColourAlpha(ColourDesired cd) noexcept : + ColourDesired(cd.AsInteger() | (0xff << 24)) { + } + constexpr ColourDesired GetColour() const noexcept { return ColourDesired(AsInteger() & 0xffffff); } @@ -189,6 +234,10 @@ public: return GetAlpha() / componentMaximum; } + constexpr bool IsOpaque() const noexcept { + return GetAlpha() == 0xff; + } + constexpr ColourAlpha MixedWith(ColourAlpha other) const noexcept { const unsigned int red = (GetRed() + other.GetRed()) / 2; const unsigned int green = (GetGreen() + other.GetGreen()) / 2; @@ -199,13 +248,51 @@ public: }; /** +* Holds an RGBA colour and stroke width to stroke a shape. +*/ +class Stroke { +public: + ColourAlpha colourStroke; + XYPOSITION widthStroke; + constexpr Stroke(ColourAlpha colourStroke_, XYPOSITION widthStroke_=1.0f) noexcept : + colourStroke(colourStroke_), widthStroke(widthStroke_) { + } +}; + +/** +* Holds an RGBA colour to fill a shape. +*/ +class Fill { +public: + ColourAlpha colourFill; + constexpr Fill(ColourAlpha colourFill_) noexcept : + colourFill(colourFill_) { + } +}; + +/** +* Holds a pair of RGBA colours and stroke width to fill and stroke a shape. +*/ +class FillStroke { +public: + Fill fill; + Stroke stroke; + constexpr FillStroke(ColourAlpha colourFill_, ColourAlpha colourStroke_, XYPOSITION widthStroke_=1.0f) noexcept : + fill(colourFill_), stroke(colourStroke_, widthStroke_) { + } + constexpr FillStroke(ColourAlpha colourBoth, XYPOSITION widthStroke_=1.0f) noexcept : + fill(colourBoth), stroke(colourBoth, widthStroke_) { + } +}; + +/** * Holds an element of a gradient with an RGBA colour and a relative position. */ class ColourStop { public: float position; ColourAlpha colour; - ColourStop(float position_, ColourAlpha colour_) noexcept : + constexpr ColourStop(float position_, ColourAlpha colour_) noexcept : position(position_), colour(colour_) { } }; diff --git a/win32/deps.mak b/win32/deps.mak index 71978a153..af07609e1 100644 --- a/win32/deps.mak +++ b/win32/deps.mak @@ -254,6 +254,9 @@ EditView.o: \ ../src/MarginView.h \ ../src/EditView.h \ ../src/ElapsedPeriod.h +Geometry.o: \ + ../src/Geometry.cxx \ + ../src/Geometry.h Indicator.o: \ ../src/Indicator.cxx \ ../src/Debugging.h \ diff --git a/win32/makefile b/win32/makefile index 5e005fe24..7dd2604bb 100644 --- a/win32/makefile +++ b/win32/makefile @@ -96,6 +96,7 @@ SRC_OBJS = \ EditModel.o \ Editor.o \ EditView.o \ + Geometry.o \ Indicator.o \ KeyMap.o \ LineMarker.o \ diff --git a/win32/nmdeps.mak b/win32/nmdeps.mak index 601f10acd..d9ba665f5 100644 --- a/win32/nmdeps.mak +++ b/win32/nmdeps.mak @@ -254,6 +254,9 @@ $(DIR_O)/EditView.obj: \ ../src/MarginView.h \ ../src/EditView.h \ ../src/ElapsedPeriod.h +$(DIR_O)/Geometry.obj: \ + ../src/Geometry.cxx \ + ../src/Geometry.h $(DIR_O)/Indicator.obj: \ ../src/Indicator.cxx \ ../src/Debugging.h \ diff --git a/win32/scintilla.mak b/win32/scintilla.mak index 7a7fb89da..edb0c7de8 100644 --- a/win32/scintilla.mak +++ b/win32/scintilla.mak @@ -89,6 +89,7 @@ SRC_OBJS=\ $(DIR_O)\EditModel.obj \ $(DIR_O)\Editor.obj \ $(DIR_O)\EditView.obj \ + $(DIR_O)\Geometry.obj \ $(DIR_O)\Indicator.obj \ $(DIR_O)\KeyMap.obj \ $(DIR_O)\LineMarker.obj \ |