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
791 bool Empty() const
792 {
793 return (L == 0.f && T == 0.f && R == 0.f && B == 0.f);
794 }
795
797 void Clear()
798 {
799 L = T = R = B = 0.f;
800 }
801
802 bool operator==(const IRECT& rhs) const
803 {
804 return (L == rhs.L && T == rhs.T && R == rhs.R && B == rhs.B);
805 }
806
807 bool operator!=(const IRECT& rhs) const
808 {
809 return !(*this == rhs);
810 }
811
813 inline float W() const { return R - L; }
814
816 inline float H() const { return B - T; }
817
819 inline float MW() const { return 0.5f * (L + R); }
820
822 inline float MH() const { return 0.5f * (T + B); }
823
825 inline float Area() const { return W() * H(); }
826
831 inline IRECT Union(const IRECT& rhs) const
832 {
833 if (Empty()) { return rhs; }
834 if (rhs.Empty()) { return *this; }
835 return IRECT(std::min(L, rhs.L), std::min(T, rhs.T), std::max(R, rhs.R), std::max(B, rhs.B));
836 }
837
842 inline IRECT Intersect(const IRECT& rhs) const
843 {
844 if (Intersects(rhs))
845 return IRECT(std::max(L, rhs.L), std::max(T, rhs.T), std::min(R, rhs.R), std::min(B, rhs.B));
846
847 return IRECT();
848 }
849
854 inline bool Intersects(const IRECT& rhs) const
855 {
856 return (!Empty() && !rhs.Empty() && R >= rhs.L && L < rhs.R && B >= rhs.T && T < rhs.B);
857 }
858
863 inline bool Contains(const IRECT& rhs) const
864 {
865 return (!Empty() && !rhs.Empty() && rhs.L >= L && rhs.R <= R && rhs.T >= T && rhs.B <= B);
866 }
867
873 inline bool Contains(float x, float y) const
874 {
875 return (!Empty() && x >= L && x < R && y >= T && y < B);
876 }
877
884 inline bool ContainsEdge(float x, float y) const
885 {
886 return (!Empty() && x >= L && x <= R && y >= T && y <= B);
887 }
888
892 inline void Constrain(float& x, float& y) const
893 {
894 if (x < L) x = L;
895 else if (x > R) x = R;
896
897 if (y < T) y = T;
898 else if (y > B) y = B;
899 }
900
903 IRECT Inset(const IRECT& rhs) const
904 {
905 return IRECT(L + rhs.L, T + rhs.T, L + rhs.R, T + rhs.B);
906 }
907
913 bool Mergeable(const IRECT& rhs) const
914 {
915 if (Empty() || rhs.Empty())
916 return true;
917 if (L == rhs.L && R == rhs.R && ((T >= rhs.T && T <= rhs.B) || (rhs.T >= T && rhs.T <= B)))
918 return true;
919 return T == rhs.T && B == rhs.B && ((L >= rhs.L && L <= rhs.R) || (rhs.L >= L && rhs.L <= R));
920 }
921
928 inline IRECT FracRect(EDirection layoutDir, float frac, bool fromTopOrRight = false) const
929 {
930 if(layoutDir == EDirection::Vertical)
931 return FracRectVertical(frac, fromTopOrRight);
932 else
933 return FracRectHorizontal(frac, fromTopOrRight);
934 }
935
940 inline IRECT FracRectHorizontal(float frac, bool rhs = false) const
941 {
942 float widthOfSubRect = W() * frac;
943
944 if(rhs)
945 return IRECT(R - widthOfSubRect, T, R, B);
946 else
947 return IRECT(L, T, L + widthOfSubRect, B);
948 }
949
954 inline IRECT FracRectVertical(float frac, bool fromTop = false) const
955 {
956 float heightOfSubRect = H() * frac;
957
958 if(fromTop)
959 return IRECT(L, T, R, T + heightOfSubRect);
960 else
961 return IRECT(L, B - heightOfSubRect, R, B);
962 }
963
971 inline IRECT SubRectVertical(int numSlices, int sliceIdx) const
972 {
973 float heightOfSubRect = H() / (float) numSlices;
974 float t = heightOfSubRect * (float) sliceIdx;
975
976 return IRECT(L, T + t, R, T + t + heightOfSubRect);
977 }
978
986 inline IRECT SubRectHorizontal(int numSlices, int sliceIdx) const
987 {
988 float widthOfSubRect = W() / (float) numSlices;
989 float l = widthOfSubRect * (float) sliceIdx;
990
991 return IRECT(L + l, T, L + l + widthOfSubRect, B);
992 }
993
999 inline IRECT SubRect(EDirection layoutDir, int numSlices, int sliceIdx) const
1000 {
1001 if(layoutDir == EDirection::Vertical)
1002 return SubRectVertical(numSlices, sliceIdx);
1003 else
1004 return SubRectHorizontal(numSlices, sliceIdx);
1005 }
1006
1011 inline IRECT GetFromTLHC(float w, float h) const { return IRECT(L, T, L+w, T+h); }
1012
1017 inline IRECT GetFromBLHC(float w, float h) const { return IRECT(L, B-h, L+w, B); }
1018
1023 inline IRECT GetFromTRHC(float w, float h) const { return IRECT(R-w, T, R, T+h); }
1024
1029 inline IRECT GetFromBRHC(float w, float h) const { return IRECT(R-w, B-h, R, B); }
1030
1034 inline IRECT GetFromTop(float amount) const { return IRECT(L, T, R, T+amount); }
1035
1039 inline IRECT GetFromBottom(float amount) const { return IRECT(L, B-amount, R, B); }
1040
1044 inline IRECT GetFromLeft(float amount) const { return IRECT(L, T, L+amount, B); }
1045
1049 inline IRECT GetFromRight(float amount) const { return IRECT(R-amount, T, R, B); }
1050
1054 inline IRECT GetReducedFromTop(float amount) const { return IRECT(L, T+amount, R, B); }
1055
1059 inline IRECT GetReducedFromBottom(float amount) const { return IRECT(L, T, R, B-amount); }
1060
1064 inline IRECT GetReducedFromLeft(float amount) const { return IRECT(L+amount, T, R, B); }
1065
1069 inline IRECT GetReducedFromRight(float amount) const { return IRECT(L, T, R-amount, B); }
1070
1074 inline IRECT ReduceFromTop(float amount) { IRECT r = GetFromTop(amount); T+=amount; return r; }
1075
1079 inline IRECT ReduceFromBottom(float amount) { IRECT r = GetFromBottom(amount); B-=amount; return r; }
1080
1084 inline IRECT ReduceFromLeft(float amount) { IRECT r = GetFromLeft(amount); L+=amount; return r; }
1085
1089 inline IRECT ReduceFromRight(float amount) { IRECT r = GetFromRight(amount); R-=amount; return r; }
1090
1097 inline IRECT GetGridCell(int row, int col, int nRows, int nColumns/*, EDirection = EDirection::Horizontal*/) const
1098 {
1099 assert(row * col <= nRows * nColumns); // not enough cells !
1100
1101 const IRECT vrect = SubRectVertical(nRows, row);
1102 return vrect.SubRectHorizontal(nColumns, col);
1103 }
1104
1112 inline IRECT GetGridCell(int cellIndex, int nRows, int nColumns, EDirection dir = EDirection::Horizontal, int nCells = 1) const
1113 {
1114 assert(cellIndex <= nRows * nColumns); // not enough cells !
1115
1116 int cell = 0;
1117
1118 if(dir == EDirection::Horizontal)
1119 {
1120 for(int row = 0; row < nRows; row++)
1121 {
1122 for(int col = 0; col < nColumns; col++)
1123 {
1124 if(cell == cellIndex)
1125 {
1126 const IRECT vrect = SubRectVertical(nRows, row);
1127 IRECT rect = vrect.SubRectHorizontal(nColumns, col);
1128
1129 for (int n = 1; n < nCells && (col + n) < nColumns; n++)
1130 {
1131 rect = rect.Union(vrect.SubRectHorizontal(nColumns, col + n));
1132 }
1133 return rect;
1134 }
1135
1136 cell++;
1137 }
1138 }
1139 }
1140 else
1141 {
1142 for(int col = 0; col < nColumns; col++)
1143 {
1144 for(int row = 0; row < nRows; row++)
1145 {
1146 if(cell == cellIndex)
1147 {
1148 const IRECT hrect = SubRectHorizontal(nColumns, col);
1149 IRECT rect = hrect.SubRectVertical(nRows, row);;
1150
1151 for (int n = 1; n < nCells && (row + n) < nRows; n++)
1152 {
1153 rect = rect.Union(hrect.SubRectVertical(nRows, row + n));
1154 }
1155 return rect;
1156 }
1157
1158 cell++;
1159 }
1160 }
1161 }
1162
1163 return *this;
1164 }
1165
1167 bool IsPixelAligned() const
1168 {
1169 // If all values are within 1/1000th of a pixel of an integer the IRECT is considered pixel aligned
1170
1171 auto isInteger = [](float x){ return std::fabs(x - std::round(x)) <= static_cast<float>(1e-3); };
1172
1173 return isInteger(L) && isInteger(T) && isInteger(R) && isInteger(B);
1174 }
1175
1180 bool IsPixelAligned(float scale) const
1181 {
1182 IRECT r = *this;
1183 r.Scale(scale);
1184 return r.IsPixelAligned();
1185 }
1186
1188 inline void PixelAlign()
1189 {
1190 L = std::floor(L);
1191 T = std::floor(T);
1192 R = std::ceil(R);
1193 B = std::ceil(B);
1194 }
1195
1199 inline void PixelAlign(float scale)
1200 {
1201 // N.B. - double precision is *required* for accuracy of the reciprocal
1202 Scale(scale);
1203 PixelAlign();
1204 Scale(static_cast<float>(1.0/static_cast<double>(scale)));
1205 }
1206
1209 inline IRECT GetPixelAligned() const
1210 {
1211 IRECT r = *this;
1212 r.PixelAlign();
1213 return r;
1214 }
1215
1219 inline IRECT GetPixelAligned(float scale) const
1220 {
1221 IRECT r = *this;
1222 r.PixelAlign(scale);
1223 return r;
1224 }
1225
1228 inline void PixelSnap()
1229 {
1230 L = std::round(L);
1231 T = std::round(T);
1232 R = std::round(R);
1233 B = std::round(B);
1234 }
1235
1238 inline void PixelSnap(float scale)
1239 {
1240 // N.B. - double precision is *required* for accuracy of the reciprocal
1241 Scale(scale);
1242 PixelSnap();
1243 Scale(static_cast<float>(1.0/static_cast<double>(scale)));
1244 }
1245
1247 inline IRECT GetPixelSnapped() const
1248 {
1249 IRECT r = *this;
1250 r.PixelSnap();
1251 return r;
1252 }
1253
1257 inline IRECT GetPixelSnapped(float scale) const
1258 {
1259 IRECT r = *this;
1260 r.PixelSnap(scale);
1261 return r;
1262 }
1263
1267 inline void Pad(float padding)
1268 {
1269 L -= padding;
1270 T -= padding;
1271 R += padding;
1272 B += padding;
1273 }
1274
1281 inline void Pad(float padL, float padT, float padR, float padB)
1282 {
1283 L -= padL;
1284 T -= padT;
1285 R += padR;
1286 B += padB;
1287 }
1288
1292 inline void HPad(float padding)
1293 {
1294 L -= padding;
1295 R += padding;
1296 }
1297
1301 inline void VPad(float padding)
1302 {
1303 T -= padding;
1304 B += padding;
1305 }
1306
1309 inline void MidHPad(float padding)
1310 {
1311 const float mw = MW();
1312 L = mw - padding;
1313 R = mw + padding;
1314 }
1315
1318 inline void MidVPad(float padding)
1319 {
1320 const float mh = MH();
1321 T = mh - padding;
1322 B = mh + padding;
1323 }
1324
1329 inline IRECT GetPadded(float padding) const
1330 {
1331 return IRECT(L-padding, T-padding, R+padding, B+padding);
1332 }
1333
1341 inline IRECT GetPadded(float padL, float padT, float padR, float padB) const
1342 {
1343 return IRECT(L-padL, T-padT, R+padR, B+padB);
1344 }
1345
1350 inline IRECT GetHPadded(float padding) const
1351 {
1352 return IRECT(L-padding, T, R+padding, B);
1353 }
1354
1359 inline IRECT GetVPadded(float padding) const
1360 {
1361 return IRECT(L, T-padding, R, B+padding);
1362 }
1363
1367 inline IRECT GetMidHPadded(float padding) const
1368 {
1369 return IRECT(MW()-padding, T, MW()+padding, B);
1370 }
1371
1375 inline IRECT GetMidVPadded(float padding) const
1376 {
1377 return IRECT(L, MH()-padding, R, MH()+padding);
1378 }
1379
1384 inline IRECT GetHSliced(float w, bool rhs = false) const
1385 {
1386 if(rhs)
1387 return IRECT(R - w, T, R, B);
1388 else
1389 return IRECT(L, T, L + w, B);
1390 }
1391
1396 inline IRECT GetVSliced(float h, bool bot = false) const
1397 {
1398 if(bot)
1399 return IRECT(L, B - h, R, B);
1400 else
1401 return IRECT(L, T, R, T + h);
1402 }
1403
1406 void Clank(const IRECT& rhs)
1407 {
1408 if (L < rhs.L)
1409 {
1410 R = std::min(rhs.R - 1, R + rhs.L - L);
1411 L = rhs.L;
1412 }
1413 if (T < rhs.T)
1414 {
1415 B = std::min(rhs.B - 1, B + rhs.T - T);
1416 T = rhs.T;
1417 }
1418 if (R >= rhs.R)
1419 {
1420 L = std::max(rhs.L, L - (R - rhs.R + 1));
1421 R = rhs.R - 1;
1422 }
1423 if (B >= rhs.B)
1424 {
1425 T = std::max(rhs.T, T - (B - rhs.B + 1));
1426 B = rhs.B - 1;
1427 }
1428 }
1429
1432 void Scale(float scale)
1433 {
1434 L *= scale;
1435 T *= scale;
1436 R *= scale;
1437 B *= scale;
1438 }
1439
1442 void ScaleAboutCentre(float scale)
1443 {
1444 float x = MW();
1445 float y = MH();
1446 float hw = W() / 2.f;
1447 float hh = H() / 2.f;
1448 L = x - (hw * scale);
1449 T = y - (hh * scale);
1450 R = x + (hw * scale);
1451 B = y + (hh * scale);
1452 }
1453
1457 IRECT GetScaled(float scale) const
1458 {
1459 IRECT r = *this;
1460 r.Scale(scale);
1461 return r;
1462 }
1463
1467 IRECT GetScaledAboutCentre(float scale) const
1468 {
1469 IRECT r = *this;
1470 r.ScaleAboutCentre(scale);
1471 return r;
1472 }
1473
1479 static IRECT LinearInterpolateBetween(const IRECT& start, const IRECT& dest, float progress)
1480 {
1481 IRECT result;
1482 result.L = start.L + progress * (dest.L - start.L);
1483 result.T = start.T + progress * (dest.T - start.T);
1484 result.R = start.R + progress * (dest.R - start.R);
1485 result.B = start.B + progress * (dest.B - start.B);
1486 return result;
1487 }
1488
1492 void GetRandomPoint(float& x, float& y) const
1493 {
1494 const float r1 = static_cast<float>(std::rand()/(static_cast<float>(RAND_MAX)+1.f));
1495 const float r2 = static_cast<float>(std::rand()/(static_cast<float>(RAND_MAX)+1.f));
1496
1497 x = L + r1 * W();
1498 y = T + r2 * H();
1499 }
1500
1503 {
1504 float l, t, r, b;
1505 GetRandomPoint(l, t);
1506 IRECT tmp = IRECT(l, t, R, B);
1507 tmp.GetRandomPoint(r, b);
1508
1509 return IRECT(l, t, r, b);
1510 }
1511
1517 void Offset(float l, float t, float r, float b)
1518 {
1519 L += l;
1520 T += t;
1521 R += r;
1522 B += b;
1523 }
1524
1531 IRECT GetOffset(float l, float t, float r, float b) const
1532 {
1533 return IRECT(L + l, T + t, R + r, B + b);
1534 }
1535
1539 void Translate(float x, float y)
1540 {
1541 L += x;
1542 T += y;
1543 R += x;
1544 B += y;
1545 }
1546
1551 IRECT GetTranslated(float x, float y) const
1552 {
1553 return IRECT(L + x, T + y, R + x, B + y);
1554 }
1555
1559 IRECT GetHShifted(float x) const
1560 {
1561 return GetTranslated(x, 0.f);
1562 }
1563
1567 IRECT GetVShifted(float y) const
1568 {
1569 return GetTranslated(0.f, y);
1570 }
1571
1576 {
1577 IRECT r;
1578 r.L = MW() - sr.W() / 2.f;
1579 r.T = MH() - sr.H() / 2.f;
1580 r.R = r.L + sr.W();
1581 r.B = r.T + sr.H();
1582
1583 return r;
1584 }
1585
1590 IRECT GetCentredInside(float w, float h = 0.f) const
1591 {
1592 w = std::max(w, 1.f);
1593
1594 if(h <= 0.f)
1595 h = w;
1596
1597 IRECT r;
1598 r.L = MW() - w / 2.f;
1599 r.T = MH() - h / 2.f;
1600 r.R = r.L + w;
1601 r.B = r.T + h;
1602
1603 return r;
1604 }
1605
1609 IRECT GetCentredInside(const IBitmap& bitmap) const
1610 {
1611 IRECT r;
1612 r.L = MW() - bitmap.FW() / 2.f;
1613 r.T = MH() - bitmap.FH() / 2.f;
1614 r.R = r.L + (float) bitmap.FW();
1615 r.B = r.T + (float) bitmap.FH();
1616
1617 return r;
1618 }
1619
1623 void VAlignTo(const IRECT& sr, EVAlign align)
1624 {
1625 const float height = H();
1626 switch (align)
1627 {
1628 case EVAlign::Top: T = sr.T; B = sr.T + height; break;
1629 case EVAlign::Bottom: T = sr.B - height; B = sr.B; break;
1630 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;
1631 }
1632 }
1633
1637 void HAlignTo(const IRECT& sr, EAlign align)
1638 {
1639 const float width = W();
1640 switch (align)
1641 {
1642 case EAlign::Near: L = sr.L; R = sr.L + width; break;
1643 case EAlign::Far: L = sr.R - width; R = sr.R; break;
1644 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;
1645 }
1646 }
1647
1652 IRECT GetVAlignedTo(const IRECT& sr, EVAlign align) const
1653 {
1654 IRECT result = *this;
1655 result.VAlignTo(sr, align);
1656 return result;
1657 }
1658
1661 {
1662 if(W() < H())
1663 return W();
1664 else
1665 return H();
1666 }
1667
1672 IRECT GetHAlignedTo(const IRECT& sr, EAlign align) const
1673 {
1674 IRECT result = *this;
1675 result.HAlignTo(sr, align);
1676 return result;
1677 }
1678
1680 void DBGPrint() { DBGMSG("L: %f, T: %f, R: %f, B: %f,: W: %f, H: %f\n", L, T, R, B, W(), H()); }
1681};
1682
1685{
1686 bool L, R, S, C, A;
1687 ITouchID touchID = 0;
1688 float touchRadius = 0.f;
1689
1697 IMouseMod(bool l = false, bool r = false, bool s = false, bool c = false, bool a = false, ITouchID touchID = 0)
1698 : L(l), R(r), S(s), C(c), A(a), touchID(touchID)
1699 {}
1700
1702 bool IsTouch() const { return touchID > 0; }
1703
1705 void DBGPrint() { DBGMSG("L: %i, R: %i, S: %i, C: %i,: A: %i\n", L, R, S, C, A); }
1706};
1707
1710{
1711 float x = 0.0, y = 0.0;
1712 float dX = 0.0, dY = 0.0;
1713 IMouseMod ms;
1714};
1715
1718{
1719 float x = 0.f;
1720 float y = 0.f;
1721 float scale = 0.f; // pinch,
1722 float velocity = 0.f; // pinch, rotate
1723 float angle = 0.f; // rotate,
1724 EGestureState state = EGestureState::Unknown;
1725 EGestureType type = EGestureType::Unknown;
1726};
1727
1730{
1731public:
1732 IRECTList()
1733 {}
1734
1735 IRECTList(const IRECTList&) = delete;
1736 IRECTList& operator=(const IRECTList&) = delete;
1737
1739 int Size() const { return mRects.GetSize(); }
1740
1743 void Add(const IRECT& rect)
1744 {
1745 mRects.Add(rect);
1746 }
1747
1751 void Set(int idx, const IRECT& rect)
1752 {
1753 *(mRects.GetFast() + idx) = rect;
1754 }
1755
1759 const IRECT& Get(int idx) const
1760 {
1761 return *(mRects.GetFast() + idx);
1762 }
1763
1765 void Clear()
1766 {
1767 mRects.Resize(0);
1768 }
1769
1773 {
1774 IRECT r = Get(0);
1775 for (auto i = 1; i < mRects.GetSize(); i++)
1776 r = r.Union(Get(i));
1777 return r;
1778 }
1779
1782 {
1783 for (auto i = 0; i < Size(); i++)
1784 {
1785 IRECT r = Get(i);
1786 r.PixelAlign();
1787 Set(i, r);
1788 }
1789 }
1790
1793 void PixelAlign(float scale)
1794 {
1795 for (auto i = 0; i < Size(); i++)
1796 {
1797 IRECT r = Get(i);
1798 r.PixelAlign(scale);
1799 Set(i, r);
1800 }
1801 }
1802
1807 int Find(float x, float y) const
1808 {
1809 for (auto i = 0; i < Size(); i++)
1810 {
1811 if(Get(i).Contains(x, y))
1812 return i;
1813 }
1814
1815 return -1;
1816 }
1817
1825 static bool GetFracGrid(const IRECT& input, IRECTList& rects, const std::initializer_list<float>& rowFractions, const std::initializer_list<float>& colFractions, EDirection layoutDir = EDirection::Horizontal)
1826 {
1827 IRECT spaceLeft = input;
1828 float y = 0.;
1829 float x = 0.;
1830
1831 if(std::accumulate(rowFractions.begin(), rowFractions.end(), 0.f) != 1.)
1832 return false;
1833
1834 if(std::accumulate(colFractions.begin(), colFractions.end(), 0.f) != 1.)
1835 return false;
1836
1837 if (layoutDir == EDirection::Horizontal)
1838 {
1839 for (auto& rowFrac : rowFractions)
1840 {
1841 IRECT thisRow = input.FracRectVertical(rowFrac, true).GetTranslated(0, y);
1842
1843 x = 0.;
1844
1845 for (auto& colFrac : colFractions)
1846 {
1847 IRECT thisCell = thisRow.FracRectHorizontal(colFrac).GetTranslated(x, 0);
1848
1849 rects.Add(thisCell);
1850
1851 x += thisCell.W();
1852 }
1853
1854 spaceLeft.Intersect(thisRow);
1855
1856 y = rects.Bounds().H();
1857 }
1858 }
1859
1860 if (layoutDir == EDirection::Vertical)
1861 {
1862 for (auto& colFrac : colFractions)
1863 {
1864 IRECT thisCol = input.FracRectHorizontal(colFrac).GetTranslated(x, 0);
1865
1866 y = 0.;
1867
1868 for (auto& rowFrac : rowFractions)
1869 {
1870 IRECT thisCell = thisCol.FracRectVertical(rowFrac, true).GetTranslated(0, y);
1871
1872 rects.Add(thisCell);
1873
1874 y += thisCell.H();
1875 }
1876
1877 spaceLeft.Intersect(thisCol);
1878
1879 x = rects.Bounds().W();
1880 }
1881 }
1882
1883 return true;
1884 }
1885
1888 {
1889 for (int i = 0; i < Size(); i++)
1890 {
1891 for (int j = i + 1; j < Size(); j++)
1892 {
1893 if (Get(i).Contains(Get(j)))
1894 {
1895 mRects.Delete(j);
1896 j--;
1897 }
1898 else if (Get(j).Contains(Get(i)))
1899 {
1900 mRects.Delete(i);
1901 i--;
1902 break;
1903 }
1904 else if (Get(i).Intersects(Get(j)))
1905 {
1906 IRECT intersection = Get(i).Intersect(Get(j));
1907
1908 if (Get(i).Mergeable(intersection))
1909 Set(i, Shrink(Get(i), intersection));
1910 else if (Get(j).Mergeable(intersection))
1911 Set(j, Shrink(Get(j), intersection));
1912 else if (Get(i).Area() < Get(j).Area())
1913 Set(i, Split(Get(i), intersection));
1914 else
1915 Set(j, Split(Get(j), intersection));
1916 }
1917 }
1918 }
1919
1920 for (int i = 0; i < Size(); i++)
1921 {
1922 for (int j = i + 1; j < Size(); j++)
1923 {
1924 if (Get(i).Mergeable(Get(j)))
1925 {
1926 Set(j, Get(i).Union(Get(j)));
1927 mRects.Delete(i);
1928 i = -1;
1929 break;
1930 }
1931 }
1932 }
1933 }
1934
1935private:
1940 IRECT Shrink(const IRECT &r, const IRECT &i)
1941 {
1942 if (i.L != r.L)
1943 return IRECT(r.L, r.T, i.L, r.B);
1944 if (i.T != r.T)
1945 return IRECT(r.L, r.T, r.R, i.T);
1946 if (i.R != r.R)
1947 return IRECT(i.R, r.T, r.R, r.B);
1948 return IRECT(r.L, i.B, r.R, r.B);
1949 }
1950
1955 IRECT Split(const IRECT r, const IRECT &i)
1956 {
1957 if (r.L == i.L)
1958 {
1959 if (r.T == i.T)
1960 {
1961 Add(IRECT(i.R, r.T, r.R, i.B));
1962 return IRECT(r.L, i.B, r.R, r.B);
1963 }
1964 else
1965 {
1966 Add(IRECT(r.L, r.T, r.R, i.T));
1967 return IRECT(i.R, i.T, r.R, r.B);
1968 }
1969 }
1970
1971 if (r.T == i.T)
1972 {
1973 Add(IRECT(r.L, r.T, i.L, 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(r.L, i.T, i.L, r.B);
1980 }
1981 }
1982
1983 WDL_TypedBuf<IRECT> mRects;
1984};
1985
1988{
1996 IMatrix(double xx, double yx, double xy, double yy, double tx, double ty)
1997 : mXX(xx), mYX(yx), mXY(xy), mYY(yy), mTX(tx), mTY(ty)
1998 {}
1999
2001 IMatrix() : IMatrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0)
2002 {}
2003
2008 IMatrix& Translate(float x, float y)
2009 {
2010 return Transform(IMatrix(1.0, 0.0, 0.0, 1.0, x, y));
2011 }
2012
2017 IMatrix& Scale(float x, float y)
2018 {
2019 return Transform(IMatrix(x, 0.0, 0.0, y, 0.0, 0.0));
2020 }
2021
2025 IMatrix& Rotate(float a)
2026 {
2027 const double rad = DegToRad(a);
2028 const double c = std::cos(rad);
2029 const double s = std::sin(rad);
2030
2031 return Transform(IMatrix(c, s, -s, c, 0.0, 0.0));
2032 }
2033
2038 IMatrix& Skew(float xa, float ya)
2039 {
2040 return Transform(IMatrix(1.0, std::tan(DegToRad(ya)), std::tan(DegToRad(xa)), 1.0, 0.0, 0.0));
2041 }
2042
2048 void TransformPoint(double& x, double& y, double x0, double y0) const
2049 {
2050 x = x0 * mXX + y0 * mXY + mTX;
2051 y = x0 * mYX + y0 * mYY + mTY;
2052 };
2053
2057 void TransformPoint(double& x, double& y) const
2058 {
2059 TransformPoint(x, y, x, y);
2060 };
2061
2066 IMatrix& Transform(const IRECT& before, const IRECT& after)
2067 {
2068 const double sx = after.W() / before.W();
2069 const double sy = after.H() / before.H();
2070 const double tx = after.L - before.L * sx;
2071 const double ty = after.T - before.T * sy;
2072
2073 return *this = IMatrix(sx, 0.0, 0.0, sy, tx, ty);
2074 }
2075
2080 {
2081 IMatrix p = *this;
2082
2083 mXX = m.mXX * p.mXX + m.mYX * p.mXY;
2084 mYX = m.mXX * p.mYX + m.mYX * p.mYY;
2085 mXY = m.mXY * p.mXX + m.mYY * p.mXY;
2086 mYY = m.mXY * p.mYX + m.mYY * p.mYY;
2087 mTX = m.mTX * p.mXX + m.mTY * p.mXY + p.mTX;
2088 mTY = m.mTX * p.mYX + m.mTY * p.mYY + p.mTY;
2089
2090 return *this;
2091 }
2092
2096 {
2097 IMatrix m = *this;
2098
2099 double d = 1.0 / (m.mXX * m.mYY - m.mYX * m.mXY);
2100
2101 mXX = m.mYY * d;
2102 mYX = -m.mYX * d;
2103 mXY = -m.mXY * d;
2104 mYY = m.mXX * d;
2105 mTX = (-(m.mTX * mXX) - (m.mTY * mXY));
2106 mTY = (-(m.mTX * mYX) - (m.mTY * mYY));
2107
2108 return *this;
2109 }
2110
2111 double mXX, mYX, mXY, mYY, mTX, mTY;
2112};
2113
2116{
2117 IColorStop()
2118 : mOffset(0.f)
2119 {}
2120
2124 IColorStop(IColor color, float offset)
2125 : mColor(color)
2126 , mOffset(offset)
2127 {
2128 assert(offset >= 0.0 && offset <= 1.0);
2129 }
2130
2131 IColor mColor;
2132 float mOffset;
2133};
2134
2137{
2138 EPatternType mType;
2139 EPatternExtend mExtend;
2140 IColorStop mStops[16];
2141 int mNStops;
2142 IMatrix mTransform;
2143
2146 IPattern(EPatternType type)
2147 : mType(type), mExtend(EPatternExtend::Pad), mNStops(0)
2148 {}
2149
2152 IPattern(const IColor& color)
2153 : mType(EPatternType::Solid), mExtend(EPatternExtend::Pad), mNStops(1)
2154 {
2155 mStops[0] = IColorStop(color, 0.0);
2156 }
2157
2165 static IPattern CreateLinearGradient(float x1, float y1, float x2, float y2, const std::initializer_list<IColorStop>& stops = {})
2166 {
2167 IPattern pattern(EPatternType::Linear);
2168
2169 // Calculate the affine transform from one line segment to another!
2170 const double xd = double(x2 - x1);
2171 const double yd = double(y2 - y1);
2172 const double d = sqrt(xd * xd + yd * yd);
2173 const double a = atan2(xd, yd);
2174 const double s = std::sin(a) / d;
2175 const double c = std::cos(a) / d;
2176
2177 const double x0 = -(x1 * c - y1 * s);
2178 const double y0 = -(x1 * s + y1 * c);
2179
2180 pattern.SetTransform(static_cast<float>(c),
2181 static_cast<float>(s),
2182 static_cast<float>(-s),
2183 static_cast<float>(c),
2184 static_cast<float>(x0),
2185 static_cast<float>(y0));
2186
2187 for (auto& stop : stops)
2188 pattern.AddStop(stop.mColor, stop.mOffset);
2189
2190 return pattern;
2191 }
2192
2198 static IPattern CreateLinearGradient(const IRECT& bounds, EDirection direction, const std::initializer_list<IColorStop>& stops = {})
2199 {
2200 float x1, y1, x2, y2;
2201
2202 if(direction == EDirection::Horizontal)
2203 {
2204 y1 = bounds.MH(); y2 = y1;
2205 x1 = bounds.L;
2206 x2 = bounds.R;
2207 }
2208 else//(direction == EDirection::Vertical)
2209 {
2210 x1 = bounds.MW(); x2 = x1;
2211 y1 = bounds.T;
2212 y2 = bounds.B;
2213 }
2214
2215 return CreateLinearGradient(x1, y1, x2, y2, stops);
2216 }
2217
2224 static IPattern CreateRadialGradient(float x1, float y1, float r, const std::initializer_list<IColorStop>& stops = {})
2225 {
2226 IPattern pattern(EPatternType::Radial);
2227
2228 const float s = 1.f / r;
2229
2230 pattern.SetTransform(s, 0, 0, s, -(x1 * s), -(y1 * s));
2231
2232 for (auto& stop : stops)
2233 pattern.AddStop(stop.mColor, stop.mOffset);
2234
2235 return pattern;
2236 }
2237
2245 static IPattern CreateSweepGradient(float x1, float y1, const std::initializer_list<IColorStop>& stops = {},
2246 float angleStart = 0.f, float angleEnd = 360.f)
2247 {
2248 IPattern pattern(EPatternType::Sweep);
2249
2250 #ifdef IGRAPHICS_SKIA
2251 angleStart -= 90;
2252 angleEnd -= 90;
2253 #endif
2254
2255 float rad = DegToRad(angleStart);
2256 float c = std::cos(rad);
2257 float s = std::sin(rad);
2258
2259 pattern.SetTransform(c, s, -s, c, -x1, -y1);
2260
2261 for (auto& stop : stops)
2262 {
2263 pattern.AddStop(stop.mColor, stop.mOffset * (angleEnd - angleStart) / 360.f);
2264 }
2265 return pattern;
2266 }
2267
2269 int NStops() const
2270 {
2271 return mNStops;
2272 }
2273
2277 const IColorStop& GetStop(int idx) const
2278 {
2279 return mStops[idx];
2280 }
2281
2285 void AddStop(IColor color, float offset)
2286 {
2287 assert(mType != EPatternType::Solid && mNStops < 16);
2288 assert(!mNStops || GetStop(mNStops - 1).mOffset < offset);
2289 if (mNStops < 16)
2290 mStops[mNStops++] = IColorStop(color, offset);
2291 }
2292
2300 void SetTransform(float xx, float yx, float xy, float yy, float tx, float ty)
2301 {
2302 mTransform = IMatrix(xx, yx, xy, yy, tx, ty);
2303 }
2304
2307 void SetTransform(const IMatrix& transform)
2308 {
2309 mTransform = transform;
2310 }
2311};
2312
2318{
2319 friend IGraphics;
2320
2321public:
2327 ILayer(APIBitmap* pBitmap, const IRECT& layerRect, IControl* pControl, const IRECT& controlRect)
2328 : mBitmap(pBitmap)
2329 , mControl(pControl)
2330 , mControlRECT(controlRect)
2331 , mRECT(layerRect)
2332 , mInvalid(false)
2333 {}
2334
2335 ILayer(const ILayer&) = delete;
2336 ILayer operator=(const ILayer&) = delete;
2337
2339 void Invalidate() { mInvalid = true; }
2340
2342 const APIBitmap* GetAPIBitmap() const { return mBitmap.get(); }
2343
2345 IBitmap GetBitmap() const { return IBitmap(mBitmap.get(), 1, false); }
2346
2348 const IRECT& Bounds() const { return mRECT; }
2349
2350private:
2351 std::unique_ptr<APIBitmap> mBitmap;
2352 IControl* mControl;
2353 IRECT mControlRECT;
2354 IRECT mRECT;
2355 bool mInvalid;
2356};
2357
2359using ILayerPtr = std::unique_ptr<ILayer>;
2360
2363{
2364 IShadow() {}
2365
2373 IShadow(const IPattern& pattern, float blurSize, float xOffset, float yOffset, float opacity, bool drawForeground = true)
2374 : mPattern(pattern)
2375 , mBlurSize(blurSize)
2376 , mXOffset(xOffset)
2377 , mYOffset(yOffset)
2378 , mOpacity(opacity)
2379 , mDrawForeground(drawForeground)
2380 {}
2381
2382 IPattern mPattern = COLOR_BLACK;
2383 float mBlurSize = 0.f;
2384 float mXOffset = 0.f;
2385 float mYOffset = 0.f;
2386 float mOpacity = 1.f;
2387 bool mDrawForeground = true;
2388};
2389
2392{
2393 IColor mColors[kNumVColors];
2394
2396 const IColor& GetColor(EVColor color) const
2397 {
2398 return mColors[(int) color];
2399 }
2400
2402 static const IColor& GetDefaultColor(EVColor idx)
2403 {
2404 switch(idx)
2405 {
2406 case kBG: return DEFAULT_BGCOLOR; // Background
2407 case kFG: return DEFAULT_FGCOLOR; // OFF/Foreground
2408 case kPR: return DEFAULT_PRCOLOR; // ON/Pressed
2409 case kFR: return DEFAULT_FRCOLOR; // Frame
2410 case kHL: return DEFAULT_HLCOLOR; // Highlight
2411 case kSH: return DEFAULT_SHCOLOR; // Shadow
2412 case kX1: return DEFAULT_X1COLOR; // Extra 1
2413 case kX2: return DEFAULT_X2COLOR; // Extra 2
2414 case kX3: return DEFAULT_X3COLOR; // Extra 3
2415 default:
2416 return COLOR_TRANSPARENT;
2417 };
2418 }
2419
2422 {
2423 ResetColors();
2424 }
2425
2428 IVColorSpec(const std::initializer_list<IColor>& colors)
2429 {
2430 assert(colors.size() <= kNumVColors);
2431
2432 int i = 0;
2433
2434 for(auto& c : colors)
2435 {
2436 mColors[i++] = c;
2437 }
2438
2439 for(; i<kNumVColors; i++)
2440 {
2441 mColors[i] = GetDefaultColor((EVColor) i);
2442 }
2443 }
2444
2447 {
2448 for (int i=0; i<kNumVColors; i++)
2449 {
2450 mColors[i] = GetDefaultColor((EVColor) i);
2451 }
2452 }
2453};
2454
2455const IVColorSpec DEFAULT_COLOR_SPEC = IVColorSpec();
2456
2457static constexpr bool DEFAULT_HIDE_CURSOR = true;
2458static constexpr bool DEFAULT_SHOW_VALUE = true;
2459static constexpr bool DEFAULT_SHOW_LABEL = true;
2460static constexpr bool DEFAULT_DRAW_FRAME = true;
2461static constexpr bool DEFAULT_DRAW_SHADOWS = true;
2462static constexpr bool DEFAULT_EMBOSS = false;
2463static constexpr float DEFAULT_ROUNDNESS = 0.f;
2464static constexpr float DEFAULT_FRAME_THICKNESS = 1.f;
2465static constexpr float DEFAULT_SHADOW_OFFSET = 3.f;
2466static constexpr float DEFAULT_WIDGET_FRAC = 1.f;
2467static constexpr float DEFAULT_WIDGET_ANGLE = 0.f;
2468static constexpr EOrientation DEFAULT_LABEL_ORIENTATION = EOrientation::North;
2469const IText DEFAULT_LABEL_TEXT {DEFAULT_TEXT_SIZE + 5.f, EVAlign::Top};
2470const IText DEFAULT_VALUE_TEXT {DEFAULT_TEXT_SIZE, EVAlign::Bottom};
2471
2474{
2475 bool hideCursor = DEFAULT_HIDE_CURSOR;
2476 bool showLabel = DEFAULT_SHOW_LABEL;
2477 bool showValue = DEFAULT_SHOW_VALUE;
2478 bool drawFrame = DEFAULT_DRAW_FRAME;
2479 bool drawShadows = DEFAULT_DRAW_SHADOWS;
2480 bool emboss = DEFAULT_EMBOSS;
2481 float roundness = DEFAULT_ROUNDNESS;
2482 float frameThickness = DEFAULT_FRAME_THICKNESS;
2483 float shadowOffset = DEFAULT_SHADOW_OFFSET;
2484 float widgetFrac = DEFAULT_WIDGET_FRAC;
2485 float angle = DEFAULT_WIDGET_ANGLE;
2486 IVColorSpec colorSpec = DEFAULT_COLOR_SPEC;
2487 IText labelText = DEFAULT_LABEL_TEXT;
2488 IText valueText = DEFAULT_VALUE_TEXT;
2489 EOrientation labelOrientation = DEFAULT_LABEL_ORIENTATION;
2490
2506 IVStyle(bool showLabel = DEFAULT_SHOW_LABEL,
2507 bool showValue = DEFAULT_SHOW_VALUE,
2508 const IVColorSpec& colors = {DEFAULT_BGCOLOR, DEFAULT_FGCOLOR, DEFAULT_PRCOLOR, DEFAULT_FRCOLOR, DEFAULT_HLCOLOR, DEFAULT_SHCOLOR, DEFAULT_X1COLOR, DEFAULT_X2COLOR, DEFAULT_X3COLOR},
2509 const IText& labelText = DEFAULT_LABEL_TEXT,
2510 const IText& valueText = DEFAULT_VALUE_TEXT,
2511 bool hideCursor = DEFAULT_HIDE_CURSOR,
2512 bool drawFrame = DEFAULT_DRAW_FRAME,
2513 bool drawShadows = DEFAULT_DRAW_SHADOWS,
2514 bool emboss = DEFAULT_EMBOSS,
2515 float roundness = DEFAULT_ROUNDNESS,
2516 float frameThickness = DEFAULT_FRAME_THICKNESS,
2517 float shadowOffset = DEFAULT_SHADOW_OFFSET,
2518 float widgetFrac = DEFAULT_WIDGET_FRAC,
2519 float angle = DEFAULT_WIDGET_ANGLE,
2520 EOrientation labelOrientation = DEFAULT_LABEL_ORIENTATION)
2521 : hideCursor(hideCursor)
2522 , showLabel(showLabel)
2523 , showValue(showValue)
2524 , drawFrame(drawFrame)
2525 , drawShadows(drawShadows)
2526 , emboss(emboss)
2527 , roundness(roundness)
2528 , frameThickness(frameThickness)
2529 , shadowOffset(shadowOffset)
2530 , widgetFrac(widgetFrac)
2531 , angle(angle)
2532 , colorSpec(colors)
2533 , labelText(labelText)
2534 , valueText(valueText)
2535 {
2536 }
2537
2540 IVStyle(const std::initializer_list<IColor>& colors)
2541 : colorSpec(colors)
2542 {
2543 }
2544
2545 IVStyle WithShowLabel(bool show = true) const { IVStyle newStyle = *this; newStyle.showLabel = show; return newStyle; }
2546 IVStyle WithShowValue(bool show = true) const { IVStyle newStyle = *this; newStyle.showValue = show; return newStyle; }
2547 IVStyle WithLabelText(const IText& text) const { IVStyle newStyle = *this; newStyle.labelText = text; return newStyle;}
2548 IVStyle WithValueText(const IText& text) const { IVStyle newStyle = *this; newStyle.valueText = text; return newStyle; }
2549 IVStyle WithHideCursor(bool hide = true) const { IVStyle newStyle = *this; newStyle.hideCursor = hide; return newStyle; }
2550 IVStyle WithColor(EVColor idx, IColor color) const { IVStyle newStyle = *this; newStyle.colorSpec.mColors[idx] = color; return newStyle; }
2551 IVStyle WithColors(const IVColorSpec& spec) const { IVStyle newStyle = *this; newStyle.colorSpec = spec; return newStyle; }
2552 IVStyle WithRoundness(float v) const { IVStyle newStyle = *this; newStyle.roundness = Clip(v, 0.f, 1.f); return newStyle; }
2553 IVStyle WithFrameThickness(float v) const { IVStyle newStyle = *this; newStyle.frameThickness = v; return newStyle; }
2554 IVStyle WithShadowOffset(float v) const { IVStyle newStyle = *this; newStyle.shadowOffset = v; return newStyle; }
2555 IVStyle WithDrawShadows(bool v = true) const { IVStyle newStyle = *this; newStyle.drawShadows = v; return newStyle; }
2556 IVStyle WithDrawFrame(bool v = true) const { IVStyle newStyle = *this; newStyle.drawFrame = v; return newStyle; }
2557 IVStyle WithWidgetFrac(float v) const { IVStyle newStyle = *this; newStyle.widgetFrac = Clip(v, 0.f, 1.f); return newStyle; }
2558 IVStyle WithAngle(float v) const { IVStyle newStyle = *this; newStyle.angle = Clip(v, 0.f, 360.f); return newStyle; }
2559 IVStyle WithEmboss(bool v = true) const { IVStyle newStyle = *this; newStyle.emboss = v; return newStyle; }
2560 IVStyle WithLabelOrientation(EOrientation v) const { IVStyle newStyle = *this; newStyle.labelOrientation = v; return newStyle; }
2561};
2562
2563const IVStyle DEFAULT_STYLE = IVStyle();
2564
2565END_IGRAPHICS_NAMESPACE
2566END_IPLUG_NAMESPACE
2567
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:2013
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
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.