iPlug 2: IGraphics.cpp Source File

1

2

3

4

5

6

7

8

9

10

12

13#define NANOSVG_IMPLEMENTATION

14#pragma warning(disable:4244)

15#include "nanosvg.h"

16

17#if defined VST3_API

18#include "pluginterfaces/base/ustring.h"

20using VST3_API_BASE = iplug::IPlugVST3;

21#elif defined VST3C_API

22#include "pluginterfaces/base/ustring.h"

24#include "IPlugVST3_View.h"

25using VST3_API_BASE = iplug::IPlugVST3Controller;

26#endif

27

30

39

40using namespace iplug;

41using namespace igraphics;

42

43static StaticStorage<APIBitmap> sBitmapCache;

44static StaticStorage<SVGHolder> sSVGCache;

45

46IGraphics::IGraphics(IGEditorDelegate& dlg, int w, int h, int fps, float scale)

47: mWidth(w)

48, mHeight(h)

49, mFPS(fps)

50, mDrawScale(scale)

51, mMinScale(DEFAULT_MIN_DRAW_SCALE)

52, mMaxScale(DEFAULT_MAX_DRAW_SCALE)

53, mDelegate(&dlg)

54{

55 StaticStorage<APIBitmap>::Accessor bitmapStorage(sBitmapCache);

56 bitmapStorage.Retain();

57 StaticStorage<SVGHolder>::Accessor svgStorage(sSVGCache);

58 svgStorage.Retain();

59}

60

61IGraphics::~IGraphics()

62{

63

64

65

66 mCursorHidden = false;

68

69 StaticStorage<APIBitmap>::Accessor bitmapStorage(sBitmapCache);

70 bitmapStorage.Release();

71 StaticStorage<SVGHolder>::Accessor svgStorage(sSVGCache);

72 svgStorage.Release();

73}

74

76{

77 mScreenScale = scale;

80

81 assert(windowWidth > 0 && windowHeight > 0 && "Window dimensions invalid");

82

84 PlatformResize(parentResized);

87 DrawResize();

88}

89

90void IGraphics::Resize(int w, int h, float scale, bool needsPlatformResize)

91{

93

94 scale = Clip(scale, mMinScale, mMaxScale);

95

97

98

100

101 mDrawScale = scale;

102 mWidth = w;

103 mHeight = h;

104

105 if (mCornerResizer)

106 mCornerResizer->OnRescale();

107

110

112 PlatformResize(parentResized);

115 DrawResize();

116

117 if(mLayoutOnResize)

119}

120

121void IGraphics::SetLayoutOnResize(bool layoutOnResize)

122{

123 mLayoutOnResize = layoutOnResize;

124}

125

127{

128 mMinScale = std::min(lo, hi);

129 mMaxScale = std::max(lo, hi);

130}

131

133{

135 mCtrlTags.erase(ctrlTag);

137}

138

140{

142 while (idx >= fromIdx)

143 {

145

148

149 if(pControl == mMouseOver)

150 ClearMouseOver();

151

152 if(pControl == mInTextEntry)

154

155 if(pControl == mInPopupMenu)

156 mInPopupMenu = nullptr;

157

158 if(pControl->GetTag() > kNoTag)

159 mCtrlTags.erase(pControl->GetTag());

160

161 mControls.Delete(idx--, true);

162 }

163

165}

166

168{

170}

171

173{

176

177 if(pControl == mMouseOver)

178 ClearMouseOver();

179

180 if(pControl == mInTextEntry)

182

183 if(pControl == mInPopupMenu)

184 mInPopupMenu = nullptr;

185

186 if(pControl->GetTag() > kNoTag)

187 mCtrlTags.erase(pControl->GetTag());

188

189 mControls.DeletePtr(pControl, true);

190

192}

193

195{

197 ClearMouseOver();

198

199 mPopupControl = nullptr;

200 mTextEntryControl = nullptr;

201 mCornerResizer = nullptr;

202 mPerfDisplay = nullptr;

203

204#ifndef NDEBUG

205 mLiveEdit = nullptr;

206#endif

207

208 mBubbleControls.Empty(true);

209

210 mCtrlTags.clear();

211 mControls.Empty(true);

212}

213

215{

219}

220

222{

226}

227

229{

233}

234

236{

237 if (!mInTextEntry)

238 return;

239

240 const IParam* pParam = mTextEntryValIdx > kNoValIdx ? mInTextEntry->GetParam(mTextEntryValIdx) : nullptr;

241

242 if (pParam)

243 {

246 }

247 else

248 {

250 }

251

253}

254

256{

257 if (!mInPopupMenu)

258 return;

259

260 if (mIsContextMenu)

261 mInPopupMenu->OnContextSelection(pMenu ? pMenu->GetChosenItemIdx() : -1);

262 else

263 mInPopupMenu->OnPopupMenuSelection(!pMenu || pMenu->GetChosenItemIdx() == -1 ? nullptr : pMenu, mPopupMenuValIdx);

264

265 int nVals = mInPopupMenu->NVals();

266

267 for (int v = 0; v < nVals; v++)

268 {

269 int paramIdx = mInPopupMenu->GetParamIdx(v);

270

271 if (paramIdx > kNoParameter)

272 {

274 }

275 }

276

277 mInPopupMenu = nullptr;

278}

279

281{

282 if (!mInPopupMenu)

283 return;

284

286}

287

289{

292 mControls.Insert(0, pBG);

293}

294

296{

299 mControls.Insert(0, pBG);

300}

301

303{

306 mControls.Insert(0, pBG);

307}

308

310{

311 if(ctrlTag > kNoTag)

312 {

313 auto result = mCtrlTags.insert(std::make_pair(ctrlTag, pControl));

314 assert(result.second && "AttachControl failed: ctrl tags must be unique");

315

316 if (!result.second)

317 return nullptr;

318 }

319

322 mControls.Add(pControl);

323

325 return pControl;

326}

327

329{

331}

332

334{

335#ifndef AUv3_API

336 assert(!mCornerResizer);

337

338 std::unique_ptr<ICornerResizerControl> control(pControl);

339

340 if (!mCornerResizer)

341 {

342 mCornerResizer.swap(control);

343 mGUISizeMode = sizeMode;

344 mLayoutOnResize = layoutOnResize;

345 mCornerResizer->SetDelegate(*GetDelegate());

346 }

347#else

348DBGMSG("AttachCornerResizer() is disabled for AUv3");

349#endif

350}

351

353{

356}

357

359{

361 mBubbleControls.Add(pControl);

362}

363

365{

366 if (!mPopupControl)

367 {

368 mPopupControl = std::make_unique<IPopupMenuControl>(kNoParameter, text, IRECT(), bounds);

369 mPopupControl->SetDelegate(*GetDelegate());

370 }

371}

372

374{

375 mPopupControl = nullptr;

376}

377

379{

380 if (!mTextEntryControl)

381 {

382 mTextEntryControl = std::make_unique<ITextEntryControl>();

383 mTextEntryControl->SetDelegate(*GetDelegate());

384 }

385}

386

388{

389 mTextEntryControl = nullptr;

390}

391

392void IGraphics::ShowBubbleControl(IControl* pCaller, float x, float y, const char* str, EDirection dir, IRECT minimumContentBounds)

393{

394 assert(mBubbleControls.GetSize() && "No bubble controls attached");

395

397 {

398 std::vector<ITouchID> touchIDsForCaller;

399 GetTouches(pCaller, touchIDsForCaller);

400 std::vector<IBubbleControl*> availableBubbleControls;

401 int nBubbleControls = mBubbleControls.GetSize();

402

403 if(touchIDsForCaller.size() == 1)

404 {

405 ITouchID touchID = touchIDsForCaller[0];

406

407

408 for(int i=0;i<nBubbleControls;i++)

409 {

410 IBubbleControl* pBubbleControl = mBubbleControls.Get(i);

411 if(pBubbleControl->GetTouchID() == touchID)

412 {

413 pBubbleControl->ShowBubble(pCaller, x, y, str, dir, minimumContentBounds, touchID);

414 return;

415 }

416 else

417 availableBubbleControls.push_back(pBubbleControl);

418 }

419

420 if(availableBubbleControls.size())

421 {

422

423 static int whichBubbleControl = 0;

424 availableBubbleControls[whichBubbleControl++]->ShowBubble(pCaller, x, y, str, dir, minimumContentBounds, touchID);

425 whichBubbleControl %= nBubbleControls;

426 }

427 }

428

429

430

431

432 }

433 else

434 mBubbleControls.Get(0)->ShowBubble(pCaller, x, y, str, dir, minimumContentBounds);

435}

436

438{

439 if (enable)

440 {

441 if (!mPerfDisplay)

442 {

443 if (mPerfDisplayBounds.Empty())

444 {

446 }

447

448 mPerfDisplay = std::make_unique<IFPSDisplayControl>(mPerfDisplayBounds);

449 mPerfDisplay->SetDelegate(*GetDelegate());

450 }

451 }

452 else

453 {

454 mPerfDisplay = nullptr;

455 ClearMouseOver();

456 }

457

459}

460

462{

463 const auto it = mCtrlTags.find(ctrlTag);

464

465 if (it != mCtrlTags.end())

466 {

467 return it->second;

468 }

469 else

470 {

471 assert("There is no control attached with this tag");

472 return nullptr;

473 }

474}

475

477{

478 for (auto c = 0; c < NControls(); c++)

479 {

481

482 if (pControl->LinkedToParam(paramIdx) > kNoValIdx)

483 {

484 return pControl;

485 }

486 }

487

488 return nullptr;

489}

490

492{

494}

495

497{

499}

500

502{

503 for (auto c = 0; c < NControls(); c++)

504 {

506

507 if (pControl->LinkedToParam(paramIdx) > kNoValIdx)

508 {

509 func(pControl);

510

511 }

512 }

513}

514

516{

517 for (auto c = 0; c < NControls(); c++)

518 {

520

521 for (auto param : params)

522 {

524 {

525 func(pControl);

526

527 }

528 }

529 }

530}

531

533{

534 for (auto c = 0; c < NControls(); c++)

535 {

537

538 if (CStringHasContents(pControl->GetGroup()))

539 {

540 if (strcmp(pControl->GetGroup(), group) == 0)

541 func(pControl);

542

543 }

544 }

545}

546

548{

549 for (auto c = 0; c < NControls(); c++)

551}

552

554{

556

557 if (mPerfDisplay)

558 func(mPerfDisplay.get());

559

560#ifndef NDEBUG

561 if (mLiveEdit)

562 func(mLiveEdit.get());

563#endif

564

565 if (mCornerResizer)

566 func(mCornerResizer.get());

567

568 if (mTextEntryControl)

569 func(mTextEntryControl.get());

570

571 if (mPopupControl)

572 func(mPopupControl.get());

573

574 if (mBubbleControls.GetSize())

575 {

576 for(int i = 0;i<mBubbleControls.GetSize();i++)

577 {

578 func(mBubbleControls.Get(i));

579 }

580 }

581}

582

583template<typename T, typename... Args>

585{

587}

588

589template<typename T, typename... Args>

591{

593}

594

596{

598}

599

601{

603}

604

606{

607 auto func = [](IControl* pControl)

608 {

609 if (pControl->GetParamIdx() > kNoParameter)

610 pControl->SetTooltip(pControl->GetParam()->GetName());

611 };

612

614}

615

617{

618 double value = pCaller->GetValue(callerValIdx);

619 int paramIdx = pCaller->GetParamIdx(callerValIdx);

620

621 auto func = [pCaller, paramIdx, value](IControl* pControl)

622 {

623 int valIdx = pControl->LinkedToParam(paramIdx);

624

625

626 if ((valIdx > kNoValIdx) && (pControl != pCaller))

627 {

628 pControl->SetValueFromDelegate(value, valIdx);

629 }

630 };

631

633}

634

636{

637 assert(valIdx > kNoValIdx);

638

640

641 if(pParam)

642 {

644 const int nDisplayTexts = pParam->NDisplayTexts();

645 WDL_String currentText;

646

647 if ( type == IParam::kTypeEnum || (type == IParam::kTypeBool && nDisplayTexts))

648 {

650 mPromptPopupMenu.Clear();

651

652

653 for (int i = 0; i < nDisplayTexts; ++i)

654 {

656

657 if (!strcmp(str, currentText.Get()))

658 mPromptPopupMenu.AddItem( new IPopupMenu::Item(str, IPopupMenu::Item::kChecked), -1 );

659 else

661

662 mPromptPopupMenu.SetRootTitle(pParam->GetName());

663 }

664

665 CreatePopupMenu(control, mPromptPopupMenu, bounds, valIdx);

666 }

667

668 else

669 {

670 pParam->GetDisplay(currentText, false);

671

673 {

674 currentText.Append(" ");

675 currentText.Append(pParam->GetLabel());

676 }

677

679 }

680 }

681}

682

684{

685 if (!str || str[0] == '\0')

686 return;

687

688 DoDrawText(text, str, bounds, pBlend);

689}

690

692{

693 if (!str || str[0] == '\0')

694 return 0.f;

695

697}

698

700{

701 IRECT bounds = { x, y, x, y };

702 DrawText(text, str, bounds, pBlend);

703}

