1 /*
2  * Include this before ANY vstgui and after you have included JuceHeader and you stand a chance
3  *
4  * IF YOU ARE READING THIS and you haven't been following the convresation on discord it will
5  * look terrible and broken and wierd. That's because right now it is. If you want some context
6  * here *please please* chat with @baconpaul in the #surge-development channel on discord or
7  * check the pinned 'status' issue on the surge github. This code has all sorts of problems
8  * (dependencies out of order, memory leaks, etc...) which I'm working through as I bootstrap
9  * our way out of vstgui.
10  */
11 
12 #ifndef SURGE_ESCAPE_FROM_VSTGUI_H
13 #define SURGE_ESCAPE_FROM_VSTGUI_H
14 
15 #include <memory>
16 #include <unordered_set>
17 #include "DebugHelpers.h"
18 
19 #if MAC
20 #include <CoreFoundation/CoreFoundation.h>
21 #endif
22 
23 #if MAC
24 #define DEBUG_EFVG_MEMORY 1
25 #define DEBUG_EFVG_MEMORY_STACKS 0
26 #else
27 #define DEBUG_EFVG_MEMORY 0
28 #define DEBUG_EFVG_MEMORY_STACKS 0
29 #endif
30 
31 #if DEBUG_EFVG_MEMORY
32 #include <unordered_map>
33 
34 #if MAC || LINUX
35 #include <execinfo.h>
36 #include <cstdio>
37 #include <cstdlib>
38 #endif
39 
40 #endif
41 
42 #include <JuceHeader.h>
43 
44 // The layers of unimpl. Really bad (D), standard, and we are OK with it for now (OKUNIMPL);
45 #define DUNIMPL                                                                                    \
46     std::cout << "Unimplemented : " << __func__ << " at " << __FILE__ << ":" << __LINE__           \
47               << std::endl;
48 //#define UNIMPL void(0);
49 #define UNIMPL DUNIMPL
50 #define UNIMPL_STACK DUNIMPL EscapeNS::Internal::printStack(__func__);
51 #define OKUNIMPL void(0);
52 
53 typedef int VstKeyCode;
54 
55 namespace EscapeFromVSTGUI
56 {
57 struct JuceVSTGUIEditorAdapterBase
58 {
59     virtual juce::AudioProcessorEditor *getJuceEditor() = 0;
60 };
61 } // namespace EscapeFromVSTGUI
62 
63 namespace EscapeNS
64 {
65 namespace Internal
66 {
printStack(const char * where)67 inline void printStack(const char *where)
68 {
69 #if MAC
70     void *callstack[128];
71     int i, frames = backtrace(callstack, 128);
72     char **strs = backtrace_symbols(callstack, frames);
73     std::ostringstream oss;
74     oss << "----- " << where << " -----\n";
75     for (i = 3; i < frames - 1 && i < 20; ++i)
76     {
77         oss << strs[i] << "\n";
78     }
79     free(strs);
80     std::cout << oss.str() << std::endl;
81 #endif
82 }
83 #if DEBUG_EFVG_MEMORY
84 struct DebugAllocRecord
85 {
DebugAllocRecordDebugAllocRecord86     DebugAllocRecord() { record("CONSTRUCT"); }
recordDebugAllocRecord87     void record(const std::string &where)
88     {
89 #if DEBUG_EFVG_MEMORY_STACKS
90 #if MAC
91         void *callstack[128];
92         int i, frames = backtrace(callstack, 128);
93         char **strs = backtrace_symbols(callstack, frames);
94         std::ostringstream oss;
95         oss << "----- " << where << " -----\n";
96         for (i = 3; i < frames - 1 && i < 20; ++i)
97         {
98             oss << strs[i] << "\n";
99         }
100         free(strs);
101         records.push_back(oss.str());
102 #endif
103 #endif
104     }
105     int remembers = 0, forgets = 0;
106     std::vector<std::string> records;
107 };
108 struct FakeRefcount;
109 
getAllocMap()110 inline std::unordered_map<FakeRefcount *, DebugAllocRecord> *getAllocMap()
111 {
112     static std::unordered_map<FakeRefcount *, DebugAllocRecord> map;
113     return &map;
114 }
115 
116 struct RefActivity
117 {
118     int creates = 0, deletes = 0;
119 };
getRefActivity()120 inline RefActivity *getRefActivity()
121 {
122     static RefActivity r;
123     return &r;
124 }
125 
126 #endif
127 struct FakeRefcount
128 {
129     explicit FakeRefcount(bool doDebug = true, bool alwaysLeak = false)
doDebugFakeRefcount130         : doDebug(doDebug), alwaysLeak(alwaysLeak)
131     {
132 #if DEBUG_EFVG_MEMORY
133         if (doDebug)
134         {
135             getAllocMap()->emplace(std::make_pair(this, DebugAllocRecord()));
136             getRefActivity()->creates++;
137         }
138 #else
139         if (alwaysLeak)
140         {
141             std::cout << "YOU LEFT ALWAYS LEAK ON SILLY" << std::endl;
142         }
143 #endif
144     }
~FakeRefcountFakeRefcount145     virtual ~FakeRefcount()
146     {
147 #if DEBUG_EFVG_MEMORY
148         if (doDebug)
149         {
150             getAllocMap()->erase(this);
151             getRefActivity()->deletes++;
152         }
153 #endif
154     }
155 
rememberFakeRefcount156     virtual void remember()
157     {
158         refCount++;
159 #if DEBUG_EFVG_MEMORY
160         if (doDebug)
161         {
162             (*getAllocMap())[this].remembers++;
163             (*getAllocMap())[this].record("Remember");
164         }
165 #endif
166     }
forgetFakeRefcount167     virtual void forget()
168     {
169         refCount--;
170 #if DEBUG_EFVG_MEMORY
171         if (doDebug)
172         {
173             (*getAllocMap())[this].forgets++;
174             (*getAllocMap())[this].record("Forget");
175         }
176 #endif
177         if (refCount == 0)
178         {
179             if (!alwaysLeak)
180                 delete this;
181         }
182     }
183     int64_t refCount = 0;
184     bool doDebug = true, alwaysLeak = false;
185 };
186 
187 #if DEBUG_EFVG_MEMORY
188 
showMemoryOutstanding()189 inline void showMemoryOutstanding()
190 {
191     std::cout << "Total activity : Create=" << getRefActivity()->creates
192               << " Delete=" << getRefActivity()->deletes << std::endl;
193     for (auto &p : *(getAllocMap()))
194     {
195         if (p.first->doDebug)
196         {
197             std::cout << "Still here! " << p.first << " " << p.first->refCount << " "
198                       << p.second.remembers << " " << p.second.forgets << " "
199                       << typeid(*(p.first)).name() << std::endl;
200             for (auto &r : p.second.records)
201                 std::cout << r << "\n" << std::endl;
202         }
203     }
204 }
205 #endif
206 
getForgetMeLater()207 inline std::unordered_set<FakeRefcount *> *getForgetMeLater()
208 {
209     static std::unordered_set<FakeRefcount *> fml;
210     return &fml;
211 }
212 
enqueueForget(FakeRefcount * c)213 inline void enqueueForget(FakeRefcount *c) { getForgetMeLater()->insert(c); }
214 
215 } // namespace Internal
216 
efvgIdle()217 inline void efvgIdle()
218 {
219     for (auto v : *(Internal::getForgetMeLater()))
220         v->forget();
221     Internal::getForgetMeLater()->clear();
222 }
223 
224 #if MAC
getBundleRef()225 inline CFBundleRef getBundleRef() { return nullptr; }
226 #endif
227 
228 typedef juce::AudioProcessorEditor EditorType;
229 typedef const char *UTF8String; // I know I know
230 
231 struct CFrame;
232 struct CBitmap;
233 struct CColor;
234 struct COptionMenu;
235 
236 typedef float CCoord;
237 struct CPoint
238 {
CPointCPoint239     CPoint() : x(0), y(0) {}
CPointCPoint240     CPoint(float x, float y) : x(x), y(y) {}
CPointCPoint241     CPoint(const juce::Point<float> &p) : x(p.x), y(p.y) {}
242     float x, y;
243 
244     bool operator==(const CPoint &that) const { return (x == that.x && y == that.y); }
245     bool operator!=(const CPoint &that) const { return !(*this == that); }
246     CPoint operator-(const CPoint &that) const { return {x - that.x, y - that.y}; }
offsetCPoint247     CPoint offset(float dx, float dy)
248     {
249         x += dx;
250         y += dy;
251         return *this;
252     }
253 
254     operator juce::Point<float>() const { return juce::Point<float>(x, y); }
255 };
256 
257 struct CRect
258 {
259     double top = 0, bottom = 0, left = 0, right = 0;
260     CRect() = default;
CRectCRect261     CRect(juce::Rectangle<int> rect) { DUNIMPL; }
CRectCRect262     CRect(const CPoint &corner, const CPoint &size)
263     {
264         top = corner.y;
265         left = corner.x;
266         right = left + size.x;
267         bottom = top + size.y;
268     }
CRectCRect269     CRect(float left, float top, float right, float bottom)
270     {
271         this->left = left;
272         this->top = top;
273         this->right = right;
274         this->bottom = bottom;
275     }
276 
getSizeCRect277     inline CPoint getSize() const { return CPoint(right - left, bottom - top); }
getTopLeftCRect278     inline CPoint getTopLeft() const { return CPoint(left, top); }
getBottomLeftCRect279     inline CPoint getBottomLeft() const { return CPoint(left, bottom); }
getTopRightCRect280     inline CPoint getTopRight() const { return CPoint(right, top); }
getBottomRightCRect281     inline CPoint getBottomRight() const { return CPoint(right, bottom); }
282 
getWidthCRect283     inline float getWidth() const { return right - left; }
getHeightCRect284     inline float getHeight() const { return bottom - top; }
285 
centerInsideCRect286     CRect centerInside(const CRect &r)
287     {
288         UNIMPL;
289         return r;
290     }
rectOverlapCRect291     bool rectOverlap(const CRect &r)
292     {
293         UNIMPL;
294         return false;
295     }
setHeightCRect296     inline void setHeight(float h) { bottom = top + h; }
setWidthCRect297     inline void setWidth(float h) { right = left + h; }
298 
insetCRect299     inline CRect inset(float dx, float dy)
300     {
301         left += dx;
302         right -= dx;
303         top += dy;
304         bottom -= dy;
305         return *this;
306     }
offsetCRect307     inline CRect offset(float x, float y)
308     {
309         top += y;
310         bottom += y;
311         left += x;
312         right += x;
313         return *this;
314     }
moveToCRect315     inline CRect moveTo(CPoint p) { return moveTo(p.x, p.y); }
moveToCRect316     inline CRect moveTo(float x, float y)
317     {
318         auto dx = x - left;
319         auto dy = y - top;
320         top += dy;
321         left += dx;
322         bottom += dy;
323         right += dx;
324         return *this;
325     }
pointInsideCRect326     inline bool pointInside(const CPoint &where) const { return asJuceFloatRect().contains(where); }
getCenterCRect327     inline CPoint getCenter()
328     {
329         auto p = asJuceFloatRect().getCentre();
330         return p;
331     }
extendCRect332     inline CRect extend(float dx, float dy) { return inset(-dx, -dy); }
boundCRect333     inline CRect bound(CRect &rect)
334     {
335         if (left < rect.left)
336             left = rect.left;
337         if (top < rect.top)
338             top = rect.top;
339         if (right > rect.right)
340             right = rect.right;
341         if (bottom > rect.bottom)
342             bottom = rect.bottom;
343         if (bottom < top)
344             bottom = top;
345         if (right < left)
346             right = left;
347         return *this;
348     }
349 
350     operator juce::Rectangle<float>() const
351     {
352         return juce::Rectangle<float>(left, top, getWidth(), getHeight());
353     }
asJuceFloatRectCRect354     juce::Rectangle<float> asJuceFloatRect() const
355     {
356         return static_cast<juce::Rectangle<float>>(*this);
357     }
asJuceIntRectCRect358     juce::Rectangle<int> asJuceIntRect() const
359     {
360         juce::Rectangle<float> f = *this;
361         return f.toNearestIntEdges();
362     }
363 };
364 
365 struct CColor
366 {
CColorCColor367     constexpr CColor() : red(0), green(0), blue(0), alpha(255) {}
CColorCColor368     constexpr CColor(uint8_t r, uint8_t g, uint8_t b) : red(r), green(g), blue(b), alpha(255) {}
CColorCColor369     constexpr CColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
370         : red(r), green(g), blue(b), alpha(a)
371     {
372     }
373 
374     bool operator==(const CColor &that)
375     {
376         return red == that.red && green == that.green && blue == that.blue && alpha == that.alpha;
377     }
asJuceColourCColor378     juce::Colour asJuceColour() const { return juce::Colour(red, green, blue, alpha); }
379     uint8_t red, green, blue, alpha;
380 };
381 
382 struct CGradient : public Internal::FakeRefcount
383 {
384     std::unique_ptr<juce::ColourGradient> grad;
CGradientCGradient385     CGradient() { grad = std::make_unique<juce::ColourGradient>(); }
386     struct ColorStopMap
387     {
388     };
createCGradient389     static CGradient *create(const ColorStopMap &m)
390     {
391         auto res = new CGradient();
392         res->remember();
393         return res;
394     };
addColorStopCGradient395     void addColorStop(float pos, const CColor &c) { grad->addColour(pos, c.asJuceColour()); }
396 };
397 
398 constexpr const CColor kBlueCColor = CColor(0, 0, 255);
399 constexpr const CColor kWhiteCColor = CColor(255, 255, 255);
400 constexpr const CColor kRedCColor = CColor(255, 0, 0);
401 constexpr const CColor kBlackCColor = CColor(0, 0, 0);
402 constexpr const CColor kTransparentCColor = CColor(0, 0, 0, 0);
403 
404 enum CDrawModeFlags : uint32_t
405 {
406     kAliasing = 0,
407     kAntiAliasing = 1,
408     kNonIntegralMode = 0xF000000
409 };
410 
411 enum CDrawStyle : uint32_t
412 {
413     kDrawStroked = 0,
414     kDrawFilled,
415     kDrawFilledAndStroked
416 };
417 
418 enum CMouseEventResult
419 {
420     kMouseEventNotImplemented = 0,
421     kMouseEventHandled,
422     kMouseEventNotHandled,
423     kMouseDownEventHandledButDontNeedMovedOrUpEvents,
424     kMouseMoveEventHandledButDontNeedMoreEvents
425 };
426 
427 enum CHoriTxtAlign
428 {
429     kLeftText = 0,
430     kCenterText,
431     kRightText
432 };
433 
434 enum CCursorType
435 {
436     /** arrow cursor */
437     kCursorDefault = 0,
438     /** wait cursor */
439     kCursorWait,
440     /** horizontal size cursor */
441     kCursorHSize,
442     /** vertical size cursor */
443     kCursorVSize,
444     /** size all cursor */
445     kCursorSizeAll,
446     /** northeast and southwest size cursor */
447     kCursorNESWSize,
448     /** northwest and southeast size cursor */
449     kCursorNWSESize,
450     /** copy cursor (mainly for drag&drop operations) */
451     kCursorCopy,
452     /** not allowed cursor (mainly for drag&drop operations) */
453     kCursorNotAllowed,
454     /** hand cursor */
455     kCursorHand,
456     /** i beam cursor */
457     kCursorIBeam,
458 };
459 
460 enum CButton
461 {
462     /** left mouse button */
463     kLButton = juce::ModifierKeys::leftButtonModifier,
464     /** middle mouse button */
465     kMButton = juce::ModifierKeys::middleButtonModifier,
466     /** right mouse button */
467     kRButton = juce::ModifierKeys::rightButtonModifier,
468     /** shift modifier */
469     kShift = juce::ModifierKeys::shiftModifier,
470     /** control modifier (Command Key on Mac OS X and Control Key on Windows) */
471     kControl = juce::ModifierKeys::ctrlModifier,
472     /** alt modifier */
473     kAlt = juce::ModifierKeys::altModifier,
474     /** apple modifier (Mac OS X only. Is the Control key) */
475     kApple = 1U << 29,
476     /** 4th mouse button */
477     kButton4 = 1U << 30,
478     /** 5th mouse button */
479     kButton5 = 1U << 31,
480     /** mouse button is double click */
481     kDoubleClick = 1U << 22,
482     /** system mouse wheel setting is inverted (Only valid for onMouseWheel methods). The distance
483        value is already transformed back to non inverted. But for scroll views we need to know if we
484        need to invert it back. */
485     kMouseWheelInverted = 1U << 11,
486     /** event caused by touch gesture instead of mouse */
487     kTouch = 1U << 12
488 };
489 
490 // https://docs.juce.com/master/classModifierKeys.html#ae15cb452a97164e1b857086a1405942f
491 struct CButtonState
492 {
493     int state = juce::ModifierKeys::noModifiers;
CButtonStateCButtonState494     CButtonState()
495     {
496         auto ms = juce::ModifierKeys::currentModifiers;
497         state = ms.getRawFlags();
498     }
CButtonStateCButtonState499     CButtonState(CButton &b) { state = (int)b; }
CButtonStateCButtonState500     CButtonState(int b) { state = b; }
CButtonStateCButtonState501     CButtonState(const juce::ModifierKeys &m) { state = m.getRawFlags(); }
502     operator int() const { return state; }
isRightButtonCButtonState503     bool isRightButton() const { return (state & kRButton); }
isTouchCButtonState504     bool isTouch() const { return (state & kTouch); }
getButtonStateCButtonState505     int getButtonState() const { return state; }
506 };
507 
508 enum CMouseWheelAxis
509 {
510     kMouseWheelAxisX,
511     kMouseWheelAxisY
512 };
513 
514 struct CLineStyle
515 {
516     enum LineCap
517     {
518         kLineCapButt = 0,
519         kLineCapRound,
520         kLineCapSquare
521     };
522 
523     enum LineJoin
524     {
525         kLineJoinMiter = 0,
526         kLineJoinRound,
527         kLineJoinBevel
528     };
CLineStyleCLineStyle529     constexpr CLineStyle() {}
530     constexpr CLineStyle(const LineCap c, const LineJoin j, int a = 0, int b = 0, bool cb = false)
531     {
532     }
533 };
534 
535 constexpr CLineStyle kLineSolid;
536 
537 struct CDrawMode
538 {
539     CDrawMode() = default;
CDrawModeCDrawMode540     CDrawMode(const CDrawModeFlags &f) { OKUNIMPL; }
CDrawModeCDrawMode541     CDrawMode(uint32_t x) { OKUNIMPL; }
542 };
543 
544 struct CGraphicsTransform
545 {
546     juce::AffineTransform juceT;
CGraphicsTransformCGraphicsTransform547     CGraphicsTransform(const juce::AffineTransform &t) : juceT(t) {}
548 
CGraphicsTransformCGraphicsTransform549     CGraphicsTransform() {}
scaleCGraphicsTransform550     CGraphicsTransform scale(float sx, float sy)
551     {
552         return CGraphicsTransform(juceT.scaled(sx, sy));
553     }
translateCGraphicsTransform554     CGraphicsTransform translate(float dx, float dy)
555     {
556         return CGraphicsTransform(juceT.translated(dx, dy));
557     }
inverseCGraphicsTransform558     CGraphicsTransform inverse() { return CGraphicsTransform(juceT.inverted()); }
559 
transformCGraphicsTransform560     CRect transform(CRect &r)
561     {
562         auto jr = r.asJuceFloatRect();
563         auto tl = jr.getTopLeft();
564         auto br = jr.getBottomRight();
565 
566         juceT.transformPoint(tl.x, tl.y);
567         juceT.transformPoint(br.x, br.y);
568 
569         r = CRect(tl.x, tl.y, br.x, br.y);
570         return r;
571     }
transformCGraphicsTransform572     CPoint transform(CPoint &r)
573     {
574         float x = r.x;
575         float y = r.y;
576         juceT.transformPoint(x, y);
577         r.x = x;
578         r.y = y;
579         return CPoint(x, y);
580     }
581 };
582 
583 // Sure why not.
584 enum CTxtFace
585 {
586     kNormalFace = 0,
587     kBoldFace = 1 << 1,
588     kItalicFace = 1 << 2,
589     kUnderlineFace = 1 << 3,
590     kStrikethroughFace = 1 << 4
591 };
592 
593 struct CFontInternal
594 {
595     juce::Font font;
CFontInternalCFontInternal596     CFontInternal() {}
CFontInternalCFontInternal597     CFontInternal(const juce::Font &f) : font(f) {}
getSizeCFontInternal598     float getSize() { return font.getHeight(); }
599     void setStyle(int newStyle = kNormalFace) { OKUNIMPL; }
600     void setSize(int newSize = 12) { OKUNIMPL; }
rememberCFontInternal601     void remember() {}
forgetCFontInternal602     void forget() {}
603 };
604 typedef std::shared_ptr<CFontInternal> CFontRef; // this is a gross signature
605 
606 struct CGraphicsPath : public Internal::FakeRefcount
607 {
608     juce::Path path;
beginSubpathCGraphicsPath609     void beginSubpath(float x, float y) { path.startNewSubPath(x, y); }
addLineCGraphicsPath610     void addLine(float x, float y) { path.lineTo(x, y); }
611 };
612 
613 struct CDrawContext
614 {
615     typedef std::vector<CPoint> PointList;
616     enum PathDrawMode
617     {
618         kPathFilled = 1,
619         kPathStroked = 2
620     };
621 
622     juce::Graphics &g;
CDrawContextCDrawContext623     explicit CDrawContext(juce::Graphics &g) : g(g) {}
624 
setLineStyleCDrawContext625     void setLineStyle(const CLineStyle &s) { OKUNIMPL; }
setDrawModeCDrawContext626     void setDrawMode(uint32_t m) { OKUNIMPL; }
setDrawModeCDrawContext627     void setDrawMode(const CDrawMode &m) { OKUNIMPL; }
getDrawModeCDrawContext628     CDrawMode getDrawMode()
629     {
630         OKUNIMPL;
631         return CDrawMode();
632     }
getStringWidthCDrawContext633     float getStringWidth(const std::string &s) { return font->font.getStringWidth(s); }
fillLinearGradientCDrawContext634     void fillLinearGradient(CGraphicsPath *p, const CGradient &cg, const CPoint &, const CPoint &,
635                             bool, CGraphicsTransform *tf)
636     {
637         g.setGradientFill(*(cg.grad));
638         g.fillPath(p->path, tf->juceT);
639     }
640 
641     struct Transform
642     {
643         juce::Graphics *g = nullptr;
TransformCDrawContext::Transform644         Transform(CDrawContext &dc, CGraphicsTransform &tf)
645         {
646             dc.g.saveState();
647             dc.g.addTransform(tf.juceT);
648             g = &(dc.g);
649         }
~TransformCDrawContext::Transform650         ~Transform() { g->restoreState(); }
651     };
652 
saveGlobalStateCDrawContext653     void saveGlobalState() { g.saveState(); }
654 
restoreGlobalStateCDrawContext655     void restoreGlobalState() { g.restoreState(); }
656 
getClipRectCDrawContext657     void getClipRect(CRect &r) const { UNIMPL; }
setClipRectCDrawContext658     void setClipRect(const CRect &r) { g.reduceClipRegion(r.asJuceIntRect()); }
659 
660     float lineWidth = 1;
setLineWidthCDrawContext661     void setLineWidth(float w) { lineWidth = w; }
getLineWidthCDrawContext662     float getLineWidth() { return lineWidth; }
663 
664     juce::Colour fillColor = juce::Colour(255, 0, 0), frameColor = juce::Colour(255, 0, 0),
665                  fontColor = juce::Colour(255, 0, 0);
setFontColorCDrawContext666     void setFontColor(const CColor &c) { fontColor = c.asJuceColour(); }
getFontColorCDrawContext667     CColor getFontColor()
668     {
669         UNIMPL;
670         return CColor();
671     }
672 
setFillColorCDrawContext673     void setFillColor(const CColor &c) { fillColor = c.asJuceColour(); }
674 
setFrameColorCDrawContext675     void setFrameColor(const CColor &c) { frameColor = c.asJuceColour(); }
676 
677     void drawRect(const CRect &r, CDrawStyle s = kDrawStroked)
678     {
679         switch (s)
680         {
681         case kDrawFilled:
682         {
683             g.setColour(fillColor);
684             g.fillRect(r.asJuceFloatRect());
685             break;
686         }
687         case kDrawStroked:
688         {
689             g.setColour(frameColor);
690             g.drawRect(r.asJuceFloatRect());
691             break;
692         }
693         case kDrawFilledAndStroked:
694         {
695             g.setColour(fillColor);
696             g.fillRect(r.asJuceFloatRect());
697             g.setColour(frameColor);
698             g.drawRect(r.asJuceFloatRect());
699         }
700         }
701     }
702 
drawPolygonCDrawContext703     void drawPolygon(const std::vector<CPoint> &l, CDrawStyle s)
704     {
705         juce::Path path;
706         bool started = false;
707         for (auto &p : l)
708         {
709             if (!started)
710                 path.startNewSubPath(p);
711             else
712                 path.lineTo(p);
713         }
714         g.setColour(kRedCColor.asJuceColour());
715         g.fillPath(path);
716         OKUNIMPL;
717     }
718 
createRoundRectGraphicsPathCDrawContext719     CGraphicsPath *createRoundRectGraphicsPath(const CRect &r, float radius)
720     {
721         auto ct = new CGraphicsPath();
722         ct->path.addRoundedRectangle(r.left, r.top, r.getWidth(), r.getHeight(), radius);
723         ct->remember();
724         return ct;
725     }
726 
727     void drawGraphicsPath(CGraphicsPath *p, int style, CGraphicsTransform *tf = nullptr)
728     {
729         g.setColour(frameColor);
730         if (tf)
731         {
732             g.strokePath(p->path, juce::PathStrokeType(1.0), tf->juceT);
733         }
734         else
735         {
736             g.strokePath(p->path, juce::PathStrokeType(1.0));
737         }
738     }
drawLineCDrawContext739     void drawLine(const CPoint &start, const CPoint &end)
740     {
741         g.setColour(frameColor);
742         g.drawLine(start.x, start.y, end.x, end.y);
743     }
744 
745     CFontRef font;
setFontCDrawContext746     void setFont(CFontRef f) { font = f; }
getFontCDrawContext747     CFontRef getFont() { return font; }
748 
749     void drawString(const char *t, const CRect &r, int align = kLeftText, bool = true)
750     {
751         auto al = juce::Justification::centredLeft;
752         if (align == kCenterText)
753             al = juce::Justification::centred;
754         if (align == kRightText)
755             al = juce::Justification::centredRight;
756 
757         g.setFont(font->font);
758         g.setColour(fontColor);
759         g.drawText(juce::CharPointer_UTF8(t), r, al);
760     }
761     void drawString(const char *c, const CPoint &p, int = 0, bool = true)
762     {
763         OKUNIMPL;
764         auto w = font->font.getStringWidth(juce::CharPointer_UTF8(c));
765         auto h = font->font.getHeight();
766         auto r = CRect(CPoint(p.x, p.y - h), CPoint(w, h));
767         drawString(c, r);
768     }
drawEllipseCDrawContext769     void drawEllipse(const CRect &r, const CDrawStyle &s)
770     {
771         if (s == kDrawFilled || s == kDrawFilledAndStroked)
772         {
773             g.setColour(fillColor);
774             g.fillEllipse(r);
775         }
776         if (s == kDrawStroked || s == kDrawFilledAndStroked)
777         {
778             g.setColour(frameColor);
779             g.drawEllipse(r, lineWidth);
780         }
781     }
782 
createGraphicsPathCDrawContext783     CGraphicsPath *createGraphicsPath()
784     {
785         auto res = new CGraphicsPath();
786         res->remember();
787         return res;
788     }
789 };
790 
791 struct COffscreenContext : public CDrawContext
792 {
793     static COffscreenContext *create(CFrame *frame, CCoord width, CCoord height,
794                                      double scaleFactor = 1.);
beginDrawCOffscreenContext795     void beginDraw() { UNIMPL; }
endDrawCOffscreenContext796     void endDraw() { UNIMPL; }
getBitmapCOffscreenContext797     CBitmap *getBitmap()
798     {
799         UNIMPL;
800         return nullptr;
801     }
802 };
803 
804 struct CResourceDescription
805 {
806     enum Type : uint32_t
807     {
808         kIntegerType = 0
809     };
CResourceDescriptionCResourceDescription810     CResourceDescription(int id)
811     {
812         u.id = id;
813         u.type = kIntegerType;
814     }
815     Type type;
816     struct U
817     {
818         int32_t id = 0;
819         Type type = kIntegerType;
820     } u;
821 };
822 
823 struct CBitmap : public Internal::FakeRefcount
824 {
CBitmapCBitmap825     CBitmap(const CResourceDescription &d) : desc(d), Internal::FakeRefcount(false, false) {}
~CBitmapCBitmap826     virtual ~CBitmap()
827     {
828         // std::cout << " Deleting bitmap with " << desc.u.id << std::endl;
829     }
830 
831     virtual void draw(CDrawContext *dc, const CRect &r, const CPoint &off = CPoint(),
832                       float alpha = 1.0)
833     {
834         juce::Graphics::ScopedSaveState gs(dc->g);
835         auto tl = r.asJuceIntRect().getTopLeft();
836 
837         auto t = juce::AffineTransform().translated(tl.x, tl.y).translated(-off.x, -off.y);
838         dc->g.reduceClipRegion(r.asJuceIntRect());
839         drawable->draw(dc->g, alpha, t);
840     }
841     CResourceDescription desc;
842     std::unique_ptr<juce::Drawable> drawable;
843 };
844 
845 struct CViewBase;
846 
847 struct OnRemovedHandler
848 {
849     virtual void onRemoved() = 0;
850 };
851 
852 template <typename T> struct juceCViewConnector : public T, public OnRemovedHandler
853 {
juceCViewConnectorjuceCViewConnector854     juceCViewConnector() : T() {}
855     ~juceCViewConnector();
856     void setViewCompanion(CViewBase *v);
857     void onRemoved() override;
858 
859     CViewBase *viewCompanion = nullptr;
860     void paint(juce::Graphics &g) override;
861 
862     CMouseEventResult traverseMouseParents(
863         const juce::MouseEvent &e,
864         std::function<CMouseEventResult(CViewBase *, const CPoint &, const CButtonState &)> vf,
865         std::function<void(const juce::MouseEvent &)> jf);
866 
867     void mouseDown(const juce::MouseEvent &e) override;
868     void mouseUp(const juce::MouseEvent &e) override;
869     void mouseEnter(const juce::MouseEvent &e) override;
870     void mouseExit(const juce::MouseEvent &e) override;
871     void mouseMove(const juce::MouseEvent &e) override;
872     void mouseDrag(const juce::MouseEvent &e) override;
873     void mouseDoubleClick(const juce::MouseEvent &e) override;
874     void mouseWheelMove(const juce::MouseEvent &event,
875                         const juce::MouseWheelDetails &wheel) override;
876     void mouseMagnify(const juce::MouseEvent &event, float scaleFactor) override;
877     bool supressMoveAndUp = false;
878 };
879 
880 struct CView;
881 
882 // Clena this up obviously
883 struct CViewBase : public Internal::FakeRefcount
884 {
CViewBaseCViewBase885     CViewBase(const CRect &size) : size(size), ma(size) {}
~CViewBaseCViewBase886     virtual ~CViewBase(){
887         // Here we probably have to make sure that the juce component is removed
888     };
889     virtual juce::Component *juceComponent() = 0;
890 
drawCViewBase891     virtual void draw(CDrawContext *dc){};
getViewSizeCViewBase892     CRect getViewSize()
893     {
894         // FIXME - this should reajju just use the cast-operator
895         auto b = juceComponent()->getBounds();
896         return CRect(CPoint(b.getX(), b.getY()),
897                      CPoint(juceComponent()->getWidth(), juceComponent()->getHeight()));
898     }
899 
getTopLeftCViewBase900     CPoint getTopLeft()
901     {
902         auto b = juceComponent()->getBounds();
903         return CPoint(b.getX(), b.getY());
904     }
905 
setViewSizeCViewBase906     void setViewSize(const CRect &r) { juceComponent()->setBounds(r.asJuceIntRect()); }
getHeightCViewBase907     float getHeight() { return juceComponent()->getHeight(); }
getWidthCViewBase908     float getWidth() { return juceComponent()->getWidth(); }
909 
magnifyCViewBase910     virtual bool magnify(CPoint &where, float amount) { return false; }
911 
onMouseDownCViewBase912     virtual CMouseEventResult onMouseDown(CPoint &where, const CButtonState &buttons)
913     {
914         return kMouseEventNotHandled;
915     }
916 
onMouseUpCViewBase917     virtual CMouseEventResult onMouseUp(CPoint &where, const CButtonState &buttons)
918     {
919         return kMouseEventNotHandled;
920     }
921 
onMouseEnteredCViewBase922     virtual CMouseEventResult onMouseEntered(CPoint &where, const CButtonState &buttons)
923     {
924         return kMouseEventNotHandled;
925     }
926 
onMouseExitedCViewBase927     virtual CMouseEventResult onMouseExited(CPoint &where, const CButtonState &buttons)
928     {
929         return kMouseEventNotHandled;
930     }
931 
onMouseMovedCViewBase932     virtual CMouseEventResult onMouseMoved(CPoint &where, const CButtonState &buttons)
933     {
934         return kMouseEventNotHandled;
935     }
936 
onWheelCViewBase937     virtual bool onWheel(const CPoint &where, const float &distance, const CButtonState &buttons)
938     {
939         return false;
940     }
941 
onWheelCViewBase942     virtual bool onWheel(const CPoint &where, const CMouseWheelAxis &, const float &distance,
943                          const CButtonState &buttons)
944     {
945         return false;
946     }
947 
invalidCViewBase948     void invalid() { juceComponent()->repaint(); }
949 
950     CRect ma;
getMouseableAreaCViewBase951     CRect getMouseableArea() { return ma; }
setMouseableAreaCViewBase952     void setMouseableArea(const CRect &r) { ma = r; }
setMouseEnabledCViewBase953     void setMouseEnabled(bool b) { OKUNIMPL; }
localToFrameCViewBase954     CPoint localToFrame(CPoint &w)
955     {
956         UNIMPL;
957         return w;
958     }
959 
960     void setDirty(bool b = true)
961     {
962         if (b)
963             invalid();
964     }
isDirtyCViewBase965     bool isDirty()
966     {
967         OKUNIMPL;
968         return true;
969     }
setVisibleCViewBase970     void setVisible(bool b)
971     {
972         if (juceComponent())
973             juceComponent()->setVisible(b);
974     }
isVisibleCViewBase975     bool isVisible()
976     {
977         if (juceComponent())
978             return juceComponent()->isVisible();
979         return false;
980     }
setSizeCViewBase981     void setSize(const CRect &s) { UNIMPL; }
setSizeCViewBase982     void setSize(float w, float h) { juceComponent()->setBounds(0, 0, w, h); }
983     CRect size;
984 
985     CView *parentView = nullptr;
getParentViewCViewBase986     CView *getParentView() { return parentView; }
987 
988     CFrame *frame = nullptr;
989     CFrame *getFrame();
990 };
991 
992 struct CView : public CViewBase
993 {
CViewCView994     CView(const CRect &size) : CViewBase(size) {}
~CViewCView995     ~CView() {}
996 
onAddedCView997     virtual void onAdded() {}
efvg_resolveDeferredAddsCView998     virtual void efvg_resolveDeferredAdds(){};
999 
1000     std::unique_ptr<juceCViewConnector<juce::Component>> comp;
juceComponentCView1001     juce::Component *juceComponent() override
1002     {
1003         if (!comp)
1004         {
1005             comp = std::make_unique<juceCViewConnector<juce::Component>>();
1006             comp->setBounds(size.asJuceIntRect());
1007             comp->setViewCompanion(this);
1008         }
1009         return comp.get();
1010     }
1011 
1012     EscapeFromVSTGUI::JuceVSTGUIEditorAdapterBase *ed = nullptr; // FIX ME obviously
1013 };
1014 
1015 #define GSPAIR(x, sT, gT, gTV)                                                                     \
1016     gT m_##x = gTV;                                                                                \
1017     virtual void set##x(sT v) { m_##x = v; }                                                       \
1018     virtual gT get##x() const { return m_##x; }
1019 
1020 #define COLPAIR(x)                                                                                 \
1021     CColor m_##x;                                                                                  \
1022     virtual void set##x(const CColor &v) { m_##x = v; }                                            \
1023     virtual CColor get##x() const { return m_##x; }
1024 
getFrame()1025 inline CFrame *CViewBase::getFrame()
1026 {
1027     if (!frame)
1028     {
1029         if (parentView)
1030         {
1031             return parentView->getFrame();
1032         }
1033     }
1034     return frame;
1035 }
1036 
1037 struct CViewContainer : public CView
1038 {
CViewContainerCViewContainer1039     CViewContainer(const CRect &size) : CView(size) {}
~CViewContainerCViewContainer1040     ~CViewContainer()
1041     {
1042         for (auto e : views)
1043         {
1044             e->forget();
1045         }
1046         views.clear();
1047     }
1048     bool transparent = false;
setTransparencyCViewContainer1049     void setTransparency(bool b) { transparent = b; }
1050 
1051     CBitmap *bg = nullptr;
setBackgroundCViewContainer1052     void setBackground(CBitmap *b)
1053     {
1054         b->remember();
1055         if (bg)
1056             bg->forget();
1057         bg = b;
1058     }
1059     CColor bgcol;
setBackgroundColorCViewContainer1060     void setBackgroundColor(const CColor &c) { bgcol = c; }
getNbViewsCViewContainer1061     int getNbViews() { return views.size(); }
getViewCViewContainer1062     CView *getView(int i)
1063     {
1064         if (i >= 0 && i < views.size())
1065             return views[i];
1066         return nullptr;
1067     }
1068 
onAddedCViewContainer1069     void onAdded() override {}
addViewCViewContainer1070     void addView(CView *v)
1071     {
1072         if (!v)
1073             return;
1074 
1075         v->remember();
1076         v->ed = ed;
1077         v->frame = frame;
1078         v->parentView = this;
1079         auto jc = v->juceComponent();
1080         if (jc && ed)
1081         {
1082             juceComponent()->addAndMakeVisible(*jc);
1083             v->efvg_resolveDeferredAdds();
1084             v->onAdded();
1085         }
1086         else
1087         {
1088             deferredAdds.push_back(v);
1089         }
1090         views.push_back(v);
1091     }
1092 
1093     std::unordered_set<std::unique_ptr<juce::Component>> rawAddedComponents;
takeOwnershipCViewContainer1094     virtual void takeOwnership(std::unique_ptr<juce::Component> c)
1095     {
1096         rawAddedComponents.insert(std::move(c));
1097     }
1098 
1099     void removeViewInternals(CView *v, bool forgetChildren = true)
1100     {
1101         auto cvc = dynamic_cast<CViewContainer *>(v);
1102         if (cvc)
1103         {
1104             cvc->removeAll(forgetChildren);
1105         }
1106 
1107         juceComponent()->removeChildComponent(v->juceComponent());
1108         auto orh = dynamic_cast<OnRemovedHandler *>(v->juceComponent());
1109         if (orh)
1110         {
1111             orh->onRemoved();
1112         }
1113         v->parentView = nullptr;
1114     }
1115     void removeView(CView *v, bool doForget = true)
1116     {
1117         auto pos = std::find(views.begin(), views.end(), v);
1118         if (pos == views.end())
1119         {
1120             std::cout << "WIERD ERROR";
1121             jassert(false);
1122             return;
1123         }
1124         removeViewInternals(v, doForget);
1125         views.erase(pos);
1126         if (doForget)
1127             v->forget();
1128         invalid();
1129     }
1130 
1131     /*void addView(COptionMenu *)
1132     {
1133         // JUCE menus work differently
1134     }
1135     void removeView(COptionMenu *, bool)
1136     {
1137         // Juce menus work differently
1138     }*/
1139 
getViewAtCViewContainer1140     CView *getViewAt(const CPoint &p)
1141     {
1142         UNIMPL;
1143         return nullptr;
1144     }
isChildCViewContainer1145     bool isChild(CView *v)
1146     {
1147         UNIMPL;
1148         return true;
1149     }
getFocusViewCViewContainer1150     CView *getFocusView()
1151     {
1152         // UNIMPL;
1153         // FIXME!!
1154         return nullptr;
1155     }
1156     void removeAll(bool b = true)
1157     {
1158         for (auto &j : rawAddedComponents)
1159         {
1160             juceComponent()->removeChildComponent(j.get());
1161         }
1162         rawAddedComponents.clear();
1163 
1164         for (auto e : views)
1165         {
1166             removeViewInternals(e, b);
1167             if (b)
1168             {
1169                 e->forget();
1170             }
1171         }
1172         views.clear();
1173     }
drawCViewContainer1174     void draw(CDrawContext *dc) override
1175     {
1176         if (bg)
1177         {
1178             bg->draw(dc, getViewSize());
1179         }
1180         else if (!transparent)
1181         {
1182             dc->setFillColor(bgcol);
1183             dc->drawRect(getViewSize(), kDrawFilled);
1184         }
1185         else
1186         {
1187         }
1188     }
1189 
onMouseDownCViewContainer1190     CMouseEventResult onMouseDown(CPoint &where, const CButtonState &buttons) override
1191     {
1192         return kMouseEventNotHandled;
1193     }
efvg_resolveDeferredAddsCViewContainer1194     void efvg_resolveDeferredAdds() override
1195     {
1196         for (auto v : deferredAdds)
1197         {
1198             v->ed = ed;
1199             juceComponent()->addAndMakeVisible(v->juceComponent());
1200             v->efvg_resolveDeferredAdds();
1201         }
1202         deferredAdds.clear();
1203     }
1204 
1205     std::vector<CView *> deferredAdds;
1206     std::vector<CView *> views;
1207 };
1208 
1209 struct CFrame : public CViewContainer
1210 {
CFrameCFrame1211     CFrame(CRect &rect, EscapeFromVSTGUI::JuceVSTGUIEditorAdapterBase *ed) : CViewContainer(rect)
1212     {
1213         this->ed = ed;
1214         this->frame = this;
1215 
1216         juceComponent()->setBounds(rect.asJuceIntRect());
1217         ed->getJuceEditor()->addAndMakeVisible(juceComponent());
1218     }
1219     ~CFrame() = default;
1220 
drawCFrame1221     void draw(CDrawContext *dc) override { CViewContainer::draw(dc); }
setCursorCFrame1222     void setCursor(CCursorType c)
1223     {
1224         auto ct = juce::MouseCursor::StandardCursorType::NormalCursor;
1225         switch (c)
1226         {
1227         case kCursorDefault:
1228             break;
1229         case kCursorWait:
1230             ct = juce::MouseCursor::StandardCursorType::WaitCursor;
1231             break;
1232         case kCursorHSize:
1233             ct = juce::MouseCursor::StandardCursorType::LeftRightResizeCursor;
1234             break;
1235         case kCursorVSize:
1236             ct = juce::MouseCursor::StandardCursorType::UpDownResizeCursor;
1237             break;
1238         case kCursorSizeAll:
1239             ct = juce::MouseCursor::StandardCursorType::UpDownLeftRightResizeCursor;
1240             break;
1241         case kCursorNESWSize:
1242             ct = juce::MouseCursor::StandardCursorType::TopLeftCornerResizeCursor;
1243             break;
1244         case kCursorNWSESize:
1245             ct = juce::MouseCursor::StandardCursorType::TopRightCornerResizeCursor;
1246             break;
1247         case kCursorCopy:
1248             ct = juce::MouseCursor::StandardCursorType::CopyingCursor;
1249             break;
1250         case kCursorHand:
1251             ct = juce::MouseCursor::StandardCursorType::PointingHandCursor;
1252             break;
1253         case kCursorIBeam:
1254             ct = juce::MouseCursor::StandardCursorType::IBeamCursor;
1255             break;
1256         case kCursorNotAllowed: // what is this?
1257             ct = juce::MouseCursor::StandardCursorType::CrosshairCursor;
1258             break;
1259         }
1260 
1261         ed->getJuceEditor()->setMouseCursor(juce::MouseCursor(ct));
1262     }
invalidCFrame1263     void invalid()
1264     {
1265         for (auto v : views)
1266             v->invalid();
1267     }
invalidRectCFrame1268     void invalidRect(const CRect &r) { invalid(); }
1269     void setDirty(bool b = true) { invalid(); }
1270 
openCFrame1271     void open(void *parent, int) { OKUNIMPL; }
closeCFrame1272     void close() { removeAll(); }
1273 
1274     COLPAIR(FocusColor);
1275 
localToFrameCFrame1276     void localToFrame(CRect &r) { UNIMPL; }
localToFrameCFrame1277     void localToFrame(CPoint &p) { UNIMPL; };
setZoomCFrame1278     void setZoom(float z) { OKUNIMPL; }
getTransformCFrame1279     CGraphicsTransform getTransform() { return CGraphicsTransform(); }
getPositionCFrame1280     void getPosition(float &x, float &y)
1281     {
1282         auto b = juceComponent()->getScreenPosition();
1283         x = b.x;
1284         y = b.y;
1285     }
getCurrentMouseLocationCFrame1286     void getCurrentMouseLocation(CPoint &w)
1287     {
1288         auto pq = juce::Desktop::getInstance().getMainMouseSource().getScreenPosition();
1289         auto b = juceComponent()->getLocalPoint(nullptr, pq);
1290         w.x = b.x;
1291         w.y = b.y;
1292     }
getCurrentMouseButtonsCFrame1293     CButtonState getCurrentMouseButtons() { return CButtonState(); }
1294 };
1295 
1296 struct CControl;
1297 struct IControlListener
1298 {
1299     virtual void valueChanged(CControl *p) = 0;
controlModifierClickedIControlListener1300     virtual int32_t controlModifierClicked(CControl *p, CButtonState s) { return false; }
1301 
controlBeginEditIControlListener1302     virtual void controlBeginEdit(CControl *control){};
controlEndEditIControlListener1303     virtual void controlEndEdit(CControl *control){};
1304 };
1305 
1306 struct IKeyboardHook
1307 {
1308     virtual int32_t onKeyDown(const VstKeyCode &code, CFrame *frame) = 0;
1309     virtual int32_t onKeyUp(const VstKeyCode &code, CFrame *frame) = 0;
1310 };
1311 
1312 struct CControl : public CView
1313 {
1314     CControl(const CRect &r, IControlListener *l = nullptr, int32_t tag = 0, CBitmap *bg = nullptr)
CViewCControl1315         : CView(r), listener(l), tag(tag)
1316     {
1317         juceComponent()->setBounds(r.asJuceIntRect());
1318         setBackground(bg);
1319     }
~CControlCControl1320     ~CControl()
1321     {
1322         /* if (bg)
1323             bg->forget();
1324             It seems that is not the semantic of CControl!
1325             */
1326     }
1327 
looseFocusCControl1328     virtual void looseFocus() { UNIMPL; }
takeFocusCControl1329     virtual void takeFocus() { UNIMPL; }
getMouseButtonsCControl1330     CButtonState getMouseButtons() { return CButtonState(); }
getRangeCControl1331     virtual float getRange()
1332     {
1333         UNIMPL;
1334         return 0;
1335     }
getValueCControl1336     virtual float getValue() { return value; }
setValueCControl1337     virtual void setValue(float v) { value = v; }
setDefaultValueCControl1338     virtual void setDefaultValue(float v) { vdef = v; }
setVisibleCControl1339     virtual void setVisible(bool b)
1340     {
1341         if (juceComponent())
1342             juceComponent()->setVisible(b);
1343     }
setMouseEnabledCControl1344     virtual void setMouseEnabled(bool) { UNIMPL; }
getMouseEnabledCControl1345     virtual bool getMouseEnabled()
1346     {
1347         UNIMPL;
1348         return true;
1349     }
1350 
1351     uint32_t tag;
getTagCControl1352     virtual uint32_t getTag() { return tag; }
setMaxCControl1353     virtual void setMax(float f) { vmax = f; }
valueChangedCControl1354     void valueChanged() { UNIMPL; }
setMinCControl1355     virtual void setMin(float f) { vmin = f; }
bounceValueCControl1356     virtual void bounceValue() { UNIMPL; }
1357 
beginEditCControl1358     virtual void beginEdit()
1359     {
1360         if (listener)
1361             listener->controlBeginEdit(this);
1362     }
1363 
endEditCControl1364     virtual void endEdit()
1365     {
1366 
1367         if (listener)
1368             listener->controlEndEdit(this);
1369     }
1370 
1371     COLPAIR(BackColor);
1372 
1373     CBitmap *bg = nullptr;
setBackgroundCControl1374     void setBackground(CBitmap *b)
1375     {
1376         // This order in case b == bg
1377         if (b)
1378             b->remember();
1379         if (bg)
1380             bg->forget();
1381 
1382         bg = b;
1383     }
getBackgroundCControl1384     CBitmap *getBackground() { return bg; }
1385 
1386     GSPAIR(Font, CFontRef, CFontRef, std::make_shared<CFontInternal>());
1387 
1388     COLPAIR(FontColor);
1389     GSPAIR(Transparency, bool, bool, false);
1390     GSPAIR(HoriAlign, CHoriTxtAlign, CHoriTxtAlign, CHoriTxtAlign::kLeftText);
1391     COLPAIR(FrameColor);
1392     COLPAIR(TextColorHighlighted);
1393     COLPAIR(FrameColorHighlighted);
1394 
1395     GSPAIR(Gradient, CGradient *, CGradient *, nullptr);
1396     GSPAIR(GradientHighlighted, CGradient *, CGradient *, nullptr);
1397 
1398     COLPAIR(FillColor);
1399     COLPAIR(TextColor);
1400     COLPAIR(BackgroundColor);
1401 
1402     float value = 0.f;
1403     float vmax = 1.f;
1404     float vmin = 0.f;
1405     float vdef = 0.f;
1406     bool editing = false;
1407     IControlListener *listener = nullptr;
1408 };
1409 
1410 struct OfCourseItHasAStringType
1411 {
OfCourseItHasAStringTypeOfCourseItHasAStringType1412     OfCourseItHasAStringType(const char *x) : s(x) {}
OfCourseItHasAStringTypeOfCourseItHasAStringType1413     OfCourseItHasAStringType(const std::string &q) : s(q) {}
stringOfCourseItHasAStringType1414     operator std::string() const { return s; }
1415 
getStringOfCourseItHasAStringType1416     std::string getString() const { return s; }
1417 
1418     std::string s;
1419 };
1420 
1421 struct CTextLabel : public CControl
1422 {
CControlCTextLabel1423     CTextLabel(const CRect &r, const char *s, CBitmap *bg = nullptr) : CControl(r)
1424     {
1425         if (bg)
1426         {
1427             img = std::make_unique<juceCViewConnector<juce::Component>>();
1428             img->setBounds(r.asJuceIntRect());
1429             img->addAndMakeVisible(*(bg->drawable.get()));
1430             img->setViewCompanion(this);
1431         }
1432         else
1433         {
1434             lab = std::make_unique<juceCViewConnector<juce::Label>>();
1435             lab->setText(juce::CharPointer_UTF8(s), juce::dontSendNotification);
1436             lab->setBounds(r.asJuceIntRect());
1437             lab->setViewCompanion(this);
1438             lab->setJustificationType(juce::Justification::centred);
1439         }
1440     }
1441 
setBackColorCTextLabel1442     void setBackColor(const CColor &v) override
1443     {
1444         CControl::setBackColor(v);
1445         if (lab)
1446             lab->setColour(juce::Label::backgroundColourId, v.asJuceColour());
1447     }
1448 
setHoriAlignCTextLabel1449     void setHoriAlign(CHoriTxtAlign v) override
1450     {
1451         CControl::setHoriAlign(v);
1452         if (lab)
1453         {
1454             switch (v)
1455             {
1456             case kRightText:
1457                 lab->setJustificationType(juce::Justification::centredRight);
1458                 break;
1459             case kLeftText:
1460                 lab->setJustificationType(juce::Justification::centredLeft);
1461                 break;
1462             case kCenterText:
1463                 lab->setJustificationType(juce::Justification::centred);
1464                 break;
1465             }
1466         }
1467     }
setFontCTextLabel1468     void setFont(CFontRef v) override
1469     {
1470         if (lab)
1471             lab->setFont(v->font);
1472 
1473         CControl::setFont(v);
1474     }
juceComponentCTextLabel1475     juce::Component *juceComponent() override
1476     {
1477         if (lab)
1478             return lab.get();
1479         return img.get();
1480     }
1481 
onMouseDownCTextLabel1482     CMouseEventResult onMouseDown(CPoint &where, const CButtonState &buttons) override
1483     {
1484         std::cout << "TL OMD" << std::endl;
1485         return CViewBase::onMouseDown(where, buttons);
1486     }
1487 
setFontColorCTextLabel1488     void setFontColor(const CColor &v) override
1489     {
1490         CControl::setFontColor(v);
1491         if (lab)
1492         {
1493             lab->setColour(juce::Label::ColourIds::textColourId, v.asJuceColour());
1494         }
1495     }
1496 
setAntialiasCTextLabel1497     void setAntialias(bool b) { OKUNIMPL; }
1498     GSPAIR(Text, const OfCourseItHasAStringType &, OfCourseItHasAStringType, "");
1499     std::unique_ptr<juceCViewConnector<juce::Label>> lab;
1500     std::unique_ptr<juceCViewConnector<juce::Component>> img;
1501 };
1502 
1503 struct CTextEdit : public CControl, public juce::TextEditor::Listener
1504 {
1505     CTextEdit(const CRect &r, IControlListener *l = nullptr, long tag = -1,
1506               const char *txt = nullptr)
CControlCTextEdit1507         : CControl(r, l, tag)
1508     {
1509         texted = std::make_unique<juceCViewConnector<juce::TextEditor>>();
1510         texted->setText(juce::CharPointer_UTF8(txt), juce::dontSendNotification);
1511         texted->setBounds(r.asJuceIntRect());
1512         texted->setViewCompanion(this);
1513         texted->addListener(this);
1514     }
1515 
textEditorReturnKeyPressedCTextEdit1516     void textEditorReturnKeyPressed(juce::TextEditor &editor) override
1517     {
1518         if (listener)
1519             listener->valueChanged(this);
1520     }
1521 
setTextInsetCTextEdit1522     void setTextInset(const CPoint &inset) { OKUNIMPL; }
1523 
1524     std::unique_ptr<juceCViewConnector<juce::TextEditor>> texted;
juceComponentCTextEdit1525     juce::Component *juceComponent() override { return texted.get(); }
1526 
setTextCTextEdit1527     void setText(const OfCourseItHasAStringType &st)
1528     {
1529         texted->setText(juce::CharPointer_UTF8(st.getString().c_str()));
1530     }
getTextCTextEdit1531     OfCourseItHasAStringType getText()
1532     {
1533         return OfCourseItHasAStringType(texted->getText().toRawUTF8());
1534     }
1535 
1536     GSPAIR(ImmediateTextChange, bool, bool, true);
1537 };
1538 
1539 struct CCheckBox : public CControl
1540 {
1541     CCheckBox(const CRect &r, IControlListener *l = nullptr, long tag = -1,
1542               const char *txt = nullptr)
CControlCCheckBox1543         : CControl(r, l, tag)
1544     {
1545         UNIMPL;
1546     }
1547 
1548     COLPAIR(BoxFrameColor);
1549     COLPAIR(BoxFillColor);
1550     COLPAIR(CheckMarkColor);
sizeToFitCCheckBox1551     void sizeToFit() { OKUNIMPL; }
1552 };
1553 
1554 struct CTextButton : public CControl, juce::Button::Listener
1555 {
CTextButtonCTextButton1556     CTextButton(const CRect &r, IControlListener *l, int32_t tag, std::string lab)
1557         : CControl(r, l, tag)
1558     {
1559         textb = std::make_unique<juceCViewConnector<juce::TextButton>>();
1560         textb->setButtonText(juce::CharPointer_UTF8(lab.c_str()));
1561         textb->setBounds(r.asJuceIntRect());
1562         textb->setViewCompanion(this);
1563         textb->addListener(this);
1564     }
~CTextButtonCTextButton1565     ~CTextButton() {}
setRoundRadiusCTextButton1566     void setRoundRadius(float f) { OKUNIMPL; }
1567 
buttonClickedCTextButton1568     void buttonClicked(juce::Button *button) override
1569     {
1570         if (listener)
1571             listener->valueChanged(this);
1572     }
1573 
1574     GSPAIR(TextAlignment, CHoriTxtAlign, CHoriTxtAlign, CHoriTxtAlign::kCenterText);
1575     std::unique_ptr<juceCViewConnector<juce::TextButton>> textb;
juceComponentCTextButton1576     juce::Component *juceComponent() override { return textb.get(); }
1577 };
1578 
1579 struct CHorizontalSwitch : public CControl
1580 {
1581     // FIX THIS obviously
CHorizontalSwitchCHorizontalSwitch1582     CHorizontalSwitch(const CRect &size, IControlListener *listener, int32_t tag, int frames,
1583                       int height, int width, CBitmap *background, CPoint offset)
1584         : CControl(size, listener, tag), heightOfOneImage(height)
1585     {
1586         setBackground(background);
1587     }
1588     float heightOfOneImage = 0;
1589 };
1590 
1591 struct CSlider : public CControl
1592 {
1593     enum
1594     {
1595         kHorizontal = 1U << 0U,
1596         kVertical = 1U << 1U,
1597         kTop = 1U << 31U,
1598         kRight = kTop,
1599         kBottom = kTop,
1600     };
1601 };
1602 
~juceCViewConnector()1603 template <typename T> inline juceCViewConnector<T>::~juceCViewConnector() {}
1604 
onRemoved()1605 template <typename T> inline void juceCViewConnector<T>::onRemoved()
1606 {
1607     // Internal::enqueueForget(viewCompanion);
1608     viewCompanion = nullptr;
1609 }
setViewCompanion(CViewBase * v)1610 template <typename T> inline void juceCViewConnector<T>::setViewCompanion(CViewBase *v)
1611 {
1612     viewCompanion = v;
1613     // viewCompanion->remember();
1614 }
1615 
paint(juce::Graphics & g)1616 template <typename T> inline void juceCViewConnector<T>::paint(juce::Graphics &g)
1617 {
1618     if (viewCompanion)
1619     {
1620         auto dc = std::make_unique<CDrawContext>(g);
1621         auto b = T::getBounds();
1622         auto t = juce::AffineTransform().translated(-b.getX(), -b.getY());
1623         juce::Graphics::ScopedSaveState gs(g);
1624         g.addTransform(t);
1625         viewCompanion->draw(dc.get());
1626     }
1627     T::paint(g);
1628 }
1629 
1630 template <typename T>
traverseMouseParents(const juce::MouseEvent & e,std::function<CMouseEventResult (CViewBase *,const CPoint &,const CButtonState &)> vf,std::function<void (const juce::MouseEvent &)> jf)1631 inline CMouseEventResult juceCViewConnector<T>::traverseMouseParents(
1632     const juce::MouseEvent &e,
1633     std::function<CMouseEventResult(CViewBase *, const CPoint &, const CButtonState &)> vf,
1634     std::function<void(const juce::MouseEvent &)> jf)
1635 {
1636     auto b = T::getBounds().getTopLeft();
1637     CPoint w(e.x + b.x, e.y + b.y);
1638     CViewBase *curr = viewCompanion;
1639     auto r = kMouseEventNotHandled;
1640     while (curr && r == kMouseEventNotHandled)
1641     {
1642         r = vf(curr, w, CButtonState(e.mods));
1643         curr = curr->getParentView();
1644     }
1645     if (r == kMouseEventNotHandled)
1646     {
1647         jf(e);
1648     }
1649 
1650     return r;
1651 }
1652 
mouseDown(const juce::MouseEvent & e)1653 template <typename T> inline void juceCViewConnector<T>::mouseDown(const juce::MouseEvent &e)
1654 {
1655     supressMoveAndUp = false;
1656     auto res = traverseMouseParents(
1657         e, [](auto *a, auto b, auto c) { return a->onMouseDown(b, c); },
1658         [this](auto e) { T::mouseDown(e); });
1659     if (res == kMouseDownEventHandledButDontNeedMovedOrUpEvents)
1660         supressMoveAndUp = true;
1661 }
1662 
mouseUp(const juce::MouseEvent & e)1663 template <typename T> inline void juceCViewConnector<T>::mouseUp(const juce::MouseEvent &e)
1664 {
1665     if (!supressMoveAndUp)
1666     {
1667         traverseMouseParents(
1668             e, [](auto *a, auto b, auto c) { return a->onMouseUp(b, c); },
1669             [this](auto e) { T::mouseUp(e); });
1670     }
1671     supressMoveAndUp = false;
1672 }
mouseMove(const juce::MouseEvent & e)1673 template <typename T> inline void juceCViewConnector<T>::mouseMove(const juce::MouseEvent &e)
1674 {
1675     // Don't supress check here because only DRAG will be called in the down
1676     traverseMouseParents(
1677         e, [](auto *a, auto b, auto c) { return a->onMouseMoved(b, c); },
1678         [this](auto e) { T::mouseMove(e); });
1679 }
1680 
mouseDrag(const juce::MouseEvent & e)1681 template <typename T> inline void juceCViewConnector<T>::mouseDrag(const juce::MouseEvent &e)
1682 {
1683     if (supressMoveAndUp)
1684         return;
1685     traverseMouseParents(
1686         e, [](auto *a, auto b, auto c) { return a->onMouseMoved(b, c); },
1687         [this](auto e) { T::mouseDrag(e); });
1688 }
1689 
mouseEnter(const juce::MouseEvent & e)1690 template <typename T> inline void juceCViewConnector<T>::mouseEnter(const juce::MouseEvent &e)
1691 {
1692     traverseMouseParents(
1693         e, [](auto *a, auto b, auto c) { return a->onMouseEntered(b, c); },
1694         [this](auto e) { T::mouseEnter(e); });
1695 }
mouseExit(const juce::MouseEvent & e)1696 template <typename T> inline void juceCViewConnector<T>::mouseExit(const juce::MouseEvent &e)
1697 {
1698     traverseMouseParents(
1699         e, [](auto *a, auto b, auto c) { return a->onMouseExited(b, c); },
1700         [this](auto e) { T::mouseExit(e); });
1701 }
1702 
mouseDoubleClick(const juce::MouseEvent & e)1703 template <typename T> inline void juceCViewConnector<T>::mouseDoubleClick(const juce::MouseEvent &e)
1704 {
1705     OKUNIMPL; // wanna do parent thing
1706     auto b = T::getBounds().getTopLeft();
1707     CPoint w(e.x + b.x, e.y + b.y);
1708     auto bs = CButtonState() | kDoubleClick;
1709 
1710     auto r = viewCompanion->onMouseDown(w, CButtonState(bs));
1711     if (r == kMouseEventNotHandled)
1712     {
1713         T::mouseDoubleClick(e);
1714     }
1715 }
1716 template <typename T>
mouseWheelMove(const juce::MouseEvent & e,const juce::MouseWheelDetails & wheel)1717 inline void juceCViewConnector<T>::mouseWheelMove(const juce::MouseEvent &e,
1718                                                   const juce::MouseWheelDetails &wheel)
1719 {
1720     auto b = T::getBounds().getTopLeft();
1721     CPoint w(e.x + b.x, e.y + b.y);
1722 
1723     OKUNIMPL;
1724     float mouseScaleFactor = 3;
1725 
1726     auto r = viewCompanion->onWheel(w, kMouseWheelAxisX, mouseScaleFactor * wheel.deltaX,
1727                                     CButtonState()) ||
1728              viewCompanion->onWheel(w, kMouseWheelAxisY, -mouseScaleFactor * wheel.deltaY,
1729                                     CButtonState());
1730 
1731     if (!r)
1732     {
1733         r = viewCompanion->onWheel(w, -mouseScaleFactor * wheel.deltaY, CButtonState());
1734     }
1735     if (!r)
1736     {
1737         T::mouseWheelMove(e, wheel);
1738     }
1739 }
1740 template <typename T>
mouseMagnify(const juce::MouseEvent & event,float scaleFactor)1741 inline void juceCViewConnector<T>::mouseMagnify(const juce::MouseEvent &event, float scaleFactor)
1742 {
1743     std::cout << "scaleFactor is " << scaleFactor << std::endl;
1744     auto b = T::getBounds().getTopLeft();
1745     CPoint w(event.x + b.x, event.y + b.y);
1746     if (!viewCompanion->magnify(w, scaleFactor))
1747     {
1748         T::mouseMagnify(event, scaleFactor);
1749     }
1750 }
1751 
1752 // The ownership here is all ascreed p and if you make the refcout del it crashes
1753 struct CMenuItem
1754 {
~CMenuItemCMenuItem1755     virtual ~CMenuItem() {}
1756     void setChecked(bool b = true) { OKUNIMPL; }
1757     void setEnabled(bool b = true) { OKUNIMPL; }
1758 
rememberCMenuItem1759     virtual void remember() {}
forgetCMenuItem1760     virtual void forget() {}
1761 
1762     std::string name;
1763 };
1764 struct CCommandMenuItem : public CMenuItem
1765 {
1766     struct Desc
1767     {
1768         std::string name;
DescCCommandMenuItem::Desc1769         Desc(const std::string &s) : name(s) {}
1770     } desc;
CCommandMenuItemCCommandMenuItem1771     CCommandMenuItem(const Desc &d) : desc(d) {}
1772     void setActions(std::function<void(CCommandMenuItem *)> f, void *userData = nullptr)
1773     {
1774         func = f;
1775     }
1776     std::function<void(CCommandMenuItem *)> func;
1777 };
1778 struct COptionMenu : public CControl
1779 {
1780     enum
1781     {
1782         kMultipleCheckStyle = 1,
1783         kNoDrawStyle = 2
1784     };
1785 
1786     juce::PopupMenu menu;
1787 
1788     COptionMenu(const CRect &r, IControlListener *l, int32_t tag, int, int = 0, int = 0)
CControlCOptionMenu1789         : CControl(r, l, tag), menu()
1790     {
1791         // Obviously fix this
1792         alwaysLeak = true;
1793         doDebug = false;
1794     }
setNbItemsPerColumnCOptionMenu1795     void setNbItemsPerColumn(int c) { OKUNIMPL; }
setEnabledCOptionMenu1796     void setEnabled(bool) { UNIMPL; }
1797     void addSeparator(int s = -1) { menu.addSeparator(); }
1798     CMenuItem *addEntry(const std::string &s, int eid = -1)
1799     {
1800         menu.addItem(juce::CharPointer_UTF8(s.c_str()), []() { UNIMPL; });
1801 
1802         auto res = new CMenuItem();
1803         res->remember();
1804         return res;
1805     }
addEntryCOptionMenu1806     CMenuItem *addEntry(CCommandMenuItem *r)
1807     {
1808         r->remember();
1809         auto op = r->func;
1810         menu.addItem(juce::CharPointer_UTF8(r->desc.name.c_str()), [op]() { op(nullptr); });
1811         auto res = new CMenuItem();
1812         res->remember();
1813         return res;
1814     }
addEntryCOptionMenu1815     CMenuItem *addEntry(COptionMenu *m, const std::string &nm)
1816     {
1817         menu.addSubMenu(juce::CharPointer_UTF8(nm.c_str()), m->menu);
1818         auto res = new CMenuItem();
1819         res->remember();
1820         return res;
1821     }
addEntryCOptionMenu1822     CMenuItem *addEntry(COptionMenu *m, const char *nm)
1823     {
1824         m->remember();
1825         menu.addSubMenu(juce::CharPointer_UTF8(nm), m->menu);
1826         auto res = new CMenuItem();
1827         res->remember();
1828         return res;
1829     }
checkEntryCOptionMenu1830     void checkEntry(int, bool) { UNIMPL; }
popupCOptionMenu1831     void popup() { menu.showMenuAsync(juce::PopupMenu::Options()); }
setHeightCOptionMenu1832     inline void setHeight(float h) { UNIMPL; }
cleanupSeparatorsCOptionMenu1833     void cleanupSeparators(bool b) { UNIMPL; }
getNbEntriesCOptionMenu1834     int getNbEntries() { return 0; }
1835 
onMouseDownCOptionMenu1836     CMouseEventResult onMouseDown(CPoint &where, const CButtonState &buttons) override
1837     {
1838         popup();
1839         return kMouseEventHandled;
1840     }
1841 };
1842 
1843 enum DragOperation
1844 {
1845 
1846 };
1847 struct DragEventData
1848 {
1849 };
1850 
1851 #define CLASS_METHODS(a, b)
1852 } // namespace EscapeNS
1853 
1854 namespace VSTGUI = EscapeNS;
1855 
1856 namespace EscapeFromVSTGUI
1857 {
1858 struct JuceVSTGUIEditorAdapter : public JuceVSTGUIEditorAdapterBase
1859 {
JuceVSTGUIEditorAdapterJuceVSTGUIEditorAdapter1860     JuceVSTGUIEditorAdapter(juce::AudioProcessorEditor *parentEd) : parentEd(parentEd) {}
1861     virtual ~JuceVSTGUIEditorAdapter() = default;
openJuceVSTGUIEditorAdapter1862     virtual bool open(void *parent) { return true; };
closeJuceVSTGUIEditorAdapter1863     virtual void close(){};
controlBeginEditJuceVSTGUIEditorAdapter1864     virtual void controlBeginEdit(VSTGUI::CControl *p){};
controlEndEditJuceVSTGUIEditorAdapter1865     virtual void controlEndEdit(VSTGUI::CControl *p){};
beginEditJuceVSTGUIEditorAdapter1866     virtual void beginEdit(int32_t id) {}
endEditJuceVSTGUIEditorAdapter1867     virtual void endEdit(int32_t id) {}
1868 
getJuceEditorJuceVSTGUIEditorAdapter1869     juce::AudioProcessorEditor *getJuceEditor() { return parentEd; }
1870 
1871     VSTGUI::CRect rect;
1872     VSTGUI::CFrame *frame = nullptr;
getFrameJuceVSTGUIEditorAdapter1873     VSTGUI::CFrame *getFrame() { return frame; }
1874 
1875     juce::AudioProcessorEditor *parentEd;
1876 };
1877 
1878 struct JuceVSTGUIEditorAdapterConcreteTestOnly : public JuceVSTGUIEditorAdapter
1879 {
JuceVSTGUIEditorAdapterConcreteTestOnlyJuceVSTGUIEditorAdapterConcreteTestOnly1880     JuceVSTGUIEditorAdapterConcreteTestOnly(juce::AudioProcessorEditor *parentEd)
1881         : JuceVSTGUIEditorAdapter(parentEd)
1882     {
1883     }
openJuceVSTGUIEditorAdapterConcreteTestOnly1884     bool open(void *parent) override { return true; }
closeJuceVSTGUIEditorAdapterConcreteTestOnly1885     void close() override {}
controlBeginEditJuceVSTGUIEditorAdapterConcreteTestOnly1886     void controlBeginEdit(VSTGUI::CControl *p) override {}
controlEndEditJuceVSTGUIEditorAdapterConcreteTestOnly1887     void controlEndEdit(VSTGUI::CControl *p) override {}
1888 };
1889 } // namespace EscapeFromVSTGUI
1890 
1891 #endif // SURGE_ESCAPE_FROM_VSTGUI_H
1892