1 // Scintilla source code edit control
3 ** Classes and functions for geometric and colour calculations.
5 // Copyright 2020 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
11 namespace Scintilla::Internal
{
13 typedef double XYPOSITION
;
14 typedef double XYACCUMULATOR
;
17 * A geometric point class.
18 * Point is similar to the Win32 POINT and GTK+ GdkPoint types.
25 constexpr explicit Point(XYPOSITION x_
=0, XYPOSITION y_
=0) noexcept
: x(x_
), y(y_
) {
28 static constexpr Point
FromInts(int x_
, int y_
) noexcept
{
29 return Point(static_cast<XYPOSITION
>(x_
), static_cast<XYPOSITION
>(y_
));
32 constexpr bool operator==(Point other
) const noexcept
{
33 return (x
== other
.x
) && (y
== other
.y
);
36 constexpr bool operator!=(Point other
) const noexcept
{
37 return (x
!= other
.x
) || (y
!= other
.y
);
40 constexpr Point
operator+(Point other
) const noexcept
{
41 return Point(x
+ other
.x
, y
+ other
.y
);
44 constexpr Point
operator-(Point other
) const noexcept
{
45 return Point(x
- other
.x
, y
- other
.y
);
48 // Other automatically defined methods (assignment, copy constructor, destructor) are fine
53 * A geometric interval class.
59 constexpr bool operator==(const Interval
&other
) const noexcept
{
60 return (left
== other
.left
) && (right
== other
.right
);
62 constexpr XYPOSITION
Width() const noexcept
{ return right
- left
; }
63 constexpr bool Empty() const noexcept
{
66 constexpr bool Intersects(Interval other
) const noexcept
{
67 return (right
> other
.left
) && (left
< other
.right
);
69 constexpr Interval
Offset(XYPOSITION offset
) const noexcept
{
70 return {left
+ offset
, right
+ offset
};
75 * A geometric rectangle class.
76 * PRectangle is similar to Win32 RECT.
77 * PRectangles contain their top and left sides, but not their right and bottom sides.
86 constexpr explicit PRectangle(XYPOSITION left_
=0, XYPOSITION top_
=0, XYPOSITION right_
=0, XYPOSITION bottom_
= 0) noexcept
:
87 left(left_
), top(top_
), right(right_
), bottom(bottom_
) {
90 static constexpr PRectangle
FromInts(int left_
, int top_
, int right_
, int bottom_
) noexcept
{
91 return PRectangle(static_cast<XYPOSITION
>(left_
), static_cast<XYPOSITION
>(top_
),
92 static_cast<XYPOSITION
>(right_
), static_cast<XYPOSITION
>(bottom_
));
95 // Other automatically defined methods (assignment, copy constructor, destructor) are fine
97 constexpr bool operator==(const PRectangle
&rc
) const noexcept
{
98 return (rc
.left
== left
) && (rc
.right
== right
) &&
99 (rc
.top
== top
) && (rc
.bottom
== bottom
);
101 constexpr bool Contains(Point pt
) const noexcept
{
102 return (pt
.x
>= left
) && (pt
.x
<= right
) &&
103 (pt
.y
>= top
) && (pt
.y
<= bottom
);
105 constexpr bool ContainsWholePixel(Point pt
) const noexcept
{
106 // Does the rectangle contain all of the pixel to left/below the point
107 return (pt
.x
>= left
) && ((pt
.x
+1) <= right
) &&
108 (pt
.y
>= top
) && ((pt
.y
+1) <= bottom
);
110 constexpr bool Contains(PRectangle rc
) const noexcept
{
111 return (rc
.left
>= left
) && (rc
.right
<= right
) &&
112 (rc
.top
>= top
) && (rc
.bottom
<= bottom
);
114 constexpr bool Intersects(PRectangle other
) const noexcept
{
115 return (right
> other
.left
) && (left
< other
.right
) &&
116 (bottom
> other
.top
) && (top
< other
.bottom
);
118 constexpr bool Intersects(Interval horizontalBounds
) const noexcept
{
119 return (right
> horizontalBounds
.left
) && (left
< horizontalBounds
.right
);
122 void Move(XYPOSITION xDelta
, XYPOSITION yDelta
) noexcept
{
129 PRectangle
WithHorizontalBounds(Interval horizontal
) const noexcept
{
130 return PRectangle(horizontal
.left
, top
, horizontal
.right
, bottom
);
133 constexpr PRectangle
Inset(XYPOSITION delta
) const noexcept
{
134 return PRectangle(left
+ delta
, top
+ delta
, right
- delta
, bottom
- delta
);
137 constexpr PRectangle
Inset(Point delta
) const noexcept
{
138 return PRectangle(left
+ delta
.x
, top
+ delta
.y
, right
- delta
.x
, bottom
- delta
.y
);
141 constexpr Point
Centre() const noexcept
{
142 return Point((left
+ right
) / 2, (top
+ bottom
) / 2);
145 constexpr XYPOSITION
Width() const noexcept
{ return right
- left
; }
146 constexpr XYPOSITION
Height() const noexcept
{ return bottom
- top
; }
147 constexpr bool Empty() const noexcept
{
148 return (Height() <= 0) || (Width() <= 0);
152 enum class Edge
{ left
, top
, bottom
, right
};
154 PRectangle
Clamp(PRectangle rc
, Edge edge
, XYPOSITION position
) noexcept
;
155 PRectangle
Side(PRectangle rc
, Edge edge
, XYPOSITION size
) noexcept
;
157 Interval
Intersection(Interval a
, Interval b
) noexcept
;
158 PRectangle
Intersection(PRectangle rc
, Interval horizontalBounds
) noexcept
;
159 Interval
HorizontalBounds(PRectangle rc
) noexcept
;
161 XYPOSITION
PixelAlign(XYPOSITION xy
, int pixelDivisions
) noexcept
;
162 XYPOSITION
PixelAlignFloor(XYPOSITION xy
, int pixelDivisions
) noexcept
;
163 XYPOSITION
PixelAlignCeil(XYPOSITION xy
, int pixelDivisions
) noexcept
;
165 Point
PixelAlign(const Point
&pt
, int pixelDivisions
) noexcept
;
167 PRectangle
PixelAlign(const PRectangle
&rc
, int pixelDivisions
) noexcept
;
168 PRectangle
PixelAlignOutside(const PRectangle
&rc
, int pixelDivisions
) noexcept
;
171 * Holds an RGBA colour with 8 bits for each component.
173 constexpr const float componentMaximum
= 255.0f
;
175 static constexpr int rgbMask
= 0xffffff;
178 constexpr explicit ColourRGBA(int co_
= 0) noexcept
: co(co_
) {
181 constexpr ColourRGBA(unsigned int red
, unsigned int green
, unsigned int blue
, unsigned int alpha
=0xff) noexcept
:
182 ColourRGBA(red
| (green
<< 8) | (blue
<< 16) | (alpha
<< 24)) {
185 constexpr ColourRGBA(ColourRGBA cd
, unsigned int alpha
) noexcept
:
186 ColourRGBA(cd
.OpaqueRGB() | (alpha
<< 24)) {
189 static constexpr ColourRGBA
FromRGB(int co_
) noexcept
{
190 return ColourRGBA(co_
| (0xffu
<< 24));
193 static constexpr ColourRGBA
FromIpRGB(intptr_t co_
) noexcept
{
194 return ColourRGBA((co_
& rgbMask
) | (0xffu
<< 24));
197 constexpr ColourRGBA
WithoutAlpha() const noexcept
{
198 return ColourRGBA(co
& rgbMask
);
201 constexpr ColourRGBA
Opaque() const noexcept
{
202 return ColourRGBA(co
| (0xffu
<< 24));
205 constexpr int AsInteger() const noexcept
{
209 constexpr int OpaqueRGB() const noexcept
{
213 // Red, green and blue values as bytes 0..255
214 constexpr unsigned char GetRed() const noexcept
{
217 constexpr unsigned char GetGreen() const noexcept
{
218 return (co
>> 8) & 0xffU
;
220 constexpr unsigned char GetBlue() const noexcept
{
221 return (co
>> 16) & 0xffU
;
223 constexpr unsigned char GetAlpha() const noexcept
{
224 // Use a temporary here to prevent a 'Wconversion' warning from GCC
225 const int shifted
= co
>> 24;
226 return shifted
& 0xffU
;
229 // Red, green, blue, and alpha values as float 0..1.0
230 constexpr float GetRedComponent() const noexcept
{
231 return GetRed() / componentMaximum
;
233 constexpr float GetGreenComponent() const noexcept
{
234 return GetGreen() / componentMaximum
;
236 constexpr float GetBlueComponent() const noexcept
{
237 return GetBlue() / componentMaximum
;
239 constexpr float GetAlphaComponent() const noexcept
{
240 return GetAlpha() / componentMaximum
;
243 constexpr bool operator==(const ColourRGBA
&other
) const noexcept
{
244 return co
== other
.co
;
247 constexpr bool IsOpaque() const noexcept
{
248 return GetAlpha() == 0xff;
251 ColourRGBA
MixedWith(ColourRGBA other
) const noexcept
;
252 ColourRGBA
MixedWith(ColourRGBA other
, double proportion
) const noexcept
;
256 * Holds an RGBA colour and stroke width to stroke a shape.
262 constexpr Stroke(ColourRGBA colour_
, XYPOSITION width_
=1.0) noexcept
:
263 colour(colour_
), width(width_
) {
265 constexpr float WidthF() const noexcept
{
266 return static_cast<float>(width
);
271 * Holds an RGBA colour to fill a shape.
276 constexpr Fill(ColourRGBA colour_
) noexcept
:
282 * Holds a pair of RGBA colours and stroke width to fill and stroke a shape.
288 constexpr FillStroke(ColourRGBA colourFill_
, ColourRGBA colourStroke_
, XYPOSITION widthStroke_
=1.0) noexcept
:
289 fill(colourFill_
), stroke(colourStroke_
, widthStroke_
) {
291 constexpr FillStroke(ColourRGBA colourBoth
, XYPOSITION widthStroke_
=1.0) noexcept
:
292 fill(colourBoth
), stroke(colourBoth
, widthStroke_
) {
297 * Holds an element of a gradient with an RGBA colour and a relative position.
303 constexpr ColourStop(XYPOSITION position_
, ColourRGBA colour_
) noexcept
:
304 position(position_
), colour(colour_
) {