704

706{

707 int srcX = 0;

708 int srcY = 0;

709

710 bmpState = Clip(bmpState, 1, bitmap.N());

711

712 if (bitmap.N() > 1 && bmpState > 1)

713 {

715 {

716 srcX = bitmap.W() * (bmpState - 1) / bitmap.N();

717 }

718 else

719 {

720 srcY = bitmap.H() * (bmpState - 1) / bitmap.N();

721 }

722 }

723

724 return DrawBitmap(bitmap, bounds, srcX, srcY, pBlend);

725}

726

728{

729 if (CStringHasContents(str))

730 {

731 int stringLength = (int) strlen(str);

732

733 float basicYOffset = 0.;

734 float basicXOffset = 0.;

735

736 if (vCenter)

737 basicYOffset = bounds.T + ((bounds.H() - charHeight) / 2.f);

738 else

739 basicYOffset = bounds.T;

740

741 if (text.mAlign == EAlign::Center)

742 basicXOffset = bounds.L + ((bounds.W() - (stringLength * charWidth)) / 2.f);

743 else if (text.mAlign == EAlign::Near)

744 basicXOffset = bounds.L;

745 else if (text.mAlign == EAlign::Far)

746 basicXOffset = bounds.R - (stringLength * charWidth);

747

748 int widthAsOneLine = charWidth * stringLength;

749

750 int nLines;

751 int stridx = 0;

752

753 int nCharsThatFitIntoLine;

754

755 if(multiline)

756 {

757 if (widthAsOneLine > bounds.W())

758 {

759 nCharsThatFitIntoLine = int(bounds.W() / (float)charWidth);

760 nLines = int(float(widthAsOneLine) / bounds.W()) + 1;

761 }

762 else

763 {

764 nCharsThatFitIntoLine = stringLength;

765 nLines = 1;

766 }

767 }

768 else

769 {

770 nCharsThatFitIntoLine = int(bounds.W() / (float) charWidth);

771 nLines = 1;

772 }

773

774 for (int line=0; line<nLines; line++)

775 {

776 float yOffset = basicYOffset + line * charHeight;

777

778 for (int linepos=0; linepos<nCharsThatFitIntoLine; linepos++)

779 {

780 if (str[stridx] == '\0') return;

781

782 int frameOffset = (int) str[stridx++] - 31;

783

784 float xOffset = ((float) linepos * ((float) charWidth + (float) charOffset)) + basicXOffset;

785 IRECT charRect = IRECT(xOffset, yOffset, xOffset + charWidth, yOffset + charHeight);

786 DrawBitmap(bitmap, charRect, frameOffset, pBlend);

787 }

788 }

789 }

790}

791

793{

794 if (dir == EDirection::Horizontal)

796 else

798}

799

801{

802 x = Clip(x, 0.0f, 1.0f);

803 float xi = bounds.L + int(x * (bounds.R - bounds.L));

804 return DrawVerticalLine(color, xi, bounds.T, bounds.B, pBlend, thickness);

805}

806

808{

809 y = Clip(y, 0.0f, 1.0f);

810 float yi = bounds.B - (y * (float) (bounds.B - bounds.T));

811 return DrawHorizontalLine(color, yi, bounds.L, bounds.R, pBlend, thickness);

812}

813

815{

816 DrawLine(color, xi, yLo, xi, yHi, pBlend, thickness);

817}

818

820{

821 DrawLine(color, xLo, yi, xHi, yi, pBlend, thickness);

822}

823

825{

826 float data[2][2];

827 RadialPoints(angle, cx, cy, rMin, rMax, 2, data);

828 DrawLine(color, data[0][0], data[0][1], data[1][0], data[1][1], pBlend, thickness);

829}

830

832{

833 float data[2][2];

834 RadialPoints(angle, cx, cy, rMin, rMax, 2, data);

835 PathLine(data[0][0], data[0][1], data[1][0], data[1][1]);

836}

837

839{

840 if (mDisplayTickFunc)

841 mDisplayTickFunc();

842

844

845 bool dirty = false;

846

847 auto func = [&dirty, &rects](IControl* pControl) {

849 {

850

852

854 {

856 }

857

858 rects.Add(rectToAdd);

859 dirty = true;

860 }

861 };

862

864

865#ifdef USE_IDLE_CALLS

866 if (dirty)

867 {

868 mIdleTicks = 0;

869 }

870 else if (++mIdleTicks > IDLE_TICKS)

871 {

873 mIdleTicks = 0;

874 }

875#endif

876

877 return dirty;

878}

879

881{

882 if(mPerfDisplay)

883 {

884 const double timestamp = GetTimestamp();

885 const double timeDiff = timestamp - mPrevTimestamp;

886 mPerfDisplay->Update((float) timeDiff);

887 mPrevTimestamp = timestamp;

888 }

889}

890

891

892void IGraphics::DrawControl(IControl* pControl, const IRECT& bounds, float scale)

893{

894 if (pControl && (!pControl->IsHidden() || pControl == GetControl(0)))

895 {

896

899

900 if (clipBounds.W() <= 0.0 || clipBounds.H() <= 0)

901 return;

902

904

905 while (pParent)

906 {

908

909 if(!clipBounds.Intersects(parentBounds))

910 return;

911

912 clipBounds.Clank(parentBounds);

913

915 }

916

917 PrepareRegion(clipBounds);

918 pControl->Draw(*this);

919#ifdef AAX_API

921#endif

922

923#ifndef NDEBUG

924 if (mShowControlBounds)

925 {

926 PrepareRegion(clipBounds);

928 }

929#endif

930

931 CompleteRegion(clipBounds);

932 }

933}

934

936{

937 ForAllControlsFunc([this, bounds, scale](IControl* pControl) { DrawControl(pControl, bounds, scale); });

938

939#ifndef NDEBUG

940 if (mShowAreaDrawn)

941 {

942 PrepareRegion(bounds);

946 CompleteRegion(bounds);

947 }

948#endif

949}

950

952{

953 if (!rects.Size())

954 return;

955

957

959

960 if (mStrict)

961 {

964 Draw(r, scale);

965 }

966 else

967 {

970

971 for (auto i = 0; i < rects.Size(); i++)

972 Draw(rects.Get(i), scale);

973 }

974

976}

977

979{

980 mStrict = strict;

982}

983

985{

986

987

988 bool singlePoint = points.size() == 1;

989

990 if(singlePoint)

991 {

992 mMouseDownX = points[0].x;

993 mMouseDownY = points[0].y;

994 }

995

996 for (auto& point : points)

997 {

998 float x = point.x;

999 float y = point.y;

1000 const IMouseMod& mod = point.ms;

1001

1002 IControl* pCapturedControl = GetMouseControl(x, y, true, false, mod.touchID);

1003

1004 if (pCapturedControl)

1005 {

1006 int nVals = pCapturedControl->NVals();

1007#if defined AAX_API || !defined IGRAPHICS_NO_CONTEXT_MENU

1009 int paramIdx = pCapturedControl->GetParamIdx((valIdx > kNoValIdx) ? valIdx : 0);

1010#endif

1011

1012#ifdef AAX_API

1013 if (mAAXViewContainer && paramIdx > kNoParameter)

1014 {

1015 auto GetAAXModifiersFromIMouseMod = [](const IMouseMod& mod) {

1016 uint32_t modifiers = 0;

1017

1018 if (mod.A) modifiers |= AAX_eModifiers_Option;

1019

1020#ifdef OS_WIN

1021 if (mod.C) modifiers |= AAX_eModifiers_Command;

1022#else

1023 if (mod.C) modifiers |= AAX_eModifiers_Control;

1024 if (mod.R) modifiers |= AAX_eModifiers_Command;

1025#endif

1026 if (mod.S) modifiers |= AAX_eModifiers_Shift;

1027 if (mod.R) modifiers |= AAX_eModifiers_SecondaryButton;

1028

1029 return modifiers;

1030 };

1031

1032 uint32_t aaxModifiersForPT = GetAAXModifiersFromIMouseMod(mod);

1033#ifdef OS_WIN

1034

1035 uint32_t aaxModifiersFromPT = 0;

1036 mAAXViewContainer->GetModifiers(&aaxModifiersFromPT);

1037 aaxModifiersForPT |= aaxModifiersFromPT;

1038#endif

1039 WDL_String paramID;

1040 paramID.SetFormatted(32, "%i", paramIdx+1);

1041

1042 if (mAAXViewContainer->HandleParameterMouseDown(paramID.Get(), aaxModifiersForPT) == AAX_SUCCESS)

1043 {

1045 return;

1046 }

1047 }

1048#endif

1049

1050#ifndef IGRAPHICS_NO_CONTEXT_MENU

1051 if (mod.R && paramIdx > kNoParameter)

1052 {

1055 return;

1056 }

1057#endif

1058

1059 for (int v = 0; v < nVals; v++)

1060 {

1061 if (pCapturedControl->GetParamIdx(v) > kNoParameter)

1063 }

1064

1065 pCapturedControl->OnMouseDown(x, y, mod);

1066 }

1067 }

1068}

1069

1071{

1072

1073

1075 {

1076 for (auto& point : points)

1077 {

1078 float x = point.x;

1079 float y = point.y;

1080 const IMouseMod& mod = point.ms;

1081 auto itr = mCapturedMap.find(mod.touchID);

1082

1083 if(itr != mCapturedMap.end())

1084 {

1085 IControl* pCapturedControl = itr->second;

1086

1087 pCapturedControl->OnMouseUp(x, y, mod);

1088

1089 int nVals = pCapturedControl->NVals();

1090

1091 for (int v = 0; v < nVals; v++)

1092 {

1093 if (pCapturedControl->GetParamIdx(v) > kNoParameter)

1095 }

1096

1097 mCapturedMap.erase(mod.touchID);

1098 }

1099 }

1100 }

1101

1102 if (mResizingInProcess)

1103 {

1104 EndDragResize();

1105 }

1106

1107 if (points.size() == 1 && !points[0].ms.IsTouch())

1108 OnMouseOver(points[0].x, points[0].y, points[0].ms);

1109}

1110

1112{

1114 {

1115

1116 for (auto& point : points)

1117 {

1118 float x = point.x;

1119 float y = point.y;

1120 const IMouseMod& mod = point.ms;

1121

1122 auto itr = mCapturedMap.find(mod.touchID);

1123

1124 if(itr != mCapturedMap.end())

1125 {

1126 IControl* pCapturedControl = itr->second;

1128 mCapturedMap.erase(mod.touchID);

1129

1130

1131 }

1132 }

1133 }

1134}

1135

1137{

1138 Trace("IGraphics::OnMouseOver", __LINE__, "x:%0.2f, y:%0.2f, mod:LRSCA: %i%i%i%i%i",

1139 x, y, mod.L, mod.R, mod.S, mod.C, mod.A);

1140

1141

1142 IControl* pControl = GetMouseControl(x, y, false, true);

1143

1144 if (pControl != mMouseOver)

1145 {

1146 if (mMouseOver)

1148

1149 mMouseOver = pControl;

1150 }

1151

1152 if (mMouseOver)

1154

1155 return pControl;

1156}

1157

1159{

1160 Trace("IGraphics::OnMouseOut", __LINE__, "");

1161

1162

1165 ClearMouseOver();

1166}

1167

1169{

1170 Trace("IGraphics::OnMouseDrag:", __LINE__, "x:%0.2f, y:%0.2f, dX:%0.2f, dY:%0.2f, mod:LRSCA: %i%i%i%i%i",

1171 points[0].x, points[0].y, points[0].dX, points[0].dY, points[0].ms.L, points[0].ms.R, points[0].ms.S, points[0].ms.C, points[0].ms.A);

1172

1173 if (mResizingInProcess && points.size() == 1)

1176 {

1177 IControl *textEntry = nullptr;

1178

1180 textEntry = mTextEntryControl.get();

1181

1182 for (auto& point : points)

1183 {

1184 float x = point.x;

1185 float y = point.y;

1186 float dX = point.dX;

1187 float dY = point.dY;

1189

1190 auto itr = mCapturedMap.find(mod.touchID);

1191

1192 if (itr != mCapturedMap.end())

1193 {

1194 IControl* pCapturedControl = itr->second;

1195

1196 if (textEntry && pCapturedControl != textEntry)

1197 pCapturedControl = nullptr;

1198

1199 if (pCapturedControl && (dX != 0 || dY != 0))

1200 {

1201 pCapturedControl->OnMouseDrag(x, y, dX, dY, mod);

1202 }

1203 }

1204 }

1205 }

1206}

1207

1209{

1210 Trace("IGraphics::OnMouseDblClick", __LINE__, "x:%0.2f, y:%0.2f, mod:LRSCA: %i%i%i%i%i",

1211 x, y, mod.L, mod.R, mod.S, mod.C, mod.A);

1212

1213 IControl* pControl = GetMouseControl(x, y, true);

1214

1215 if (pControl)

1216 {

1218 {

1220 info.x = x;

1221 info.y = y;

1222 info.ms = mod;

1223 std::vector<IMouseInfo> list {info};

1225 }

1226 else

1227 {

1230 }

1231 }

1232

1233 return pControl;

1234}

1235

