iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IGraphicsStructs.h
1/*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9*/
10
11#pragma once
12
19#include <functional>
20#include <chrono>
21#include <numeric>
22
23#include "IPlugUtilities.h"
24#include "IPlugLogger.h"
25#include "IPlugStructs.h"
26
27#include "IGraphicsPrivate.h"
28#include "IGraphicsUtilities.h"
29#include "IGraphicsConstants.h"
30
31BEGIN_IPLUG_NAMESPACE
32BEGIN_IGRAPHICS_NAMESPACE
33
34class IGraphics;
35class IControl;
36class ILambdaControl;
37class IPopupMenu;
38struct IRECT;
39struct IVec2;
40struct IMouseInfo;
41struct IColor;
42struct IGestureInfo;
43
44using IActionFunction = std::function<void(IControl*)>;
45using IAnimationFunction = std::function<void(IControl*)>;
46using IControlFunction = std::function<void(IControl*)>;
47using ILambdaDrawFunction = std::function<void(ILambdaControl*, IGraphics&, IRECT&)>;
48using IKeyHandlerFunc = std::function<bool(const IKeyPress& key, bool isUp)>;
49using IMsgBoxCompletionHandlerFunc = std::function<void(EMsgBoxResult result)>;
50using IFileDialogCompletionHandlerFunc = std::function<void(const WDL_String& fileName, const WDL_String& path)>;
51using IColorPickerHandlerFunc = std::function<void(const IColor& result)>;
52using IGestureFunc = std::function<void(IControl*, const IGestureInfo&)>;
53using IPopupFunction = std::function<void(IPopupMenu* pMenu)>;
54using IDisplayTickFunc = std::function<void()>;
55using IUIAppearanceChangedFunc = std::function<void(EUIAppearance appearance)>;
56using ITouchID = uintptr_t;
57
59void EmptyClickActionFunc(IControl* pCaller);
60
62void DefaultClickActionFunc(IControl* pCaller);
63
65void DefaultAnimationFunc(IControl* pCaller);
66
68void SplashClickActionFunc(IControl* pCaller);
69
71void SplashAnimationFunc(IControl* pCaller);
72
75
78
79using MTLTexturePtr = void*;
80
81using Milliseconds = std::chrono::duration<double, std::chrono::milliseconds::period>;
82using TimePoint = std::chrono::time_point<std::chrono::high_resolution_clock, Milliseconds>;
83
88{
89public:
95 IBitmap(APIBitmap* pAPIBitmap, int n, bool framesAreHorizontal, const char* name = "")
96 : mAPIBitmap(pAPIBitmap)
97 , mW(static_cast<int>(pAPIBitmap->GetWidth() / pAPIBitmap->GetScale()))
98 , mH(static_cast<int>(pAPIBitmap->GetHeight() / pAPIBitmap->GetScale()))
99 , mN(n)
100 , mFramesAreHorizontal(framesAreHorizontal)
101 , mResourceName(name, static_cast<int>(strlen(name)))
102 {
103 }
104
105 IBitmap()
106 : mAPIBitmap(nullptr)
107 , mW(0)
108 , mH(0)
109 , mN(0)
110 , mFramesAreHorizontal(false)
111 {
112 }
113
115 int W() const { return mW; }
116
118 int H() const { return mH; }
119
121 int FW() const { return (mFramesAreHorizontal ? mW / mN : mW); }
122
124 int FH() const { return (mFramesAreHorizontal ? mH : mH / mN); }
125
127 int N() const { return mN; }
128
130 float GetScale() const { return mAPIBitmap->GetScale(); }
131
133 float GetDrawScale() const { return mAPIBitmap->GetDrawScale(); }
134
136 APIBitmap* GetAPIBitmap() const { return mAPIBitmap; }
137
139 bool GetFramesAreHorizontal() const { return mFramesAreHorizontal; }
140
142 const WDL_String& GetResourceName() const { return mResourceName; }
143
145 inline bool IsValid() const { return mAPIBitmap != nullptr; }
146
147private:
149 APIBitmap* mAPIBitmap;
151 int mW;
153 int mH;
155 int mN;
157 bool mFramesAreHorizontal;
159 WDL_String mResourceName;
160};
161
165#ifdef SVG_USE_SKIA
166struct ISVG
167{
168 ISVG(sk_sp<SkSVGDOM> svgDom)
169 : mSVGDom(svgDom)
170 {
171 }
172
174 float W() const
175 {
176 assert(mSVGDom);
177 return mSVGDom->containerSize().width();
178 }
179
181 float H() const
182 {
183 assert(mSVGDom);
184 return mSVGDom->containerSize().height();
185 }
186
188 inline bool IsValid() const { return mSVGDom != nullptr; }
189
190 sk_sp<SkSVGDOM> mSVGDom;
191};
192#else
193struct ISVG
194{
195 ISVG(NSVGimage* pImage)
196 {
197 mImage = pImage;
198 }
199
201 float W() const
202 {
203 assert(mImage);
204 return mImage->width;
205 }
206
208 float H() const
209 {
210 assert(mImage);
211 return mImage->height;
212 }
213
215 inline bool IsValid() const { return mImage != nullptr; }
216
217 NSVGimage* mImage = nullptr;
218};
219#endif
220
222struct IColor
223{
224 int A, R, G, B;
225
231 IColor(int a = 255, int r = 0, int g = 0, int b = 0) : A(a), R(r), G(g), B(b) {}
232
233 bool operator==(const IColor& rhs) { return (rhs.A == A && rhs.R == R && rhs.G == G && rhs.B == B); }
234 bool operator!=(const IColor& rhs) { return !operator==(rhs); }
235
241 void Set(int a = 255, int r = 0, int g = 0, int b = 0) { A = a; R = r; G = g; B = b; }
242
244 bool Empty() const { return A == 0 && R == 0 && G == 0 && B == 0; }
245
247 void Clamp() { A = Clip(A, 0, 255); R = Clip(R, 0, 255); G = Clip(G, 0, 255); B = Clip(B, 0, 255); }
248
251 void Randomise(int alpha = 255) { A = alpha; R = std::rand() % 255; G = std::rand() % 255; B = std::rand() % 255; }
252
255 void SetOpacity(float alpha)
256 {
257 A = static_cast<int>(Clip(alpha, 0.f, 1.f) * 255.f);
258 }
259
263 IColor WithOpacity(float alpha) const
264 {
265 IColor n = *this;
266 n.SetOpacity(alpha);
267 return n;
268 }
269
272 void Contrast(float c)
273 {
274 const int mod = static_cast<int>(c * 255.f);
275 R = Clip(R += mod, 0, 255);
276 G = Clip(G += mod, 0, 255);
277 B = Clip(B += mod, 0, 255);
278 }
279
283 IColor WithContrast(float c) const
284 {
285 IColor n = *this;
286 n.Contrast(c);
287 return n;
288 }
289
292 void GetRGBf(float* rgbf) const
293 {
294 rgbf[0] = R / 255.f;
295 rgbf[1] = G / 255.f;
296 rgbf[2] = B / 255.f;
297 }
298
301 void GetRGBAf(float* rgbaf) const
302 {
303 rgbaf[0] = R / 255.f;
304 rgbaf[1] = G / 255.f;
305 rgbaf[2] = B / 255.f;
306 rgbaf[3] = A / 255.f;
307 }
308
314 void GetHSLA(float& h, float& s, float& l, float& a) const
315 {
316 const float fR = R / 255.f;
317 const float fG = G / 255.f;
318 const float fB = B / 255.f;
319 a = A / 255.f;
320
321 const float fMin = std::min(fR, std::min(fG, fB));
322 const float fMax = std::max(fR, std::max(fG, fB));
323 const float fDiff = fMax - fMin;
324 const float fSum = fMax + fMin;
325
326 l = 50.f * fSum;
327
328 if (fMin == fMax) { s = 0.f; h = 0.f; l /= 100.f; return; }
329 else if (l < 50.f) { s = 100.f * fDiff / fSum; }
330 else { s = 100.f * fDiff / (2.f - fDiff); }
331
332 if (fMax == fR) { h = 60.f * (fG - fB) / fDiff; }
333 if (fMax == fG) { h = 60.f * (fB - fR) / fDiff + 120.f; }
334 if (fMax == fB) { h = 60.f * (fR - fG) / fDiff + 240.f; }
335
336 if (h < 0.f) { h = h + 360.f; }
337
338 h /= 360.f;
339 s /= 100.f;
340 l /= 100.f;
341 }
342
345 int GetLuminosity() const
346 {
347 int min = R < G ? (R < B ? R : B) : (G < B ? G : B);
348 int max = R > G ? (R > B ? R : B) : (G > B ? G : B);
349 return (min + max) / 2;
350 };
351
355 static IColor GetRandomColor(bool randomAlpha = false)
356 {
357 int A = randomAlpha ? std::rand() & 0xFF : 255;
358 int R = std::rand() & 0xFF;
359 int G = std::rand() & 0xFF;
360 int B = std::rand() & 0xFF;
361
362 return IColor(A, R, G, B);
363 }
364
368 static IColor FromRGBf(float* rgbf)
369 {
370 int A = 255;
371 int R = static_cast<int>(rgbf[0] * 255.f);
372 int G = static_cast<int>(rgbf[1] * 255.f);
373 int B = static_cast<int>(rgbf[2] * 255.f);
374
375 return IColor(A, R, G, B);
376 }
377
381 static IColor FromRGBAf(float* rgbaf)
382 {
383 int R = static_cast<int>(rgbaf[0] * 255.f);
384 int G = static_cast<int>(rgbaf[1] * 255.f);
385 int B = static_cast<int>(rgbaf[2] * 255.f);
386 int A = static_cast<int>(rgbaf[3] * 255.f);
387
388 return IColor(A, R, G, B);
389 }
390
400 static IColor FromColorCode(int colorCode, int A = 0xFF)
401 {
402 int R = (colorCode >> 16) & 0xFF;
403 int G = (colorCode >> 8) & 0xFF;
404 int B = colorCode & 0xFF;
405
406 return IColor(A, R, G, B);
407 }
408
412 static IColor FromColorCodeStr(const char* hexStr)
413 {
414 WDL_String str(hexStr);
415
416 if ((str.GetLength() == 7 || str.GetLength() == 9) && str.Get()[0] == '#')
417 {
418 str.DeleteSub(0, 1);
419
420 return FromColorCode(static_cast<int>(std::stoul(str.Get(), nullptr, 16)));
421 }
422 else
423 {
424 assert(0 && "Invalid color code str, returning black");
425 return IColor();
426 }
427 }
428
430 int ToColorCode() const
431 {
432 return (R << 16) | (G << 8) | B;
433 }
434
436 void ToColorCodeStr(WDL_String& str, bool withAlpha = true) const
437 {
438 if (withAlpha)
439 str.SetFormatted(32, "#%02x%02x%02x%02x", R, G, B, A);
440 else
441 str.SetFormatted(32, "#%02x%02x%02x", R, G, B);
442 }
443
450 static IColor FromHSLA(float h, float s, float l, float a = 1.f)
451 {
452 auto hue = [](float h, float m1, float m2) {
453 if (h < 0) h += 1;
454 if (h > 1) h -= 1;
455 if (h < 1.0f / 6.0f)
456 return m1 + (m2 - m1) * h * 6.0f;
457 else if (h < 3.0f / 6.0f)
458 return m2;
459 else if (h < 4.0f / 6.0f)
460 return m1 + (m2 - m1) * (2.0f / 3.0f - h) * 6.0f;
461 return m1;
462 };
463
464 IColor col;
465 h = std::fmodf(h, 1.0f);
466 if (h < 0.0f) h += 1.0f;
467 s = Clip(s, 0.0f, 1.0f);
468 l = Clip(l, 0.0f, 1.0f);
469 float m2 = l <= 0.5f ? (l * (1 + s)) : (l + s - l * s);
470 float m1 = 2 * l - m2;
471 col.R = static_cast<int>(Clip(hue(h + 1.0f / 3.0f, m1, m2), 0.0f, 1.0f) * 255.f);
472 col.G = static_cast<int>(Clip(hue(h, m1, m2), 0.0f, 1.0f) * 255.f);
473 col.B = static_cast<int>(Clip(hue(h - 1.0f / 3.0f, m1, m2), 0.0f, 1.0f) * 255.f);
474 col.A = static_cast<int>(a * 255.f);
475 return col;
476 }
477
482 static IColor LinearInterpolateBetween(const IColor& start, const IColor& dest, float progress)
483 {
484 IColor result;
485 result.A = start.A + static_cast<int>(progress * static_cast<float>(dest.A - start.A));
486 result.R = start.R + static_cast<int>(progress * static_cast<float>(dest.R - start.R));
487 result.G = start.G + static_cast<int>(progress * static_cast<float>(dest.G - start.G));
488 result.B = start.B + static_cast<int>(progress * static_cast<float>(dest.B - start.B));
489 return result;
490 }
491};
492
493const IColor COLOR_TRANSPARENT(0, 0, 0, 0);
494const IColor COLOR_TRANSLUCENT(10, 0, 0, 0);
495const IColor COLOR_BLACK(255, 0, 0, 0);
496const IColor COLOR_BLACK_DROP_SHADOW(128, 0, 0, 0);
497const IColor COLOR_GRAY(255, 127, 127, 127);
498const IColor COLOR_LIGHT_GRAY(255, 240, 240, 240);
499const IColor COLOR_MID_GRAY(255, 200, 200, 200);
500const IColor COLOR_DARK_GRAY(255, 70, 70, 70);
501const IColor COLOR_WHITE(255, 255, 255, 255);
502const IColor COLOR_RED(255, 255, 0, 0);
503const IColor COLOR_GREEN(255, 0, 255, 0);
504const IColor COLOR_BLUE(255, 0, 0, 255);
505const IColor COLOR_YELLOW(255, 255, 255, 0);
506const IColor COLOR_ORANGE(255, 255, 127, 0);
507const IColor COLOR_INDIGO(255, 75, 0, 130);
508const IColor COLOR_VIOLET(255, 148, 0, 211);
509
510static IColor GetRainbow(int colorIdx)
511{
512 switch (colorIdx) {
513 case 0: return COLOR_RED;
514 case 1: return COLOR_ORANGE;
515 case 2: return COLOR_YELLOW;
516 case 3: return COLOR_GREEN;
517 case 4: return COLOR_BLUE;
518 case 5: return COLOR_INDIGO;
519 case 6: return COLOR_VIOLET;
520 default:
521 assert(0);
522 return COLOR_WHITE;
523 }
524}
525
526const IColor DEFAULT_GRAPHICS_BGCOLOR = COLOR_GRAY;
527const IColor DEFAULT_BGCOLOR = COLOR_TRANSPARENT;
528const IColor DEFAULT_FGCOLOR = COLOR_MID_GRAY;
529const IColor DEFAULT_PRCOLOR = COLOR_LIGHT_GRAY;
530
531const IColor DEFAULT_FRCOLOR = COLOR_DARK_GRAY;
532const IColor DEFAULT_HLCOLOR = COLOR_TRANSLUCENT;
533const IColor DEFAULT_SHCOLOR = IColor(60, 0, 0, 0);
534const IColor DEFAULT_X1COLOR = COLOR_BLACK;
535const IColor DEFAULT_X2COLOR = COLOR_GREEN;
536const IColor DEFAULT_X3COLOR = COLOR_BLUE;
537
538const IColor DEFAULT_TEXT_FGCOLOR = COLOR_BLACK;
539const IColor DEFAULT_TEXTENTRY_BGCOLOR = COLOR_WHITE;
540const IColor DEFAULT_TEXTENTRY_FGCOLOR = COLOR_BLACK;
541
543struct IBlend
544{
545 EBlend mMethod;
546 float mWeight;
547
551 IBlend(EBlend type = EBlend::Default, float weight = 1.0f)
552 : mMethod(type)
553 , mWeight(Clip(weight, 0.f, 1.f))
554 {}
555};
556
560inline float BlendWeight(const IBlend* pBlend)
561{
562 return (pBlend ? pBlend->mWeight : 1.0f);
563}
564
565const IBlend BLEND_75 = IBlend(EBlend::Default, 0.75f);
566const IBlend BLEND_50 = IBlend(EBlend::Default, 0.5f);
567const IBlend BLEND_25 = IBlend(EBlend::Default, 0.25f);
568const IBlend BLEND_10 = IBlend(EBlend::Default, 0.1f);
569const IBlend BLEND_05 = IBlend(EBlend::Default, 0.05f);
570const IBlend BLEND_01 = IBlend(EBlend::Default, 0.01f);
571const IBlend BLEND_DST_IN = IBlend(EBlend::DstIn, 1.f);
572const IBlend BLEND_DST_OVER = IBlend(EBlend::DstOver, 1.f);
573
576{
577 EFillRule mFillRule { EFillRule::Winding };
578 bool mPreserve { false };
579
580 IFillOptions(bool preserve = false, EFillRule fillRule = EFillRule::Winding)
581 : mFillRule(fillRule)
582 , mPreserve(preserve)
583 {
584 }
585
586};
587
590{
592 class DashOptions
593 {
594 public:
596 DashOptions()
597 : mOffset(0)
598 , mCount(0)
599 {}
600
605 DashOptions(float* array, float offset, int count)
606 {
607 SetDash(array, offset, count);
608 }
609
611 int GetCount() const { return mCount; }
612
614 float GetOffset() const { return mOffset; }
615
617 const float* GetArray() const { return mArray; }
618
623 void SetDash(float* pArray, float offset, int count)
624 {
625 assert(count >= 0 && count <= 8);
626
627 mCount = count;
628 mOffset = offset;
629
630 for (int i = 0; i < count; i++)
631 mArray[i] = pArray[i];
632 }
633
634 private:
635 float mArray[8] = {};
636 float mOffset;
637 int mCount;
638 };
639
640 float mMiterLimit = 10.f;
641 bool mPreserve = false;
642 ELineCap mCapOption = ELineCap::Butt;
643 ELineJoin mJoinOption = ELineJoin::Miter;
644 DashOptions mDash;
645};
646
648static const char* TextStyleString(ETextStyle style)
649{
650 switch (style)
651 {
652 case ETextStyle::Bold: return "Bold";
653 case ETextStyle::Italic: return "Italic";
654 case ETextStyle::Normal:
655 default:
656 return "Regular";
657 }
658}
659
661struct IText
662{
672 IText(float size = DEFAULT_TEXT_SIZE,
673 const IColor& color = DEFAULT_TEXT_FGCOLOR,
674 const char* fontID = nullptr,
675 EAlign align = EAlign::Center,
676 EVAlign valign = EVAlign::Middle,
677 float angle = 0,
678 const IColor& TEBGColor = DEFAULT_TEXTENTRY_BGCOLOR,
679 const IColor& TEFGColor = DEFAULT_TEXTENTRY_FGCOLOR)
680 : mSize(size)
681 , mFGColor(color)
682 , mTextEntryBGColor(TEBGColor)
683 , mTextEntryFGColor(TEFGColor)
684 , mAngle(angle)
685 , mAlign(align)
686 , mVAlign(valign)
687 {
688 strcpy(mFont, (fontID ? fontID : DEFAULT_FONT));
689 }
690
695 IText(float size, EVAlign valign, const IColor& color = DEFAULT_TEXT_FGCOLOR)
696 : IText()
697 {
698 mSize = size;
699 mVAlign = valign;
700 mFGColor = color;
701 }
702
707 IText(float size, EAlign align, const IColor& color = DEFAULT_TEXT_FGCOLOR)
708 : IText()
709 {
710 mSize = size;
711 mAlign = align;
712 mFGColor = color;
713 }
714
718 IText(float size, const char* fontID)
719 : IText()
720 {
721 mSize = size;
722 strcpy(mFont, (fontID ? fontID : DEFAULT_FONT));
723 }
724
725 IText WithFGColor(const IColor& fgColor) const { IText newText = *this; newText.mFGColor = fgColor; return newText; }
726 IText WithTEColors(const IColor& teBgColor, const IColor& teFgColor) const { IText newText = *this; newText.mTextEntryBGColor = teBgColor; newText.mTextEntryFGColor = teFgColor; return newText; }
727 IText WithAlign(EAlign align) const { IText newText = *this; newText.mAlign = align; return newText; }
728 IText WithVAlign(EVAlign valign) const { IText newText = *this; newText.mVAlign = valign; return newText; }
729 IText WithSize(float size) const { IText newText = *this; newText.mSize = size; return newText; }
730 IText WithAngle(float v) const { IText newText = *this; newText.mAngle = v; return newText; }
731 IText WithFont(const char* fontID) const { IText newText = *this; strcpy(newText.mFont, (fontID ? fontID : DEFAULT_FONT));; return newText; }
732
733 char mFont[FONT_LEN];
734 float mSize;
735 IColor mFGColor;
736 IColor mTextEntryBGColor;
737 IColor mTextEntryFGColor;
738 float mAngle = 0.f; // Degrees ccwise from normal.
739 EAlign mAlign = EAlign::Near;
740 EVAlign mVAlign = EVAlign::Middle;
741};
742
743const IText DEFAULT_TEXT = IText();
744
748struct IRECT
749{
750 float L, T, R, B;
751
754 {
755 L = T = R = B = 0.f;
756 }
757
763 IRECT(float l, float t, float r, float b)
764 : L(l), T(t), R(r), B(b)
765 {}
766
771 IRECT(float x, float y, const IBitmap& bitmap)
772 {
773 L = x;
774 T = y;
775 R = L + (float) bitmap.FW();
776 B = T + (float) bitmap.FH();
777 }
778
785 static IRECT MakeXYWH(float l, float t, float w, float h)
786 {
787 return IRECT(l, t, l+w, t+h);
788 }
789
796 static IRECT MakeMidXYWH(float x, float y, float w, float h)
797 {
798 return IRECT(x-(w/2.0f), y-(h/2.0f), x+(w/2.0f), y+(h/2.0f));
799 }
800
802 bool Empty() const
803 {
804 return (L == 0.f && T == 0.f && R == 0.f && B == 0.f);
805 }
806
808 void Clear()
809 {
810 L = T = R = B = 0.f;
811 }
812
813 bool operator==(const IRECT& rhs) const
814 {
815 return (L == rhs.L && T == rhs.T && R == rhs.R && B == rhs.B);
816 }
817
818 bool operator!=(const IRECT& rhs) const
819 {
820 return !(*this == rhs);
821 }
822
824 inline float W() const { return R - L; }
825
827 inline float H() const { return B - T; }
828
830 inline float MW() const { return 0.5f * (L + R); }
831
833 inline float MH() const { return 0.5f * (T + B); }
834
836 inline float Area() const { return W() * H(); }
837
842 inline IRECT Union(const IRECT& rhs) const
843 {
844 if (Empty()) { return rhs; }
845 if (rhs.Empty()) { return *this; }
846 return IRECT(std::min(L, rhs.L), std::min(T, rhs.T), std::max(R, rhs.R), std::max(B, rhs.B));
847 }
848
853 inline IRECT Intersect(const IRECT& rhs) const
854 {
855 if (Intersects(rhs))
856 return IRECT(std::max(L, rhs.L), std::max(T, rhs.T), std::min(R, rhs.R), std::min(B, rhs.B));
857
858 return IRECT();
859 }
860
865 inline bool Intersects(const IRECT& rhs) const
866 {
867 return (!Empty() && !rhs.Empty() && R >= rhs.L && L < rhs.R && B >= rhs.T && T < rhs.B);
868 }
869
874 inline bool Contains(const IRECT& rhs) const
875 {
876 return (!Empty() && !rhs.Empty() && rhs.L >= L && rhs.R <= R && rhs.T >= T && rhs.B <= B);
877 }
878
884 inline bool Contains(float x, float y) const
885 {
886 return (!Empty() && x >= L && x < R && y >= T && y < B);
887 }
888
895 inline bool ContainsEdge(float x, float y) const
896 {
897 return (!Empty() && x >= L && x <= R && y >= T && y <= B);
898 }
899
903 inline void Constrain(float& x, float& y) const
904 {
905 if (x < L) x = L;
906 else if (x > R) x = R;
907
908 if (y < T) y = T;
909 else if (y > B) y = B;
910 }
911
914 IRECT Inset(const IRECT& rhs) const
915 {
916 return IRECT(L + rhs.L, T + rhs.T, L + rhs.R, T + rhs.B);
917 }
918
924 bool Mergeable(const IRECT& rhs) const
925 {
926 if (Empty() || rhs.Empty())
927 return true;
928 if (L == rhs.L && R == rhs.R && ((T >= rhs.T && T <= rhs.B) || (rhs.T >= T && rhs.T <= B)))
929 return true;
930 return T == rhs.T && B == rhs.B && ((L >= rhs.L && L <= rhs.R) || (rhs.L >= L && rhs.L <= R));
931 }
932
939 inline IRECT FracRect(EDirection layoutDir, float frac, bool fromTopOrRight = false) const
940 {
941 if(layoutDir == EDirection::Vertical)
942 return FracRectVertical(frac, fromTopOrRight);
943 else
944 return FracRectHorizontal(frac, fromTopOrRight);
945 }
946
951 inline IRECT FracRectHorizontal(float frac, bool rhs = false) const
952 {
953 float widthOfSubRect = W() * frac;
954
955 if(rhs)
956 return IRECT(R - widthOfSubRect, T, R, B);
957 else
958 return IRECT(L, T, L + widthOfSubRect, B);
959 }
960
965 inline IRECT FracRectVertical(float frac, bool fromTop = false) const
966 {
967 float heightOfSubRect = H() * frac;
968
969 if(fromTop)
970 return IRECT(L, T, R, T + heightOfSubRect);
971 else
972 return IRECT(L, B - heightOfSubRect, R, B);
973 }
974
982 inline IRECT SubRectVertical(int numSlices, int sliceIdx) const
983 {
984 float heightOfSubRect = H() / (float) numSlices;
985 float t = heightOfSubRect * (float) sliceIdx;
986
987 return IRECT(L, T + t, R, T + t + heightOfSubRect);
988 }
989
997 inline IRECT SubRectHorizontal(int numSlices, int sliceIdx) const
998 {
999 float widthOfSubRect = W() / (float) numSlices;
1000 float l = widthOfSubRect * (float) sliceIdx;
1001
1002 return IRECT(L + l, T, L + l + widthOfSubRect, B);
1003 }
1004
1010 inline IRECT SubRect(EDirection layoutDir, int numSlices, int sliceIdx) const
1011 {
1012 if(layoutDir == EDirection::Vertical)
1013 return SubRectVertical(numSlices, sliceIdx);
1014 else
1015 return SubRectHorizontal(numSlices, sliceIdx);
1016 }
1017
1022 inline IRECT GetFromTLHC(float w, float h) const { return IRECT(L, T, L+w, T+h); }
1023
1028 inline IRECT GetFromBLHC(float w, float h) const { return IRECT(L, B-h, L+w, B); }
1029
1034 inline IRECT GetFromTRHC(float w, float h) const { return IRECT(R-w, T, R, T+h); }
1035
1040 inline IRECT GetFromBRHC(float w, float h) const { return IRECT(R-w, B-h, R, B); }
1041
1045 inline IRECT GetFromTop(float amount) const { return IRECT(L, T, R, T+amount); }
1046
1050 inline IRECT GetFromBottom(float amount) const { return IRECT(L, B-amount, R, B); }
1051
1055 inline IRECT GetFromLeft(float amount) const { return IRECT(L, T, L+amount, B); }
1056
1060 inline IRECT GetFromRight(float amount) const { return IRECT(R-amount, T, R, B); }
1061
1065 inline IRECT GetReducedFromTop(float amount) const { return IRECT(L, T+amount, R, B); }
1066
1070 inline IRECT GetReducedFromBottom(float amount) const { return IRECT(L, T, R, B-amount); }
1071
1075 inline IRECT GetReducedFromLeft(float amount) const { return IRECT(L+amount, T, R, B); }
1076
1080 inline IRECT GetReducedFromRight(float amount) const { return IRECT(L, T, R-amount, B); }
1081
1085 inline IRECT ReduceFromTop(float amount) { IRECT r = GetFromTop(amount); T+=amount; return r; }
1086
1090 inline IRECT ReduceFromBottom(float amount) { IRECT r = GetFromBottom(amount); B-=amount; return r; }
1091
1095 inline IRECT ReduceFromLeft(float amount) { IRECT r = GetFromLeft(amount); L+=amount; return r; }
1096
1100 inline IRECT ReduceFromRight(float amount) { IRECT r = GetFromRight(amount); R-=amount; return r; }
1101
1108 inline IRECT GetGridCell(int row, int col, int nRows, int nColumns/*, EDirection = EDirection::Horizontal*/) const
1109 {
1110 assert(row * col <= nRows * nColumns); // not enough cells !
1111
1112 const IRECT vrect = SubRectVertical(nRows, row);
1113 return vrect.SubRectHorizontal(nColumns, col);
1114 }
1115
1123 inline IRECT GetGridCell(int cellIndex, int nRows, int nColumns, EDirection dir = EDirection::Horizontal, int nCells = 1) const
1124 {
1125 assert(cellIndex <= nRows * nColumns); // not enough cells !
1126
1127 int cell = 0;
1128
1129 if(dir == EDirection::Horizontal)
1130 {
1131 for(int row = 0; row < nRows; row++)
1132 {
1133 for(int col = 0; col < nColumns; col++)
1134 {
1135 if(cell == cellIndex)
1136 {
1137 const IRECT vrect = SubRectVertical(nRows, row);
1138 IRECT rect = vrect.SubRectHorizontal(nColumns, col);
1139
1140 for (int n = 1; n < nCells && (col + n) < nColumns; n++)
1141 {
1142 rect = rect.Union(vrect.SubRectHorizontal(nColumns, col + n));
1143 }
1144 return rect;
1145 }
1146
1147 cell++;
1148 }
1149 }
1150 }
1151 else
1152 {
1153 for(int col = 0; col < nColumns; col++)
1154 {
1155 for(int row = 0; row < nRows; row++)
1156 {
1157 if(cell == cellIndex)
1158 {
1159 const IRECT hrect = SubRectHorizontal(nColumns, col);
1160 IRECT rect = hrect.SubRectVertical(nRows, row);;
1161
1162 for (int n = 1; n < nCells && (row + n) < nRows; n++)
1163 {
1164 rect = rect.Union(hrect.SubRectVertical(nRows, row + n));
1165 }
1166 return rect;
1167 }
1168
1169 cell++;
1170 }
1171 }
1172 }
1173
1174 return *this;
1175 }
1176
1178 bool IsPixelAligned() const
1179 {
1180 // If all values are within 1/1000th of a pixel of an integer the IRECT is considered pixel aligned
1181
1182 auto isInteger = [](float x){ return std::fabs(x - std::round(x)) <= static_cast<float>(1e-3); };
1183
1184 return isInteger(L) && isInteger(T) && isInteger(R) && isInteger(B);
1185 }
1186
1191 bool IsPixelAligned(float scale) const
1192 {
1193 IRECT r = *this;
1194 r.Scale(scale);
1195 return r.IsPixelAligned();
1196 }
1197
1199 inline void PixelAlign()
1200 {
1201 L = std::floor(L);
1202 T = std::floor(T);
1203 R = std::ceil(R);
1204 B = std::ceil(B);
1205 }
1206
1210 inline void PixelAlign(float scale)
1211 {
1212 // N.B. - double precision is *required* for accuracy of the reciprocal
1213 Scale(scale);
1214 PixelAlign();
1215 Scale(static_cast<float>(1.0/static_cast<double>(scale)));
1216 }
1217
1220 inline IRECT GetPixelAligned() const
1221 {
1222 IRECT r = *this;
1223 r.PixelAlign();
1224 return r;
1225 }
1226
1230 inline IRECT GetPixelAligned(float scale) const
1231 {
1232 IRECT r = *this;
1233 r.PixelAlign(scale);
1234 return r;
1235 }
1236
1239 inline void PixelSnap()
1240 {
1241 L = std::round(L);
1242 T = std::round(T);
1243 R = std::round(R);
1244 B = std::round(B);
1245 }
1246
1249 inline void PixelSnap(float scale)
1250 {
1251 // N.B. - double precision is *required* for accuracy of the reciprocal
1252 Scale(scale);
1253 PixelSnap();
1254 Scale(static_cast<float>(1.0/static_cast<double>(scale)));
1255 }
1256
1258 inline IRECT GetPixelSnapped() const
1259 {
1260 IRECT r = *this;
1261 r.PixelSnap();
1262 return r;
1263 }
1264
1268 inline IRECT GetPixelSnapped(float scale) const
1269 {
1270 IRECT r = *this;
1271 r.PixelSnap(scale);
1272 return r;
1273 }
1274
1278 inline void Pad(float padding)
1279 {
1280 L -= padding;
1281 T -= padding;
1282 R += padding;
1283 B += padding;
1284 }
1285
1292 inline void Pad(float padL, float padT, float padR, float padB)
1293 {
1294 L -= padL;
1295 T -= padT;
1296 R += padR;
1297 B += padB;
1298 }
1299
1303 inline void HPad(float padding)
1304 {
1305 L -= padding;
1306 R += padding;
1307 }
1308
1312 inline void VPad(float padding)
1313 {
1314 T -= padding;
1315 B += padding;
1316 }
1317
1320 inline void MidHPad(float padding)
1321 {
1322 const float mw = MW();
1323 L = mw - padding;
1324 R = mw + padding;
1325 }
1326
1329 inline void MidVPad(float padding)
1330 {
1331 const float mh = MH();
1332 T = mh - padding;
1333 B = mh + padding;
1334 }
1335
1340 inline IRECT GetPadded(float padding) const
1341 {
1342 return IRECT(L-padding, T-padding, R+padding, B+padding);
1343 }
1344
1352 inline IRECT GetPadded(float padL, float padT, float padR, float padB) const
1353 {
1354 return IRECT(L-padL, T-padT, R+padR, B+padB);
1355 }
1356
1361 inline IRECT GetHPadded(float padding) const
1362 {
1363 return IRECT(L-padding, T, R+padding, B);
1364 }
1365
1370 inline IRECT GetVPadded(float padding) const
1371 {
1372 return IRECT(L, T-padding, R, B+padding);
1373 }
1374
1378 inline IRECT GetMidHPadded(float padding) const
1379 {
1380 return IRECT(MW()-padding, T, MW()+padding, B);
1381 }
1382
1386 inline IRECT GetMidVPadded(float padding) const
1387 {
1388 return IRECT(L, MH()-padding, R, MH()+padding);
1389 }
1390
1395 inline IRECT GetHSliced(float w, bool rhs = false) const
1396 {
1397 if(rhs)
1398 return IRECT(R - w, T, R, B);
1399 else
1400 return IRECT(L, T, L + w, B);
1401 }
1402
1407 inline IRECT GetVSliced(float h, bool bot = false) const
1408 {
1409 if(bot)
1410 return IRECT(L, B - h, R, B);
1411 else
1412 return IRECT(L, T, R, T + h);
1413 }
1414
1417 void Clank(const IRECT& rhs)
1418 {
1419 if (L < rhs.L)
1420 {
1421 R = std::min(rhs.R - 1, R + rhs.L - L);
1422 L = rhs.L;
1423 }
1424 if (T < rhs.T)
1425 {
1426 B = std::min(rhs.B - 1, B + rhs.T - T);
1427 T = rhs.T;
1428 }
1429 if (R >= rhs.R)
1430 {
1431 L = std::max(rhs.L, L - (R - rhs.R + 1));
1432 R = rhs.R - 1;
1433 }
1434 if (B >= rhs.B)
1435 {
1436 T = std::max(rhs.T, T - (B - rhs.B + 1));
1437 B = rhs.B - 1;
1438 }
1439 }
1440
1443 void Scale(float scale)
1444 {
1445 L *= scale;
1446 T *= scale;
1447 R *= scale;
1448 B *= scale;
1449 }
1450
1453 void ScaleAboutCentre(float scale)
1454 {
1455 float x = MW();
1456 float y = MH();
1457 float hw = W() / 2.f;
1458 float hh = H() / 2.f;
1459 L = x - (hw * scale);
1460 T = y - (hh * scale);
1461 R = x + (hw * scale);
1462 B = y + (hh * scale);
1463 }
1464
1468 IRECT GetScaled(float scale) const
1469 {
1470 IRECT r = *this;
1471 r.Scale(scale);
1472 return r;
1473 }
1474
1478 IRECT GetScaledAboutCentre(float scale) const
1479 {
1480 IRECT r = *this;
1481 r.ScaleAboutCentre(scale);
1482 return r;
1483 }
1484
1490 static IRECT LinearInterpolateBetween(const IRECT& start, const IRECT& dest, float progress)
1491 {
1492 IRECT result;
1493 result.L = start.L + progress * (dest.L - start.L);
1494 result.T = start.T + progress * (dest.T - start.T);
1495 result.R = start.R + progress * (dest.R - start.R);
1496 result.B = start.B + progress * (dest.B - start.B);
1497 return result;
1498 }
1499
1503 void GetRandomPoint(float& x, float& y) const
1504 {
1505 const float r1 = static_cast<float>(std::rand()/(static_cast<float>(RAND_MAX)+1.f));
1506 const float r2 = static_cast<float>(std::rand()/(static_cast<float>(RAND_MAX)+1.f));
1507
1508 x = L + r1 * W();
1509 y = T + r2 * H();
1510 }
1511
1514 {
1515 float l, t, r, b;
1516 GetRandomPoint(l, t);
1517 IRECT tmp = IRECT(l, t, R, B);
1518 tmp.GetRandomPoint(r, b);
1519
1520 return IRECT(l, t, r, b);
1521 }
1522
1528 void Offset(float l, float t, float r, float b)
1529 {
1530 L += l;
1531 T += t;
1532 R += r;
1533 B += b;
1534 }
1535
1542 IRECT GetOffset(float l, float t, float r, float b) const
1543 {
1544 return IRECT(L + l, T + t, R + r, B + b);
1545 }
1546
1550 void Translate(float x, float y)
1551 {
1552 L += x;
1553 T += y;
1554 R += x;
1555 B += y;
1556 }
1557
1562 IRECT GetTranslated(float x, float y) const
1563 {
1564 return IRECT(L + x, T + y, R + x, B + y);
1565 }
1566
1570 IRECT GetHShifted(float x) const
1571 {
1572 return GetTranslated(x, 0.f);
1573 }
1574
1578 IRECT GetVShifted(float y) const
1579 {
1580 return GetTranslated(0.f, y);
1581 }
1582
1587 {
1588 IRECT r;
1589 r.L = MW() - sr.W() / 2.f;
1590 r.T = MH() - sr.H() / 2.f;
1591 r.R = r.L + sr.W();
1592 r.B = r.T + sr.H();
1593
1594 return r;
1595 }
1596
1601 IRECT GetCentredInside(float w, float h = 0.f) const
1602 {
1603 w = std::max(w, 1.f);
1604
1605 if(h <= 0.f)
1606 h = w;
1607
1608 IRECT r;
1609 r.L = MW() - w / 2.f;
1610 r.T = MH() - h / 2.f;
1611 r.R = r.L + w;
1612 r.B = r.T + h;
1613
1614 return r;
1615 }
1616
1620 IRECT GetCentredInside(const IBitmap& bitmap) const
1621 {
1622 IRECT r;
1623 r.L = MW() - bitmap.FW() / 2.f;
1624 r.T = MH() - bitmap.FH() / 2.f;
1625 r.R = r.L + (float) bitmap.FW();
1626 r.B = r.T + (float) bitmap.FH();
1627
1628 return r;
1629 }
1630
1634 void VAlignTo(const IRECT& sr, EVAlign align)
1635 {
1636 const float height = H();
1637 switch (align)
1638 {
1639 case EVAlign::Top: T = sr.T; B = sr.T + height; break;
1640 case EVAlign::Bottom: T = sr.B - height; B = sr.B; break;
1641 case EVAlign::Middle: T = sr.T + (sr.H() * 0.5f) - (height * 0.5f); B = sr.T + (sr.H() * 0.5f) - (height * 0.5f) + height; break;
1642 }
1643 }
1644
1648 void HAlignTo(const IRECT& sr, EAlign align)
1649 {
1650 const float width = W();
1651 switch (align)
1652 {
1653 case EAlign::Near: L = sr.L; R = sr.L + width; break;
1654 case EAlign::Far: L = sr.R - width; R = sr.R; break;
1655 case EAlign::Center: L = sr.L + (sr.W() * 0.5f) - (width * 0.5f); R = sr.L + (sr.W() * 0.5f) - (width * 0.5f) + width; break;
1656 }
1657 }
1658
1663 IRECT GetVAlignedTo(const IRECT& sr, EVAlign align) const
1664 {
1665 IRECT result = *this;
1666 result.VAlignTo(sr, align);
1667 return result;
1668 }
1669
1672 {
1673 if(W() < H())
1674 return W();
1675 else
1676 return H();
1677 }
1678
1683 IRECT GetHAlignedTo(const IRECT& sr, EAlign align) const
1684 {
1685 IRECT result = *this;
1686 result.HAlignTo(sr, align);
1687 return result;
1688 }
1689
1691 void DBGPrint() { DBGMSG("L: %f, T: %f, R: %f, B: %f,: W: %f, H: %f\n", L, T, R, B, W(), H()); }
1692};
1693
1696{
1697 bool L, R, S, C, A;
1698 ITouchID touchID = 0;
1699 float touchRadius = 0.f;
1700
1708 IMouseMod(bool l = false, bool r = false, bool s = false, bool c = false, bool a = false, ITouchID touchID = 0)
1709 : L(l), R(r), S(s), C(c), A(a), touchID(touchID)
1710 {}
1711
1713 bool IsTouch() const { return touchID > 0; }
1714
1716 void DBGPrint() { DBGMSG("L: %i, R: %i, S: %i, C: %i,: A: %i\n", L, R, S, C, A); }
1717};
1718
1721{
1722 float x = 0.0, y = 0.0;
1723 float dX = 0.0, dY = 0.0;
1724 IMouseMod ms;
1725};
1726
1729{
1730 float x = 0.f;
1731 float y = 0.f;
1732 float scale = 0.f; // pinch,
1733 float velocity = 0.f; // pinch, rotate
1734 float angle = 0.f; // rotate,
1735 EGestureState state = EGestureState::Unknown;
1736 EGestureType type = EGestureType::Unknown;
1737};
1738
1741{
1742public:
1743 IRECTList()
1744 {}
1745
1746 IRECTList(const IRECTList&) = delete;
1747 IRECTList& operator=(const IRECTList&) = delete;
1748
1750 int Size() const { return mRects.GetSize(); }
1751
1754 void Add(const IRECT& rect)
1755 {
1756 mRects.Add(rect);
1757 }
1758
1762 void Set(int idx, const IRECT& rect)
1763 {
1764 *(mRects.GetFast() + idx) = rect;
1765 }
1766
1770 const IRECT& Get(int idx) const
1771 {
1772 return *(mRects.GetFast() + idx);
1773 }
1774
1776 void Clear()
1777 {
1778 mRects.Resize(0);
1779 }
1780
1784 {
1785 IRECT r = Get(0);
1786 for (auto i = 1; i < mRects.GetSize(); i++)
1787 r = r.Union(Get(i));
1788 return r;
1789 }
1790
1793 {
1794 for (auto i = 0; i < Size(); i++)
1795 {
1796 IRECT r = Get(i);
1797 r.PixelAlign();
1798 Set(i, r);
1799 }
1800 }
1801
1804 void PixelAlign(float scale)
1805 {
1806 for (auto i = 0; i < Size(); i++)
1807 {
1808 IRECT r = Get(i);
1809 r.PixelAlign(scale);
1810 Set(i, r);
1811 }
1812 }
1813
1818 int Find(float x, float y) const
1819 {
1820 for (auto i = 0; i < Size(); i++)
1821 {
1822 if(Get(i).Contains(x, y))
1823 return i;
1824 }
1825
1826 return -1;
1827 }
1828
1836 static bool GetFracGrid(const IRECT& input, IRECTList& rects, const std::initializer_list<float>& rowFractions, const std::initializer_list<float>& colFractions, EDirection layoutDir = EDirection::Horizontal)
1837 {
1838 IRECT spaceLeft = input;
1839 float y = 0.;
1840 float x = 0.;
1841
1842 if(std::accumulate(rowFractions.begin(), rowFractions.end(), 0.f) != 1.)
1843 return false;
1844
1845 if(std::accumulate(colFractions.begin(), colFractions.end(), 0.f) != 1.)
1846 return false;
1847
1848 if (layoutDir == EDirection::Horizontal)
1849 {
1850 for (auto& rowFrac : rowFractions)
1851 {
1852 IRECT thisRow = input.FracRectVertical(rowFrac, true).GetTranslated(0, y);
1853
1854 x = 0.;
1855
1856 for (auto& colFrac : colFractions)
1857 {
1858 IRECT thisCell = thisRow.FracRectHorizontal(colFrac).GetTranslated(x, 0);
1859
1860 rects.Add(thisCell);
1861
1862 x += thisCell.W();
1863 }
1864
1865 spaceLeft.Intersect(thisRow);
1866
1867 y = rects.Bounds().H();
1868 }
1869 }
1870
1871 if (layoutDir == EDirection::Vertical)
1872 {
1873 for (auto& colFrac : colFractions)
1874 {
1875 IRECT thisCol = input.FracRectHorizontal(colFrac).GetTranslated(x, 0);
1876
1877 y = 0.;
1878
1879 for (auto& rowFrac : rowFractions)
1880 {
1881 IRECT thisCell = thisCol.FracRectVertical(rowFrac, true).GetTranslated(0, y);
1882
1883 rects.Add(thisCell);
1884
1885 y += thisCell.H();
1886 }
1887
1888 spaceLeft.Intersect(thisCol);
1889
1890 x = rects.Bounds().W();
1891 }
1892 }
1893
1894 return true;
1895 }
1896
1899 {
1900 for (int i = 0; i < Size(); i++)
1901 {
1902 for (int j = i + 1; j < Size(); j++)
1903 {
1904 if (Get(i).Contains(Get(j)))
1905 {
1906 mRects.Delete(j);
1907 j--;
1908 }
1909 else if (Get(j).Contains(Get(i)))
1910 {
1911 mRects.Delete(i);
1912 i--;
1913 break;
1914 }
1915 else if (Get(i).Intersects(Get(j)))
1916 {
1917 IRECT intersection = Get(i).Intersect(Get(j));
1918
1919 if (Get(i).Mergeable(intersection))
1920 Set(i, Shrink(Get(i), intersection));
1921 else if (Get(j).Mergeable(intersection))
1922 Set(j, Shrink(Get(j), intersection));
1923 else if (Get(i).Area() < Get(j).Area())
1924 Set(i, Split(Get(i), intersection));
1925 else
1926 Set(j, Split(Get(j), intersection));
1927 }
1928 }
1929 }
1930
1931 for (int i = 0; i < Size(); i++)
1932 {
1933 for (int j = i + 1; j < Size(); j++)
1934 {
1935 if (Get(i).Mergeable(Get(j)))
1936 {
1937 Set(j, Get(i).Union(Get(j)));
1938 mRects.Delete(i);
1939 i = -1;
1940 break;
1941 }
1942 }
1943 }
1944 }
1945
1946private:
1951 IRECT Shrink(const IRECT &r, const IRECT &i)
1952 {
1953 if (i.L != r.L)
1954 return IRECT(r.L, r.T, i.L, r.B);
1955 if (i.T != r.T)
1956 return IRECT(r.L, r.T, r.R, i.T);
1957 if (i.R != r.R)
1958 return IRECT(i.R, r.T, r.R, r.B);
1959 return IRECT(r.L, i.B, r.R, r.B);
1960 }
1961
1966 IRECT Split(const IRECT r, const IRECT &i)
1967 {
1968 if (r.L == i.L)
1969 {
1970 if (r.T == i.T)
1971 {
1972 Add(IRECT(i.R, r.T, r.R, i.B));
1973 return IRECT(r.L, i.B, r.R, r.B);
1974 }
1975 else
1976 {
1977 Add(IRECT(r.L, r.T, r.R, i.T));
1978 return IRECT(i.R, i.T, r.R, r.B);
1979 }
1980 }
1981
1982 if (r.T == i.T)
1983 {
1984 Add(IRECT(r.L, r.T, i.L, i.B));
1985 return IRECT(r.L, i.B, r.R, r.B);
1986 }
1987 else
1988 {
1989 Add(IRECT(r.L, r.T, r.R, i.T));
1990 return IRECT(r.L, i.T, i.L, r.B);
1991 }
1992 }
1993
1994 WDL_TypedBuf<IRECT> mRects;
1995};
1996
1999{
2007 IMatrix(double xx, double yx, double xy, double yy, double tx, double ty)
2008 : mXX(xx), mYX(yx), mXY(xy), mYY(yy), mTX(tx), mTY(ty)
2009 {}
2010
2012 IMatrix() : IMatrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0)
2013 {}
2014
2019 IMatrix& Translate(float x, float y)
2020 {
2021 return Transform(IMatrix(1.0, 0.0, 0.0, 1.0, x, y));
2022 }
2023
2028 IMatrix& Scale(float x, float y)
2029 {
2030 return Transform(IMatrix(x, 0.0, 0.0, y, 0.0, 0.0));
2031 }
2032
2036 IMatrix& Rotate(float a)
2037 {
2038 const double rad = DegToRad(a);
2039 const double c = std::cos(rad);
2040 const double s = std::sin(rad);
2041
2042 return Transform(IMatrix(c, s, -s, c, 0.0, 0.0));
2043 }
2044
2049 IMatrix& Skew(float xa, float ya)
2050 {
2051 return Transform(IMatrix(1.0, std::tan(DegToRad(ya)), std::tan(DegToRad(xa)), 1.0, 0.0, 0.0));
2052 }
2053
2059 void TransformPoint(double& x, double& y, double x0, double y0) const
2060 {
2061 x = x0 * mXX + y0 * mXY + mTX;
2062 y = x0 * mYX + y0 * mYY + mTY;
2063 };
2064
2068 void TransformPoint(double& x, double& y) const
2069 {
2070 TransformPoint(x, y, x, y);
2071 };
2072
2077 IMatrix& Transform(const IRECT& before, const IRECT& after)
2078 {
2079 const double sx = after.W() / before.W();
2080 const double sy = after.H() / before.H();
2081 const double tx = after.L - before.L * sx;
2082 const double ty = after.T - before.T * sy;
2083
2084 return *this = IMatrix(sx, 0.0, 0.0, sy, tx, ty);
2085 }
2086
2091 {
2092 IMatrix p = *this;
2093
2094 mXX = m.mXX * p.mXX + m.mYX * p.mXY;
2095 mYX = m.mXX * p.mYX + m.mYX * p.mYY;
2096 mXY = m.mXY * p.mXX + m.mYY * p.mXY;
2097 mYY = m.mXY * p.mYX + m.mYY * p.mYY;
2098 mTX = m.mTX * p.mXX + m.mTY * p.mXY + p.mTX;
2099 mTY = m.mTX * p.mYX + m.mTY * p.mYY + p.mTY;
2100
2101 return *this;
2102 }
2103
2107 {
2108 IMatrix m = *this;
2109
2110 double d = 1.0 / (m.mXX * m.mYY - m.mYX * m.mXY);
2111
2112 mXX = m.mYY * d;
2113 mYX = -m.mYX * d;
2114 mXY = -m.mXY * d;
2115 mYY = m.mXX * d;
2116 mTX = (-(m.mTX * mXX) - (m.mTY * mXY));
2117 mTY = (-(m.mTX * mYX) - (m.mTY * mYY));
2118
2119 return *this;
2120 }
2121
2122 double mXX, mYX, mXY, mYY, mTX, mTY;
2123};
2124
2127{
2128 IColorStop()
2129 : mOffset(0.f)
2130 {}
2131
2135 IColorStop(IColor color, float offset)
2136 : mColor(color)
2137 , mOffset(offset)
2138 {
2139 assert(offset >= 0.0 && offset <= 1.0);
2140 }
2141
2142 IColor mColor;
2143 float mOffset;
2144};
2145
2148{
2149 EPatternType mType;
2150 EPatternExtend mExtend;
2151 IColorStop mStops[16];
2152 int mNStops;
2153 IMatrix mTransform;
2154
2157 IPattern(EPatternType type)
2158 : mType(type), mExtend(EPatternExtend::Pad), mNStops(0)
2159 {}
2160
2163 IPattern(const IColor& color)
2164 : mType(EPatternType::Solid), mExtend(EPatternExtend::Pad), mNStops(1)
2165 {
2166 mStops[0] = IColorStop(color, 0.0);
2167 }
2168
2176 static IPattern CreateLinearGradient(float x1, float y1, float x2, float y2, const std::initializer_list<IColorStop>& stops = {})
2177 {
2178 IPattern pattern(EPatternType::Linear);
2179
2180 // Calculate the affine transform from one line segment to another!
2181 const double xd = double(x2 - x1);
2182 const double yd = double(y2 - y1);
2183 const double d = sqrt(xd * xd + yd * yd);
2184 const double a = atan2(xd, yd);
2185 const double s = std::sin(a) / d;
2186 const double c = std::cos(a) / d;
2187
2188 const double x0 = -(x1 * c - y1 * s);
2189 const double y0 = -(x1 * s + y1 * c);
2190
2191 pattern.SetTransform(static_cast<float>(c),
2192 static_cast<float>(s),
2193 static_cast<float>(-s),
2194 static_cast<float>(c),
2195 static_cast<float>(x0),
2196 static_cast<float>(y0));
2197
2198 for (auto& stop : stops)
2199 pattern.AddStop(stop.mColor, stop.mOffset);
2200
2201 return pattern;
2202 }
2203
2209 static IPattern CreateLinearGradient(const IRECT& bounds, EDirection direction, const std::initializer_list<IColorStop>& stops = {})
2210 {
2211 float x1, y1, x2, y2;
2212
2213 if(direction == EDirection::Horizontal)
2214 {
2215 y1 = bounds.MH(); y2 = y1;
2216 x1 = bounds.L;
2217 x2 = bounds.R;
2218 }
2219 else//(direction == EDirection::Vertical)
2220 {
2221 x1 = bounds.MW(); x2 = x1;
2222 y1 = bounds.T;
2223 y2 = bounds.B;
2224 }
2225
2226 return CreateLinearGradient(x1, y1, x2, y2, stops);
2227 }
2228
2235 static IPattern CreateRadialGradient(float x1, float y1, float r, const std::initializer_list<IColorStop>& stops = {})
2236 {
2237 IPattern pattern(EPatternType::Radial);
2238
2239 const float s = 1.f / r;
2240
2241 pattern.SetTransform(s, 0, 0, s, -(x1 * s), -(y1 * s));
2242
2243 for (auto& stop : stops)
2244 pattern.AddStop(stop.mColor, stop.mOffset);
2245
2246 return pattern;
2247 }
2248
2256 static IPattern CreateSweepGradient(float x1, float y1, const std::initializer_list<IColorStop>& stops = {},
2257 float angleStart = 0.f, float angleEnd = 360.f)
2258 {
2259 IPattern pattern(EPatternType::Sweep);
2260
2261 #ifdef IGRAPHICS_SKIA
2262 angleStart -= 90;
2263 angleEnd -= 90;
2264 #endif
2265
2266 float rad = DegToRad(angleStart);
2267 float c = std::cos(rad);
2268 float s = std::sin(rad);
2269
2270 pattern.SetTransform(c, s, -s, c, -x1, -y1);
2271
2272 for (auto& stop : stops)
2273 {
2274 pattern.AddStop(stop.mColor, stop.mOffset * (angleEnd - angleStart) / 360.f);
2275 }
2276 return pattern;
2277 }
2278
2280 int NStops() const
2281 {
2282 return mNStops;
2283 }
2284
2288 const IColorStop& GetStop(int idx) const
2289 {
2290 return mStops[idx];
2291 }
2292
2296 void AddStop(IColor color, float offset)
2297 {
2298 assert(mType != EPatternType::Solid && mNStops < 16);
2299 assert(!mNStops || GetStop(mNStops - 1).mOffset < offset);
2300 if (mNStops < 16)
2301 mStops[mNStops++] = IColorStop(color, offset);
2302 }
2303
2311 void SetTransform(float xx, float yx, float xy, float yy, float tx, float ty)
2312 {
2313 mTransform = IMatrix(xx, yx, xy, yy, tx, ty);
2314 }
2315
2318 void SetTransform(const IMatrix& transform)
2319 {
2320 mTransform = transform;
2321 }
2322};
2323
2329{
2330 friend IGraphics;
2331
2332public:
2338 ILayer(APIBitmap* pBitmap, const IRECT& layerRect, IControl* pControl, const IRECT& controlRect)
2339 : mBitmap(pBitmap)
2340 , mControl(pControl)
2341 , mControlRECT(controlRect)
2342 , mRECT(layerRect)
2343 , mInvalid(false)
2344 {}
2345
2346 ILayer(const ILayer&) = delete;
2347 ILayer operator=(const ILayer&) = delete;
2348
2350 void Invalidate() { mInvalid = true; }
2351
2353 const APIBitmap* GetAPIBitmap() const { return mBitmap.get(); }
2354
2356 IBitmap GetBitmap() const { return IBitmap(mBitmap.get(), 1, false); }
2357
2359 const IRECT& Bounds() const { return mRECT; }
2360
2361private:
2362 std::unique_ptr<APIBitmap> mBitmap;
2363 IControl* mControl;
2364 IRECT mControlRECT;
2365 IRECT mRECT;
2366 bool mInvalid;
2367};
2368
2370using ILayerPtr = std::unique_ptr<ILayer>;
2371
2374{
2375 IShadow() {}
2376
2384 IShadow(const IPattern& pattern, float blurSize, float xOffset, float yOffset, float opacity, bool drawForeground = true)
2385 : mPattern(pattern)
2386 , mBlurSize(blurSize)
2387 , mXOffset(xOffset)
2388 , mYOffset(yOffset)
2389 , mOpacity(opacity)
2390 , mDrawForeground(drawForeground)
2391 {}
2392
2393 IPattern mPattern = COLOR_BLACK;
2394 float mBlurSize = 0.f;
2395 float mXOffset = 0.f;
2396 float mYOffset = 0.f;
2397 float mOpacity = 1.f;
2398 bool mDrawForeground = true;
2399};
2400
2403{
2404 IColor mColors[kNumVColors];
2405
2407 const IColor& GetColor(EVColor color) const
2408 {
2409 return mColors[(int) color];
2410 }
2411
2413 static const IColor& GetDefaultColor(EVColor idx)
2414 {
2415 switch(idx)
2416 {
2417 case kBG: return DEFAULT_BGCOLOR; // Background
2418 case kFG: return DEFAULT_FGCOLOR; // OFF/Foreground
2419 case kPR: return DEFAULT_PRCOLOR; // ON/Pressed
2420 case kFR: return DEFAULT_FRCOLOR; // Frame
2421 case kHL: return DEFAULT_HLCOLOR; // Highlight
2422 case kSH: return DEFAULT_SHCOLOR; // Shadow
2423 case kX1: return DEFAULT_X1COLOR; // Extra 1
2424 case kX2: return DEFAULT_X2COLOR; // Extra 2
2425 case kX3: return DEFAULT_X3COLOR; // Extra 3
2426 default:
2427 return COLOR_TRANSPARENT;
2428 };
2429 }
2430
2433 {
2434 ResetColors();
2435 }
2436
2439 IVColorSpec(const std::initializer_list<IColor>& colors)
2440 {
2441 assert(colors.size() <= kNumVColors);
2442
2443 int i = 0;
2444
2445 for(auto& c : colors)
2446 {
2447 mColors[i++] = c;
2448 }
2449
2450 for(; i<kNumVColors; i++)
2451 {
2452 mColors[i] = GetDefaultColor((EVColor) i);
2453 }
2454 }
2455
2458 {
2459 for (int i=0; i<kNumVColors; i++)
2460 {
2461 mColors[i] = GetDefaultColor((EVColor) i);
2462 }
2463 }
2464};
2465
2466const IVColorSpec DEFAULT_COLOR_SPEC = IVColorSpec();
2467
2468static constexpr bool DEFAULT_HIDE_CURSOR = true;
2469static constexpr bool DEFAULT_SHOW_VALUE = true;
2470static constexpr bool DEFAULT_SHOW_LABEL = true;
2471static constexpr bool DEFAULT_DRAW_FRAME = true;
2472static constexpr bool DEFAULT_DRAW_SHADOWS = true;
2473static constexpr bool DEFAULT_EMBOSS = false;
2474static constexpr float DEFAULT_ROUNDNESS = 0.f;
2475static constexpr float DEFAULT_FRAME_THICKNESS = 1.f;
2476static constexpr float DEFAULT_SHADOW_OFFSET = 3.f;
2477static constexpr float DEFAULT_WIDGET_FRAC = 1.f;
2478static constexpr float DEFAULT_WIDGET_ANGLE = 0.f;
2479static constexpr EOrientation DEFAULT_LABEL_ORIENTATION = EOrientation::North;
2480const IText DEFAULT_LABEL_TEXT {DEFAULT_TEXT_SIZE + 5.f, EVAlign::Top};
2481const IText DEFAULT_VALUE_TEXT {DEFAULT_TEXT_SIZE, EVAlign::Bottom};
2482
2485{
2486 bool hideCursor = DEFAULT_HIDE_CURSOR;
2487 bool showLabel = DEFAULT_SHOW_LABEL;
2488 bool showValue = DEFAULT_SHOW_VALUE;
2489 bool drawFrame = DEFAULT_DRAW_FRAME;
2490 bool drawShadows = DEFAULT_DRAW_SHADOWS;
2491 bool emboss = DEFAULT_EMBOSS;
2492 float roundness = DEFAULT_ROUNDNESS;
2493 float frameThickness = DEFAULT_FRAME_THICKNESS;
2494 float shadowOffset = DEFAULT_SHADOW_OFFSET;
2495 float widgetFrac = DEFAULT_WIDGET_FRAC;
2496 float angle = DEFAULT_WIDGET_ANGLE;
2497 IVColorSpec colorSpec = DEFAULT_COLOR_SPEC;
2498 IText labelText = DEFAULT_LABEL_TEXT;
2499 IText valueText = DEFAULT_VALUE_TEXT;
2500 EOrientation labelOrientation = DEFAULT_LABEL_ORIENTATION;
2501
2517 IVStyle(bool showLabel = DEFAULT_SHOW_LABEL,
2518 bool showValue = DEFAULT_SHOW_VALUE,
2519 const IVColorSpec& colors = {DEFAULT_BGCOLOR, DEFAULT_FGCOLOR, DEFAULT_PRCOLOR, DEFAULT_FRCOLOR, DEFAULT_HLCOLOR, DEFAULT_SHCOLOR, DEFAULT_X1COLOR, DEFAULT_X2COLOR, DEFAULT_X3COLOR},
2520 const IText& labelText = DEFAULT_LABEL_TEXT,
2521 const IText& valueText = DEFAULT_VALUE_TEXT,
2522 bool hideCursor = DEFAULT_HIDE_CURSOR,
2523 bool drawFrame = DEFAULT_DRAW_FRAME,
2524 bool drawShadows = DEFAULT_DRAW_SHADOWS,
2525 bool emboss = DEFAULT_EMBOSS,
2526 float roundness = DEFAULT_ROUNDNESS,
2527 float frameThickness = DEFAULT_FRAME_THICKNESS,
2528 float shadowOffset = DEFAULT_SHADOW_OFFSET,
2529 float widgetFrac = DEFAULT_WIDGET_FRAC,
2530 float angle = DEFAULT_WIDGET_ANGLE,
2531 EOrientation labelOrientation = DEFAULT_LABEL_ORIENTATION)
2532 : hideCursor(hideCursor)
2533 , showLabel(showLabel)
2534 , showValue(showValue)
2535 , drawFrame(drawFrame)
2536 , drawShadows(drawShadows)
2537 , emboss(emboss)
2538 , roundness(roundness)
2539 , frameThickness(frameThickness)
2540 , shadowOffset(shadowOffset)
2541 , widgetFrac(widgetFrac)
2542 , angle(angle)
2543 , colorSpec(colors)
2544 , labelText(labelText)
2545 , valueText(valueText)
2546 {
2547 }
2548
2551 IVStyle(const std::initializer_list<IColor>& colors)
2552 : colorSpec(colors)
2553 {
2554 }
2555
2556 IVStyle WithShowLabel(bool show = true) const { IVStyle newStyle = *this; newStyle.showLabel = show; return newStyle; }
2557 IVStyle WithShowValue(bool show = true) const { IVStyle newStyle = *this; newStyle.showValue = show; return newStyle; }
2558 IVStyle WithLabelText(const IText& text) const { IVStyle newStyle = *this; newStyle.labelText = text; return newStyle;}
2559 IVStyle WithValueText(const IText& text) const { IVStyle newStyle = *this; newStyle.valueText = text; return newStyle; }
2560 IVStyle WithHideCursor(bool hide = true) const { IVStyle newStyle = *this; newStyle.hideCursor = hide; return newStyle; }
2561 IVStyle WithColor(EVColor idx, IColor color) const { IVStyle newStyle = *this; newStyle.colorSpec.mColors[idx] = color; return newStyle; }
2562 IVStyle WithColors(const IVColorSpec& spec) const { IVStyle newStyle = *this; newStyle.colorSpec = spec; return newStyle; }
2563 IVStyle WithRoundness(float v) const { IVStyle newStyle = *this; newStyle.roundness = Clip(v, 0.f, 1.f); return newStyle; }
2564 IVStyle WithFrameThickness(float v) const { IVStyle newStyle = *this; newStyle.frameThickness = v; return newStyle; }
2565 IVStyle WithShadowOffset(float v) const { IVStyle newStyle = *this; newStyle.shadowOffset = v; return newStyle; }
2566 IVStyle WithDrawShadows(bool v = true) const { IVStyle newStyle = *this; newStyle.drawShadows = v; return newStyle; }
2567 IVStyle WithDrawFrame(bool v = true) const { IVStyle newStyle = *this; newStyle.drawFrame = v; return newStyle; }
2568 IVStyle WithWidgetFrac(float v) const { IVStyle newStyle = *this; newStyle.widgetFrac = Clip(v, 0.f, 1.f); return newStyle; }
2569 IVStyle WithAngle(float v) const { IVStyle newStyle = *this; newStyle.angle = Clip(v, 0.f, 360.f); return newStyle; }
2570 IVStyle WithEmboss(bool v = true) const { IVStyle newStyle = *this; newStyle.emboss = v; return newStyle; }
2571 IVStyle WithLabelOrientation(EOrientation v) const { IVStyle newStyle = *this; newStyle.labelOrientation = v; return newStyle; }
2572};
2573
2574const IVStyle DEFAULT_STYLE = IVStyle();
2575
2576END_IGRAPHICS_NAMESPACE
2577END_IPLUG_NAMESPACE
2578
IPlug logging a.k.a tracing functionality.
Utility functions and macros.
A base class interface for a bitmap abstraction around the different drawing back end bitmap represen...
float GetScale() const
float GetDrawScale() const
User-facing bitmap abstraction that you use to manage bitmap data, independant of draw class/platform...
int W() const
bool GetFramesAreHorizontal() const
const WDL_String & GetResourceName() const
int N() const
int FH() const
float GetDrawScale() const
float GetScale() const
int H() const
int FW() const
APIBitmap * GetAPIBitmap() const
IBitmap(APIBitmap *pAPIBitmap, int n, bool framesAreHorizontal, const char *name="")
IBitmap Constructor.
bool IsValid() const
The lowest level base class of an IGraphics control.
Definition: IControl.h:49
The lowest level base class of an IGraphics context.
Definition: IGraphics.h:86
A control that can be specialised with a lambda function, for quick experiments without making a cust...
Definition: IControl.h:2018
An abstraction that is used to store a temporary raster image/framebuffer.
const APIBitmap * GetAPIBitmap() const
ILayer(APIBitmap *pBitmap, const IRECT &layerRect, IControl *pControl, const IRECT &controlRect)
Create a layer/offscreen context (used internally)
const IRECT & Bounds() const
void Invalidate()
Mark the layer as needing its contents redrawn
IBitmap GetBitmap() const
A class for setting the contents of a pop up menu.
Used to manage a list of rectangular areas and optimize them for drawing to the screen.
void Clear()
Clear the list.
void Set(int idx, const IRECT &rect)
Set a specific rectangle in the list (will crash if idx is invalid)
IRECT Bounds()
Get a union of all rectangles in the list.
int Size() const
void Add(const IRECT &rect)
Add a rectangle to the list.
void PixelAlign(float scale)
Pixel-align the IRECTs at the given scale factor then scale them back down.
void PixelAlign()
Align the rectangles to pixel boundaries.
void Optimize()
Remove rects that are contained by other rects and intersections and merge any rects that can be merg...
int Find(float x, float y) const
Find the first index of the rect that contains point x, y, if it exists.
static bool GetFracGrid(const IRECT &input, IRECTList &rects, const std::initializer_list< float > &rowFractions, const std::initializer_list< float > &colFractions, EDirection layoutDir=EDirection::Horizontal)
Fill an IRECTList with divisons of an input IRECT.
const IRECT & Get(int idx) const
Get an IRECT from the list (will crash if idx is invalid)
void DefaultAnimationFunc(IControl *pCaller)
An animation function that just calls the caller control's OnEndAnimation() method at the end of the ...
Definition: IControl.cpp:21
void EmptyClickActionFunc(IControl *pCaller)
A click action function that does nothing.
Definition: IControl.cpp:43
static const char * TextStyleString(ETextStyle style)
Helper to get a CString based on ETextStyle.
void DefaultClickActionFunc(IControl *pCaller)
A click action function that triggers the default animation function for DEFAULT_ANIMATION_DURATION.
Definition: IControl.cpp:45
void SplashClickActionFunc(IControl *pCaller)
The splash click action function is used by IVControls to start SplashAnimationFunc.
Definition: IControl.cpp:47
void SplashAnimationFunc(IControl *pCaller)
The splash animation function is used by IVControls to animate the splash.
Definition: IControl.cpp:30
std::unique_ptr< ILayer > ILayerPtr
ILayerPtr is a managed pointer for transferring the ownership of layers.
float BlendWeight(const IBlend *pBlend)
Helper function to extract the blend weight value from an IBlend ptr if it is valid.
void ShowBubbleVerticalActionFunc(IControl *pCaller)
Use with a param-linked control to popup the bubble control vertically.
Definition: IControl.cpp:66
void ShowBubbleHorizontalActionFunc(IControl *pCaller)
Use with a param-linked control to popup the bubble control horizontally.
Definition: IControl.cpp:55
Used to describe a particular gesture.
Used to group mouse coordinates with mouse modifier information.
Used to manage stroke behaviour for path based drawing back ends.
BEGIN_IPLUG_NAMESPACE T Clip(T x, T lo, T hi)
Clips the value x between lo and hi.
Used to manage composite/blend operations, independent of draw class/platform.
IBlend(EBlend type=EBlend::Default, float weight=1.0f)
Creates a new IBlend.
Used to manage color data, independent of draw class/platform.
IColor(int a=255, int r=0, int g=0, int b=0)
Create an IColor from ARGB values.
void SetOpacity(float alpha)
Set the color's opacity/alpha component with a float.
static IColor FromColorCode(int colorCode, int A=0xFF)
Create an IColor from a color code.
static IColor FromRGBAf(float *rgbaf)
Create an IColor from a 4 float RGBA array.
void GetRGBAf(float *rgbaf) const
Get the color as a 4 float array.
void Set(int a=255, int r=0, int g=0, int b=0)
Set the color parts.
IColor WithContrast(float c) const
Returns a new contrasted IColor based on this one.
void Randomise(int alpha=255)
Randomise the color parts, with optional alpha.
static IColor FromHSLA(float h, float s, float l, float a=1.f)
Create an IColor from Hue Saturation and Luminance values.
void GetRGBf(float *rgbf) const
Get the color as a 3 float array.
int ToColorCode() const
Convert the IColor to a single int (no alpha)
IColor WithOpacity(float alpha) const
Returns a new IColor with a different opacity.
int GetLuminosity() const
static IColor FromColorCodeStr(const char *hexStr)
Create an IColor from a color code in a CString.
static IColor FromRGBf(float *rgbf)
Create an IColor from a 3 float RGB array.
bool Empty() const
static IColor LinearInterpolateBetween(const IColor &start, const IColor &dest, float progress)
Helper function to linear interpolate between two IColors.
void GetHSLA(float &h, float &s, float &l, float &a) const
Get the Hue, Saturation and Luminance of the color.
void Contrast(float c)
Contrast the color.
void ToColorCodeStr(WDL_String &str, bool withAlpha=true) const
Convert the IColor to a hex string e.g.
static IColor GetRandomColor(bool randomAlpha=false)
Get a random IColor.
void Clamp()
Keep the member int variables within the range 0-255.
Used to represent a point/stop in a gradient.
IColorStop(IColor color, float offset)
Create an IColor stop.
Used to manage fill behaviour.
Used for key press info, such as ASCII representation, virtual key (mapped to win32 codes) and modifi...
Definition: IPlugStructs.h:616
Used to store transformation matrices.
IMatrix(double xx, double yx, double xy, double yy, double tx, double ty)
Create an IMatrix, specifying the values.
IMatrix & Rotate(float a)
Set the matrix for a rotation transform.
IMatrix & Scale(float x, float y)
Set the matrix for a scale transform.
IMatrix()
Create an identity matrix.
IMatrix & Transform(const IMatrix &m)
Transform this matrix with another.
IMatrix & Invert()
Changes the matrix to be the inverse of its original value.
void TransformPoint(double &x, double &y) const
Transforms the point x, y with the matrix.
IMatrix & Transform(const IRECT &before, const IRECT &after)
IMatrix & Translate(float x, float y)
Set the matrix for a translation transform.
IMatrix & Skew(float xa, float ya)
Set the matrix for a skew transform.
void TransformPoint(double &x, double &y, double x0, double y0) const
Transforms the point x, y.
Used to manage mouse modifiers i.e.
bool IsTouch() const
true if this IMouseMod is linked to a touch event
IMouseMod(bool l=false, bool r=false, bool s=false, bool c=false, bool a=false, ITouchID touchID=0)
Create an IMouseMod.
void DBGPrint()
Print the mouse modifier values to the console in Debug builds.
Used to store pattern information for gradients.
const IColorStop & GetStop(int idx) const
Get the IColorStop at a particular index (will crash if out of bounds)
int NStops() const
IPattern(const IColor &color)
Create an IPattern with a solid color fill.
void AddStop(IColor color, float offset)
Add an IColorStop to the IPattern.
static IPattern CreateLinearGradient(float x1, float y1, float x2, float y2, const std::initializer_list< IColorStop > &stops={})
Create a linear gradient IPattern.
static IPattern CreateSweepGradient(float x1, float y1, const std::initializer_list< IColorStop > &stops={}, float angleStart=0.f, float angleEnd=360.f)
Create a sweep gradient IPattern (SKIA only)
static IPattern CreateLinearGradient(const IRECT &bounds, EDirection direction, const std::initializer_list< IColorStop > &stops={})
Create a linear gradient IPattern across a rectangular area.
static IPattern CreateRadialGradient(float x1, float y1, float r, const std::initializer_list< IColorStop > &stops={})
Create a radial gradient IPattern.
void SetTransform(float xx, float yx, float xy, float yy, float tx, float ty)
Set the affine transform for the IPattern with values.
IPattern(EPatternType type)
Create an IPattern.
void SetTransform(const IMatrix &transform)
Set the affine transform for the IPattern with an IMatrix.
Used to manage a rectangular area, independent of draw class/platform.
IRECT ReduceFromRight(float amount)
Reduce in width from the right edge by 'amount' and return the removed region.
IRECT GetCentredInside(const IBitmap &bitmap) const
Get a rectangle with the same center point as this rectangle and the size of the bitmap.
IRECT GetReducedFromTop(float amount) const
Get a subrect of this IRECT reduced in height from the top edge by 'amount'.
IRECT GetFromTRHC(float w, float h) const
Get a subrect of this IRECT expanding from the top-right corner.
void VPad(float padding)
Pad this IRECT in the Y-axis N.B.
void MidHPad(float padding)
Set the width of this IRECT to 2*padding without changing it's center point on the X-axis.
IRECT GetReducedFromLeft(float amount) const
Get a subrect of this IRECT reduced in width from the left edge by 'amount'.
void Clear()
Set all fields of this IRECT to 0.
IRECT GetReducedFromRight(float amount) const
Get a subrect of this IRECT reduced in width from the right edge by 'amount'.
IRECT ReduceFromLeft(float amount)
Reduce in width from the left edge by 'amount' and return the removed region.
IRECT GetCentredInside(float w, float h=0.f) const
Get a rectangle with the same center point as this rectangle and the given size.
IRECT(float l, float t, float r, float b)
Construct a new IRECT with dimensions.
bool Contains(float x, float y) const
Returns true if this IRECT completely contains the point (x,y).
IRECT Intersect(const IRECT &rhs) const
Create a new IRECT that is the intersection of this IRECT and rhs.
void Pad(float padding)
Pad this IRECT N.B.
IRECT GetFromTLHC(float w, float h) const
Get a subrect of this IRECT expanding from the top-left corner.
IRECT GetFromRight(float amount) const
Get a subrect of this IRECT bounded in X by 'amount' and the right edge.
IRECT GetFromBottom(float amount) const
Get a subrect of this IRECT bounded in Y by 'amount' and the bottom edge.
IRECT GetCentredInside(const IRECT &sr) const
Get a rectangle the size of sr but with the same center point as this rectangle.
bool IsPixelAligned() const
IRECT GetPixelAligned() const
Get a copy of this IRECT with PixelAlign() called.
IRECT Inset(const IRECT &rhs) const
Offsets the input IRECT based on the parent.
static IRECT MakeXYWH(float l, float t, float w, float h)
Create a new IRECT with the given position and size.
void PixelAlign()
Pixel aligns the rect in an inclusive manner (moves all points outwards)
bool Mergeable(const IRECT &rhs) const
Return if this IRECT and rhs may be merged.
float GetLengthOfShortestSide() const
void Pad(float padL, float padT, float padR, float padB)
Pad this IRECT N.B.
IRECT()
Construct an empty IRECT
void GetRandomPoint(float &x, float &y) const
Get a random point within this rectangle.
IRECT ReduceFromTop(float amount)
Reduce in height from the top edge by 'amount' and return the removed region.
IRECT GetTranslated(float x, float y) const
Get a translated copy of this rectangle.
float MH() const
IRECT GetScaledAboutCentre(float scale) const
Get a copy of this IRECT where the width and height are multiplied by scale without changing the cent...
void PixelSnap()
Pixel aligns to nearest pixels This may make the IRECT smaller, unlike PixelAlign().
void VAlignTo(const IRECT &sr, EVAlign align)
Vertically align this rect to the reference IRECT.
bool ContainsEdge(float x, float y) const
Returns true if the point (x,y) is either contained in this IRECT or on an edge.
IRECT GetVSliced(float h, bool bot=false) const
Get a copy of this IRECT with a new height.
IRECT GetFromBLHC(float w, float h) const
Get a subrect of this IRECT expanding from the bottom-left corner.
IRECT GetReducedFromBottom(float amount) const
Get a subrect of this IRECT reduced in height from the bottom edge by 'amount'.
IRECT FracRectVertical(float frac, bool fromTop=false) const
Returns a new IRECT with a height that is multiplied by frac.
void Offset(float l, float t, float r, float b)
Offset each field of the rectangle.
void MidVPad(float padding)
Set the height of this IRECT to 2*padding without changing it's center point on the Y-axis.
IRECT SubRect(EDirection layoutDir, int numSlices, int sliceIdx) const
Get a new rectangle which is a "slice" of this rectangle.
IRECT GetPixelSnapped() const
bool Empty() const
static IRECT MakeMidXYWH(float x, float y, float w, float h)
Create a new IRECT of size (y,h) centred at the given position (x,y)
void HAlignTo(const IRECT &sr, EAlign align)
Horizontally align this rect to the reference IRECT.
IRECT SubRectHorizontal(int numSlices, int sliceIdx) const
Returns a new IRECT which is a vertical "slice" of this IRECT.
IRECT GetScaled(float scale) const
Get a copy of this IRECT with all values multiplied by scale.
IRECT GetGridCell(int row, int col, int nRows, int nColumns) const
Get a subrect (by row, column) of this IRECT which is a cell in a grid of size (nRows * nColumns)
IRECT GetVPadded(float padding) const
Get a copy of this IRECT padded in the Y-axis N.B.
IRECT FracRect(EDirection layoutDir, float frac, bool fromTopOrRight=false) const
Get a new rectangle which is a fraction of this rectangle.
float W() const
IRECT ReduceFromBottom(float amount)
Reduce in height from the bottom edge by 'amount' and return the removed region.
static IRECT LinearInterpolateBetween(const IRECT &start, const IRECT &dest, float progress)
Get a rectangle that is a linear interpolation between start and dest
void Clank(const IRECT &rhs)
Clank will limit this IRECT's bounds based on the boundaries of the IRECT passed in as an argument.
void Scale(float scale)
Multiply each field of this IRECT by scale.
IRECT FracRectHorizontal(float frac, bool rhs=false) const
Returns a new IRECT with a width that is multiplied by frac.
void PixelAlign(float scale)
Pixel-align this IRECT at the given scale factor then scale it back down When scaling this mutliples ...
void HPad(float padding)
Pad this IRECT in the X-axis N.B.
IRECT Union(const IRECT &rhs) const
Create a new IRECT that is a union of this IRECT and rhs.
IRECT GetVShifted(float y) const
Get a copy of this rectangle translated on the Y axis.
float Area() const
void Constrain(float &x, float &y) const
Ensure the point (x,y) is inside this IRECT.
IRECT GetPixelAligned(float scale) const
Get a copy of this IRECT with PixelAlign(scale) called.
bool Intersects(const IRECT &rhs) const
Returns true if this IRECT shares any common pixels with rhs, false otherwise.
IRECT GetRandomSubRect() const
IRECT SubRectVertical(int numSlices, int sliceIdx) const
Returns a new IRECT which is a horizontal "slice" of this IRECT.
IRECT GetFromLeft(float amount) const
Get a subrect of this IRECT bounded in X by the left edge and 'amount'.
bool IsPixelAligned(float scale) const
Return true if, when scaled by scale, this IRECT is pixel aligned When scaling this mutliples each va...
IRECT GetFromTop(float amount) const
Get a subrect of this IRECT bounded in Y by the top edge and 'amount'.
float H() const
void Translate(float x, float y)
Translate this rectangle.
IRECT GetFromBRHC(float w, float h) const
Get a subrect of this IRECT expanding from the bottom-right corner.
IRECT(float x, float y, const IBitmap &bitmap)
Construct a new IRECT at the given position and with the same size as the bitmap.
IRECT GetHShifted(float x) const
Get a copy of this rectangle translated on the X axis.
IRECT GetMidHPadded(float padding) const
Get a copy of this IRECT where its width = 2 * padding but the center point on the X-axis has not cha...
IRECT GetHAlignedTo(const IRECT &sr, EAlign align) const
Get a rectangle the same dimensions as this one, horizontally aligned to the reference IRECT.
void ScaleAboutCentre(float scale)
Scale the width and height of this IRECT by scale without changing the center point.
float MW() const
bool Contains(const IRECT &rhs) const
Returns true if this IRECT completely contains rhs.
void PixelSnap(float scale)
Pixel align a scaled version of this IRECT.
IRECT GetPadded(float padding) const
Get a copy of this IRECT with each value padded by padding N.B.
IRECT GetHPadded(float padding) const
Get a copy of this IRECT padded in the X-axis N.B.
IRECT GetPixelSnapped(float scale) const
Get a copy of this IRECT with PixelSnap(scale) called.
void DBGPrint()
Print the IRECT's details to the console in Debug builds.
IRECT GetOffset(float l, float t, float r, float b) const
Get a copy of this rectangle where each field is offset by a specified amount.
IRECT GetVAlignedTo(const IRECT &sr, EVAlign align) const
Get a rectangle the same dimensions as this one, vertically aligned to the reference IRECT.
IRECT GetMidVPadded(float padding) const
Get a copy of this IRECT where its height = 2 * padding but the center point on the Y-axis has not ch...
IRECT GetPadded(float padL, float padT, float padR, float padB) const
Get a copy of this IRECT with the values padded N.B.
IRECT GetHSliced(float w, bool rhs=false) const
Get a copy of this IRECT with a new width.
IRECT GetGridCell(int cellIndex, int nRows, int nColumns, EDirection dir=EDirection::Horizontal, int nCells=1) const
Get a subrect (by index) of this IRECT which is a cell (or union of nCells sequential cells on same r...
User-facing SVG abstraction that you use to manage SVG data ISVG doesn't actually own the image data.
bool IsValid() const
float H() const
float W() const
Used to specify properties of a drop-shadow to a layer.
IShadow(const IPattern &pattern, float blurSize, float xOffset, float yOffset, float opacity, bool drawForeground=true)
Create an IShadow.
IText is used to manage font and text/text entry style for a piece of text on the UI,...
IText(float size=DEFAULT_TEXT_SIZE, const IColor &color=DEFAULT_TEXT_FGCOLOR, const char *fontID=nullptr, EAlign align=EAlign::Center, EVAlign valign=EVAlign::Middle, float angle=0, const IColor &TEBGColor=DEFAULT_TEXTENTRY_BGCOLOR, const IColor &TEFGColor=DEFAULT_TEXTENTRY_FGCOLOR)
Create a new IText with size, color, fontID ...
IText(float size, const char *fontID)
Create a new IText with size and fontID.
IText(float size, EVAlign valign, const IColor &color=DEFAULT_TEXT_FGCOLOR)
Create a new IText with size, vertical align, color.
IText(float size, EAlign align, const IColor &color=DEFAULT_TEXT_FGCOLOR)
Create a new IText with size, horizontal align, color.
Contains a set of 9 colors used to theme IVControls.
IVColorSpec(const std::initializer_list< IColor > &colors)
Create a new IVColorSpec object specifying the colors.
static const IColor & GetDefaultColor(EVColor idx)
void ResetColors()
Reset the colors to the defaults.
const IColor & GetColor(EVColor color) const
IVColorSpec()
Create a new IVColorSpec object with default colors.
A struct encapsulating a set of properties used to configure IVControls.
IVStyle(const std::initializer_list< IColor > &colors)
Create a new IVStyle based on a list of colors, and defaults for the other elements.
IVStyle(bool showLabel=DEFAULT_SHOW_LABEL, bool showValue=DEFAULT_SHOW_VALUE, const IVColorSpec &colors={DEFAULT_BGCOLOR, DEFAULT_FGCOLOR, DEFAULT_PRCOLOR, DEFAULT_FRCOLOR, DEFAULT_HLCOLOR, DEFAULT_SHCOLOR, DEFAULT_X1COLOR, DEFAULT_X2COLOR, DEFAULT_X3COLOR}, const IText &labelText=DEFAULT_LABEL_TEXT, const IText &valueText=DEFAULT_VALUE_TEXT, bool hideCursor=DEFAULT_HIDE_CURSOR, bool drawFrame=DEFAULT_DRAW_FRAME, bool drawShadows=DEFAULT_DRAW_SHADOWS, bool emboss=DEFAULT_EMBOSS, float roundness=DEFAULT_ROUNDNESS, float frameThickness=DEFAULT_FRAME_THICKNESS, float shadowOffset=DEFAULT_SHADOW_OFFSET, float widgetFrac=DEFAULT_WIDGET_FRAC, float angle=DEFAULT_WIDGET_ANGLE, EOrientation labelOrientation=DEFAULT_LABEL_ORIENTATION)
Create a new IVStyle to configure common styling for IVControls.
Encapsulate an xy point in one struct.