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 ↦
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