1237{

1238 IControl* pControl = GetMouseControl(x, y, false);

1239

1240 if (pControl)

1242

1243 return pControl;

1244}

1245

1247{

1248 Trace("IGraphics::OnKeyDown", __LINE__, "x:%0.2f, y:%0.2f, key:%s",

1249 x, y, key.utf8);

1250

1251 bool handled = false;

1252

1253 IControl* pControl = GetMouseControl(x, y, false);

1254

1255 if (pControl && pControl != GetControl(0))

1256 handled = pControl->OnKeyDown(x, y, key);

1257

1258 if(!handled)

1259 handled = mKeyHandlerFunc ? mKeyHandlerFunc(key, false) : false;

1260

1261 return handled;

1262}

1263

1265{

1266 Trace("IGraphics::OnKeyUp", __LINE__, "x:%0.2f, y:%0.2f, key:%s",

1267 x, y, key.utf8);

1268

1269 bool handled = false;

1270

1271 IControl* pControl = GetMouseControl(x, y, false);

1272

1273 if (pControl && pControl != GetControl(0))

1274 handled = pControl->OnKeyUp(x, y, key);

1275

1276 if(!handled)

1277 handled = mKeyHandlerFunc ? mKeyHandlerFunc(key, true) : false;

1278

1279 return handled;

1280}

1281

1283{

1284 IControl* pControl = GetMouseControl(x, y, false);

1285 if (pControl) pControl->OnDrop(str);

1286}

1287

1289{

1290 IControl* pControl = GetMouseControl(x, y, false);

1292}

1293

1295{

1296 mCapturedMap.clear();

1297 if (mCursorHidden)

1299}

1300

1301int IGraphics::GetMouseControlIdx(float x, float y, bool mouseOver)

1302{

1303 if (!mouseOver || mEnableMouseOver)

1304 {

1305

1306 for (auto c = NControls() - 1; c >= (mouseOver ? 1 : 0); --c)

1307 {

1309

1310#ifndef NDEBUG

1311 if(!mLiveEdit)

1312 {

1313#endif

1315 {

1317 {

1318 if (pControl->IsHit(x, y))

1319 {

1320 return c;

1321 }

1322 }

1323 }

1324#ifndef NDEBUG

1325 }

1327 {

1328 return c;

1329 }

1330#endif

1331 }

1332 }

1333

1334 return -1;

1335}

1336

1337IControl* IGraphics::GetMouseControl(float x, float y, bool capture, bool mouseOver, ITouchID touchID)

1338{

1339 IControl* pControl = nullptr;

1340

1341 auto itr = mCapturedMap.find(touchID);

1342

1344 {

1345 pControl = itr->second;

1346

1347 if(pControl)

1348 return pControl;

1349 }

1350

1351 int controlIdx = -1;

1352

1353 if (!pControl && mPopupControl && mPopupControl->GetExpanded())

1354 pControl = mPopupControl.get();

1355

1356 if (!pControl && mTextEntryControl && mTextEntryControl->EditInProgress())

1357 pControl = mTextEntryControl.get();

1358

1359

1360#if !defined(NDEBUG)

1361 if (!pControl && mLiveEdit)

1362 pControl = mLiveEdit.get();

1363#endif

1364

1365 if (!pControl && mCornerResizer && mCornerResizer->GetRECT().Contains(x, y))

1366 pControl = mCornerResizer.get();

1367

1368 if (!pControl && mPerfDisplay && mPerfDisplay->GetRECT().Contains(x, y))

1369 pControl = mPerfDisplay.get();

1370

1371 if (!pControl)

1372 {

1373 controlIdx = GetMouseControlIdx(x, y, mouseOver);

1374 pControl = (controlIdx >= 0) ? GetControl(controlIdx) : nullptr;

1375 }

1376

1377 if (capture && pControl)

1378 {

1380 {

1382

1384 return nullptr;

1385 }

1386

1387 mCapturedMap.insert(std::make_pair(touchID, pControl));

1388

1389

1390 }

1391

1392 if (mouseOver)

1393 mMouseOverIdx = controlIdx;

1394

1395 return pControl;

1396}

1397

1399{

1400 IControl* pControl = GetMouseControl(x, y, false);

1401 int idx = mLastClickedParam = pControl ? pControl->GetParamIdx() : -1;

1402 return idx;

1403}

1404

1406{

1407 const int idx = mLastClickedParam;

1408 mLastClickedParam = kNoParameter;

1409 return idx;

1410}

1411

1413{

1415}

1416

1418{

1419 IPopupMenu& contextMenu = mPromptPopupMenu;

1420 contextMenu.Clear();

1421

1422 if(pControl)

1423 {

1425

1426#if defined VST3_API || defined VST3C_API

1427 VST3_API_BASE* pVST3 = dynamic_cast<VST3_API_BASE*>(GetDelegate());

1428

1429 if (!pVST3->GetComponentHandler() || !pVST3->GetView())

1430 return;

1431

1432 Steinberg::FUnknownPtr<Steinberg::Vst::IComponentHandler3>handler(pVST3->GetComponentHandler() );

1433

1434 if (handler == 0)

1435 return;

1436

1437 Steinberg::Vst::ParamID p = paramIdx;

1438

1439 Steinberg::Vst::IContextMenu* pVST3ContextMenu = handler->createContextMenu(pVST3->GetView(), &p);

1440

1441 if (pVST3ContextMenu)

1442 {

1443 std::function<void(IPopupMenu* pCurrentMenu)> populateFunc;

1444 Steinberg::int32 tag = 0;

1445

1446 populateFunc = [&populateFunc, &tag, pVST3ContextMenu, pControl](IPopupMenu* pCurrentMenu) {

1447 Steinberg::Vst::IContextMenu::Item item = {0};

1448

1449 for (int i = 0; i < pCurrentMenu->NItems(); i++)

1450 {

1451 Steinberg::UString128 (pCurrentMenu->GetItemText(i)).copyTo (item.name, 128);

1452 item.tag = tag++;

1453 item.flags = 0;

1454

1455 if (pCurrentMenu->GetItem(i)->GetIsSeparator())

1456 {

1457 item.flags = Steinberg::Vst::IContextMenu::Item::kIsSeparator;

1458 }

1459 else if (auto pSubMenu = pCurrentMenu->GetItem(i)->GetSubmenu())

1460 {

1461 item.flags = Steinberg::Vst::IContextMenu::Item::kIsGroupStart;

1462 pVST3ContextMenu->addItem(item, pControl);

1463 populateFunc(pSubMenu);

1464 item.tag = tag++;

1465 item.flags = Steinberg::Vst::IContextMenu::Item::kIsGroupEnd;

1466 pVST3ContextMenu->addItem(item, pControl);

1467 continue;

1468 }

1469 else

1470 {

1471 if (!pCurrentMenu->GetItem(i)->GetEnabled())

1472 item.flags |= Steinberg::Vst::IContextMenu::Item::kIsDisabled;

1473

1474 if (pCurrentMenu->GetItem(i)->GetChecked())

1475 item.flags |= Steinberg::Vst::IContextMenu::Item::kIsChecked;

1476 }

1477

1478 pVST3ContextMenu->addItem(item, pControl);

1479 }

1480 };

1481

1482 populateFunc(&contextMenu);

1483

1484#ifdef OS_WIN

1487#else

1490#endif

1491 pVST3ContextMenu->popup((Steinberg::UCoord) x, (Steinberg::UCoord) y);

1492 pVST3ContextMenu->release();

1493 }

1494

1495#else

1496 if(!contextMenu.NItems())

1497 return;

1498

1499 DoCreatePopupMenu(*pControl, contextMenu, IRECT(x, y, x, y), kNoValIdx, true);

1500#endif

1501 }

1502}

1503

1505{

1507}

1508

1510{

1511 TRACE

1513}

1514

1516{

1517 if(mGUISizeMode == EUIResizerMode::Scale)

1518 {

1519 float scaleX = (x * GetDrawScale()) / mMouseDownX;

1520 float scaleY = (y * GetDrawScale()) / mMouseDownY;

1521

1523 }

1524 else

1525 {

1527 }

1528}

1529

1531{

1532 if (mAppearanceChangedFunc)

1533 mAppearanceChangedFunc(appearance);

1534}

1535

1537{

1538

1539

1541}

1542

1544{

1545 mEnableTooltips = enable;

1546 if (enable) mEnableMouseOver = true;

1547}

1548

1550{

1551#ifndef NDEBUG

1552 if (enable)

1553 {

1554 if (!mLiveEdit)

1555 {

1556 mLiveEdit = std::make_unique<IGraphicsLiveEdit>(mEnableMouseOver);

1558 }

1559 }

1560 else

1561 {

1562 mLiveEdit = nullptr;

1563 }

1564

1565 ClearMouseOver();

1569#endif

1570}

1571

1572

1573#ifdef SVG_USE_SKIA

1575{

1576 StaticStorage<SVGHolder>::Accessor storage(sSVGCache);

1577 SVGHolder* pHolder = storage.Find(fileName);

1578

1579 if(!pHolder)

1580 {

1581 WDL_TypedBuf<uint8_t> svgData = LoadResource(fileName, "svg");

1582 if (svgData.GetSize() == 0)

1583 {

1584 return ISVG(nullptr);

1585 }

1586 else

1587 {

1588 return LoadSVG(fileName, svgData.Get(), svgData.GetSize(), units, dpi);

1589 }

1590 }

1591

1592 return ISVG(pHolder->mSVGDom);

1593}

1594

1595ISVG IGraphics::LoadSVG(const char* name, const void* pData, int dataSize, const char* units, float dpi)

1596{

1597 StaticStorage<SVGHolder>::Accessor storage(sSVGCache);

1598 SVGHolder* pHolder = storage.Find(name);

1599

1600 if (!pHolder)

1601 {

1602 sk_sp<SkSVGDOM> svgDOM;

1603 SkDOM xmlDom;

1604

1605 SkMemoryStream svgStream(pData, dataSize);

1606 svgDOM = SkSVGDOM::MakeFromStream(svgStream);

1607

1608 if (!svgDOM)

1609 return ISVG(nullptr);

1610

1611

1612

1613 if (svgDOM->containerSize().width() == 0)

1614 {

1615 NSVGimage* pImage = nullptr;

1616

1617 WDL_String svgStr;

1618 svgStr.Set((const char*)pData, dataSize);

1619 pImage = nsvgParse(svgStr.Get(), units, dpi);

1620

1621 assert(pImage);

1622

1623 svgDOM->setContainerSize(SkSize::Make(pImage->width, pImage->height));

1624

1625 nsvgDelete(pImage);

1626 }

1627

1628 pHolder = new SVGHolder(svgDOM);

1629 storage.Add(pHolder, name);

1630 }

1631

1632 return ISVG(pHolder->mSVGDom);

1633}

1634

1635#else

1637{

1638 StaticStorage<SVGHolder>::Accessor storage(sSVGCache);

1639 SVGHolder* pHolder = storage.Find(fileName);

1640

1641 if(!pHolder)

1642 {

1643 WDL_TypedBuf<uint8_t> svgData = LoadResource(fileName, "svg");

1644 if (svgData.GetSize() == 0)

1645 {

1646 return ISVG(nullptr);

1647 }

1648 else

1649 {

1650 return LoadSVG(fileName, svgData.Get(), svgData.GetSize(), units, dpi);

1651 }

1652 }

1653

1654 return ISVG(pHolder->mImage);

1655}

1656

1657ISVG IGraphics::LoadSVG(const char* name, const void* pData, int dataSize, const char* units, float dpi)

1658{

1659 StaticStorage<SVGHolder>::Accessor storage(sSVGCache);

1660 SVGHolder* pHolder = storage.Find(name);

1661

1662 if (!pHolder)

1663 {

1664 NSVGimage* pImage = nullptr;

1665

1666 WDL_String svgStr;

1667 svgStr.Set(reinterpret_cast<const char*>(pData), dataSize);

1668 pImage = nsvgParse(svgStr.Get(), units, dpi);

1669

1670 if (!pImage)

1671 return ISVG(nullptr);

1672

1673 pHolder = new SVGHolder(pImage);

1674

1675 storage.Add(pHolder, name);

1676 }

1677

1678 return ISVG(pHolder->mImage);

1679}

1680#endif

1681

1683{

1684 WDL_TypedBuf<uint8_t> result;

1685

1686 WDL_String path;

1688

1689 if (resourceFound == EResourceLocation::kNotFound)

1690 return result;

1691

1692#ifdef OS_WIN

1693 if (resourceFound == EResourceLocation::kWinBinary)

1694 {

1695 int size = 0;

1697 result.Resize(size);

1698 result.Set((const uint8_t*)pResData, size);

1699 }

1700#endif

1701 if (resourceFound == EResourceLocation::kAbsolutePath)

1702 {

1703 FILE* fd = fopen(path.Get(), "rb");

1704

1705 if (!fd)

1706 return result;

1707

1708

1709 if (fseek(fd, 0, SEEK_END))

1710 {

1711 fclose(fd);

1712 return result;

1713 }

1714 long size = ftell(fd);

1715

1716

1717 if (fseek(fd, 0, SEEK_SET))

1718 {

1719 fclose(fd);

1720 return result;

1721 }

1722

1723 result.Resize((int)size);

1724 size_t bytesRead = fread(result.Get(), 1, (size_t)size, fd);

1725 if (bytesRead != (size_t)size)

1726 {

1727 fclose(fd);

1728 result.Resize(0, true);

1729 return result;

1730 }

1731 fclose(fd);

1732 }

1733

1734 return result;

1735}

