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 ILiveEditEventFunc = std::function<void(const char* eventJson)>;
57using ITouchID = uintptr_t;
58
60void EmptyClickActionFunc(IControl* pCaller);
61
63void DefaultClickActionFunc(IControl* pCaller);
64
66void DefaultAnimationFunc(IControl* pCaller);
67
69void SplashClickActionFunc(IControl* pCaller);
70
72void SplashAnimationFunc(IControl* pCaller);
73
76
79
80using MTLTexturePtr = void*;
81
82using Milliseconds = std::chrono::duration<double, std::chrono::milliseconds::period>;
83using TimePoint = std::chrono::time_point<std::chrono::high_resolution_clock, Milliseconds>;
84
89{
90public:
96 IBitmap(APIBitmap* pAPIBitmap, int n, bool framesAreHorizontal, const char* name = "")
97 : mAPIBitmap(pAPIBitmap)
98 , mW(static_cast<int>(pAPIBitmap->GetWidth() / pAPIBitmap->GetScale()))
99 , mH(static_cast<int>(pAPIBitmap->GetHeight() / pAPIBitmap->GetScale()))
100 , mN(n)
101 , mFramesAreHorizontal(framesAreHorizontal)
102 , mResourceName(name, static_cast<int>(strlen(name)))
103 {
104 }
105
106 IBitmap()
107 : mAPIBitmap(nullptr)
108 , mW(0)
109 , mH(0)
110 , mN(0)
111 , mFramesAreHorizontal(false)
112 {
113 }
114
116 int W() const { return mW; }
117
119 int H() const { return mH; }
120
122 int FW() const { return (mFramesAreHorizontal ? mW / mN : mW); }
123
125 int FH() const { return (mFramesAreHorizontal ? mH : mH / mN); }
126
128 int N() const { return mN; }
129
131 float GetScale() const { return mAPIBitmap->GetScale(); }
132
134 float GetDrawScale() const { return mAPIBitmap->GetDrawScale(); }
135
137 APIBitmap* GetAPIBitmap() const { return mAPIBitmap; }
138
140 bool GetFramesAreHorizontal() const { return mFramesAreHorizontal; }
141
143 const WDL_String& GetResourceName() const { return mResourceName; }
144
146 inline bool IsValid() const { return mAPIBitmap != nullptr; }
147
148private:
150 APIBitmap* mAPIBitmap;
152 int mW;
154 int mH;
156 int mN;
158 bool mFramesAreHorizontal;
160 WDL_String mResourceName;
161};
162
166#ifdef SVG_USE_SKIA
167struct ISVG
168{
169 ISVG(sk_sp<SkSVGDOM> svgDom)
170 : mSVGDom(svgDom)
171 {
172 }
173
175 float W() const
176 {
177 assert(mSVGDom);
178 return mSVGDom->containerSize().width();
179 }
180
182 float H() const
183 {
184 assert(mSVGDom);
185 return mSVGDom->containerSize().height();
186 }
187
189 inline bool IsValid() const { return mSVGDom != nullptr; }
190
191 sk_sp<SkSVGDOM> mSVGDom;
192};
193#else
194struct ISVG
195{
196 ISVG(NSVGimage* pImage)
197 {
198 mImage = pImage;
199 }
200
202 float W() const
203 {
204 assert(mImage);
205 return mImage->width;
206 }
207
209 float H() const
210 {
211 assert(mImage);
212 return mImage->height;
213 }
214
216 inline bool IsValid() const { return mImage != nullptr; }
217
218 NSVGimage* mImage = nullptr;
219};
220#endif
221
223struct IColor
224{
225 int A, R, G, B;
226
232 IColor(int a = 255, int r = 0, int g = 0, int b = 0) : A(a), R(r), G(g), B(b) {}
233
234 bool operator==(const IColor& rhs) { return (rhs.A == A && rhs.R == R && rhs.G == G && rhs.B == B); }
235 bool operator!=(const IColor& rhs) { return !operator==(rhs); }
236
242 void Set(int a = 255, int r = 0, int g = 0, int b = 0) { A = a; R = r; G = g; B = b; }
243
245 bool Empty() const { return A == 0 && R == 0 && G == 0 && B == 0; }
246
248 void Clamp() { A = Clip(A, 0, 255); R = Clip(R, 0, 255); G = Clip(G, 0, 255); B = Clip(B, 0, 255); }
249
252 void Randomise(int alpha = 255) { A = alpha; R = std::rand() % 255; G = std::rand() % 255; B = std::rand() % 255; }
253
256 void SetOpacity(float alpha)
257 {
258 A = static_cast<int>(Clip(alpha, 0.f, 1.f) * 255.f);
259 }
260
264 IColor WithOpacity(float alpha) const
265 {
266 IColor n = *this;
267 n.SetOpacity(alpha);
268 return n;
269 }
270
273 void Contrast(float c)
274 {
275 const int mod = static_cast<int>(c * 255.f);
276 R = Clip(R += mod, 0, 255);
277 G = Clip(G += mod, 0, 255);
278 B = Clip(B += mod, 0, 255);
279 }
280
284 IColor WithContrast(float c) const
285 {
286 IColor n = *this;
287 n.Contrast(c);
288 return n;
289 }
290
293 void GetRGBf(float* rgbf) const
294 {
295 rgbf[0] = R / 255.f;
296 rgbf[1] = G / 255.f;
297 rgbf[2] = B / 255.f;
298 }
299
302 void GetRGBAf(float* rgbaf) const
303 {
304 rgbaf[0] = R / 255.f;
305 rgbaf[1] = G / 255.f;
306 rgbaf[2] = B / 255.f;
307 rgbaf[3] = A / 255.f;
308 }
309
315 void GetHSLA(float& h, float& s, float& l, float& a) const
316 {
317 const float fR = R / 255.f;
318 const float fG = G / 255.f;
319 const float fB = B / 255.f;
320 a = A / 255.f;
321
322 const float fMin = std::min(fR, std::min(fG, fB));
323 const float fMax = std::max(fR, std::max(fG, fB));
324 const float fDiff = fMax - fMin;
325 const float fSum = fMax + fMin;
326
327 l = 50.f * fSum;
328
329 if (fMin == fMax) { s = 0.f; h = 0.f; l /= 100.f; return; }
330 else if (l < 50.f) { s = 100.f * fDiff / fSum; }
331 else { s = 100.f * fDiff / (2.f - fDiff); }
332
333 if (fMax == fR) { h = 60.f * (fG - fB) / fDiff; }
334 if (fMax == fG) { h = 60.f * (fB - fR) / fDiff + 120.f; }
335 if (fMax == fB) { h = 60.f * (fR - fG) / fDiff + 240.f; }
336
337 if (h < 0.f) { h = h + 360.f; }
338
339 h /= 360.f;
340 s /= 100.f;
341 l /= 100.f;
342 }
343
346 int GetLuminosity() const
347 {
348 int min = R < G ? (R < B ? R : B) : (G < B ? G : B);
349 int max = R > G ? (R > B ? R : B) : (G > B ? G : B);
350 return (min + max) / 2;
351 };
352
356 static IColor GetRandomColor(bool randomAlpha = false)
357 {
358 int A = randomAlpha ? std::rand() & 0xFF : 255;
359 int R = std::rand() & 0xFF;
360 int G = std::rand() & 0xFF;
361 int B = std::rand() & 0xFF;
362
363 return IColor(A, R, G, B);
364 }
365
369 static IColor FromRGBf(float* rgbf)
370 {
371 int A = 255;
372 int R = static_cast<int>(rgbf[0] * 255.f);
373 int G = static_cast<int>(rgbf[1] * 255.f);
374 int B = static_cast<int>(rgbf[2] * 255.f);
375
376 return IColor(A, R, G, B);
377 }
378
382 static IColor FromRGBAf(float* rgbaf)
383 {
384 int R = static_cast<int>(rgbaf[0] * 255.f);
385 int G = static_cast<int>(rgbaf[1] * 255.f);
386 int B = static_cast<int>(rgbaf[2] * 255.f);
387 int A = static_cast<int>(rgbaf[3] * 255.f);
388
389 return IColor(A, R, G, B);
390 }
391
401 static IColor FromColorCode(int colorCode, int A = 0xFF)
402 {
403 int R = (colorCode >> 16) & 0xFF;
404 int G = (colorCode >> 8) & 0xFF;
405 int B = colorCode & 0xFF;
406
407 return IColor(A, R, G, B);
408 }
409
413 static IColor FromColorCodeStr(const char* hexStr)
414 {
415 WDL_String str(hexStr);
416
417 if ((str.GetLength() == 7 || str.GetLength() == 9) && str.Get()[0] == '#')
418 {
419 str.DeleteSub(0, 1);
420
421 return FromColorCode(static_cast<int>(std::stoul(str.Get(), nullptr, 16)));
422 }
423 else
424 {
425 assert(0 && "Invalid color code str, returning black");
426 return IColor();
427 }
428 }
429
431 int ToColorCode() const
432 {
433 return (R << 16) | (G << 8) | B;
434 }
435
437 void ToColorCodeStr(WDL_String& str, bool withAlpha = true) const
438 {
439 if (withAlpha)
440 str.SetFormatted(32, "#%02x%02x%02x%02x", R, G, B, A);
441 else
442 str.SetFormatted(32, "#%02x%02x%02x", R, G, B);
443 }
444
451 static IColor FromHSLA(float h, float s, float l, float a = 1.f)
452 {
453 auto hue = [](float h, float m1, float m2) {
454 if (h < 0) h += 1;
455 if (h > 1) h -= 1;
456 if (h < 1.0f / 6.0f)
457 return m1 + (m2 - m1) * h * 6.0f;
458 else if (h < 3.0f / 6.0f)
459 return m2;
460 else if (h < 4.0f / 6.0f)
461 return m1 + (m2 - m1) * (2.0f / 3.0f - h) * 6.0f;
462 return m1;
463 };
464
465 IColor col;
466 h = std::fmodf(h, 1.0f);
467 if (h < 0.0f) h += 1.0f;
468 s = Clip(s, 0.0f, 1.0f);
469 l = Clip(l, 0.0f, 1.0f);
470 float m2 = l <= 0.5f ? (l * (1 + s)) : (l + s - l * s);
471 float m1 = 2 * l - m2;
472 col.R = static_cast<int>(Clip(hue(h + 1.0f / 3.0f, m1, m2), 0.0f, 1.0f) * 255.f);
473 col.G = static_cast<int>(Clip(hue(h, m1, m2), 0.0f, 1.0f) * 255.f);
474 col.B = static_cast<int>(Clip(hue(h - 1.0f / 3.0f, m1, m2), 0.0f, 1.0f) * 255.f);
475 col.A = static_cast<int>(a * 255.f);
476 return col;
477 }
478
483 static IColor LinearInterpolateBetween(const IColor& start, const IColor& dest, float progress)
484 {
485 IColor result;
486 result.A = start.A + static_cast<int>(progress * static_cast<float>(dest.A - start.A));
487 result.R = start.R + static_cast<int>(progress * static_cast<float>(dest.R - start.R));
488 result.G = start.G + static_cast<int>(progress * static_cast<float>(dest.G - start.G));
489 result.B = start.B + static_cast<int>(progress * static_cast<float>(dest.B - start.B));
490 return result;
491 }
492};
493
494const IColor COLOR_TRANSPARENT(0, 0, 0, 0);
495const IColor COLOR_TRANSLUCENT(10, 0, 0, 0);
496const IColor COLOR_BLACK(255, 0, 0, 0);
497const IColor COLOR_BLACK_DROP_SHADOW(128, 0, 0, 0);
498const IColor COLOR_GRAY(255, 127, 127, 127);
499const IColor COLOR_LIGHT_GRAY(255, 240, 240, 240);
500const IColor COLOR_MID_GRAY(255, 200, 200, 200);
501const IColor COLOR_DARK_GRAY(255, 70, 70, 70);
502const IColor COLOR_WHITE(255, 255, 255, 255);
503const IColor COLOR_RED(255, 255, 0, 0);
504const IColor COLOR_GREEN(255, 0, 255, 0);
505const IColor COLOR_BLUE(255, 0, 0, 255);
506const IColor COLOR_YELLOW(255, 255, 255, 0);
507const IColor COLOR_ORANGE(255, 255, 127, 0);
508const IColor COLOR_INDIGO(255, 75, 0, 130);
509const IColor COLOR_VIOLET(255, 148, 0, 211);
510
511static IColor GetRainbow(int colorIdx)
512{
513 switch (colorIdx) {
514 case 0: return COLOR_RED;
515 case 1: return COLOR_ORANGE;
516 case 2: return COLOR_YELLOW;
517 case 3: return COLOR_GREEN;
518 case 4: return COLOR_BLUE;
519 case 5: return COLOR_INDIGO;
520 case 6: return COLOR_VIOLET;
521 default:
522 assert(0);
523 return COLOR_WHITE;
524 }
525}
526
527const IColor DEFAULT_GRAPHICS_BGCOLOR = COLOR_GRAY;
528const IColor DEFAULT_BGCOLOR = COLOR_TRANSPARENT;
529const IColor DEFAULT_FGCOLOR = COLOR_MID_GRAY;
530const IColor DEFAULT_PRCOLOR = COLOR_LIGHT_GRAY;
531
532const IColor DEFAULT_FRCOLOR = COLOR_DARK_GRAY;
533const IColor DEFAULT_HLCOLOR = COLOR_TRANSLUCENT;
534const IColor DEFAULT_SHCOLOR = IColor(60, 0, 0, 0);
535const IColor DEFAULT_X1COLOR = COLOR_BLACK;
536const IColor DEFAULT_X2COLOR = COLOR_GREEN;
537const IColor DEFAULT_X3COLOR = COLOR_BLUE;
538
539const IColor DEFAULT_TEXT_FGCOLOR = COLOR_BLACK;
540const IColor DEFAULT_TEXTENTRY_BGCOLOR = COLOR_WHITE;
541const IColor DEFAULT_TEXTENTRY_FGCOLOR = COLOR_BLACK;
542
544struct IBlend
545{
546 EBlend mMethod;
547 float mWeight;
548
552 IBlend(EBlend type = EBlend::Default, float weight = 1.0f)
553 : mMethod(type)
554 , mWeight(Clip(weight, 0.f, 1.f))
555 {}
556};
557
561inline float BlendWeight(const IBlend* pBlend)
562{
563 return (pBlend ? pBlend->mWeight : 1.0f);
564}
565
566const IBlend BLEND_75 = IBlend(EBlend::Default, 0.75f);
567const IBlend BLEND_50 = IBlend(EBlend::Default, 0.5f);
568const IBlend BLEND_25 = IBlend(EBlend::Default, 0.25f);
569const IBlend BLEND_10 = IBlend(EBlend::Default, 0.1f);
570const IBlend BLEND_05 = IBlend(EBlend::Default, 0.05f);
571const IBlend BLEND_01 = IBlend(EBlend::Default, 0.01f);
572const IBlend BLEND_DST_IN = IBlend(EBlend::DstIn, 1.f);
573const IBlend BLEND_DST_OVER = IBlend(EBlend::DstOver, 1.f);
574
577{
578 EFillRule mFillRule { EFillRule::Winding };
579 bool mPreserve { false };
580
581 IFillOptions(bool preserve = false, EFillRule fillRule = EFillRule::Winding)
582 : mFillRule(fillRule)
583 , mPreserve(preserve)
584 {
585 }
586
587};
588
591{
593 class DashOptions
594 {
595 public:
597 DashOptions()
598 : mOffset(0)
599 , mCount(0)
600 {}
601
606 DashOptions(float* array, float offset, int count)
607 {
608 SetDash(array, offset, count);
609 }
610
612 int GetCount() const { return mCount; }
613
615 float GetOffset() const { return mOffset; }
616
618 const float* GetArray() const { return mArray; }
619
624 void SetDash(float* pArray, float offset, int count)
625 {
626 assert(count >= 0 && count <= 8);
627
628 mCount = count;
629 mOffset = offset;
630
631 for (int i = 0; i < count; i++)
632 mArray[i] = pArray[i];
633 }
634
635 private:
636 float mArray[8] = {};
637 float mOffset;
638 int mCount;
639 };
640
641 float mMiterLimit = 10.f;
642 bool mPreserve = false;
643 ELineCap mCapOption = ELineCap::Butt;
644 ELineJoin mJoinOption = ELineJoin::Miter;
645 DashOptions mDash;
646};
647
649static const char* TextStyleString(ETextStyle style)
650{
651 switch (style)
652 {
653 case ETextStyle::Bold: return "Bold";
654 case ETextStyle::Italic: return "Italic";
655 case ETextStyle::Normal:
656 default:
657 return "Regular";
658 }
659}
660
662struct IText
663{
673 IText(float size = DEFAULT_TEXT_SIZE,
674 const IColor& color = DEFAULT_TEXT_FGCOLOR,
675 const char* fontID = nullptr,
676 EAlign align = EAlign::Center,
677 EVAlign valign = EVAlign::Middle,
678 float angle = 0,
679 const IColor& TEBGColor = DEFAULT_TEXTENTRY_BGCOLOR,
680 const IColor& TEFGColor = DEFAULT_TEXTENTRY_FGCOLOR)
681 : mSize(size)
682 , mFGColor(color)
683 , mTextEntryBGColor(TEBGColor)
684 , mTextEntryFGColor(TEFGColor)
685 , mAngle(angle)
686 , mAlign(align)
687 , mVAlign(valign)
688 {
689 strcpy(mFont, (fontID ? fontID : DEFAULT_FONT));
690 }
691
696 IText(float size, EVAlign valign, const IColor& color = DEFAULT_TEXT_FGCOLOR)
697 : IText()
698 {
699 mSize = size;
700 mVAlign = valign;
701 mFGColor = color;
702 }
703
708 IText(float size, EAlign align, const IColor& color = DEFAULT_TEXT_FGCOLOR)
709 : IText()
710 {
711 mSize = size;
712 mAlign = align;
713 mFGColor = color;
714 }
715
719 IText(float size, const char* fontID)
720 : IText()
721 {
722 mSize = size;
723 strcpy(mFont, (fontID ? fontID : DEFAULT_FONT));
724 }
725
726 IText WithFGColor(const IColor& fgColor) const { IText newText = *this; newText.mFGColor = fgColor; return newText; }
727 IText WithTEColors(const IColor& teBgColor, const IColor& teFgColor) const { IText newText = *this; newText.mTextEntryBGColor = teBgColor; newText.mTextEntryFGColor = teFgColor; return newText; }
728 IText WithAlign(EAlign align) const { IText newText = *this; newText.mAlign = align; return newText; }
729 IText WithVAlign(EVAlign valign) const { IText newText = *this; newText.mVAlign = valign; return newText; }
730 IText WithSize(float size) const { IText newText = *this; newText.mSize = size; return newText; }
731 IText WithAngle(float v) const { IText newText = *this; newText.mAngle = v; return newText; }
732 IText WithFont(const char* fontID) const { IText newText = *this; strcpy(newText.mFont, (fontID ? fontID : DEFAULT_FONT));; return newText; }
733
734 char mFont[FONT_LEN];
735 float mSize;
736 IColor mFGColor;
737 IColor mTextEntryBGColor;
738 IColor mTextEntryFGColor;
739 float mAngle = 0.f; // Degrees ccwise from normal.
740 EAlign mAlign = EAlign::Near;
741 EVAlign mVAlign = EVAlign::Middle;
742};
743
744const IText DEFAULT_TEXT = IText();
745
749struct IRECT
750{
751 float L, T, R, B;
752
755 {
756 L = T = R = B = 0.f;
757 }
758
764 IRECT(float l, float t, float r, float b)
765 : L(l), T(t), R(r), B(b)
766 {}
767
772 IRECT(float x, float y, const IBitmap& bitmap)
773 {
774 L = x;
775 T = y;
776 R = L + (float) bitmap.FW();
777 B = T + (float) bitmap.FH();
778 }
779
786 static IRECT MakeXYWH(float l, float t, float w, float h)
787 {
788 return IRECT(l, t, l+w, t+h);
789 }
790
797 static IRECT MakeMidXYWH(float x, float y, float w, float h)
798 {
799 return IRECT(x-(w/2.0f), y-(h/2.0f), x+(w/2.0f), y+(h/2.0f));
800 }
801
803 bool Empty() const
804 {
805 return (L == 0.f && T == 0.f && R == 0.f && B == 0.f);
806 }
807
809 void Clear()
810 {
811 L = T = R = B = 0.f;
812 }
813
814 bool operator==(const IRECT& rhs) const
815 {
816 return (L == rhs.L && T == rhs.T && R == rhs.R && B == rhs.B);
817 }
818
819 bool operator!=(const IRECT& rhs) const
820 {
821 return !(*this == rhs);
822 }
823
825 inline float W() const { return R - L; }
826
828 inline float H() const { return B - T; }
829
831 inline float MW() const { return 0.5f * (L + R); }
832
834 inline float MH() const { return 0.5f * (T + B); }
835
837 inline float Area() const { return W() * H(); }
838
843 inline IRECT Union(const IRECT& rhs) const
844 {
845 if (Empty()) { return rhs; }
846 if (rhs.Empty()) { return *this; }
847 return IRECT(std::min(L, rhs.L), std::min(T, rhs.T), std::max(R, rhs.R), std::max(B, rhs.B));
848 }
849
854 inline IRECT Intersect(const IRECT& rhs) const
855 {
856 if (Intersects(rhs))
857 return IRECT(std::max(L, rhs.L), std::max(T, rhs.T), std::min(R, rhs.R), std::min(B, rhs.B));
858
859 return IRECT();
860 }
861
866 inline bool Intersects(const IRECT& rhs) const
867 {
868 return (!Empty() && !rhs.Empty() && R >= rhs.L && L < rhs.R && B >= rhs.T && T < rhs.B);
869 }
870
875 inline bool Contains(const IRECT& rhs) const
876 {
877 return (!Empty() && !rhs.Empty() && rhs.L >= L && rhs.R <= R && rhs.T >= T && rhs.B <= B);
878 }
879
885 inline bool Contains(float x, float y) const
886 {
887 return (!Empty() && x >= L && x < R && y >= T && y < B);
888 }
889
896 inline bool ContainsEdge(float x, float y) const
897 {
898 return (!Empty() && x >= L && x <= R && y >= T && y <= B);
899 }
900
904 inline void Constrain(float& x, float& y) const
905 {
906 if (x < L) x = L;
907 else if (x > R) x = R;
908
909 if (y < T) y = T;
910 else if (y > B) y = B;
911 }
912
915 IRECT Inset(const IRECT& rhs) const
916 {
917 return IRECT(L + rhs.L, T + rhs.T, L + rhs.R, T + rhs.B);
918 }
919
925 bool Mergeable(const IRECT& rhs) const
926 {
927 if (Empty() || rhs.Empty())
928 return true;
929 if (L == rhs.L && R == rhs.R && ((T >= rhs.T && T <= rhs.B) || (rhs.T >= T && rhs.T <= B)))
930 return true;
931 return T == rhs.T && B == rhs.B && ((L >= rhs.L && L <= rhs.R) || (rhs.L >= L && rhs.L <= R));
932 }
933
940 inline IRECT FracRect(EDirection layoutDir, float frac, bool fromTopOrRight = false) const
941 {
942 if(layoutDir == EDirection::Vertical)
943 return FracRectVertical(frac, fromTopOrRight);
944 else
945 return FracRectHorizontal(frac, fromTopOrRight);
946 }
947
952 inline IRECT FracRectHorizontal(float frac, bool rhs = false) const
953 {
954 float widthOfSubRect = W() * frac;
955
956 if(rhs)
957 return IRECT(R - widthOfSubRect, T, R, B);
958 else
959 return IRECT(L, T, L + widthOfSubRect, B);
960 }
961
966 inline IRECT FracRectVertical(float frac, bool fromTop = false) const
967 {
968 float heightOfSubRect = H() * frac;
969
970 if(fromTop)
971 return IRECT(L, T, R, T + heightOfSubRect);
972 else
973 return IRECT(L, B - heightOfSubRect, R, B);
974 }
975
983 inline IRECT SubRectVertical(int numSlices, int sliceIdx) const
984 {
985 float heightOfSubRect = H() / (float) numSlices;
986 float t = heightOfSubRect * (float) sliceIdx;
987
988 return IRECT(L, T + t, R, T + t + heightOfSubRect);
989 }
990
998 inline IRECT SubRectHorizontal(int numSlices, int sliceIdx) const
999 {
1000 float widthOfSubRect = W() / (float) numSlices;
1001 float l = widthOfSubRect * (float) sliceIdx;
1002
1003 return IRECT(L + l, T, L + l + widthOfSubRect, B);
1004 }
1005
1011 inline IRECT SubRect(EDirection layoutDir, int numSlices, int sliceIdx) const
1012 {
1013 if(layoutDir == EDirection::Vertical)
1014 return SubRectVertical(numSlices, sliceIdx);
1015 else
1016 return SubRectHorizontal(numSlices, sliceIdx);
1017 }
1018
1023 inline IRECT GetFromTLHC(float w, float h) const { return IRECT(L, T, L+w, T+h); }
1024
1029 inline IRECT GetFromBLHC(float w, float h) const { return IRECT(L, B-h, L+w, B); }
1030
1035 inline IRECT GetFromTRHC(float w, float h) const { return IRECT(R-w, T, R, T+h); }
1036
1041 inline IRECT GetFromBRHC(float w, float h) const { return IRECT(R-w, B-h, R, B); }
1042
1046 inline IRECT GetFromTop(float amount) const { return IRECT(L, T, R, T+amount); }
1047
1051 inline IRECT GetFromBottom(float amount) const { return IRECT(L, B-amount, R, B); }
1052
1056 inline IRECT GetFromLeft(float amount) const { return IRECT(L, T, L+amount, B); }
1057
1061 inline IRECT GetFromRight(float amount) const { return IRECT(R-amount, T, R, B); }
1062
1066 inline IRECT GetReducedFromTop(float amount) const { return IRECT(L, T+amount, R, B); }
1067
1071 inline IRECT GetReducedFromBottom(float amount) const { return IRECT(L, T, R, B-amount); }
1072
1076 inline IRECT GetReducedFromLeft(float amount) const { return IRECT(L+amount, T, R, B); }
1077
1081 inline IRECT GetReducedFromRight(float amount) const { return IRECT(L, T, R-amount, B); }
1082
1086 inline IRECT ReduceFromTop(float amount) { IRECT r = GetFromTop(amount); T+=amount; return r; }
1087
1091 inline IRECT ReduceFromBottom(float amount) { IRECT r = GetFromBottom(amount); B-=amount; return r; }
1092
1096 inline IRECT ReduceFromLeft(float amount) { IRECT r = GetFromLeft(amount); L+=amount; return r; }
1097
1101 inline IRECT ReduceFromRight(float amount) { IRECT r = GetFromRight(amount); R-=amount; return r; }
1102
1109 inline IRECT GetGridCell(int row, int col, int nRows, int nColumns/*, EDirection = EDirection::Horizontal*/) const
1110 {
1111 assert(row * col <= nRows * nColumns); // not enough cells !
1112
1113 const IRECT vrect = SubRectVertical(nRows, row);
1114 return vrect.SubRectHorizontal(nColumns, col);
1115 }
1116
1124 inline IRECT GetGridCell(int cellIndex, int nRows, int nColumns, EDirection dir = EDirection::Horizontal, int nCells = 1) const
1125 {
1126 assert(cellIndex <= nRows * nColumns); // not enough cells !
1127
1128 int cell = 0;
1129
1130 if(dir == EDirection::Horizontal)
1131 {
1132 for(int row = 0; row < nRows; row++)
1133 {
1134 for(int col = 0; col < nColumns; col++)
1135 {
1136 if(cell == cellIndex)
1137 {
1138 const IRECT vrect = SubRectVertical(nRows, row);
1139 IRECT rect = vrect.SubRectHorizontal(nColumns, col);
1140
1141 for (int n = 1; n < nCells && (col + n) < nColumns; n++)
1142 {
1143 rect = rect.Union(vrect.SubRectHorizontal(nColumns, col + n));
1144 }
1145 return rect;
1146 }
1147
1148 cell++;
1149 }
1150 }
1151 }
1152 else
1153 {
1154 for(int col = 0; col < nColumns; col++)
1155 {
1156 for(int row = 0; row < nRows; row++)
1157 {
1158 if(cell == cellIndex)
1159 {
1160 const IRECT hrect = SubRectHorizontal(nColumns, col);
1161 IRECT rect = hrect.SubRectVertical(nRows, row);;
1162
1163 for (int n = 1; n < nCells && (row + n) < nRows; n++)
1164 {
1165 rect = rect.Union(hrect.SubRectVertical(nRows, row + n));
1166 }
1167 return rect;
1168 }
1169
1170 cell++;
1171 }
1172 }
1173 }
1174
1175 return *this;
1176 }
1177
1179 bool IsPixelAligned() const
1180 {
1181 // If all values are within 1/1000th of a pixel of an integer the IRECT is considered pixel aligned
1182
1183 auto isInteger = [](float x){ return std::fabs(x - std::round(x)) <= static_cast<float>(1e-3); };
1184
1185 return isInteger(L) && isInteger(T) && isInteger(R) && isInteger(B);
1186 }
1187
1192 bool IsPixelAligned(float scale) const
1193 {
1194 IRECT r = *this;
1195 r.Scale(scale);
1196 return r.IsPixelAligned();
1197 }
1198
1200 inline void PixelAlign()
1201 {
1202 L = std::floor(L);
1203 T = std::floor(T);
1204 R = std::ceil(R);
1205 B = std::ceil(B);
1206 }
1207
1211 inline void PixelAlign(float scale)
1212 {
1213 // N.B. - double precision is *required* for accuracy of the reciprocal
1214 Scale(scale);
1215 PixelAlign();
1216 Scale(static_cast<float>(1.0/static_cast<double>(scale)));
1217 }
1218
1221 inline IRECT GetPixelAligned() const
1222 {
1223 IRECT r = *this;
1224 r.PixelAlign();
1225 return r;
1226 }
1227
1231 inline IRECT GetPixelAligned(float scale) const
1232 {
1233 IRECT r = *this;
1234 r.PixelAlign(scale);
1235 return r;
1236 }
1237
1240 inline void PixelSnap()
1241 {
1242 L = std::round(L);
1243 T = std::round(T);
1244 R = std::round(R);
1245 B = std::round(B);
1246 }
1247
1250 inline void PixelSnap(float scale)
1251 {
1252 // N.B. - double precision is *required* for accuracy of the reciprocal
1253 Scale(scale);
1254 PixelSnap();
1255 Scale(static_cast<float>(1.0/static_cast<double>(scale)));
1256 }
1257
1259 inline IRECT GetPixelSnapped() const
1260 {
1261 IRECT r = *this;
1262 r.PixelSnap();
1263 return r;
1264 }
1265
1269 inline IRECT GetPixelSnapped(float scale) const
1270 {
1271 IRECT r = *this;
1272 r.PixelSnap(scale);
1273 return r;
1274 }
1275
1279 inline void Pad(float padding)
1280 {
1281 L -= padding;
1282 T -= padding;
1283 R += padding;
1284 B += padding;
1285 }
1286
1293 inline void Pad(float padL, float padT, float padR, float padB)
1294 {
1295 L -= padL;
1296 T -= padT;
1297 R += padR;
1298 B += padB;
1299 }
1300
1304 inline void HPad(float padding)
1305 {
1306 L -= padding;
1307 R += padding;
1308 }
1309
1313 inline void VPad(float padding)
1314 {
1315 T -= padding;
1316 B += padding;
1317 }
1318
1321 inline void MidHPad(float padding)
1322 {
1323 const float mw = MW();
1324 L = mw - padding;
1325 R = mw + padding;
1326 }
1327
1330 inline void MidVPad(float padding)
1331 {
1332 const float mh = MH();
1333 T = mh - padding;
1334 B = mh + padding;
1335 }
1336
1341 inline IRECT GetPadded(float padding) const
1342 {
1343 return IRECT(L-padding, T-padding, R+padding, B+padding);
1344 }
1345
1353 inline IRECT GetPadded(float padL, float padT, float padR, float padB) const
1354 {
1355 return IRECT(L-padL, T-padT, R+padR, B+padB);
1356 }
1357
1362 inline IRECT GetHPadded(float padding) const
1363 {
1364 return IRECT(L-padding, T, R+padding, B);
1365 }
1366
1371 inline IRECT GetVPadded(float padding) const
1372 {
1373 return IRECT(L, T-padding, R, B+padding);
1374 }
1375
1379 inline IRECT GetMidHPadded(float padding) const
1380 {
1381 return IRECT(MW()-padding, T, MW()+padding, B);
1382 }
1383
1387 inline IRECT GetMidVPadded(float padding) const
1388 {
1389 return IRECT(L, MH()-padding, R, MH()+padding);
1390 }
1391
1396 inline IRECT GetHSliced(float w, bool rhs = false) const
1397 {
1398 if(rhs)
1399 return IRECT(R - w, T, R, B);
1400 else
1401 return IRECT(L, T, L + w, B);
1402 }
1403
1408 inline IRECT GetVSliced(float h, bool bot = false) const
1409 {
1410 if(bot)
1411 return IRECT(L, B - h, R, B);
1412 else
1413 return IRECT(L, T, R, T + h);
1414 }
1415
1418 void Clank(const IRECT& rhs)
1419 {
1420 if (L < rhs.L)
1421 {
1422 R = std::min(rhs.R - 1, R + rhs.L - L);
1423 L = rhs.L;
1424 }
1425 if (T < rhs.T)
1426 {
1427 B = std::min(rhs.B - 1, B + rhs.T - T);
1428 T = rhs.T;
1429 }
1430 if (R >= rhs.R)
1431 {
1432 L = std::max(rhs.L, L - (R - rhs.R + 1));
1433 R = rhs.R - 1;
1434 }
1435 if (B >= rhs.B)
1436 {
1437 T = std::max(rhs.T, T - (B - rhs.B + 1));
1438 B = rhs.B - 1;
1439 }
1440 }
1441
1444 void Scale(float scale)
1445 {
1446 L *= scale;
1447 T *= scale;
1448 R *= scale;
1449 B *= scale;
1450 }
1451
1454 void ScaleAboutCentre(float scale)
1455 {
1456 float x = MW();
1457 float y = MH();
1458 float hw = W() / 2.f;
1459 float hh = H() / 2.f;
1460 L = x - (hw * scale);
1461 T = y - (hh * scale);
1462 R = x + (hw * scale);
1463 B = y + (hh * scale);
1464 }
1465
1469 IRECT GetScaled(float scale) const
1470 {
1471 IRECT r = *this;
1472 r.Scale(scale);
1473 return r;
1474 }
1475
1479 IRECT GetScaledAboutCentre(float scale) const
1480 {
1481 IRECT r = *this;
1482 r.ScaleAboutCentre(scale);
1483 return r;
1484 }
1485
1491 static IRECT LinearInterpolateBetween(const IRECT& start, const IRECT& dest, float progress)
1492 {
1493 IRECT result;
1494 result.L = start.L + progress * (dest.L - start.L);
1495 result.T = start.T + progress * (dest.T - start.T);
1496 result.R = start.R + progress * (dest.R - start.R);
1497 result.B = start.B + progress * (dest.B - start.B);
1498 return result;
1499 }
1500
1504 void GetRandomPoint(float& x, float& y) const
1505 {
1506 const float r1 = static_cast<float>(std::rand()/(static_cast<float>(RAND_MAX)+1.f));
1507 const float r2 = static_cast<float>(std::rand()/(static_cast<float>(RAND_MAX)+1.f));
1508
1509 x = L + r1 * W();
1510 y = T + r2 * H();
1511 }
1512
1515 {
1516 float l, t, r, b;
1517 GetRandomPoint(l, t);
1518 IRECT tmp = IRECT(l, t, R, B);
1519 tmp.GetRandomPoint(r, b);
1520
1521 return IRECT(l, t, r, b);
1522 }
1523
1529 void Offset(float l, float t, float r, float b)
1530 {
1531 L += l;
1532 T += t;
1533 R += r;
1534 B += b;
1535 }
1536
1543 IRECT GetOffset(float l, float t, float r, float b) const
1544 {
1545 return IRECT(L + l, T + t, R + r, B + b);
1546 }
1547
1551 void Translate(float x, float y)
1552 {
1553 L += x;
1554 T += y;
1555 R += x;
1556 B += y;
1557 }
1558
1563 IRECT GetTranslated(float x, float y) const
1564 {
1565 return IRECT(L + x, T + y, R + x, B + y);
1566 }
1567
1571 IRECT GetHShifted(float x) const
1572 {
1573 return GetTranslated(x, 0.f);
1574 }
1575
1579 IRECT GetVShifted(float y) const
1580 {
1581 return GetTranslated(0.f, y);
1582 }
1583
1588 {
1589 IRECT r;
1590 r.L = MW() - sr.W() / 2.f;
1591 r.T = MH() - sr.H() / 2.f;
1592 r.R = r.L + sr.W();
1593 r.B = r.T + sr.H();
1594
1595 return r;
1596 }
1597
1602 IRECT GetCentredInside(float w, float h = 0.f) const
1603 {
1604 w = std::max(w, 1.f);
1605
1606 if(h <= 0.f)
1607 h = w;
1608
1609 IRECT r;
1610 r.L = MW() - w / 2.f;
1611 r.T = MH() - h / 2.f;
1612 r.R = r.L + w;
1613 r.B = r.T + h;
1614
1615 return r;
1616 }
1617
1621 IRECT GetCentredInside(const IBitmap& bitmap) const
1622 {
1623 IRECT r;
1624 r.L = MW() - bitmap.FW() / 2.f;
1625 r.T = MH() - bitmap.FH() / 2.f;
1626 r.R = r.L + (float) bitmap.FW();
1627 r.B = r.T + (float) bitmap.FH();
1628
1629 return r;
1630 }
1631
1635 void VAlignTo(const IRECT& sr, EVAlign align)
1636 {
1637 const float height = H();
1638 switch (align)
1639 {
1640 case EVAlign::Top: T = sr.T; B = sr.T + height; break;
1641 case EVAlign::Bottom: T = sr.B - height; B = sr.B; break;
1642 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;
1643 }
1644 }
1645
1649 void HAlignTo(const IRECT& sr, EAlign align)
1650 {
1651 const float width = W();
1652 switch (align)
1653 {
1654 case EAlign::Near: L = sr.L; R = sr.L + width; break;
1655 case EAlign::Far: L = sr.R - width; R = sr.R; break;
1656 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;
1657 }
1658 }
1659
1664 IRECT GetVAlignedTo(const IRECT& sr, EVAlign align) const
1665 {
1666 IRECT result = *this;
1667 result.VAlignTo(sr, align);
1668 return result;
1669 }
1670
1673 {
1674 if(W() < H())
1675 return W();
1676 else
1677 return H();
1678 }
1679
1684 IRECT GetHAlignedTo(const IRECT& sr, EAlign align) const
1685 {
1686 IRECT result = *this;
1687 result.HAlignTo(sr, align);
1688 return result;
1689 }
1690
1692 void DBGPrint() { DBGMSG("L: %f, T: %f, R: %f, B: %f,: W: %f, H: %f\n", L, T, R, B, W(), H()); }
1693};
1694
1697{
1698 bool L, R, S, C, A;
1699 ITouchID touchID = 0;
1700 float touchRadius = 0.f;
1701
1709 IMouseMod(bool l = false, bool r = false, bool s = false, bool c = false, bool a = false, ITouchID touchID = 0)
1710 : L(l), R(r), S(s), C(c), A(a), touchID(touchID)
1711 {}
1712
1714 bool IsTouch() const { return touchID > 0; }
1715
1717 void DBGPrint() { DBGMSG("L: %i, R: %i, S: %i, C: %i,: A: %i\n", L, R, S, C, A); }
1718};
1719
1722{
1723 float x = 0.0, y = 0.0;
1724 float dX = 0.0, dY = 0.0;
1725 IMouseMod ms;
1726};
1727
1730{
1731 float x = 0.f;
1732 float y = 0.f;
1733 float scale = 0.f; // pinch,
1734 float velocity = 0.f; // pinch, rotate
1735 float angle = 0.f; // rotate,
1736 EGestureState state = EGestureState::Unknown;
1737 EGestureType type = EGestureType::Unknown;
1738};
1739
1742{
1743public:
1744 IRECTList()
1745 {}
1746
1747 IRECTList(const IRECTList&) = delete;
1748 IRECTList& operator=(const IRECTList&) = delete;
1749
1751 int Size() const { return mRects.GetSize(); }
1752
1755 void Add(const IRECT& rect)
1756 {
1757 mRects.Add(rect);
1758 }
1759
1763 void Set(int idx, const IRECT& rect)
1764 {
1765 *(mRects.GetFast() + idx) = rect;
1766 }
1767
1771 const IRECT& Get(int idx) const
1772 {
1773 return *(mRects.GetFast() + idx);
1774 }
1775
1777 void Clear()
1778 {
1779 mRects.Resize(0);
1780 }
1781
1785 {
1786 IRECT r = Get(0);
1787 for (auto i = 1; i < mRects.GetSize(); i++)
1788 r = r.Union(Get(i));
1789 return r;
1790 }
1791
1794 {
1795 for (auto i = 0; i < Size(); i++)
1796 {
1797 IRECT r = Get(i);
1798 r.PixelAlign();
1799 Set(i, r);
1800 }
1801 }
1802
1805 void PixelAlign(float scale)
1806 {
1807 for (auto i = 0; i < Size(); i++)
1808 {
1809 IRECT r = Get(i);
1810 r.PixelAlign(scale);
1811 Set(i, r);
1812 }
1813 }
1814
1819 int Find(float x, float y) const
1820 {
1821 for (auto i = 0; i < Size(); i++)
1822 {
1823 if(Get(i).Contains(x, y))
1824 return i;
1825 }
1826
1827 return -1;
1828 }
1829
1837 static bool GetFracGrid(const IRECT& input, IRECTList& rects, const std::initializer_list<float>& rowFractions, const std::initializer_list<float>& colFractions, EDirection layoutDir = EDirection::Horizontal)
1838 {
1839 IRECT spaceLeft = input;
1840 float y = 0.;
1841 float x = 0.;
1842
1843 if(std::accumulate(rowFractions.begin(), rowFractions.end(), 0.f) != 1.)
1844 return false;
1845
1846 if(std::accumulate(colFractions.begin(), colFractions.end(), 0.f) != 1.)
1847 return false;
1848
1849 if (layoutDir == EDirection::Horizontal)
1850 {
1851 for (auto& rowFrac : rowFractions)
1852 {
1853 IRECT thisRow = input.FracRectVertical(rowFrac, true).GetTranslated(0, y);
1854
1855 x = 0.;
1856
1857 for (auto& colFrac : colFractions)
1858 {
1859 IRECT thisCell = thisRow.FracRectHorizontal(colFrac).GetTranslated(x, 0);
1860
1861 rects.Add(thisCell);
1862
1863 x += thisCell.W();
1864 }
1865
1866 spaceLeft.Intersect(thisRow);
1867
1868 y = rects.Bounds().H();
1869 }
1870 }
1871
1872 if (layoutDir == EDirection::Vertical)
1873 {
1874 for (auto& colFrac : colFractions)
1875 {
1876 IRECT thisCol = input.FracRectHorizontal(colFrac).GetTranslated(x, 0);
1877
1878 y = 0.;
1879
1880 for (auto& rowFrac : rowFractions)
1881 {
1882 IRECT thisCell = thisCol.FracRectVertical(rowFrac, true).GetTranslated(0, y);
1883
1884 rects.Add(thisCell);
1885
1886 y += thisCell.H();
1887 }
1888
1889 spaceLeft.Intersect(thisCol);
1890
1891 x = rects.Bounds().W();
1892 }
1893 }
1894
1895 return true;
1896 }
1897
1900 {
1901 for (int i = 0; i < Size(); i++)
1902 {
1903 for (int j = i + 1; j < Size(); j++)
1904 {
1905 if (Get(i).Contains(Get(j)))
1906 {
1907 mRects.Delete(j);
1908 j--;
1909 }
1910 else if (Get(j).Contains(Get(i)))
1911 {
1912 mRects.Delete(i);
1913 i--;
1914 break;
1915 }
1916 else if (Get(i).Intersects(Get(j)))
1917 {
1918 IRECT intersection = Get(i).Intersect(Get(j));
1919
1920 if (Get(i).Mergeable(intersection))
1921 Set(i, Shrink(Get(i), intersection));
1922 else if (Get(j).Mergeable(intersection))
1923 Set(j, Shrink(Get(j), intersection));
1924 else if (Get(i).Area() < Get(j).Area())
1925 Set(i, Split(Get(i), intersection));
1926 else
1927 Set(j, Split(Get(j), intersection));
1928 }
1929 }
1930 }
1931
1932 for (int i = 0; i < Size(); i++)
1933 {
1934 for (int j = i + 1; j < Size(); j++)
1935 {
1936 if (Get(i).Mergeable(Get(j)))
1937 {
1938 Set(j, Get(i).Union(Get(j)));
1939 mRects.Delete(i);
1940 i = -1;
1941 break;
1942 }
1943 }
1944 }
1945 }
1946
1947private:
1952 IRECT Shrink(const IRECT &r, const IRECT &i)
1953 {
1954 if (i.L != r.L)
1955 return IRECT(r.L, r.T, i.L, r.B);
1956 if (i.T != r.T)
1957 return IRECT(r.L, r.T, r.R, i.T);
1958 if (i.R != r.R)
1959 return IRECT(i.R, r.T, r.R, r.B);
1960 return IRECT(r.L, i.B, r.R, r.B);
1961 }
1962
1967 IRECT Split(const IRECT r, const IRECT &i)
1968 {
1969 if (r.L == i.L)
1970 {
1971 if (r.T == i.T)
1972 {
1973 Add(IRECT(i.R, r.T, r.R, i.B));
1974 return IRECT(r.L, i.B, r.R, r.B);
1975 }
1976 else
1977 {
1978 Add(IRECT(r.L, r.T, r.R, i.T));
1979 return IRECT(i.R, i.T, r.R, r.B);
1980 }
1981 }
1982
1983 if (r.T == i.T)
1984 {
1985 Add(IRECT(r.L, r.T, i.L, i.B));
1986 return IRECT(r.L, i.B, r.R, r.B);
1987 }
1988 else
1989 {
1990 Add(IRECT(r.L, r.T, r.R, i.T));
1991 return IRECT(r.L, i.T, i.L, r.B);
1992 }
1993 }
1994
1995 WDL_TypedBuf<IRECT> mRects;
1996};
1997
2000{
2008 IMatrix(double xx, double yx, double xy, double yy, double tx, double ty)
2009 : mXX(xx), mYX(yx), mXY(xy), mYY(yy), mTX(tx), mTY(ty)
2010 {}
2011
2013 IMatrix() : IMatrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0)
2014 {}
2015
2020 IMatrix& Translate(float x, float y)
2021 {
2022 return Transform(IMatrix(1.0, 0.0, 0.0, 1.0, x, y));
2023 }
2024
2029 IMatrix& Scale(float x, float y)
2030 {
2031 return Transform(IMatrix(x, 0.0, 0.0, y, 0.0, 0.0));
2032 }
2033
2037 IMatrix& Rotate(float a)
2038 {
2039 const double rad = DegToRad(a);
2040 const double c = std::cos(rad);
2041 const double s = std::sin(rad);
2042
2043 return Transform(IMatrix(c, s, -s, c, 0.0, 0.0));
2044 }
2045
2050 IMatrix& Skew(float xa, float ya)
2051 {
2052 return Transform(IMatrix(1.0, std::tan(DegToRad(ya)), std::tan(DegToRad(xa)), 1.0, 0.0, 0.0));
2053 }
2054
2060 void TransformPoint(double& x, double& y, double x0, double y0) const
2061 {
2062 x = x0 * mXX + y0 * mXY + mTX;
2063 y = x0 * mYX + y0 * mYY + mTY;
2064 };
2065
2069 void TransformPoint(double& x, double& y) const
2070 {
2071 TransformPoint(x, y, x, y);
2072 };
2073
2078 IMatrix& Transform(const IRECT& before, const IRECT& after)
2079 {
2080 const double sx = after.W() / before.W();
2081 const double sy = after.H() / before.H();
2082 const double tx = after.L - before.L * sx;
2083 const double ty = after.T - before.T * sy;
2084
2085 return *this = IMatrix(sx, 0.0, 0.0, sy, tx, ty);
2086 }
2087
2092 {
2093 IMatrix p = *this;
2094
2095 mXX = m.mXX * p.mXX + m.mYX * p.mXY;
2096 mYX = m.mXX * p.mYX + m.mYX * p.mYY;
2097 mXY = m.mXY * p.mXX + m.mYY * p.mXY;
2098 mYY = m.mXY * p.mYX + m.mYY * p.mYY;
2099 mTX = m.mTX * p.mXX + m.mTY * p.mXY + p.mTX;
2100 mTY = m.mTX * p.mYX + m.mTY * p.mYY + p.mTY;
2101
2102 return *this;
2103 }
2104
2108 {
2109 IMatrix m = *this;
2110
2111 double d = 1.0 / (m.mXX * m.mYY - m.mYX * m.mXY);
2112
2113 mXX = m.mYY * d;
2114 mYX = -m.mYX * d;
2115 mXY = -m.mXY * d;
2116 mYY = m.mXX * d;
2117 mTX = (-(m.mTX * mXX) - (m.mTY * mXY));
2118 mTY = (-(m.mTX * mYX) - (m.mTY * mYY));
2119
2120 return *this;
2121 }
2122
2123 double mXX, mYX, mXY, mYY, mTX, mTY;
2124};
2125
2128{
2129 IColorStop()
2130 : mOffset(0.f)
2131 {}
2132
2136 IColorStop(IColor color, float offset)
2137 : mColor(color)
2138 , mOffset(offset)
2139 {
2140 assert(offset >= 0.0 && offset <= 1.0);
2141 }
2142
2143 IColor mColor;
2144 float mOffset;
2145};
2146
2149{
2150 EPatternType mType;
2151 EPatternExtend mExtend;
2152 IColorStop mStops[16];
2153 int mNStops;
2154 IMatrix mTransform;
2155
2158 IPattern(EPatternType type)
2159 : mType(type), mExtend(EPatternExtend::Pad), mNStops(0)
2160 {}
2161
2164 IPattern(const IColor& color)
2165 : mType(EPatternType::Solid), mExtend(EPatternExtend::Pad), mNStops(1)
2166 {
2167 mStops[0] = IColorStop(color, 0.0);
2168 }
2169
2177 static IPattern CreateLinearGradient(float x1, float y1, float x2, float y2, const std::initializer_list<IColorStop>& stops = {})
2178 {
2179 IPattern pattern(EPatternType::Linear);
2180
2181 // Calculate the affine transform from one line segment to another!
2182 const double xd = double(x2 - x1);
2183 const double yd = double(y2 - y1);
2184 const double d = sqrt(xd * xd + yd * yd);
2185 const double a = atan2(xd, yd);
2186 const double s = std::sin(a) / d;
2187 const double c = std::cos(a) / d;
2188
2189 const double x0 = -(x1 * c - y1 * s);
2190 const double y0 = -(x1 * s + y1 * c);
2191
2192 pattern.SetTransform(static_cast<float>(c),
2193 static_cast<float>(s),
2194 static_cast<float>(-s),
2195 static_cast<float>(c),
2196 static_cast<float>(x0),
2197 static_cast<float>(y0));
2198
2199 for (auto& stop : stops)
2200 pattern.AddStop(stop.mColor, stop.mOffset);
2201
2202 return pattern;
2203 }
2204
2210 static IPattern CreateLinearGradient(const IRECT& bounds, EDirection direction, const std::initializer_list<IColorStop>& stops = {})
2211 {
2212 float x1, y1, x2, y2;
2213
2214 if(direction == EDirection::Horizontal)
2215 {
2216 y1 = bounds.MH(); y2 = y1;
2217 x1 = bounds.L;
2218 x2 = bounds.R;
2219 }
2220 else//(direction == EDirection::Vertical)
2221 {
2222 x1 = bounds.MW(); x2 = x1;
2223 y1 = bounds.T;
2224 y2 = bounds.B;
2225 }
2226
2227 return CreateLinearGradient(x1, y1, x2, y2, stops);
2228 }
2229
2236 static IPattern CreateRadialGradient(float x1, float y1, float r, const std::initializer_list<IColorStop>& stops = {})
2237 {
2238 IPattern pattern(EPatternType::Radial);
2239
2240 const float s = 1.f / r;
2241
2242 pattern.SetTransform(s, 0, 0, s, -(x1 * s), -(y1 * s));
2243
2244 for (auto& stop : stops)
2245 pattern.AddStop(stop.mColor, stop.mOffset);
2246
2247 return pattern;
2248 }
2249
2257 static IPattern CreateSweepGradient(float x1, float y1, const std::initializer_list<IColorStop>& stops = {},
2258 float angleStart = 0.f, float angleEnd = 360.f)
2259 {
2260 IPattern pattern(EPatternType::Sweep);
2261
2262 #ifdef IGRAPHICS_SKIA
2263 angleStart -= 90;
2264 angleEnd -= 90;
2265 #endif
2266
2267 float rad = DegToRad(angleStart);
2268 float c = std::cos(rad);
2269 float s = std::sin(rad);
2270
2271 pattern.SetTransform(c, s, -s, c, -x1, -y1);
2272
2273 for (auto& stop : stops)
2274 {
2275 pattern.AddStop(stop.mColor, stop.mOffset * (angleEnd - angleStart) / 360.f);
2276 }
2277 return pattern;
2278 }
2279
2281 int NStops() const
2282 {
2283 return mNStops;
2284 }
2285
2289 const IColorStop& GetStop(int idx) const
2290 {
2291 return mStops[idx];
2292 }
2293
2297 void AddStop(IColor color, float offset)
2298 {
2299 assert(mType != EPatternType::Solid && mNStops < 16);
2300 assert(!mNStops || GetStop(mNStops - 1).mOffset < offset);
2301 if (mNStops < 16)
2302 mStops[mNStops++] = IColorStop(color, offset);
2303 }
2304
2312 void SetTransform(float xx, float yx, float xy, float yy, float tx, float ty)
2313 {
2314 mTransform = IMatrix(xx, yx, xy, yy, tx, ty);
2315 }
2316
2319 void SetTransform(const IMatrix& transform)
2320 {
2321 mTransform = transform;
2322 }
2323};
2324
2330{
2331 friend IGraphics;
2332
2333public:
2339 ILayer(APIBitmap* pBitmap, const IRECT& layerRect, IControl* pControl, const IRECT& controlRect)
2340 : mBitmap(pBitmap)
2341 , mControl(pControl)
2342 , mControlRECT(controlRect)
2343 , mRECT(layerRect)
2344 , mInvalid(false)
2345 {}
2346
2347 ILayer(const ILayer&) = delete;
2348 ILayer operator=(const ILayer&) = delete;
2349
2351 void Invalidate() { mInvalid = true; }
2352
2354 const APIBitmap* GetAPIBitmap() const { return mBitmap.get(); }
2355
2357 IBitmap GetBitmap() const { return IBitmap(mBitmap.get(), 1, false); }
2358
2360 const IRECT& Bounds() const { return mRECT; }
2361
2362private:
2363 std::unique_ptr<APIBitmap> mBitmap;
2364 IControl* mControl;
2365 IRECT mControlRECT;
2366 IRECT mRECT;
2367 bool mInvalid;
2368};
2369
2371using ILayerPtr = std::unique_ptr<ILayer>;
2372
2375{
2376 IShadow() {}
2377
2385 IShadow(const IPattern& pattern, float blurSize, float xOffset, float yOffset, float opacity, bool drawForeground = true)
2386 : mPattern(pattern)
2387 , mBlurSize(blurSize)
2388 , mXOffset(xOffset)
2389 , mYOffset(yOffset)
2390 , mOpacity(opacity)
2391 , mDrawForeground(drawForeground)
2392 {}
2393
2394 IPattern mPattern = COLOR_BLACK;
2395 float mBlurSize = 0.f;
2396 float mXOffset = 0.f;
2397 float mYOffset = 0.f;
2398 float mOpacity = 1.f;
2399 bool mDrawForeground = true;
2400};
2401
2404{
2405 IColor mColors[kNumVColors];
2406
2408 const IColor& GetColor(EVColor color) const
2409 {
2410 return mColors[(int) color];
2411 }
2412
2414 static const IColor& GetDefaultColor(EVColor idx)
2415 {
2416 switch(idx)
2417 {
2418 case kBG: return DEFAULT_BGCOLOR; // Background
2419 case kFG: return DEFAULT_FGCOLOR; // OFF/Foreground
2420 case kPR: return DEFAULT_PRCOLOR; // ON/Pressed
2421 case kFR: return DEFAULT_FRCOLOR; // Frame
2422 case kHL: return DEFAULT_HLCOLOR; // Highlight
2423 case kSH: return DEFAULT_SHCOLOR; // Shadow
2424 case kX1: return DEFAULT_X1COLOR; // Extra 1
2425 case kX2: return DEFAULT_X2COLOR; // Extra 2
2426 case kX3: return DEFAULT_X3COLOR; // Extra 3
2427 default:
2428 return COLOR_TRANSPARENT;
2429 };
2430 }
2431
2434 {
2435 ResetColors();
2436 }
2437
2440 IVColorSpec(const std::initializer_list<IColor>& colors)
2441 {
2442 assert(colors.size() <= kNumVColors);
2443
2444 int i = 0;
2445
2446 for(auto& c : colors)
2447 {
2448 mColors[i++] = c;
2449 }
2450
2451 for(; i<kNumVColors; i++)
2452 {
2453 mColors[i] = GetDefaultColor((EVColor) i);
2454 }
2455 }
2456
2459 {
2460 for (int i=0; i<kNumVColors; i++)
2461 {
2462 mColors[i] = GetDefaultColor((EVColor) i);
2463 }
2464 }
2465};
2466
2467const IVColorSpec DEFAULT_COLOR_SPEC = IVColorSpec();
2468
2469static constexpr bool DEFAULT_HIDE_CURSOR = true;
2470static constexpr bool DEFAULT_SHOW_VALUE = true;
2471static constexpr bool DEFAULT_SHOW_LABEL = true;
2472static constexpr bool DEFAULT_DRAW_FRAME = true;
2473static constexpr bool DEFAULT_DRAW_SHADOWS = true;
2474static constexpr bool DEFAULT_EMBOSS = false;
2475static constexpr float DEFAULT_ROUNDNESS = 0.f;
2476static constexpr float DEFAULT_FRAME_THICKNESS = 1.f;
2477static constexpr float DEFAULT_SHADOW_OFFSET = 3.f;
2478static constexpr float DEFAULT_WIDGET_FRAC = 1.f;
2479static constexpr float DEFAULT_WIDGET_ANGLE = 0.f;
2480static constexpr EOrientation DEFAULT_LABEL_ORIENTATION = EOrientation::North;
2481const IText DEFAULT_LABEL_TEXT {DEFAULT_TEXT_SIZE + 5.f, EVAlign::Top};
2482const IText DEFAULT_VALUE_TEXT {DEFAULT_TEXT_SIZE, EVAlign::Bottom};
2483
2486{
2487 bool hideCursor = DEFAULT_HIDE_CURSOR;
2488 bool showLabel = DEFAULT_SHOW_LABEL;
2489 bool showValue = DEFAULT_SHOW_VALUE;
2490 bool drawFrame = DEFAULT_DRAW_FRAME;
2491 bool drawShadows = DEFAULT_DRAW_SHADOWS;
2492 bool emboss = DEFAULT_EMBOSS;
2493 float roundness = DEFAULT_ROUNDNESS;
2494 float frameThickness = DEFAULT_FRAME_THICKNESS;
2495 float shadowOffset = DEFAULT_SHADOW_OFFSET;
2496 float widgetFrac = DEFAULT_WIDGET_FRAC;
2497 float angle = DEFAULT_WIDGET_ANGLE;
2498 IVColorSpec colorSpec = DEFAULT_COLOR_SPEC;
2499 IText labelText = DEFAULT_LABEL_TEXT;
2500 IText valueText = DEFAULT_VALUE_TEXT;
2501 EOrientation labelOrientation = DEFAULT_LABEL_ORIENTATION;
2502
2518 IVStyle(bool showLabel = DEFAULT_SHOW_LABEL,
2519 bool showValue = DEFAULT_SHOW_VALUE,
2520 const IVColorSpec& colors = {DEFAULT_BGCOLOR, DEFAULT_FGCOLOR, DEFAULT_PRCOLOR, DEFAULT_FRCOLOR, DEFAULT_HLCOLOR, DEFAULT_SHCOLOR, DEFAULT_X1COLOR, DEFAULT_X2COLOR, DEFAULT_X3COLOR},
2521 const IText& labelText = DEFAULT_LABEL_TEXT,
2522 const IText& valueText = DEFAULT_VALUE_TEXT,
2523 bool hideCursor = DEFAULT_HIDE_CURSOR,
2524 bool drawFrame = DEFAULT_DRAW_FRAME,
2525 bool drawShadows = DEFAULT_DRAW_SHADOWS,
2526 bool emboss = DEFAULT_EMBOSS,
2527 float roundness = DEFAULT_ROUNDNESS,
2528 float frameThickness = DEFAULT_FRAME_THICKNESS,
2529 float shadowOffset = DEFAULT_SHADOW_OFFSET,
2530 float widgetFrac = DEFAULT_WIDGET_FRAC,
2531 float angle = DEFAULT_WIDGET_ANGLE,
2532 EOrientation labelOrientation = DEFAULT_LABEL_ORIENTATION)
2533 : hideCursor(hideCursor)
2534 , showLabel(showLabel)
2535 , showValue(showValue)
2536 , drawFrame(drawFrame)
2537 , drawShadows(drawShadows)
2538 , emboss(emboss)
2539 , roundness(roundness)
2540 , frameThickness(frameThickness)
2541 , shadowOffset(shadowOffset)
2542 , widgetFrac(widgetFrac)
2543 , angle(angle)
2544 , colorSpec(colors)
2545 , labelText(labelText)
2546 , valueText(valueText)
2547 {
2548 }
2549
2552 IVStyle(const std::initializer_list<IColor>& colors)
2553 : colorSpec(colors)
2554 {
2555 }
2556
2557 IVStyle WithShowLabel(bool show = true) const { IVStyle newStyle = *this; newStyle.showLabel = show; return newStyle; }
2558 IVStyle WithShowValue(bool show = true) const { IVStyle newStyle = *this; newStyle.showValue = show; return newStyle; }
2559 IVStyle WithLabelText(const IText& text) const { IVStyle newStyle = *this; newStyle.labelText = text; return newStyle;}
2560 IVStyle WithValueText(const IText& text) const { IVStyle newStyle = *this; newStyle.valueText = text; return newStyle; }
2561 IVStyle WithHideCursor(bool hide = true) const { IVStyle newStyle = *this; newStyle.hideCursor = hide; return newStyle; }
2562 IVStyle WithColor(EVColor idx, IColor color) const { IVStyle newStyle = *this; newStyle.colorSpec.mColors[idx] = color; return newStyle; }
2563 IVStyle WithColors(const IVColorSpec& spec) const { IVStyle newStyle = *this; newStyle.colorSpec = spec; return newStyle; }
2564 IVStyle WithRoundness(float v) const { IVStyle newStyle = *this; newStyle.roundness = Clip(v, 0.f, 1.f); return newStyle; }
2565 IVStyle WithFrameThickness(float v) const { IVStyle newStyle = *this; newStyle.frameThickness = v; return newStyle; }
2566 IVStyle WithShadowOffset(float v) const { IVStyle newStyle = *this; newStyle.shadowOffset = v; return newStyle; }
2567 IVStyle WithDrawShadows(bool v = true) const { IVStyle newStyle = *this; newStyle.drawShadows = v; return newStyle; }
2568 IVStyle WithDrawFrame(bool v = true) const { IVStyle newStyle = *this; newStyle.drawFrame = v; return newStyle; }
2569 IVStyle WithWidgetFrac(float v) const { IVStyle newStyle = *this; newStyle.widgetFrac = Clip(v, 0.f, 1.f); return newStyle; }
2570 IVStyle WithAngle(float v) const { IVStyle newStyle = *this; newStyle.angle = Clip(v, 0.f, 360.f); return newStyle; }
2571 IVStyle WithEmboss(bool v = true) const { IVStyle newStyle = *this; newStyle.emboss = v; return newStyle; }
2572 IVStyle WithLabelOrientation(EOrientation v) const { IVStyle newStyle = *this; newStyle.labelOrientation = v; return newStyle; }
2573};
2574
2575const IVStyle DEFAULT_STYLE = IVStyle();
2576
2577END_IGRAPHICS_NAMESPACE
2578END_IPLUG_NAMESPACE
2579
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
Gets the lightness of the color (HSL lightness component)
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:615
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)
Sets up a transformation matrix to map one rectangle to another.
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 a point using this matrix.
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.