18#if !defined(NDEBUG) || defined(IPLUG_LIVE_EDIT)
27#if defined(IPLUG_LIVE_EDIT_CLASS_NAME)
30#if defined(__GNUG__) && !defined(_WIN32)
37BEGIN_IGRAPHICS_NAMESPACE
49 , mMouseOversEnabled(mouseOversEnabled)
67 int c =
GetUI()->GetMouseControlIdx(x, y,
true);
72 mMouseDownRECT = pControl->
GetRECT();
76 mSelectedControls.Empty();
78 mSelectedControls.Add(pControl);
84 mMouseClickedOnResizeHandle =
false;
85 EmitControlAdded(
GetUI()->GetControl(mClickedOnControl));
89 mClickedOnControl = c;
94 mClickedOnControl = c;
96 if (GetHandleRect(mMouseDownRECT).Contains(x, y))
98 mMouseClickedOnResizeHandle =
true;
108 mSelectedControls.Empty();
109 mDragRegion.L = mDragRegion.R = x;
110 mDragRegion.T = mDragRegion.B = y;
113 EmitSelectionChanged();
120 const bool waitingForControlPopup = mod.R && mClickedOnControl > 0;
122 if (mClickedOnControl > 0)
127 if (mMouseClickedOnResizeHandle)
132 if (w < 0.f || h < 0.f)
134 pControl->
SetRECT(mMouseDownRECT);
140 if (r.L != mMouseDownRECT.L || r.T != mMouseDownRECT.T ||
141 r.R != mMouseDownRECT.R || r.B != mMouseDownRECT.B)
143 EmitControlChanged(pControl, mMouseDownRECT);
147 if (!waitingForControlPopup)
148 mClickedOnControl = -1;
150 mMouseClickedOnResizeHandle =
false;
153 EmitSelectionChanged();
155 mDragRegion =
IRECT();
164 int c =
GetUI()->GetMouseControlIdx(x, y,
true);
168 IRECT h = GetHandleRect(cr);
184 float mouseDownX, mouseDownY;
187 if (mClickedOnControl > 0)
191 if (mMouseClickedOnResizeHandle)
194 r.R = SnapToGrid(mMouseDownRECT.R + (x - mouseDownX));
195 r.B = SnapToGrid(mMouseDownRECT.B + (y - mouseDownY));
197 if (r.R < mMouseDownRECT.L +mGridSize) r.R = mMouseDownRECT.L+mGridSize;
198 if (r.B < mMouseDownRECT.T +mGridSize) r.B = mMouseDownRECT.T+mGridSize;
204 const float x1 = SnapToGrid(mMouseDownRECT.L + (x - mouseDownX));
205 const float y1 = SnapToGrid(mMouseDownRECT.T + (y - mouseDownY));
212 float mouseDownX, mouseDownY;
214 mDragRegion.L = x < mouseDownX ? x : mouseDownX;
215 mDragRegion.R = x < mouseDownX ? mouseDownX : x;
216 mDragRegion.T = y < mouseDownY ? y : mouseDownY;
217 mDragRegion.B = y < mouseDownY ? mouseDownY : y;
221 if (mSelectedControls.FindR(pControl) == -1)
222 mSelectedControls.Add(pControl);
225 int idx = mSelectedControls.FindR(pControl);
227 mSelectedControls.Delete(idx);
237 if (key.VK == kVK_BACK || key.VK == kVK_DELETE)
239 if (mSelectedControls.GetSize())
241 std::vector<IControl*> snapshot;
242 snapshot.reserve(mSelectedControls.GetSize());
243 for (
int i = 0; i < mSelectedControls.GetSize(); i++)
244 snapshot.push_back(mSelectedControls.Get(i));
245 EmitControlsDeleted(snapshot.data(),
static_cast<int>(snapshot.size()));
246 for (
int i = 0; i < mSelectedControls.GetSize(); i++)
248 IControl* pControl = mSelectedControls.Get(i);
252 mSelectedControls.Empty();
255 EmitSelectionChanged();
268 mClickedOnControl = -1;
272 if (pSelectedMenu && pSelectedMenu == &mRightClickOutsideControlMenu)
274 auto idx = pSelectedMenu->GetChosenItemIdx();
284 EmitControlAdded(
GetUI()->GetControl(
GetUI()->NControls() - 1));
292 if (pSelectedMenu && pSelectedMenu == &mRightClickOnControlMenu)
294 auto idx = pSelectedMenu->GetChosenItemIdx();
301 IControl* controls[1] = { pToDelete };
303 EmitControlsDeleted(controls, 1);
304 mSelectedControls.Empty();
305 if (mClickedOnControl > 0)
307 EmitSelectionChanged();
314 mClickedOnControl = -1;
320 IBlend b {EBlend::Add, 0.25f};
337 IRECT h = GetHandleRect(cr);
338 g.
FillTriangle(mRectColor, h.L, h.B, h.R, h.B, h.R, h.T);
339 g.
DrawTriangle(COLOR_BLACK, h.L, h.B, h.R, h.B, h.R, h.T);
343 for (
int i = 0; i< mSelectedControls.GetSize(); i++)
345 g.
DrawDottedRect(COLOR_WHITE, mSelectedControls.Get(i)->GetRECT());
348 if (!mDragRegion.
Empty())
356 mSelectedControls.Empty();
365 return IRECT(r.R - RESIZE_HANDLE_SIZE, r.B - RESIZE_HANDLE_SIZE, r.R, r.B);
368 inline float SnapToGrid(
float input)
371 return (
float) std::round(input / (
float) mGridSize) * mGridSize;
376 static void AppendJsonString(std::string& out,
const char* str)
382 for (
const char* p = str; *p; ++p)
384 unsigned char c =
static_cast<unsigned char>(*p);
388 case '\\': out +=
"\\\\";
break;
389 case '"': out +=
"\\\"";
break;
390 case '\b': out +=
"\\b";
break;
391 case '\f': out +=
"\\f";
break;
392 case '\n': out +=
"\\n";
break;
393 case '\r': out +=
"\\r";
break;
394 case '\t': out +=
"\\t";
break;
400 std::snprintf(esc,
sizeof(esc),
"\\u%04x", c);
405 out.push_back(
static_cast<char>(c));
416#if defined(IPLUG_LIVE_EDIT_CLASS_NAME)
417 static std::string DemangledClassName(
IControl* pControl)
422 const char* mangled =
typeid(*pControl).name();
423#if defined(__GNUG__) && !defined(_WIN32)
425 char* demangled = abi::__cxa_demangle(mangled,
nullptr,
nullptr, &status);
426 const char* name = (status == 0 && demangled) ? demangled : (mangled ? mangled :
"");
428 const char* name = mangled ? mangled :
"";
430 static const char prefix[] =
"iplug::igraphics::";
431 const std::size_t prefixLen =
sizeof(prefix) - 1;
432 const char* compact = std::strncmp(name, prefix, prefixLen) == 0 ? name + prefixLen : name;
433 std::string result(compact);
435#if defined(__GNUG__) && !defined(_WIN32)
437 std::free(demangled);
444 void AppendControlDescriptor(std::string& out,
IControl* pControl)
454 out += std::to_string(
GetUI()->GetControlIdx(pControl));
455#if defined(IPLUG_LIVE_EDIT_CLASS_NAME)
456 out +=
",\"className\":";
457 AppendJsonString(out, DemangledClassName(pControl).c_str());
460 out += std::to_string(pControl->
GetTag());
461 out +=
",\"paramIdx\":";
464 out += std::to_string(
static_cast<int>(std::round(r.L)));
466 out += std::to_string(
static_cast<int>(std::round(r.T)));
468 out += std::to_string(
static_cast<int>(std::round(r.R)));
470 out += std::to_string(
static_cast<int>(std::round(r.B)));
474 static void AppendRect(std::string& out,
const IRECT& r)
477 out += std::to_string(
static_cast<int>(std::round(r.L)));
479 out += std::to_string(
static_cast<int>(std::round(r.T)));
481 out += std::to_string(
static_cast<int>(std::round(r.R)));
483 out += std::to_string(
static_cast<int>(std::round(r.B)));
487 void EmitControlChanged(
IControl* pControl,
const IRECT& previousRECT)
489 if (!
GetUI()->HasLiveEditEventFunc())
492 std::string json =
"{\"type\":\"iplug:live-edit:control-changed\",\"control\":";
493 AppendControlDescriptor(json, pControl);
494 json +=
",\"prev\":";
495 AppendRect(json, previousRECT);
497 GetUI()->EmitLiveEditEvent(json.c_str());
500 void EmitControlAdded(
IControl* pControl)
502 if (!
GetUI()->HasLiveEditEventFunc())
505 std::string json =
"{\"type\":\"iplug:live-edit:control-added\",\"control\":";
506 AppendControlDescriptor(json, pControl);
508 GetUI()->EmitLiveEditEvent(json.c_str());
511 void EmitControlsDeleted(
IControl*
const* controls,
int count)
513 if (!
GetUI()->HasLiveEditEventFunc())
519 std::string json =
"{\"type\":\"iplug:live-edit:controls-deleted\",\"deleted\":[";
521 for (
int i = 0; i < count; i++)
526 AppendControlDescriptor(json, controls[i]);
530 GetUI()->EmitLiveEditEvent(json.c_str());
533 void EmitSelectionChanged()
535 if (!
GetUI()->HasLiveEditEventFunc())
538 std::string json =
"{\"type\":\"iplug:live-edit:selection-changed\",\"selection\":[";
540 for (
int i = 0; i < mSelectedControls.GetSize(); i++)
545 AppendControlDescriptor(json, mSelectedControls.Get(i));
549 GetUI()->EmitLiveEditEvent(json.c_str());
553 IPopupMenu mRightClickOutsideControlMenu {
"Outside Control", {
"Add Place Holder"}};
554 IPopupMenu mRightClickOnControlMenu{
"On Control", {
"Delete Control"} };
556 bool mMouseOversEnabled =
false;
557 bool mMouseClickedOnResizeHandle =
false;
558 bool mMouseIsDragging =
false;
559 WDL_String mErrorMessage;
560 WDL_PtrList<IControl> mSelectedControls;
562 IColor mGridColor = COLOR_WHITE;
563 IColor mRectColor = COLOR_WHITE;
564 static const int RESIZE_HANDLE_SIZE = 10;
566 IRECT mMouseDownRECT;
567 IRECT mMouseDownTargetRECT;
570 float mGridSize = 10;
571 int mClickedOnControl = -1;
574END_IGRAPHICS_NAMESPACE
This file contains the base IControl implementation, along with some base classes for specific types ...
The lowest level base class of an IGraphics control.
const IRECT & GetTargetRECT() const
Get the rectangular mouse tracking target area, within the graphics context for this control.
int GetParamIdx(int valIdx=0) const
Get the index of a parameter that the control is linked to Normaly controls are either linked to a si...
const IRECT & GetRECT() const
Get the rectangular draw area for this control, within the graphics context.
void SetTargetRECT(const IRECT &bounds)
Set the rectangular mouse tracking target area, within the graphics context for this control.
int GetTag() const
Get the control's tag.
void SetRECT(const IRECT &bounds)
Set the rectangular draw area for this control, within the graphics context.
IContainerBase * GetParent() const
The lowest level base class of an IGraphics context.
void RemoveControl(int idx)
Remove a control at a particular index, (frees memory).
void CreatePopupMenu(IControl &control, IPopupMenu &menu, const IRECT &bounds, int valIdx=0)
Shows a pop up/contextual menu in relation to a rectangular region of the graphics context.
virtual ECursor SetMouseCursor(ECursor cursorType=ECursor::ARROW)
Sets the mouse cursor to one of ECursor (implementations should return the result of the base impleme...
virtual void DrawDottedRect(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0, float thickness=1.f, float dashLen=2.f)
Draw a dotted rectangle to the graphics context.
void ReleaseMouseCapture()
Used to tell the graphics context to stop tracking mouse interaction with a control.
void GetMouseDownPoint(float &x, float &y) const
Get the x, y position of the last mouse down message.
virtual void FillTriangle(const IColor &color, float x1, float y1, float x2, float y2, float x3, float y3, const IBlend *pBlend=0)
Fill a triangle with a color.
virtual void DrawGrid(const IColor &color, const IRECT &bounds, float gridSizeH, float gridSizeV, const IBlend *pBlend=0, float thickness=1.f)
Draw a grid to the graphics context.
void SetAllControlsDirty()
Calls SetDirty() on every control.
void SetControlSize(IControl *pControl, float w, float h)
Resize a control, redrawing the interface correctly.
IControl * GetControl(int idx)
Get the control at a certain index in the control stack.
void ForStandardControlsFunc(IControlFunction func)
For all standard controls in the main control stack perform a function.
virtual void DrawTriangle(const IColor &color, float x1, float y1, float x2, float y2, float x3, float y3, const IBlend *pBlend=0, float thickness=1.f)
Draw a triangle to the graphics context.
void SetControlPosition(IControl *pControl, float x, float y)
Reposition a control, redrawing the interface correctly.
void EnableMouseOver(bool enable)
IRECT GetBounds() const
Returns an IRECT that represents the entire UI bounds This is useful for programatically arranging UI...
IControl * AttachControl(IControl *pControl, int ctrlTag=kNoTag, const char *group="")
Attach an IControl to the graphics context and add it to the top of the control stack.
A control to enable live modification of control layout in an IGraphics context in debug builds This ...
void OnResize() override
Called when IControl is constructed or resized using SetRect().
bool OnKeyDown(float x, float y, const IKeyPress &key) override
Implement this method to respond to a key down event on this control.
void OnMouseOver(float x, float y, const IMouseMod &mod) override
Implement this method to respond to a mouseover event on this control.
void OnMouseDrag(float x, float y, float dX, float dY, const IMouseMod &mod) override
Implement this method to respond to a mouse drag event on this control.
void OnPopupMenuSelection(IPopupMenu *pSelectedMenu, int valIdx) override
Implement this method to handle popup menu selection after IGraphics::CreatePopupMenu/IControlPromptU...
void OnInit() override
Called just prior to when the control is attached, after its delegate and graphics member variable se...
void OnMouseUp(float x, float y, const IMouseMod &mod) override
Implement this method to respond to a mouse up event on this control.
void OnMouseDown(float x, float y, const IMouseMod &mod) override
Implement this method to respond to a mouse down event on this control.
void OnMouseDblClick(float x, float y, const IMouseMod &mod) override
Implement this method to respond to a mouse double click event on this control.
void Draw(IGraphics &g) override
Draw the control to the graphics context.
bool IsDirty() override
Called at each display refresh by the IGraphics draw loop, after IControl::Animate(),...
A control to use as a placeholder during development.
Used to manage composite/blend operations, independent of draw class/platform.
Used to manage color data, independent of draw class/platform.
Used for key press info, such as ASCII representation, virtual key (mapped to win32 codes) and modifi...
Used to manage mouse modifiers i.e.
Used to manage a rectangular area, independent of draw class/platform.
bool Contains(const IRECT &rhs) const
Returns true if this IRECT completely contains rhs.