1736

1738{

1739 if (targetScale == 0)

1741

1742 StaticStorage<APIBitmap>::Accessor storage(sBitmapCache);

1743 APIBitmap* pAPIBitmap = storage.Find(name, targetScale);

1744

1745

1746 if (!pAPIBitmap)

1747 {

1748 WDL_String fullPath;

1749 std::unique_ptr<APIBitmap> loadedBitmap;

1750 int sourceScale = 0;

1751

1752 const char* ext = name + strlen(name) - 1;

1753 while (ext >= name && *ext != '.') --ext;

1754 ++ext;

1755

1757

1758 if (!bitmapTypeSupported)

1759 return IBitmap();

1760

1761 EResourceLocation resourceLocation = SearchImageResource(name, ext, fullPath, targetScale, sourceScale);

1762

1763 if (resourceLocation == EResourceLocation::kNotFound)

1764 {

1765

1767 }

1768 else

1769 {

1770

1771 if (sourceScale != targetScale)

1772 pAPIBitmap = storage.Find(name, sourceScale);

1773

1774

1775 if (!pAPIBitmap)

1776 {

1777 loadedBitmap = std::unique_ptr<APIBitmap>(LoadAPIBitmap(fullPath.Get(), sourceScale, resourceLocation, ext));

1778 pAPIBitmap= loadedBitmap.get();

1779 }

1780 }

1781

1782

1783 assert(pAPIBitmap && "Bitmap not found");

1784

1785

1786 if (pAPIBitmap->GetScale() != targetScale)

1787 {

1788 return ScaleBitmap(IBitmap(pAPIBitmap, nStates, framesAreHorizontal, name), name, targetScale);

1789 }

1790 else if (loadedBitmap)

1791 {

1792 RetainBitmap(IBitmap(loadedBitmap.release(), nStates, framesAreHorizontal, name), name);

1793 }

1794 }

1795

1796 return IBitmap(pAPIBitmap, nStates, framesAreHorizontal, name);

1797}

1798

1799IBitmap IGraphics::LoadBitmap(const char *name, const void *pData, int dataSize, int nStates, bool framesAreHorizontal, int targetScale)

1800{

1801 if (targetScale == 0)

1803

1804 StaticStorage<APIBitmap>::Accessor storage(sBitmapCache);

1805 APIBitmap* pAPIBitmap = storage.Find(name, targetScale);

1806

1807

1808 if (!pAPIBitmap)

1809 {

1810 WDL_String fullPath;

1811 std::unique_ptr<APIBitmap> loadedBitmap;

1812 int sourceScale = 0;

1813

1814 const char* ext = name + strlen(name) - 1;

1815 while (ext >= name && *ext != '.') --ext;

1816 ++ext;

1817

1819

1820 if (!bitmapTypeSupported)

1821 return IBitmap();

1822

1823

1825

1826 if (!pAPIBitmap)

1827 {

1828 loadedBitmap = std::unique_ptr<APIBitmap>(LoadAPIBitmap(name, pData, dataSize, 1));

1829 pAPIBitmap= loadedBitmap.get();

1830 }

1831

1832

1833

1834 assert(pAPIBitmap && "Bitmap not found");

1835

1836

1837 if (pAPIBitmap->GetScale() != targetScale)

1838 {

1839 return ScaleBitmap(IBitmap(pAPIBitmap, nStates, framesAreHorizontal, name), name, targetScale);

1840 }

1841 else if (loadedBitmap)

1842 {

1843 RetainBitmap(IBitmap(loadedBitmap.release(), nStates, framesAreHorizontal, name), name);

1844 }

1845 }

1846

1847 return IBitmap(pAPIBitmap, nStates, framesAreHorizontal, name);

1848}

1849

1851{

1852 StaticStorage<APIBitmap>::Accessor storage(sBitmapCache);

1854}

1855

1857{

1858 StaticStorage<APIBitmap>::Accessor storage(sBitmapCache);

1860}

1861

1863{

1866

1867 mScreenScale = scale;

1869

1872 DrawBitmap(inBitmap, bounds, 0, 0, nullptr);

1876

1877 mScreenScale = screenScale;

1878 mDrawScale = drawScale;

1879

1880 return outBitmap;

1881}

1882

1883auto SearchNextScale = [](int& sourceScale, int targetScale) {

1884 if (sourceScale == targetScale && (targetScale != MAX_IMG_SCALE))

1885 sourceScale = MAX_IMG_SCALE;

1886 else if (sourceScale == targetScale + 1)

1887 sourceScale = targetScale - 1;

1888 else

1889 sourceScale--;

1890};

1891

1892EResourceLocation IGraphics::SearchImageResource(const char* name, const char* type, WDL_String& result, int targetScale, int& sourceScale)

1893{

1894 for (sourceScale = targetScale ; sourceScale > 0; SearchNextScale(sourceScale, targetScale))

1895 {

1896 WDL_String fullName(name);

1897

1898 if (sourceScale != 1)

1899 {

1900 WDL_String baseName(name); baseName.remove_fileext();

1901 WDL_String ext(fullName.get_fileext());

1902 fullName.SetFormatted((int) (strlen(name) + strlen("@2x")), "%s@%dx%s", baseName.Get(), sourceScale, ext.Get());

1903 }

1904

1906

1907 if (found > EResourceLocation::kNotFound)

1908 return found;

1909 }

1910

1911 return EResourceLocation::kNotFound;

1912}

1913

1915{

1916 StaticStorage<APIBitmap>::Accessor storage(sBitmapCache);

1917

1918 for (sourceScale = targetScale; sourceScale > 0; SearchNextScale(sourceScale, targetScale))

1919 {

1920 APIBitmap* pBitmap = storage.Find(name, sourceScale);

1921

1922 if (pBitmap)

1923 return pBitmap;

1924 }

1925

1926 return nullptr;

1927}

1928

1930{

1931 for (auto c = 0; c < NControls(); c++)

1932 {

1934 if (pVB)

1936 }

1937}

1938

1940{

1941 mInTextEntry = &control;

1942 mTextEntryValIdx = valIdx;

1943

1944 int paramIdx = valIdx > kNoValIdx ? control.GetParamIdx(valIdx) : kNoParameter;

1945

1946 if (mTextEntryControl)

1947 mTextEntryControl->CreateTextEntry(paramIdx, text, bounds, control.GetTextEntryLength(), str);

1948 else

1950

1951 mInTextEntry->SetDirty(false);

1952}

1953

1954void IGraphics::DoCreatePopupMenu(IControl& control, IPopupMenu& menu, const IRECT& bounds, int valIdx, bool isContext)

1955{

1957

1958 mInPopupMenu = &control;

1959 mPopupMenuValIdx = valIdx;

1960 mIsContextMenu = isContext;

1961

1962 if (mPopupControl)

1963 {

1964 mPopupControl->CreatePopupMenu(menu, bounds);

1965 }

1966 else

1967 {

1968 bool isAsync = false;

1970

1971 if (!isAsync)

1973 }

1974}

1975

1977{

1978 DoCreatePopupMenu(control, menu, bounds, valIdx, false);

1979}

1980

1981void IGraphics::EndDragResize()

1982{

1983 mResizingInProcess = false;

1984

1986 {

1987

1990 }

1991 else if (mCornerResizer)

1992 mCornerResizer->SetDirty(false);

1993}

1994

1996{

1999 const int w = static_cast<int>(std::ceil(pixelBackingScale * std::ceil(alignedBounds.W())));

2000 const int h = static_cast<int>(std::ceil(pixelBackingScale * std::ceil(alignedBounds.H())));

2001

2003}

2004

2006{

2008

2009 ownedLayer.swap(layer);

2010 ILayer* pOwnerlessLayer = ownedLayer.release();

2011

2012 if (pOwnerlessLayer)

2013 {

2015 }

2016}

2017

2019{

2021}

2022

2024{

2025 mLayers.push(pLayer);

2030}

2031

2033{

2034 ILayer* pLayer = nullptr;

2035

2036 if (!mLayers.empty())

2037 {

2038 pLayer = mLayers.top();

2039 mLayers.pop();

2040 }

2041

2046

2047 return pLayer;

2048}

2049

2051{

2052 const APIBitmap* pBitmap = layer ? layer->GetAPIBitmap() : nullptr;

2053

2054 if (pBitmap && layer->mControl && layer->mControlRECT != layer->mControl->GetRECT())

2055 {

2056 layer->mControlRECT = layer->mControl->GetRECT();

2057 layer->Invalidate();

2058 }

2059

2061}

2062

2064{

2067 DrawBitmap(layer->GetBitmap(), layer->Bounds(), 0, 0, pBlend);

2069}

2070

2072{

2073 IBitmap bitmap = layer->GetBitmap();

2074 IRECT layerBounds = layer->Bounds();

2077 IRECT newBounds(0., 0., layerBounds.W(), layerBounds.H());

2079 DrawBitmap(bitmap, newBounds, 0, 0, pBlend);

2081}

2082

2084{

2087 IBitmap bitmap = layer->GetBitmap();

2088 IRECT bounds = layer->Bounds();

2091}

2092

2094{

2095 auto GaussianBlurSwap = [](uint8_t* out, uint8_t* in, uint8_t* kernel, int width, int height,

2096 int outStride, int inStride, int kernelSize, uint32_t norm)

2097 {

2098 int repeats = 0;

2099 int fullKernelSize = kernelSize * 2 + 1;

2100 uint32_t last = 0;

2101

2102 auto RepeatCheck = [&](int idx)

2103 {

2104 repeats = last == in[idx * 4] ? std::min(repeats + 1, fullKernelSize) : 1;

2105 last = in[idx * 4];

2106

2107 return repeats == fullKernelSize;

2108 };

2109

2110 for (int i = 0; i < height; i++, in += inStride)

2111 {

2112 for (int j = 0; j < kernelSize - 1; j++)

2113 {

2114 uint32_t accum = in[j * 4] * kernel[0];

2115 for (int k = 1; k < j + 1; k++)

2116 accum += kernel[k] * in[(j - k) * 4];

2117 for (int k = 1; k < kernelSize; k++)

2118 accum += kernel[k] * in[(j + k) * 4];

2119 out[j * outStride + (i * 4)] = static_cast<uint8_t>(std::min(static_cast<uint32_t>(255), accum / norm));

2120 }

2121 for (int j = 0; j < kernelSize * 2 - 2; j++)

2122 RepeatCheck(j);

2123 for (int j = kernelSize - 1; j < (width - kernelSize) + 1; j++)

2124 {

2125 if (RepeatCheck(j + kernelSize - 1))

2126 {

2127 out[j * outStride + (i * 4)] = static_cast<uint8_t>(last);

2128 continue;

2129 }

2130

2131 uint32_t accum = in[j * 4] * kernel[0];

2132 for (int k = 1; k < kernelSize; k++)

2133 accum += kernel[k] * (in[(j - k) * 4] + in[(j + k) * 4]);

2134 out[j * outStride + (i * 4)] = static_cast<uint8_t>(std::min(static_cast<uint32_t>(255), accum / norm));

2135 }

2136 for (int j = (width - kernelSize) + 1; j < width; j++)

2137 {

2138 uint32_t accum = in[j * 4] * kernel[0];

2139 for (int k = 1; k < kernelSize; k++)

2140 accum += kernel[k] * in[(j - k) * 4];

2141 for (int k = 1; k < width - j; k++)

2142 accum += kernel[k] * in[(j + k) * 4];

2143 out[j * outStride + (i * 4)] = static_cast<uint8_t>(std::min(static_cast<uint32_t>(255), accum / norm));

2144 }

2145 }

2146 };

2147

2148 RawBitmapData temp1;

2149 RawBitmapData temp2;

2150 RawBitmapData kernel;

2151

2152

2154

2155 if (!temp1.GetSize())

2156 return;

2157 temp2.Resize(temp1.GetSize());

2158

2159

2161 float scale = layer->GetAPIBitmap()->GetScale() * layer->GetAPIBitmap()->GetDrawScale();

2162 float blurSize = std::max(1.f, (shadow.mBlurSize * scale) + 1.f);

2163 float blurConst = 4.5f / (blurSize * blurSize);

2164 int iSize = static_cast<int>(ceil(blurSize));

2165 int width = layer->GetAPIBitmap()->GetWidth();

2166 int height = layer->GetAPIBitmap()->GetHeight();

2167 int stride1 = temp1.GetSize() / width;

2168 int stride2 = flipped ? -temp1.GetSize() / height : temp1.GetSize() / height;

2169 int stride3 = flipped ? -stride2 : stride2;

2170

2171 kernel.Resize(iSize);

2172

2173 for (int i = 0; i < iSize; i++)

2174 kernel.Get()[i] = static_cast<uint8_t>(std::round(255.f * std::expf(-(i * i) * blurConst)));

2175

2176

2177 int normFactor = kernel.Get()[0];

2178

2179 for (int i = 1; i < iSize; i++)

2180 normFactor += kernel.Get()[i] + kernel.Get()[i];

2181

2182

2183 uint8_t* asRows = temp1.Get() + AlphaChannel();

2184 uint8_t* inRows = flipped ? asRows + stride3 * (height - 1) : asRows;

2185 uint8_t* asCols = temp2.Get() + AlphaChannel();

2186

2187 GaussianBlurSwap(asCols, inRows, kernel.Get(), width, height, stride1, stride2, iSize, normFactor);

2188 GaussianBlurSwap(asRows, asCols, kernel.Get(), height, width, stride3, stride1, iSize, normFactor);

2189

2190

2192}

2193

2195{

2196 PlatformFontPtr font = LoadPlatformFont(fontID, fileNameOrResID);

2197

2198 if (font)

2199 {

2201 {

2203 return true;

2204 }

2205 }

2206

2207 DBGMSG("Could not locate font %s\n", fileNameOrResID);

2208 return false;

2209}

2210

2212{

2213 PlatformFontPtr font = LoadPlatformFont(fontID, pData, dataSize);

2214

2215 if (font)

2216 {

2218 {

2220 return true;

2221 }

2222 }

2223

2224 DBGMSG("Could not load font %s\n", fontID);

2225 return false;

2226}

2227

2229{

2230 PlatformFontPtr font = LoadPlatformFont(fontID, fontName, style);

2231

2232 if (font)

2233 {

2235 {

2237 return true;

2238 }

2239 }

2240

2241 DBGMSG("Could not locate font %s\n", fontID);

2242 return false;

2243}

2244

2246{

2247 double tx = 0.0, ty = 0.0;

2248

2250 rect.Translate(static_cast<float>(tx), static_cast<float>(ty));

2251}

2252

2254{

2255 if (!text.mAngle)

2256 return;

2257

2259

2260 double x0 = rect.L;

2261 double y0 = rect.T;

2262 double x1 = rect.R;

2263 double y1 = rect.T;

2264 double x2 = rect.R;

2265 double y2 = rect.B;

2266 double x3 = rect.L;

2267 double y3 = rect.B;

2268

2273

2274 IRECT r1(static_cast<float>(std::min(x0, x3)), static_cast<float>(std::min(y0, y3)), static_cast<float>(std::max(x0, x3)), static_cast<float>(std::max(y0, y3)));

2275 IRECT r2(static_cast<float>(std::min(x1, x2)), static_cast<float>(std::min(y1, y2)), static_cast<float>(std::max(x1, x2)), static_cast<float>(std::max(y1, y2)));

2276 rect = r1.Union(r2);

2277

2278 switch (text.mAlign)

2279 {

2280 case EAlign::Near: tx = bounds.L - rect.L; break;

2281 case EAlign::Center: tx = bounds.MW() - rect.MW(); break;

2282 case EAlign::Far: tx = bounds.R - rect.R; break;

2283 }

2284

2285 switch (text.mVAlign)

2286 {

2287 case EVAlign::Top: ty = bounds.T - rect.T; break;

2288 case EVAlign::Middle: ty = bounds.MH() - rect.MH(); break;

2289 case EVAlign::Bottom: ty = bounds.B - rect.B; break;

2290 }

2291}

2292

2294{

2297

2298 int note = 0;

2299 static int base = 48;

2300 static bool keysDown[128] = {};

2301

2302 auto onOctSwitch = [&]() {

2303 base = Clip(base, 24, 96);

2304

2305 for(auto i=0;i<128;i++) {

2306 if(keysDown[i]) {

2309 if(func)

2310 func(msg);

2311 }

2312 }

2313 };

2314

2315 switch (key.VK) {

2316 case kVK_A: note = 0; break;

2317 case kVK_W: note = 1; break;

2318 case kVK_S: note = 2; break;

2319 case kVK_E: note = 3; break;

2320 case kVK_D: note = 4; break;

2321 case kVK_F: note = 5; break;

2322 case kVK_T: note = 6; break;

2323 case kVK_G: note = 7; break;

2324 case kVK_Y: note = 8; break;

2325 case kVK_H: note = 9; break;

2326 case kVK_U: note = 10; break;

2327 case kVK_J: note = 11; break;

2328 case kVK_K: note = 12; break;

2329 case kVK_O: note = 13; break;

2330 case kVK_L: note = 14; break;

2331 case kVK_Z: if(!isUp) { base -= 12; onOctSwitch(); } return true;

2332 case kVK_X: if(!isUp) { base += 12; onOctSwitch(); } return true;

2333 default: return true;

2334 }

2335

2336 int pitch = base + note;

2337

2338 if(!isUp) {

2339 if(keysDown[pitch] == false) {

2341 keysDown[pitch] = true;

2343 if(func)

2344 func(msg);

2345 }

2346 }

2347 else {

2348 if(keysDown[pitch] == true) {

2350 keysDown[pitch] = false;

2352 if(func)

2353 func(msg);

2354 }

2355 }

2356

2357 return true;

2358 });

2359}

2360

2362{

2363 IControl* pControl = GetMouseControl(x, y, false, false);

2364

2366 return true;

2367

2368 if(mGestureRegions.Size() == 0)

2369 return false;

2370 else

2371 {

2372 int regionIdx = mGestureRegions.Find(x, y);

2373

2374 if(regionIdx > -1)

2375 return true;

2376 }

2377

2378 return false;

2379}

2380

2382{

2383 IControl* pControl = GetMouseControl(info.x, info.y, false, false);

2384

2387 else

2388 {

2389 int regionIdx = mGestureRegions.Find(info.x, info.y);

2390

2391 if(regionIdx > -1)

2392 mGestureRegionFuncs.find(regionIdx)->second(nullptr, info);

2393 }

2394}

2395

2397{

2398 if (std::find(std::begin(mRegisteredGestures), std::end(mRegisteredGestures), type) != std::end(mRegisteredGestures))

2399 {

2400 mRegisteredGestures.push_back(type);

2401 }

2402}

2403

2405{

2406 mGestureRegions.Add(bounds);

2408 mGestureRegionFuncs.insert(std::make_pair(mGestureRegions.Size()-1, func));

2409}

2410

2412{

2413 mGestureRegions.Clear();

2414 mGestureRegionFuncs.clear();

2415}

2416

2418{

2419 float width = bitmap.W() / bitmap.GetDrawScale();

2420 float height = bitmap.H() / bitmap.GetDrawScale();

2421

2425 DrawBitmap(bitmap, IRECT(-width * 0.5f, - height * 0.5f, width * 0.5f, height * 0.5f), 0, 0, pBlend);

2427}

2428

2430{

2431 FillRect(color, IRECT(x, y, x+1.f, y+1.f), pBlend);

2432}

2433

2435{

2440}

2441

2443{

2445

2446

2447 if (gridSizeH > 1.f)

2448 {

2449 for (float x = bounds.L + gridSizeH; x < bounds.R; x += gridSizeH)

2450 {

2453 }

2454 }

2455

2456 if (gridSizeV > 1.f)

2457 {

2458 for (float y = bounds.T + gridSizeV; y < bounds.B; y += gridSizeV)

2459 {

2462 }

2463 }

2464

2466}

2467

2468void IGraphics::DrawData(const IColor& color, const IRECT& bounds, float* normYPoints, int nPoints, float* normXPoints, const IBlend* pBlend, float thickness, const IColor* pFillColor)

2469{

2470 if (nPoints == 0)

2471 return;

2472

2474

2475 float xPos = bounds.L;

2476

2477 PathMoveTo(xPos, bounds.B - (bounds.H() * normYPoints[0]));

2478

2479 for (auto i = 1; i < nPoints; i++)

2480 {

2481 if (normXPoints)

2482 xPos = bounds.L + (bounds.W() * normXPoints[i]);

2483 else

2484 xPos = bounds.L + ((bounds.W() / (float) (nPoints - 1) * i));

2485

2486 PathLineTo(xPos, bounds.B - (bounds.H() * normYPoints[i]));

2487 }

2488

2489 if (pFillColor)

2490 {

2492 }

2493

2495}

2496

2498{

2500

2502 options.mDash.SetDash(&dashLen, 0.0, 1);

2505 PathStroke(color, thickness, options, pBlend);

2506}

2507

2509{

2513}

2514

2516{

2520}

2521

2523{

2527}

2528

2530{

2534}

2535

2537{

2541}

2542

2544{

2546 PathArc(cx, cy, r, a1, a2);

2548}

2549

2551{

2555}

2556

2558{

2561 options.mDash.SetDash(&dashLen, 0., 1);

2563 PathStroke(color, thickness, options, pBlend);

2564}

2565

2567{

2571}

2572

2574{

2578}

2579

2581{

2585}

2586

2588{

2592}

2593

2595{

2599}

2600

2602{

2606}

2607

2609{

2613}

2614

2616{

2619 PathArc(cx, cy, r, a1, a2);

2622}

2623

2625{

2629}

2630

2632{

2636}

2637

2639{

2643}

2644

2646{

2651}

2652

2654{

2660}

2661

2663{

2664 if (ctl <= 0.f && ctr <= 0.f && cbl <= 0.f && cbr <= 0.f)

2665 {

2667 }

2668 else

2669 {

2670 const float y = bounds.B - bounds.H();

2672 PathArc(bounds.L + ctl, y + ctl, ctl, 270.f, 360.f);

2673 PathArc(bounds.L + bounds.W() - ctr, y + ctr, ctr, 0.f, 90.f);

2674 PathArc(bounds.L + bounds.W() - cbr, y + bounds.H() - cbr, cbr, 90.f, 180.f);

2675 PathArc(bounds.L + cbl, y + bounds.H() - cbl, cbl, 180.f, 270.f);

2677 }

2678}

2679

2681{

2683}

2684

2686{

2688

2689 if (r1 <= 0.0 || r2 <= 0.0)

2690 return;

2691

2695

2697

2699}

2700

2702{

2703 PathEllipse(bounds.MW(), bounds.MH(), bounds.W() / 2.f, bounds.H() / 2.f);

2704}

2705

2707{

2709 PathArc(cx, cy, r, 0.f, 360.f);

2711}

2712

2714{

2716 for(int i = 1; i < nPoints; i++)

2719}

2720

2722{

2723 mTransformStates.push(mTransform);

2724}

2725

2727{

2728 if (!mTransformStates.empty())

2729 {

2730 mTransform = mTransformStates.top();

2731 mTransformStates.pop();

2732 PathTransformSetMatrix(mTransform);

2733 }

2734}

2735

2737{

2738 if (clearStates)

2739 {

2740 std::stack<IMatrix> newStack;

2741 mTransformStates.swap(newStack);

2742 }

2743

2745 PathTransformSetMatrix(mTransform);

2746}

2747

2749{

2751 PathTransformSetMatrix(mTransform);

2752}

2753

2755{

2756 mTransform.Scale(scaleX, scaleY);

2757 PathTransformSetMatrix(mTransform);

2758}

2759

2761{

2763}

2764

2766{

2767 mTransform.Rotate(angle);

2768 PathTransformSetMatrix(mTransform);

2769}

2770

2772{

2773 mTransform.Skew(xAngle, yAngle);

2774 PathTransformSetMatrix(mTransform);

2775}

2776

2778{

2780 PathTransformSetMatrix(mTransform);

2781}

2782

2784{

2785 IRECT drawArea = mLayers.empty() ? mClipRECT : mLayers.top()->Bounds();

2787 PathTransformSetMatrix(IMatrix());

2788 SetClipRegion(clip);

2789 PathTransformSetMatrix(mTransform);

2790}

2791

2793{

2796 IRECT newBounds(0., 0., static_cast<float>(bitmap.W()), static_cast<float>(bitmap.H()));

2797 PathTransformScale(bounds.W() / static_cast<float>(bitmap.W()), bounds.H() / static_cast<float>(bitmap.H()));

2798 DrawBitmap(bitmap, newBounds, 0, 0, pBlend);

2800}

2801

2803{

2804 float xScale = dest.W() / svg.W();

2805 float yScale = dest.H() / svg.H();

2806 float scale = xScale < yScale ? xScale : yScale;

2807

2811 DoDrawSVG(svg, pBlend, pStrokeColor, pFillColor);

2813}

2814

2816{

2820 DrawSVG(svg, IRECT(-width * 0.5f, - height * 0.5f, width * 0.5f, height * 0.5f), pBlend);

2822}

2823

2824IPattern IGraphics::GetSVGPattern(const NSVGpaint& paint, float opacity)

2825{

2826 int alpha = std::min(255, std::max(int(roundf(opacity * 255.f)), 0));

2827

2828 switch (paint.type)

2829 {

2830 case NSVG_PAINT_COLOR:

2831 return IColor(alpha, (paint.color >> 0) & 0xFF, (paint.color >> 8) & 0xFF, (paint.color >> 16) & 0xFF);

2832

2833 case NSVG_PAINT_LINEAR_GRADIENT:

2834 case NSVG_PAINT_RADIAL_GRADIENT:

2835 {

2836 NSVGgradient* pGrad = paint.gradient;

2837

2838 IPattern pattern(paint.type == NSVG_PAINT_LINEAR_GRADIENT ? EPatternType::Linear : EPatternType::Radial);

2839

2840

2841 switch (pGrad->spread)

2842 {

2843 case NSVG_SPREAD_PAD: pattern.mExtend = EPatternExtend::Pad; break;

2844 case NSVG_SPREAD_REFLECT: pattern.mExtend = EPatternExtend::Reflect; break;

2845 case NSVG_SPREAD_REPEAT: pattern.mExtend = EPatternExtend::Repeat; break;

2846 }

2847

2848

2849 for (int i = 0; i < pGrad->nstops; i++)

2850 {

2851 unsigned int color = pGrad->stops[i].color;

2852 pattern.AddStop(IColor(255, (color >> 0) & 0xFF, (color >> 8) & 0xFF, (color >> 16) & 0xFF), pGrad->stops[i].offset);

2853 }

2854

2855

2856 pattern.SetTransform(pGrad->xform[0], pGrad->xform[1], pGrad->xform[2], pGrad->xform[3], pGrad->xform[4], pGrad->xform[5]);

2857

2858 return pattern;

2859 }

2860 default:

2861 return IColor(alpha, 0, 0, 0);

2862 }

2863}

2864

2865void IGraphics::DoDrawSVG(const ISVG& svg, const IBlend* pBlend, const IColor* pStrokeColor, const IColor* pFillColor)

2866{

2867#ifdef SVG_USE_SKIA

2868 SkCanvas* canvas = static_cast<SkCanvas*>(GetDrawContext());

2869 svg.mSVGDom->render(canvas);

2870#else

2871 NSVGimage* pImage = svg.mImage;

2872

2873 assert(pImage != nullptr);

2874

2875 for (NSVGshape* pShape = pImage->shapes; pShape; pShape = pShape->next)

2876 {

2877 if (!(pShape->flags & NSVG_FLAGS_VISIBLE))

2878 continue;

2879

2880

2882

2883

2884 for (NSVGpath* pPath = pShape->paths; pPath; pPath = pPath->next)

2885 {

2886 PathMoveTo(pPath->pts[0], pPath->pts[1]);

2887

2888 for (int i = 1; i < pPath->npts; i += 3)

2889 {

2890 float *p = &pPath->pts[i*2];

2892 }

2893

2894 if (pPath->closed)

2896

2897

2898 int crossings = 0;

2899 IVec2 p0{pPath->pts[0], pPath->pts[1]};

2900 IVec2 p1{pPath->bounds[0] - 1.0f, pPath->bounds[1] - 1.0f};

2901

2902 for (NSVGpath *pPath2 = pShape->paths; pPath2; pPath2 = pPath2->next)

2903 {

2904 if (pPath2 == pPath)

2905 continue;

2906

2907 if (pPath2->npts < 4)

2908 continue;

2909 for (int i = 1; i < pPath2->npts + 3; i += 3)

2910 {

2911 float *p = &pPath2->pts[2*i];

2912

2913 IVec2 p2 {p[-2], p[-1]};

2914

2915 IVec2 p3 = (i < pPath2->npts) ? IVec2{p[4], p[5]} : IVec2{pPath2->pts[0], pPath2->pts[1]};

2916 float crossing = GetLineCrossing(p0, p1, p2, p3);

2917 float crossing2 = GetLineCrossing(p2, p3, p0, p1);

2918 if (0.0 <= crossing && crossing < 1.0 && 0.0 <= crossing2)

2919 {

2920 crossings++;

2921 }

2922 }

2923 }

2925 }

2926

2927

2928 if (pShape->fill.type != NSVG_PAINT_NONE)

2929 {

2931 options.mFillRule = EFillRule::Preserve;

2932

2933 options.mPreserve = pShape->stroke.type != NSVG_PAINT_NONE;

2934 PathFill(pFillColor ? IPattern(*pFillColor) : GetSVGPattern(pShape->fill, pShape->opacity), options, pBlend);

2935 }

2936

2937

2938 if (pShape->stroke.type != NSVG_PAINT_NONE)

2939 {

2941

2942 options.mMiterLimit = pShape->miterLimit;

2943

2944 switch (pShape->strokeLineCap)

2945 {

2946 case NSVG_CAP_BUTT: options.mCapOption = ELineCap::Butt; break;

2947 case NSVG_CAP_ROUND: options.mCapOption = ELineCap::Round; break;

2948 case NSVG_CAP_SQUARE: options.mCapOption = ELineCap::Square; break;

2949 }

2950

2951 switch (pShape->strokeLineJoin)

2952 {

2953 case NSVG_JOIN_MITER: options.mJoinOption = ELineJoin::Miter; break;

2954 case NSVG_JOIN_ROUND: options.mJoinOption = ELineJoin::Round; break;

2955 case NSVG_JOIN_BEVEL: options.mJoinOption = ELineJoin::Bevel; break;

2956 }

2957

2958 options.mDash.SetDash(pShape->strokeDashArray, pShape->strokeDashOffset, pShape->strokeDashCount);

2959

2960 PathStroke(pStrokeColor ? IPattern(*pStrokeColor) : GetSVGPattern(pShape->stroke, pShape->opacity), pShape->strokeWidth, options, pBlend);

2961 }

2962 }

2963#endif

2964 }

This file contains the base IControl implementation, along with some base classes for specific types ...

A collection of IControls for common UI widgets, such as knobs, sliders, switches.

const void * LoadWinResource(const char *resID, const char *type, int &sizeInBytes, void *pHInstance)

Load a resource from the binary (windows only).

EResourceLocation LocateResource(const char *fileNameOrResID, const char *type, WDL_String &result, const char *bundleID, void *pHInstance, const char *sharedResourcesSubPath)

Find the absolute path of a resource based on it's file name (e.g.

A Text entry widget drawn by IGraphics to optionally override platform text entries.

A base class interface for a bitmap abstraction around the different drawing back end bitmap represen...

float GetDrawScale() const

A basic control to draw a bitmap, or one frame of a stacked bitmap depending on the current value.

User-facing bitmap abstraction that you use to manage bitmap data, independant of draw class/platform...

bool GetFramesAreHorizontal() const

const WDL_String & GetResourceName() const

float GetDrawScale() const

APIBitmap * GetAPIBitmap() const

A special control to draw contextual info as a slider etc is moved If used in the main IControl stack...

The lowest level base class of an IGraphics control.

virtual bool GetWantsGestures() const

virtual void OnResize()

Called when IControl is constructed or resized using SetRect().

const char * GetGroup() const

Get the group that the control belongs to, if any.

int GetTextEntryLength() const

Get the max number of characters that are allowed in text entry.

virtual void OnDropMultiple(const std::vector< const char * > &paths)

Implement to handle multiple items drag 'n dropped onto this control.

virtual bool OnKeyUp(float x, float y, const IKeyPress &key)

Implement this method to respond to a key up event on this control.

virtual void OnMouseOut()

Implement this method to respond to a mouseout event on this control.

bool GetWantsMultiTouch() const

virtual void OnGUIIdle()

This is an idle timer tick call on the GUI thread, only active if USE_IDLE_CALLS is defined.

bool GetMouseEventsWhenDisabled() const

bool GetMouseOverWhenDisabled() const

virtual void OnMouseOver(float x, float y, const IMouseMod &mod)

Implement this method to respond to a mouseover event on this control.

virtual void SetPosition(float x, float y)

Set the position of the control, preserving the width and height.

void SetGroup(const char *groupName)

Assign the control to a control group.

virtual void OnPopupMenuSelection(IPopupMenu *pSelectedMenu, int valIdx)

Implement this method to handle popup menu selection after IGraphics::CreatePopupMenu/IControlPromptU...

virtual void OnMouseDown(float x, float y, const IMouseMod &mod)

Implement this method to respond to a mouse down event on this control.

virtual void SetValueFromUserInput(double value, int valIdx=0)

Set the control's value after user input.

virtual bool IsDirty()

Called at each display refresh by the IGraphics draw loop, after IControl::Animate(),...

virtual bool IsHit(float x, float y) const

Hit test the control.

virtual void Hide(bool hide)

Shows or hides the IControl.

virtual void OnRescale()

Implement to do something when graphics is scaled globally (e.g.

void SetDelegate(IGEditorDelegate &dlg)

Used internally to set the mDelegate (and mGraphics) variables.

virtual void OnDeleteFromPopupMenu(IPopupMenu *pMenu, int itemIdx)

Implement this method to handle popup menu deletion interactions (on IOS) after IGraphics::CreatePopu...

virtual void OnTouchCancelled(float x, float y, const IMouseMod &mod)

Implement this method to respond to a touch cancel event on this control.

virtual void OnDrop(const char *str)

Implement to do something when something was drag 'n dropped onto 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.

virtual bool OnKeyDown(float x, float y, const IKeyPress &key)

Implement this method to respond to a key down event on this control.

int LinkedToParam(int paramIdx) const

Check if the control is linked to a particular parameter.

bool GetIgnoreMouse() const

virtual void OnMouseDblClick(float x, float y, const IMouseMod &mod)

Implement this method to respond to a mouse double click event on this control.

int GetTag() const

Get the control's tag.

virtual void OnMouseUp(float x, float y, const IMouseMod &mod)

Implement this method to respond to a mouse up event on this control.

virtual void DrawPTHighlight(IGraphics &g)

Implement this to customise how a colored highlight is drawn on the control in ProTools (AAX format o...

virtual void CreateContextMenu(IPopupMenu &contextMenu)

Called by default when the user right clicks a control.

virtual void OnAttached()

Called after the control has been attached, and its delegate and graphics member variable set.

virtual bool OnGesture(const IGestureInfo &info)

virtual void OnMouseDrag(float x, float y, float dX, float dY, const IMouseMod &mod)

Implement this method to respond to a mouse drag event on this control.

virtual void OnMouseWheel(float x, float y, const IMouseMod &mod, float d)

Implement this method to respond to a mouse wheel event on this control.

virtual void Draw(IGraphics &g)=0

Draw the control to the graphics context.

const IParam * GetParam(int valIdx=0) const

Get a const pointer to the IParam object (owned by the editor delegate class), associated with this c...

const IText & GetText() const

Get the Text object for the control.

bool GetMouseDblAsSingleClick() const

Get double click as single click By default, mouse double click has its own handler.

virtual void SetSize(float w, float h)

Set the size of the control, preserving the current position.

void SetPTParameterHighlight(bool isHighlighted, int color)

Used internally by the AAX wrapper view interface to set the control parmeter highlight.

virtual void OnTextEntryCompletion(const char *str, int valIdx)

Implement this method to handle text input after IGraphics::CreateTextEntry/IControlPromptUserInput.

virtual void SetDisabled(bool disable)

Sets disabled mode for the control, the default implementation modifies the mBlend member.

double GetValue(int valIdx=0) const

Get the control's value.

void SetTargetAndDrawRECTs(const IRECT &bounds)

Set BOTH the draw rect and the target area, within the graphics context for this control.

virtual void OnContextSelection(int itemSelected)

Implement this to respond to a menu selection from CreateContextMenu();.

virtual int GetValIdxForPos(float x, float y) const

Check to see which of the control's values relates to this x and y coordinate.

IContainerBase * GetParent() const

virtual void SetDirty(bool triggerAction=true, int valIdx=kNoValIdx)

Mark the control as dirty, i.e.

bool GetPromptShowsParamLabel() const

A control for resizing the plug-in window by clicking and dragging in the bottom right-hand corner Th...

virtual void BeginInformHostOfParamChangeFromUI(int paramIdx)=0

Called by the UI at the beginning of a parameter change gesture, in order to notify the host (via a c...

virtual void EndInformHostOfParamChangeFromUI(int paramIdx)=0

Called by the user interface at the end of a parameter change gesture, in order to notify the host (v...

virtual void SendMidiMsgFromUI(const IMidiMsg &msg)

SendMidiMsgFromUI (Abbreviation: SMMFUI) This method should be used when sending a MIDI message from ...

virtual bool ConstrainEditorResize(int &w, int &h) const

Constrain the incoming editor width and height values based on the minimum and maximum.

virtual bool EditorResizeFromUI(int viewWidth, int viewHeight, bool needsPlatformResize)

If the editor changes UI dimensions, e.g.

An editor delegate base class that uses IGraphics for the UI.

virtual void LayoutUI(IGraphics *pGraphics)

Called to layout controls when the GUI is initially opened and again if the UI size changes.

bool ControlIsCaptured() const

Check to see if any control is captured.

void EnableTooltips(bool enable)

virtual float DoMeasureText(const IText &text, const char *str, IRECT &bounds) const =0

Internal method to measure text dimensions.

void Resize(int w, int h, float scale, bool needsPlatformResize=true)

Resizes the graphics context to new dimensions and scale.

virtual void DrawRotatedSVG(const ISVG &svg, float destCentreX, float destCentreY, float width, float height, double angle, const IBlend *pBlend=0)

Draw an SVG image to the graphics context with rotation.

virtual void DrawRect(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0, float thickness=1.f)

Draw a rectangle to the graphics context.

virtual void FillEllipse(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0)

Fill an ellipse within a rectangular region of the graphics context.

ILayer * PopLayer()

Pop a layer off the stack.

virtual void DrawConvexPolygon(const IColor &color, float *x, float *y, int nPoints, const IBlend *pBlend=0, float thickness=1.f)

Draw a convex polygon to the graphics context.

virtual void DrawEllipse(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0, float thickness=1.f)

Draw an ellipse within a rectangular region of the graphics context.

virtual void DrawFittedBitmap(const IBitmap &bitmap, const IRECT &bounds, const IBlend *pBlend=0)

Draw a bitmap (raster) image to the graphics context, scaling the image to fit the bounds.

void DrawBitmapedText(const IBitmap &bitmap, const IRECT &bounds, IText &text, IBlend *pBlend, const char *str, bool vCenter=true, bool multiline=false, int charWidth=6, int charHeight=12, int charOffset=0)

Draws mono spaced bitmap text.

void AttachPopupMenuControl(const IText &text=DEFAULT_TEXT, const IRECT &bounds=IRECT())

Attach a control for pop-up menus, to override platform style menus.

virtual void DrawPoint(const IColor &color, float x, float y, const IBlend *pBlend=0)

Fill a rectangle corresponding to a pixel on a 1:1 screen with a color.

void RemoveControl(int idx)

Remove a control at a particular index, (frees memory).

void DeleteFromPopupMenu(IPopupMenu *pMenu, int itemIdx)

Called by IOS platform (or other supported platforms) in order to update a control with a deletion in...

virtual const char * GetBundleID() const

Get the bundle ID on macOS and iOS, returns emtpy string on other OSs.

void PathConvexPolygon(float *x, float *y, int nPoints)

Add a convex polygon to the current path.

virtual void PathFill(const IPattern &pattern, const IFillOptions &options=IFillOptions(), const IBlend *pBlend=0)=0

Fill the current current path.

virtual float GetPlatformWindowScale() const

Returns a scaling factor for resizing parent windows via the host/plugin API.

void DrawText(const IText &text, const char *str, const IRECT &bounds, const IBlend *pBlend=0)

Draw some text to the graphics context in a specific rectangle.

float GetTotalScale() const

Gets the combined draw and screen/display scaling factor.

int GetParamIdxForPTAutomation(float x, float y)

[AAX only] This can be called by the ProTools API class (e.g.

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.

void CreateTextEntry(IControl &control, const IText &text, const IRECT &bounds, const char *str="", int valIdx=0)

Create a text entry box.

virtual void PathClear()=0

Clear the stack of path drawing commands.

virtual void * GetDrawContext()=0

Gets a void pointer to underlying drawing context, for the IGraphics backend See draw class implement...

void PathRoundRect(const IRECT &bounds, float ctl, float ctr, float cbl, float cbr)

Add a rounded rectangle to the current path, with independent corner roundness.

void SetPTParameterHighlight(int paramIdx, bool isHighlighted, int color)

[AAX only] See AAX_CEffectGUI::SetControlHighlightInfo()

virtual void PathClose()=0

Close the path that is being specified.

void PathTransformTranslate(float x, float y)

Apply a translation transform to the current path.

void ClearInTextEntryControl()

Called when the text entry is dismissed, to reset mInTextEntry.

void DrawRadialLine(const IColor &color, float cx, float cy, float angle, float rMin, float rMax, const IBlend *pBlend=0, float thickness=1.f)

Draw a radial line to the graphics context, useful for pointers on dials.

void PathRect(const IRECT &bounds)

Add a rectangle to the current path.

virtual void RetainBitmap(const IBitmap &bitmap, const char *cacheName)

Adds an IBitmap to the cache/static storage.

void ForMatchingControls(T method, int paramIdx, Args... args)

For all standard controls in the main control stack that are linked to a specific parameter,...

virtual void CreatePlatformTextEntry(int paramIdx, const IText &text, const IRECT &bounds, int length, const char *str)=0

Creates a platform native text entry field.

void ResumeLayer(ILayerPtr &layer)

If a layer already exists, continue drawing to it.

void PathTransformMatrix(const IMatrix &matrix)

Apply an arbitary affine transform matrix to the current path.

void DrawRotatedLayer(const ILayerPtr &layer, double angle)

Draw a layer to the main IGraphics context, with rotation.

void PathTransformScale(float x, float y)

Apply a scale transform to the current path, with independant x, y scales.

virtual ECursor SetMouseCursor(ECursor cursorType=ECursor::ARROW)

Sets the mouse cursor to one of ECursor (implementations should return the result of the base impleme...

void PathLine(float x1, float y1, float x2, float y2)

Add a line to the current path.

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.

IControl * GetControlWithTag(int ctrlTag) const

Get the control with a particular tag.

virtual void PathSetWinding(bool clockwise)

NanoVG only.

void OnMouseDrag(const std::vector< IMouseInfo > &points)

Called when the platform class sends drag events.

virtual void ReleaseBitmap(const IBitmap &bitmap)

Releases an IBitmap from the cache/static storage.

virtual void DrawRoundRect(const IColor &color, const IRECT &bounds, float cornerRadius=5.f, const IBlend *pBlend=0, float thickness=1.f)

Draw a rounded rectangle to the graphics context.

void OnMouseOut()

Called when the mouse leaves the graphics context.

void UpdatePeers(IControl *pCaller, int callerValIdx)

This method is called after interacting with a control, so that any other controls linked to the same...

void RemovePopupMenuControl()

Remove the IGraphics popup menu, use platform popup menu if available.

virtual float GetBackingPixelScale() const

virtual void DrawRotatedBitmap(const IBitmap &bitmap, float destCentreX, float destCentreY, double angle, const IBlend *pBlend=0)

Draw a bitmap (raster) image to the graphics context with rotation.

bool OnKeyDown(float x, float y, const IKeyPress &key)

virtual int AlphaChannel() const =0

void AttachGestureRecognizerToRegion(const IRECT &bounds, EGestureType type, IGestureFunc func)

Attach a gesture recognizer to a rectangular region of the GUI, i.e.

bool MultiTouchEnabled() const

int Width() const

Gets the width of the graphics context.

virtual void EndFrame()

Called by some drawing API classes to finally blit the draw bitmap onto the screen or perform other c...

void DisableControl(int paramIdx, bool diable)

Disable or enable controls linked to a specific parameter.

void SetControlBounds(IControl *pControl, const IRECT &r)

Set a controls target and draw rect to r, redrawing the interface correctly.

void PathTriangle(float x1, float y1, float x2, float y2, float x3, float y3)

Add a triangle to the current path.

void DoMeasureTextRotation(const IText &text, const IRECT &bounds, IRECT &rect) const

Measures text bounds accounting for rotation.

void AttachTextEntryControl()

Attach a control for text entry, to override platform text entry.

void AttachCornerResizer(EUIResizerMode sizeMode=EUIResizerMode::Scale, bool layoutOnResize=false, const IColor &color=COLOR_TRANSLUCENT, const IColor &mouseOverColor=COLOR_BLACK, const IColor &dragColor=COLOR_BLACK, float size=20.f)

Attach the default control to scale or increase the UI size by dragging the plug-in bottom right-hand...

virtual void AttachGestureRecognizer(EGestureType type)

Registers a gesture recognizer with the graphics context.

virtual APIBitmap * CreateAPIBitmap(int width, int height, float scale, double drawScale, bool cacheable=false)=0

Creates a new API bitmap, either in memory or as a GPU texture.

void OnMouseUp(const std::vector< IMouseInfo > &points)

Called when the platform class sends mouse up events.

void PathTransformReset(bool clearStates=false)

Reset the affine transform of the current path, to the default state.

void OnAppearanceChanged(EUIAppearance appearance)

Called by the platform class if the view changes to dark/light mode.

void CalculateTextRotation(const IText &text, const IRECT &bounds, IRECT &rect, double &tx, double &ty) const

Calculates rotation parameters for text drawing.

bool IsInPlatformTextEntry()

virtual void PathStroke(const IPattern &pattern, float thickness, const IStrokeOptions &options=IStrokeOptions(), const IBlend *pBlend=0)=0

Stroke the current current path.

bool CheckLayer(const ILayerPtr &layer)

Test to see if a layer needs drawing, for instance if the control's bounds were changed.

int WindowWidth() const

Gets the width of the graphics context including draw scaling.

void Draw(IRECTList &rects)

Called by the platform class indicating a number of rectangles in the UI that need to redraw.

EResourceLocation SearchImageResource(const char *fileName, const char *type, WDL_String &result, int targetScale, int &sourceScale)

Search for a bitmap image resource matching the target scale.

IControl * GetControlWithParamIdx(int paramIdx)

Get the first control with a parameter index that matches paramIdx.

virtual void ApplyShadowMask(ILayerPtr &layer, RawBitmapData &mask, const IShadow &shadow)=0

Implemented by a graphics backend to apply a calculated shadow mask to a layer, according to the shad...

void EnableLiveEdit(bool enable)

Live edit mode allows you to relocate controls at runtime in debug builds.

void PathTransformRestore()

Restore the affine transform of the current path, to the previously saved state.

void SetControlValueAfterPopupMenu(IPopupMenu *pMenu)

Called by PopupMenuControl in order to update a control with a new value after returning from the non...

void DrawLayer(const ILayerPtr &layer, const IBlend *pBlend=nullptr)

Draw a layer to the main IGraphics context.

void PushLayer(ILayer *pLayer)

Push a layer on to the stack.

void ReleaseMouseCapture()

Used to tell the graphics context to stop tracking mouse interaction with a control.

int GetLastClickedParamForPTAutomation()

[AAX only]

void ForControlWithParam(int paramIdx, IControlFunction func)

For all standard controls in the main control stack that are linked to a specific parameter,...

void AttachBubbleControl(const IText &text=DEFAULT_TEXT)

Attach the default control to show text as a control changes.

EUIResizerMode GetResizerMode() const

virtual void FillRect(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0)

Fill a rectangular region of the graphics context with a color.

int GetRoundedScreenScale() const

Gets the screen/display scaling factor, rounded up.

APIBitmap * SearchBitmapInCache(const char *fileName, int targetScale, int &sourceScale)

Search the static storage cache for a bitmap image resource matching the target scale.

virtual void DrawLine(const IColor &color, float x1, float y1, float x2, float y2, const IBlend *pBlend=0, float thickness=1.f)

Draw a line to the graphics context.

virtual void DrawArc(const IColor &color, float cx, float cy, float r, float a1, float a2, const IBlend *pBlend=0, float thickness=1.f)

Draw an arc to the graphics context.

void OnTouchCancelled(const std::vector< IMouseInfo > &points)

Called when the platform class sends touch cancel events.

bool OnMouseOver(float x, float y, const IMouseMod &mod)

void OnDragResize(float x, float y)

Called by ICornerResizerControl as the corner is dragged to resize.

virtual PlatformFontPtr LoadPlatformFont(const char *fontID, const char *fileNameOrResID)=0

Load a font from disk or resource in a platform format.

void ForAllControlsFunc(IControlFunction func)

For all controls, including the "special controls" call a method.

void HideControl(int paramIdx, bool hide)

Hide controls linked to a specific parameter.

virtual bool LoadFont(const char *fontID, const char *fileNameOrResID)

Load a font to be used by the graphics context.

virtual bool BitmapExtSupported(const char *ext)=0

Checks a file extension and reports whether this drawing API supports loading that extension.

void RemoveAllControls()

Removes all regular IControls from the control list, as well as special controls (frees memory).

virtual void DrawCircle(const IColor &color, float cx, float cy, float r, const IBlend *pBlend=0, float thickness=1.f)

Draw a circle to the graphics context.

void OnMouseDown(const std::vector< IMouseInfo > &points)

Called when the platform class sends mouse down events.

int Height() const

Gets the height of the graphics context.

void PathClipRegion(const IRECT r=IRECT())

Clip the current path to a particular region.

void PathCircle(float cx, float cy, float r)

Add a circle to the current path.

void PathRadialLine(float cx, float cy, float angle, float rMin, float rMax)

Add a radial line to the current path.

void PathTransformRotate(float angle)

Apply a rotation transform to the current path.

bool OnKeyUp(float x, float y, const IKeyPress &key)

bool IsDirty(IRECTList &rects)

Called repeatedly at frame rate by the platform class to check what the graphics context says is dirt...

virtual void FillRoundRect(const IColor &color, const IRECT &bounds, float cornerRadius=5.f, const IBlend *pBlend=0)

Fill a rounded rectangle with a color.

virtual void GetLayerBitmapData(const ILayerPtr &layer, RawBitmapData &data)=0

Get the contents of a layer as Raw RGBA bitmap data NOTE: you should only call this within IControl::...

bool RespondsToGesture(float x, float y)

Called by platform class to see if the point at x, y is linked to a gesture recognizer.

void ForAllControls(T method, Args... args)

For all controls, including the "special controls" call a method.

void ClearGestureRegions()

Remove all gesture recognizers linked to regions.

void SetControlValueAfterTextEdit(const char *str)

Called by the platform class after returning from a text entry in order to update a control with a ne...

virtual void * GetWinModuleHandle()

virtual void UpdateLayer()

Implemented by a graphics backend to prepare for drawing to the layer at the top of the stack.

virtual void DrawData(const IColor &color, const IRECT &bounds, float *normYPoints, int nPoints, float *normXPoints=nullptr, const IBlend *pBlend=0, float thickness=1.f, const IColor *pFillColor=nullptr)

Draw a line between a collection of normalized points.

void SetQwertyMidiKeyHandlerFunc(std::function< void(const IMidiMsg &msg)> func=nullptr)

A helper to set the IGraphics KeyHandlerFunc in order to make an instrument playable via QWERTY keys.

void AttachSVGBackground(const char *fileName)

Attach an ISVGControl as the lowest IControl in the control stack to be the background for the graphi...

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 ApplyLayerDropShadow(ILayerPtr &layer, const IShadow &shadow)

Applies a drop shadow directly onto a layer.

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.

virtual IBitmap ScaleBitmap(const IBitmap &inBitmap, const char *cacheName, int targetScale)

Returns a new IBitmap, an integer scaled version of the input, and adds it to the cache.

IControl * GetControlInTextEntry()

IBitmap GetScaledBitmap(IBitmap &inBitmap)

Get a version of the input bitmap from the cache that corresponds to the current screen scale For exa...

void AttachPanelBackground(const IPattern &color)

Attach an IPanelControl as the lowest IControl in the control stack to fill the background with a sol...

virtual void FillConvexPolygon(const IColor &color, float *x, float *y, int nPoints, const IBlend *pBlend=0)

Fill a convex polygon with a color.

bool OnMouseWheel(float x, float y, const IMouseMod &mod, float delta)

void SetAllControlsClean()

Calls SetClean() on every control.

void StyleAllVectorControls(const IVStyle &style)

Helper method to style all of the controls which inherit IVectorBase.

virtual IPopupMenu * CreatePlatformPopupMenu(IPopupMenu &menu, const IRECT bounds, bool &isAsync)=0

Calls the platform backend to create the platform popup menu.

void RemoveControlWithTag(int ctrlTag)

Remove controls from the control list with a particular tag.

void GetTouches(IControl *pControl, std::vector< ITouchID > &touchesOnThisControl) const

Populate a vector with the touchIDs active on pControl.

void DrawVerticalLine(const IColor &color, const IRECT &bounds, float x, const IBlend *pBlend=0, float thickness=1.f)

Draw a vertical line, within a rectangular region of the graphics context.

virtual void PathMoveTo(float x, float y)=0

Move the current point in the current path.

virtual void PathArc(float cx, float cy, float r, float a1, float a2, EWinding winding=EWinding::CW)=0

Add an arc to the current path.

void PopupHostContextMenuForParam(int controlIdx, int paramIdx, float x, float y)

[VST3 primarily] In VST3 plug-ins this enable support for the IContextMenu interface,...

virtual bool FlippedBitmap() const =0

void PromptUserInput(IControl &control, const IRECT &bounds, int valIdx=0)

Prompt for user input either using a text entry or pop up menu.

void SetControlSize(IControl *pControl, float w, float h)

Resize a control, redrawing the interface correctly.

float GetScreenScale() const

Gets the screen/display scaling factor, e.g.

virtual bool LoadAPIFont(const char *fontID, const PlatformFontPtr &font)=0

Drawing API method to load a font from a PlatformFontPtr, called internally.

void OnDropMultiple(const std::vector< const char * > &paths, float x, float y)

void AssignParamNameToolTips()

Call this method in order to create tool tips for every IControl that show the associated parameter's...

virtual ISVG LoadSVG(const char *fileNameOrResID, const char *units="px", float dpi=72.f)

Load an SVG from disk or from windows resource.

virtual APIBitmap * LoadAPIBitmap(const char *fileNameOrResID, int scale, EResourceLocation location, const char *ext)=0

Drawing API method to load a bitmap, called internally.

virtual void HideMouseCursor(bool hide=true, bool lock=true)=0

Call to hide/show the mouse cursor.

void SetScaleConstraints(float lo, float hi)

Sets the minimum and maximum (draw) scaling values.

void DrawHorizontalLine(const IColor &color, const IRECT &bounds, float y, const IBlend *pBlend=0, float thickness=1.f)

Draw a horizontal line, within a rectangular region of the graphics context.

void ForControlInGroup(const char *group, IControlFunction func)

For all standard controls in the main control stack that are linked to a group, execute a function.

virtual void DoDrawText(const IText &text, const char *str, const IRECT &bounds, const IBlend *pBlend=nullptr)=0

Internal method to draw text.

void PathTransformSave()

Save the current affine transform of the current path.

virtual void FillArc(const IColor &color, float cx, float cy, float r, float a1, float a2, const IBlend *pBlend=0)

Fill an arc segment with a color.

void SetKeyHandlerFunc(IKeyHandlerFunc func)

Set a function that is called when key presses are not intercepted by any controls.

virtual void DrawDottedLine(const IColor &color, float x1, float y1, float x2, float y2, const IBlend *pBlend=0, float thickness=1.f, float dashLen=2.f)

Draw a dotted line to the graphics context.

void RemoveTextEntryControl()

Remove the IGraphics text entry, use platform text entry if available.

void ShowFPSDisplay(bool enable)

Shows a control to display the frame rate of drawing.

virtual void PathLineTo(float x, float y)=0

Add a line to the current path from the current point to the specified location.

void DrawLineAcross(const IColor &color, const IRECT &bounds, EDirection dir, float pos, const IBlend *pBlend=0, float thickness=1.f)

Draw a horzional or vertical line, within a rectangular region of the graphics context.

const char * GetSharedResourcesSubPath() const

Gets the name of the shared resources subpath.

void PathTransformSkew(float xAngle, float yAngle)

Apply a skew transform to the current path.

float GetDrawScale() const

Gets the graphics context scaling factor.

void DrawFittedLayer(const ILayerPtr &layer, const IRECT &bounds, const IBlend *pBlend)

Draw a layer to the main IGraphics context, fitting it to a rectangle that is different to the layer'...

void RemoveControls(int fromIdx)

Remove controls from the control list above a particular index, (frees memory).

void AttachBackground(const char *fileName)

Attach an IBitmapControl as the lowest IControl in the control stack to be the background for the gra...

void SetStrictDrawing(bool strict)

Enables strict drawing mode.

void OnGUIIdle()

This is an idle timer tick call on the GUI thread, only active if USE_IDLE_CALLS is defined.

IGEditorDelegate * GetDelegate()

Gets a pointer to the delegate class that handles communication to and from this graphics context.

IControl * GetControl(int idx)

Get the control at a certain index in the control stack.

void StartLayer(IControl *pOwner, const IRECT &r, bool cacheable=false)

Create an IGraphics layer.

void OnGestureRecognized(const IGestureInfo &info)

Called by platform class when a gesture is recognized.

virtual void CachePlatformFont(const char *fontID, const PlatformFontPtr &font)=0

Called to indicate that the platform should cache data about the platform font if needed.

bool OnMouseDblClick(float x, float y, const IMouseMod &mod)

virtual void DrawSVG(const ISVG &svg, const IRECT &bounds, const IBlend *pBlend=0, const IColor *pStrokeColor=nullptr, const IColor *pFillColor=nullptr)

Draw an SVG image to the graphics context.

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.

virtual void PathCubicBezierTo(float c1x, float c1y, float c2x, float c2y, float x2, float y2)=0

Add a cubic bezier to the current path from the current point to the specified location.

int WindowHeight() const

Gets the height of the graphics context including draw scaling.

void PathEllipse(const IRECT &bounds)

Add an ellipse to the current path, specifying the rectangular region.

virtual IBitmap LoadBitmap(const char *fileNameOrResID, int nStates=1, bool framesAreHorizontal=false, int targetScale=0)

Load a bitmap image from disk or from windows resource.

virtual void BeginFrame()

Called at the beginning of drawing.

virtual void FillCircle(const IColor &color, float cx, float cy, float r, const IBlend *pBlend=0)

Fill a circle with a color.

void SetControlPosition(IControl *pControl, float x, float y)

Reposition a control, redrawing the interface correctly.

void SetScreenScale(float scale)

Called by the platform IGraphics class when moving to a new screen to set DPI.

ILayerPtr EndLayer()

End an IGraphics layer.

virtual WDL_TypedBuf< uint8_t > LoadResource(const char *fileNameOrResID, const char *fileType)

Load a resource from the file system, the bundle, or a Windows resource, and returns its data.

void OnDrop(const char *str, float x, float y)

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.

virtual void DrawBitmap(const IBitmap &bitmap, const IRECT &bounds, int srcX, int srcY, const IBlend *pBlend=0)=0

Draw a bitmap (raster) image to the graphics context.

virtual float MeasureText(const IText &text, const char *str, IRECT &bounds) const

Measure the rectangular region that some text will occupy.

An abstraction that is used to store a temporary raster image/framebuffer.

const IRECT & Bounds() const

A basic control to fill a rectangle with a color or gradient.

EParamType Type() const

Get the parameter's type.

double ToNormalized(double nonNormalizedValue) const

Convert a real value to normalized value for this parameter.

void GetDisplay(WDL_String &display, bool withDisplayText=true) const

Get the current textual display for the current parameter value.

const char * GetLabel() const

Returns the parameter's label.

double StringToValue(const char *str) const

Convert a textual representation of the parameter value to a double (real value)

const char * GetName() const

Returns the parameter's name.

const char * GetDisplayText(double value) const

Get the display text for a particular value.

int NDisplayTexts() const

Get the number of display texts for the parameter.

EParamType

Defines types or parameter.

Used to manage a list of rectangular areas and optimize them for drawing to the screen.

void Clear()

Clear the list.

IRECT Bounds()

Get a union of all rectangles in the list.

void Add(const IRECT &rect)

Add a rectangle to the list.

void PixelAlign()

Align the rectangles to pixel boundaries.

void Optimize()

Remove rects that are contained by other rects and intersections and merge any rects that can be merg...

int Find(float x, float y) const

Find the first index of the rect that contains point x, y, if it exists.

const IRECT & Get(int idx) const

Get an IRECT from the list (will crash if idx is invalid)

A basic control to draw an SVG image to the screen.

A base interface to be combined with IControl for vectorial controls "IVControls",...

virtual void SetStyle(const IVStyle &style)

Set the Style of this IVControl.

std::unique_ptr< ILayer > ILayerPtr

ILayerPtr is a managed pointer for transferring the ownership of layers.

Used to describe a particular gesture.

Used to group mouse coordinates with mouse modifier information.

Used to manage stroke behaviour for path based drawing back ends.

BEGIN_IPLUG_NAMESPACE T Clip(T x, T lo, T hi)

Clips the value x between lo and hi.

Used to manage composite/blend operations, independent of draw class/platform.

Used to manage color data, independent of draw class/platform.

void Randomise(int alpha=255)

Randomise the color parts, with optional alpha.

Used to manage fill behaviour.

Used for key press info, such as ASCII representation, virtual key (mapped to win32 codes) and modifi...

Used to store transformation matrices.

IMatrix & Rotate(float a)

Set the matrix for a rotation transform.

IMatrix & Scale(float x, float y)

Set the matrix for a scale transform.

IMatrix & Transform(const IRECT &before, const IRECT &after)

Sets up a transformation matrix to map one rectangle to another.

IMatrix & Translate(float x, float y)

Set the matrix for a translation transform.

IMatrix & Skew(float xa, float ya)

Set the matrix for a skew transform.

void TransformPoint(double &x, double &y, double x0, double y0) const

Transforms a point using this matrix.

Encapsulates a MIDI message and provides helper functions.

void MakeNoteOnMsg(int noteNumber, int velocity, int offset, int channel=0)

Make a Note On message.

void MakeNoteOffMsg(int noteNumber, int offset, int channel=0)

Make a Note Off message.

Used to manage mouse modifiers i.e.

Used to store pattern information for gradients.

Used to manage a rectangular area, independent of draw class/platform.

IRECT Intersect(const IRECT &rhs) const

Create a new IRECT that is the intersection of this IRECT and rhs.

IRECT GetFromTLHC(float w, float h) const

Get a subrect of this IRECT expanding from the top-left corner.

IRECT GetPixelAligned() const

Get a copy of this IRECT with PixelAlign() called.

void PixelAlign()

Pixel aligns the rect in an inclusive manner (moves all points outwards)

void Clank(const IRECT &rhs)

Clank will limit this IRECT's bounds based on the boundaries of the IRECT passed in as an argument.

IRECT Union(const IRECT &rhs) const

Create a new IRECT that is a union of this IRECT and rhs.

bool Intersects(const IRECT &rhs) const

Returns true if this IRECT shares any common pixels with rhs, false otherwise.

void Translate(float x, float y)

Translate this rectangle.

bool Contains(const IRECT &rhs) const

Returns true if this IRECT completely contains rhs.

IRECT GetPadded(float padding) const

Get a copy of this IRECT with each value padded by padding N.B.

User-facing SVG abstraction that you use to manage SVG data ISVG doesn't actually own the image data.

Used to specify properties of a drop-shadow to a layer.

IText is used to manage font and text/text entry style for a piece of text on the UI,...

A struct encapsulating a set of properties used to configure IVControls.

Encapsulate an xy point in one struct.