1 // This file is part of VSTGUI. It is subject to the license terms
2 // in the LICENSE file found in the top-level directory of this
3 // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
4
5 #include "cframe.h"
6 #include "coffscreencontext.h"
7 #include "ctooltipsupport.h"
8 #include "itouchevent.h"
9 #include "iscalefactorchangedlistener.h"
10 #include "idatapackage.h"
11 #include "animation/animator.h"
12 #include "controls/ctextedit.h"
13 #include "platform/iplatformframe.h"
14 #include <cassert>
15 #include <vector>
16 #include <queue>
17 #include <limits>
18
19 namespace VSTGUI {
20
21 IdStringPtr kMsgNewFocusView = "kMsgNewFocusView";
22 IdStringPtr kMsgOldFocusView = "kMsgOldFocusView";
23
24 #define DEBUG_MOUSE_VIEWS 0//DEBUG
25
26 //------------------------------------------------------------------------
27 struct CFrame::CollectInvalidRects
28 {
29 explicit CollectInvalidRects (CFrame* frame);
30 ~CollectInvalidRects () noexcept;
31
32 void addRect (const CRect& rect);
33 void flush ();
34
35 private:
36 using InvalidRects = std::vector<CRect>;
37
38 SharedPointer<CFrame> frame;
39 InvalidRects invalidRects;
40 uint32_t lastTicks;
41 #if VSTGUI_LOG_COLLECT_INVALID_RECTS
42 uint32_t numAddedRects;
43 #endif
44 };
45
46 //------------------------------------------------------------------------
47 struct ModalViewSession
48 {
49 ModalViewSessionID identifier {};
50 SharedPointer<CView> view;
51 };
52
53 //------------------------------------------------------------------------
54 struct CFrame::Impl
55 {
56 using ViewList = std::list<CView*>;
57 using FunctionQueue = std::queue<EventProcessingFunction>;
58 using ModalViewSessionStack = std::stack<ModalViewSession>;
59
60 SharedPointer<IPlatformFrame> platformFrame;
61 VSTGUIEditorInterface* editor {nullptr};
62 IViewAddedRemovedObserver* viewAddedRemovedObserver {nullptr};
63 SharedPointer<CTooltipSupport> tooltips;
64 SharedPointer<Animation::Animator> animator;
65 #if VSTGUI_ENABLE_DEPRECATED_METHODS
66 Optional<ModalViewSessionID> legacyModalViewSessionID;
67 #endif
68 CView* focusView {nullptr};
69 CView* activeFocusView {nullptr};
70 CollectInvalidRects* collectInvalidRects {nullptr};
71
72 ViewList mouseViews;
73 ModalViewSessionStack modalViewSessionStack;
74 DispatchList<CView*> windowActiveStateChangeViews;
75 DispatchList<IScaleFactorChangedListener*> scaleFactorChangedListenerList;
76 DispatchList<IMouseObserver*> mouseObservers;
77 DispatchList<IFocusViewObserver*> focusViewObservers;
78 DispatchList<IKeyboardHook*> keyboardHooks;
79 FunctionQueue postEventFunctionQueue;
80
81 ModalViewSessionID modalViewSessionIDCounter {0};
82 double userScaleFactor {1.};
83 double platformScaleFactor {1.};
84 bool active {false};
85 bool windowActive {false};
86 bool inEventHandling {false};
87 BitmapInterpolationQuality bitmapQuality {BitmapInterpolationQuality::kDefault};
88
89 struct PostEventHandler
90 {
PostEventHandlerVSTGUI::CFrame::Impl::PostEventHandler91 PostEventHandler (Impl& impl) : impl (impl)
92 {
93 wasInEventHandling = impl.inEventHandling;
94 impl.inEventHandling = true;
95 }
~PostEventHandlerVSTGUI::CFrame::Impl::PostEventHandler96 ~PostEventHandler () noexcept
97 {
98 vstgui_assert (impl.inEventHandling == true);
99 impl.inEventHandling = wasInEventHandling;
100 FunctionQueue fl;
101 impl.postEventFunctionQueue.swap (fl);
102 while (!fl.empty ())
103 {
104 fl.front () ();
105 fl.pop ();
106 }
107 }
108
109 private:
110 Impl& impl;
111 bool wasInEventHandling;
112 };
113 };
114
115 //-----------------------------------------------------------------------------
116 // CFrame Implementation
117 //-----------------------------------------------------------------------------
118 /*! @class CFrame
119 It creates a platform dependend view object.
120
121 On Mac OS X it is a HIView or NSView.\n
122 On Windows it's a WS_CHILD Window.
123
124 */
125 //-----------------------------------------------------------------------------
CFrame(const CRect & inSize,VSTGUIEditorInterface * inEditor)126 CFrame::CFrame (const CRect& inSize, VSTGUIEditorInterface* inEditor) : CViewContainer (inSize)
127 {
128 pImpl = new Impl;
129 pImpl->editor = inEditor;
130
131 setParentFrame (this);
132 }
133
134 //-----------------------------------------------------------------------------
beforeDelete()135 void CFrame::beforeDelete ()
136 {
137 clearMouseViews (CPoint (0, 0), 0, false);
138
139 clearModalViewSessions ();
140
141 setCursor (kCursorDefault);
142
143 setParentFrame (nullptr);
144 removeAll ();
145
146 pImpl->tooltips = nullptr;
147 pImpl->animator = nullptr;
148
149 #if DEBUG
150 if (!pImpl->scaleFactorChangedListenerList.empty ())
151 {
152 DebugPrint ("Warning: Scale Factor Changed Listeners are not cleaned up correctly.\n If you register a change listener you must also unregister it !\n");
153 }
154
155 if (!pImpl->mouseObservers.empty ())
156 {
157 DebugPrint ("Warning: Mouse Observers are not cleaned up correctly.\n If you register a mouse oberver you must also unregister it !\n");
158 }
159
160 if (!pImpl->keyboardHooks.empty ())
161 {
162 DebugPrint ("Warning: Keyboard Hooks are not cleaned up correctly.\n If you register a keyboard hook you must also unregister it !\n");
163 }
164 #endif
165
166 if (pImpl->platformFrame)
167 {
168 pImpl->platformFrame->onFrameClosed ();
169 pImpl->platformFrame = nullptr;
170 }
171
172 setViewFlag (kIsAttached, false);
173
174 delete pImpl;
175 pImpl = nullptr;
176
177 CViewContainer::beforeDelete ();
178 }
179
180 //-----------------------------------------------------------------------------
close()181 void CFrame::close ()
182 {
183 clearMouseViews (CPoint (0, 0), 0, false);
184
185 clearModalViewSessions ();
186
187 setCursor (kCursorDefault);
188 setParentFrame (nullptr);
189 removeAll ();
190 if (pImpl->platformFrame)
191 {
192 pImpl->platformFrame->onFrameClosed ();
193 pImpl->platformFrame = nullptr;
194 }
195 forget ();
196 }
197
198 //-----------------------------------------------------------------------------
open(void * systemWin,PlatformType systemWindowType,IPlatformFrameConfig * config)199 bool CFrame::open (void* systemWin, PlatformType systemWindowType, IPlatformFrameConfig* config)
200 {
201 if (!systemWin || isAttached ())
202 return false;
203
204 pImpl->platformFrame = owned (IPlatformFrame::createPlatformFrame (this, getViewSize (), systemWin, systemWindowType, config));
205 if (!pImpl->platformFrame)
206 {
207 return false;
208 }
209
210 CollectInvalidRects cir (this);
211
212 attached (this);
213
214 setParentView (nullptr);
215
216 invalid ();
217
218 return true;
219 }
220
221 //-----------------------------------------------------------------------------
attached(CView * parent)222 bool CFrame::attached (CView* parent)
223 {
224 if (isAttached ())
225 return false;
226 vstgui_assert (parent == this);
227 if (CView::attached (parent))
228 {
229 setParentView (nullptr);
230
231 for (const auto& pV : getChildren ())
232 pV->attached (this);
233
234 return true;
235 }
236 return false;
237 }
238
239 //-----------------------------------------------------------------------------
setZoom(double zoomFactor)240 bool CFrame::setZoom (double zoomFactor)
241 {
242 if (zoomFactor == 0.)
243 return false;
244
245 bool result = true;
246 CGraphicsTransform currentTransform = getTransform ();
247 CCoord origWidth = getWidth () / currentTransform.m11;
248 CCoord origHeight = getHeight () / currentTransform.m22;
249 CCoord newWidth = std::round (origWidth * zoomFactor);
250 CCoord newHeight = std::round (origHeight * zoomFactor);
251 setAutosizingEnabled (false);
252 setTransform (CGraphicsTransform ().scale (zoomFactor, zoomFactor));
253 if (!setSize (newWidth, newHeight))
254 {
255 setTransform (currentTransform);
256 setSize (origWidth * currentTransform.m11, origHeight * currentTransform.m22);
257 result = false;
258 }
259 invalid ();
260 setAutosizingEnabled (true);
261 if (result)
262 {
263 pImpl->userScaleFactor = zoomFactor;
264 dispatchNewScaleFactor (getScaleFactor ());
265 }
266 return result;
267 }
268
269 //-----------------------------------------------------------------------------
getZoom() const270 double CFrame::getZoom () const
271 {
272 return pImpl->userScaleFactor;
273 }
274
275 //-----------------------------------------------------------------------------
setBitmapInterpolationQuality(BitmapInterpolationQuality quality)276 void CFrame::setBitmapInterpolationQuality (BitmapInterpolationQuality quality)
277 {
278 if (pImpl && pImpl->bitmapQuality != quality)
279 {
280 pImpl->bitmapQuality = quality;
281 invalid ();
282 }
283 }
284
285 //-----------------------------------------------------------------------------
getBitmapInterpolationQuality() const286 BitmapInterpolationQuality CFrame::getBitmapInterpolationQuality () const
287 {
288 if (pImpl)
289 return pImpl->bitmapQuality;
290 return BitmapInterpolationQuality::kDefault;
291 }
292
293 //-----------------------------------------------------------------------------
getScaleFactor() const294 double CFrame::getScaleFactor () const
295 {
296 return pImpl->platformScaleFactor * pImpl->userScaleFactor;
297 }
298
299 //-----------------------------------------------------------------------------
enableTooltips(bool state,uint32_t delayTimeInMs)300 void CFrame::enableTooltips (bool state, uint32_t delayTimeInMs)
301 {
302 if (state)
303 {
304 if (pImpl->tooltips == nullptr)
305 pImpl->tooltips = makeOwned<CTooltipSupport> (this, delayTimeInMs);
306 }
307 else if (pImpl->tooltips)
308 {
309 pImpl->tooltips = nullptr;
310 }
311 }
312
313 //-----------------------------------------------------------------------------
draw(CDrawContext * pContext)314 void CFrame::draw (CDrawContext* pContext)
315 {
316 return CFrame::drawRect (pContext, getViewSize ());
317 }
318
319 //-----------------------------------------------------------------------------
drawRect(CDrawContext * pContext,const CRect & updateRect)320 void CFrame::drawRect (CDrawContext* pContext, const CRect& updateRect)
321 {
322 if (updateRect.getWidth () <= 0 || updateRect.getHeight () <= 0 || pContext == nullptr)
323 return;
324
325 auto lifeGuard = shared (pContext);
326
327 if (pImpl)
328 pContext->setBitmapInterpolationQuality (pImpl->bitmapQuality);
329
330 drawClipped (pContext, updateRect, [&] () {
331 // draw the background and the children
332 CViewContainer::drawRect (pContext, updateRect);
333 });
334 }
335
336 //-----------------------------------------------------------------------------
clearMouseViews(const CPoint & where,const CButtonState & buttons,bool callMouseExit)337 void CFrame::clearMouseViews (const CPoint& where, const CButtonState& buttons, bool callMouseExit)
338 {
339 CPoint lp;
340 auto it = pImpl->mouseViews.rbegin ();
341 while (it != pImpl->mouseViews.rend ())
342 {
343 if (callMouseExit)
344 {
345 lp = where;
346 (*it)->frameToLocal (lp);
347 (*it)->onMouseExited (lp, buttons);
348 #if DEBUG_MOUSE_VIEWS
349 DebugPrint ("mouseExited : %p\n", (*it));
350 #endif
351 }
352 if (pImpl->tooltips)
353 pImpl->tooltips->onMouseExited ((*it));
354
355 callMouseObserverMouseExited ((*it));
356
357 (*it)->forget ();
358 ++it;
359 }
360 pImpl->mouseViews.clear ();
361 }
362
363 //-----------------------------------------------------------------------------
removeFromMouseViews(CView * view)364 void CFrame::removeFromMouseViews (CView* view)
365 {
366 bool found = false;
367 auto it = pImpl->mouseViews.begin ();
368 while (it != pImpl->mouseViews.end ())
369 {
370 if (found || (*it) == view)
371 {
372 if (pImpl->tooltips)
373 pImpl->tooltips->onMouseExited ((*it));
374
375 callMouseObserverMouseExited ((*it));
376
377 (*it)->forget ();
378 pImpl->mouseViews.erase (it++);
379 found = true;
380 }
381 else
382 ++it;
383 }
384 }
385
386 //-----------------------------------------------------------------------------
checkMouseViews(const CPoint & where,const CButtonState & buttons)387 void CFrame::checkMouseViews (const CPoint& where, const CButtonState& buttons)
388 {
389 if (getMouseDownView ())
390 return;
391 CPoint lp;
392 CView* mouseView = getViewAt (where, GetViewOptions ().deep ().mouseEnabled ().includeViewContainer ());
393 CView* currentMouseView = pImpl->mouseViews.empty () == false ? pImpl->mouseViews.back () : nullptr;
394 if (currentMouseView == mouseView)
395 return; // no change
396
397 if (pImpl->tooltips)
398 {
399 if (currentMouseView)
400 pImpl->tooltips->onMouseExited (currentMouseView);
401 if (mouseView && mouseView != this)
402 pImpl->tooltips->onMouseEntered (mouseView);
403 }
404
405 if (mouseView == nullptr || mouseView == this)
406 {
407 clearMouseViews (where, buttons);
408 return;
409 }
410 CViewContainer* vc = currentMouseView ? currentMouseView->asViewContainer () : nullptr;
411 // if the currentMouseView is not a view container, we know that the new mouseView won't be a child of it and that all other
412 // views in the list are viewcontainers
413 if (vc == nullptr && currentMouseView)
414 {
415 lp = where;
416 currentMouseView->frameToLocal (lp);
417 currentMouseView->onMouseExited (lp, buttons);
418 callMouseObserverMouseExited (currentMouseView);
419 #if DEBUG_MOUSE_VIEWS
420 DebugPrint ("mouseExited : %p\n", currentMouseView);
421 #endif
422 currentMouseView->forget ();
423 pImpl->mouseViews.remove (currentMouseView);
424 }
425 auto it = pImpl->mouseViews.rbegin ();
426 while (it != pImpl->mouseViews.rend ())
427 {
428 vc = static_cast<CViewContainer*> ((*it));
429 if (vc == mouseView)
430 return;
431 if (vc->isChild (mouseView, true) == false)
432 {
433 lp = where;
434 vc->frameToLocal (lp);
435 vc->onMouseExited (lp, buttons);
436 callMouseObserverMouseExited (vc);
437 #if DEBUG_MOUSE_VIEWS
438 DebugPrint ("mouseExited : %p\n", vc);
439 #endif
440 vc->forget ();
441 pImpl->mouseViews.erase (--it.base ());
442 }
443 else
444 break;
445 }
446 vc = pImpl->mouseViews.empty () == false ? pImpl->mouseViews.back ()->asViewContainer () : nullptr;
447 if (vc)
448 {
449 auto it2 = pImpl->mouseViews.end ();
450 --it2;
451 CView* container = mouseView;
452 while ((vc = static_cast<CViewContainer*> (container->getParentView ())) != *it2 && vc)
453 {
454 pImpl->mouseViews.emplace_back (vc);
455 vc->remember ();
456 container = vc;
457 }
458 pImpl->mouseViews.emplace_back (mouseView);
459 mouseView->remember ();
460 ++it2;
461 while (it2 != pImpl->mouseViews.end ())
462 {
463 lp = where;
464 (*it2)->frameToLocal (lp);
465 (*it2)->onMouseEntered (lp, buttons);
466 callMouseObserverMouseEntered ((*it2));
467 #if DEBUG_MOUSE_VIEWS
468 DebugPrint ("mouseEntered : %p\n", (*it2));
469 #endif
470 ++it2;
471 }
472 }
473 else
474 {
475 // must be pMouseViews.size () == 0
476 vstgui_assert (pImpl->mouseViews.empty ());
477 pImpl->mouseViews.emplace_back (mouseView);
478 mouseView->remember ();
479 while ((vc = static_cast<CViewContainer*> (mouseView->getParentView ())) != this && vc)
480 {
481 pImpl->mouseViews.push_front (vc);
482 vc->remember ();
483 mouseView = vc;
484 }
485 auto it2 = pImpl->mouseViews.begin ();
486 while (it2 != pImpl->mouseViews.end ())
487 {
488 lp = where;
489 (*it2)->frameToLocal (lp);
490 (*it2)->onMouseEntered (lp, buttons);
491 callMouseObserverMouseEntered ((*it2));
492 #if DEBUG_MOUSE_VIEWS
493 DebugPrint ("mouseEntered : %p\n", (*it2));
494 #endif
495 ++it2;
496 }
497 }
498 }
499
500 //------------------------------------------------------------------------
hitTestSubViews(const CPoint & where,const CButtonState & buttons)501 bool CFrame::hitTestSubViews (const CPoint& where, const CButtonState& buttons)
502 {
503 if (auto modalView = getModalView ())
504 {
505 CPoint where2 (where);
506 getTransform ().inverse ().transform (where2);
507 if (modalView->isVisible () && modalView->getMouseEnabled () && modalView->hitTest (where2, buttons))
508 {
509 if (auto viewContainer = modalView->asViewContainer ())
510 {
511 return viewContainer->hitTestSubViews (where2, buttons);
512 }
513 return true;
514 }
515 return false;
516 }
517 return CViewContainer::hitTestSubViews (where, buttons);
518 }
519
520 //-----------------------------------------------------------------------------
onMouseDown(CPoint & where,const CButtonState & buttons)521 CMouseEventResult CFrame::onMouseDown (CPoint &where, const CButtonState& buttons)
522 {
523 CPoint where2 (where);
524 getTransform ().inverse ().transform (where2);
525
526 if (pImpl->tooltips)
527 pImpl->tooltips->onMouseDown (where2);
528
529 CMouseEventResult result = callMouseObserverMouseDown (where, buttons);
530 if (result != kMouseEventNotHandled)
531 return result;
532
533 // reset views
534 setMouseDownView (nullptr);
535 if (pImpl->focusView && dynamic_cast<CTextEdit*> (pImpl->focusView))
536 setFocusView (nullptr);
537
538 if (auto modalView = getModalView ())
539 {
540 CBaseObjectGuard rg (modalView);
541
542 if (modalView->isVisible () && modalView->getMouseEnabled ())
543 {
544 result = modalView->callMouseListener (MouseListenerCall::MouseDown, where2, buttons);
545 if (result == kMouseEventNotHandled || result == kMouseEventNotImplemented)
546 result = modalView->onMouseDown (where2, buttons);
547 if (result == kMouseEventHandled)
548 {
549 setMouseDownView (modalView);
550 return kMouseEventHandled;
551 }
552 return result;
553 }
554 }
555 else
556 return CViewContainer::onMouseDown (where, buttons);
557 return kMouseEventNotHandled;
558 }
559
560 //-----------------------------------------------------------------------------
onMouseUp(CPoint & where,const CButtonState & buttons)561 CMouseEventResult CFrame::onMouseUp (CPoint &where, const CButtonState& buttons)
562 {
563 CMouseEventResult result = CViewContainer::onMouseUp (where, buttons);
564 CButtonState modifiers = buttons & (kShift | kControl | kAlt | kApple);
565 checkMouseViews (where, modifiers);
566 return result;
567 }
568
569 //-----------------------------------------------------------------------------
onMouseMoved(CPoint & where,const CButtonState & buttons)570 CMouseEventResult CFrame::onMouseMoved (CPoint &where, const CButtonState& buttons)
571 {
572 CPoint where2 (where);
573 getTransform ().inverse ().transform (where2);
574
575 if (pImpl->tooltips)
576 pImpl->tooltips->onMouseMoved (where2);
577
578 checkMouseViews (where, buttons);
579
580 CMouseEventResult result = callMouseObserverMouseMoved (where, buttons);
581 if (result != kMouseEventNotHandled)
582 return result;
583
584 if (auto modalView = getModalView ())
585 {
586 CBaseObjectGuard rg (modalView);
587 result = modalView->callMouseListener (MouseListenerCall::MouseMoved, where2, buttons);
588 if (result == kMouseEventNotHandled || result == kMouseEventNotImplemented)
589 result = modalView->onMouseMoved (where2, buttons);
590 }
591 else
592 {
593 result = CViewContainer::onMouseMoved (where, buttons);
594 }
595 if (result == kMouseEventNotHandled)
596 {
597 CButtonState buttons2 = (buttons & (kShift | kControl | kAlt | kApple));
598 auto it = pImpl->mouseViews.rbegin ();
599 while (it != pImpl->mouseViews.rend ())
600 {
601 CPoint p = where2;
602 auto parent = (*it)->getParentView ();
603 if (parent)
604 {
605 parent->frameToLocal (p);
606 result = (*it)->onMouseMoved (p, buttons2);
607 if (result == kMouseEventHandled)
608 break;
609 }
610 ++it;
611 }
612 }
613 return result;
614 }
615
616 //-----------------------------------------------------------------------------
onMouseExited(CPoint & where,const CButtonState & buttons)617 CMouseEventResult CFrame::onMouseExited (CPoint &where, const CButtonState& buttons)
618 { // this should only get called from the platform implementation
619
620 if (getMouseDownView () == nullptr)
621 {
622 clearMouseViews (where, buttons);
623 if (pImpl->tooltips)
624 pImpl->tooltips->hideTooltip ();
625 }
626
627 return kMouseEventHandled;
628 }
629
630 //-----------------------------------------------------------------------------
onKeyDown(VstKeyCode & keyCode)631 int32_t CFrame::onKeyDown (VstKeyCode& keyCode)
632 {
633 int32_t result = keyboardHooksOnKeyDown (keyCode);
634
635 if (result == -1 && pImpl->focusView)
636 {
637 CBaseObjectGuard og (pImpl->focusView);
638 if (pImpl->focusView->getMouseEnabled ())
639 result = pImpl->focusView->onKeyDown (keyCode);
640 if (result == -1)
641 {
642 CView* parent = pImpl->focusView->getParentView ();
643 while (parent && parent != this && result == -1)
644 {
645 if (parent->getMouseEnabled ())
646 result = parent->onKeyDown (keyCode);
647 parent = parent->getParentView ();
648 }
649 }
650 }
651
652 if (result == -1)
653 {
654 if (auto modalView = getModalView ())
655 {
656 CBaseObjectGuard og (modalView);
657 result = modalView->onKeyDown (keyCode);
658 }
659 }
660
661 if (result == -1 && keyCode.virt == VKEY_TAB)
662 {
663 if (keyCode.modifier == 0 || keyCode.modifier == MODIFIER_SHIFT)
664 result = advanceNextFocusView (pImpl->focusView, (keyCode.modifier & MODIFIER_SHIFT) ? true : false) ? 1 : -1;
665 }
666
667 return result;
668 }
669
670 //-----------------------------------------------------------------------------
onKeyUp(VstKeyCode & keyCode)671 int32_t CFrame::onKeyUp (VstKeyCode& keyCode)
672 {
673 int32_t result = keyboardHooksOnKeyUp (keyCode);
674
675 if (result == -1 && pImpl->focusView)
676 {
677 if (pImpl->focusView->getMouseEnabled ())
678 result = pImpl->focusView->onKeyUp (keyCode);
679 if (result == -1)
680 {
681 CView* parent = pImpl->focusView->getParentView ();
682 while (parent && parent != this && result == -1)
683 {
684 if (parent->getMouseEnabled ())
685 result = parent->onKeyUp (keyCode);
686 parent = parent->getParentView ();
687 }
688 }
689 }
690
691 if (result == -1)
692 {
693 if (auto modalView = getModalView ())
694 result = modalView->onKeyUp (keyCode);
695 }
696
697 return result;
698 }
699
700 //------------------------------------------------------------------------
onWheel(const CPoint & where,const CMouseWheelAxis & axis,const float & distance,const CButtonState & buttons)701 bool CFrame::onWheel (const CPoint &where, const CMouseWheelAxis &axis, const float &distance, const CButtonState &buttons)
702 {
703 if (auto modalView = getModalView ())
704 {
705 CPoint where2 (where);
706 getTransform ().inverse ().transform (where2);
707 return modalView->onWheel (where2, axis, distance, buttons);
708 }
709
710 bool result = false;
711 if (getMouseDownView () == nullptr)
712 {
713 result = CViewContainer::onWheel (where, axis, distance, buttons);
714 checkMouseViews (where, buttons);
715 }
716 return result;
717 }
718
719 //-----------------------------------------------------------------------------
getClipboard()720 SharedPointer<IDataPackage> CFrame::getClipboard ()
721 {
722 if (pImpl->platformFrame)
723 return pImpl->platformFrame->getClipboard ();
724 return nullptr;
725 }
726
727 //-----------------------------------------------------------------------------
setClipboard(const SharedPointer<IDataPackage> & data)728 void CFrame::setClipboard (const SharedPointer<IDataPackage>& data)
729 {
730 if (pImpl->platformFrame)
731 pImpl->platformFrame->setClipboard (data);
732 }
733
734 //-----------------------------------------------------------------------------
idle()735 void CFrame::idle ()
736 {
737 if (CView::kDirtyCallAlwaysOnMainThread)
738 return;
739 invalidateDirtyViews ();
740 }
741
742 //-----------------------------------------------------------------------------
getAnimator()743 Animation::Animator* CFrame::getAnimator ()
744 {
745 if (pImpl->animator == nullptr)
746 pImpl->animator = makeOwned<Animation::Animator> ();
747 return pImpl->animator;
748 }
749
750 //-----------------------------------------------------------------------------
751 /**
752 * @return tick count in milliseconds
753 */
getTicks() const754 uint32_t CFrame::getTicks () const
755 {
756 if (pImpl->platformFrame)
757 return pImpl->platformFrame->getTicks ();
758 return std::numeric_limits<uint32_t>::max ();
759 }
760
761 //-----------------------------------------------------------------------------
762 int32_t CFrame::kDefaultKnobMode = kCircularMode;
763
764 //-----------------------------------------------------------------------------
getKnobMode() const765 int32_t CFrame::getKnobMode () const
766 {
767 int32_t result = pImpl->editor ? pImpl->editor->getKnobMode () : -1;
768 if (result == -1)
769 result = kDefaultKnobMode;
770 return result;
771 }
772
773 //-----------------------------------------------------------------------------
774 /**
775 * repositions the frame
776 * @param x x coordinate
777 * @param y y coordinate
778 * @return true on success
779 */
setPosition(CCoord x,CCoord y)780 bool CFrame::setPosition (CCoord x, CCoord y)
781 {
782 if (pImpl->platformFrame)
783 {
784 CRect rect (getViewSize ());
785 rect.offset (x - getViewSize ().left, y - getViewSize ().top);
786 if (pImpl->platformFrame->setSize (rect))
787 {
788 setViewSize (rect, false);
789 return true;
790 }
791 }
792 return false;
793 }
794
795 //-----------------------------------------------------------------------------
796 /**
797 * get global position of frame
798 * @param x x coordinate
799 * @param y y coordinate
800 * @return true on success
801 */
getPosition(CCoord & x,CCoord & y) const802 bool CFrame::getPosition (CCoord &x, CCoord &y) const
803 {
804 if (pImpl->platformFrame)
805 {
806 CPoint p;
807 if (pImpl->platformFrame->getGlobalPosition (p))
808 {
809 x = p.x;
810 y = p.y;
811 return true;
812 }
813 }
814 return false;
815 }
816
817 //-----------------------------------------------------------------------------
setViewSize(const CRect & rect,bool invalid)818 void CFrame::setViewSize (const CRect& rect, bool invalid)
819 {
820 CViewContainer::setViewSize (rect, invalid);
821 }
822
823 //-----------------------------------------------------------------------------
824 /**
825 * set size of frame (and the platform representation)
826 * @param width new width
827 * @param height new height
828 * @return true on success
829 */
setSize(CCoord width,CCoord height)830 bool CFrame::setSize (CCoord width, CCoord height)
831 {
832 if ((width == getViewSize ().getWidth ()) && (height == getViewSize ().getHeight ()))
833 return false;
834
835 CRect newSize (getViewSize ());
836 newSize.setWidth (width);
837 newSize.setHeight (height);
838
839 if (getEditor ())
840 {
841 if (getEditor ()->beforeSizeChange (newSize, getViewSize ()) == false)
842 return false;
843 }
844 if (pImpl->platformFrame)
845 {
846 if (pImpl->platformFrame->setSize (newSize))
847 {
848 CViewContainer::setViewSize (newSize);
849 return true;
850 }
851 return false;
852 }
853 CViewContainer::setViewSize (newSize);
854 return true;
855 }
856
857 //-----------------------------------------------------------------------------
858 /**
859 * get size relative to parent
860 * @param pRect size
861 * @return true on success
862 */
getSize(CRect * pRect) const863 bool CFrame::getSize (CRect* pRect) const
864 {
865 if (pImpl->platformFrame && pRect)
866 return pImpl->platformFrame->getSize (*pRect);
867 return false;
868 }
869
870 //-----------------------------------------------------------------------------
getSize(CRect & outSize) const871 bool CFrame::getSize (CRect& outSize) const
872 {
873 return getSize (&outSize);
874 }
875
876 #if VSTGUI_ENABLE_DEPRECATED_METHODS
877 //-----------------------------------------------------------------------------
878 /**
879 * @param pView the view which should be set to modal.
880 * @return true if view could be set as the modal view. false if there is a already a modal view or the view to be set as modal is already attached.
881 */
setModalView(CView * pView)882 bool CFrame::setModalView (CView* pView)
883 {
884 if (pImpl->modalViewSessionStack.empty () && pView == nullptr)
885 return true;
886
887 if (pView && !pImpl->modalViewSessionStack.empty ())
888 return false;
889
890 if (!pView)
891 endLegacyModalViewSession ();
892 else
893 pImpl->legacyModalViewSessionID = beginModalViewSession (pView);
894
895 return true;
896 }
897
898 //-----------------------------------------------------------------------------
endLegacyModalViewSession()899 void CFrame::endLegacyModalViewSession ()
900 {
901 vstgui_assert (pImpl->legacyModalViewSessionID);
902 vstgui_assert (pImpl->modalViewSessionStack.top ().identifier ==
903 *pImpl->legacyModalViewSessionID);
904 pImpl->modalViewSessionStack.top ().view->remember ();
905 endModalViewSession (*pImpl->legacyModalViewSessionID);
906 pImpl->legacyModalViewSessionID = {};
907 }
908
909 #endif
910
911 //-----------------------------------------------------------------------------
getModalView() const912 CView* CFrame::getModalView () const
913 {
914 if (!pImpl->modalViewSessionStack.empty ())
915 return pImpl->modalViewSessionStack.top ().view;
916 return nullptr;
917 }
918
919 //-----------------------------------------------------------------------------
initModalViewSession(const ModalViewSession & session)920 void CFrame::initModalViewSession (const ModalViewSession& session)
921 {
922 if (auto view = getMouseDownView ())
923 {
924 onMouseCancel ();
925 }
926 clearMouseViews (CPoint (0, 0), 0, true);
927 if (auto container = session.view->asViewContainer ())
928 container->advanceNextFocusView (nullptr, false);
929 else
930 setFocusView (session.view->wantsFocus () ? session.view : nullptr);
931
932 if (isAttached ())
933 {
934 CPoint where;
935 getCurrentMouseLocation (where);
936 checkMouseViews (where, getCurrentMouseButtons ());
937 }
938 }
939
940 //-----------------------------------------------------------------------------
clearModalViewSessions()941 void CFrame::clearModalViewSessions ()
942 {
943 #if VSTGUI_ENABLE_DEPRECATED_METHODS
944 if (pImpl->legacyModalViewSessionID)
945 endLegacyModalViewSession ();
946 #endif
947 while (!pImpl->modalViewSessionStack.empty ())
948 endModalViewSession (pImpl->modalViewSessionStack.top ().identifier);
949 }
950
951 //-----------------------------------------------------------------------------
beginModalViewSession(CView * view)952 Optional<ModalViewSessionID> CFrame::beginModalViewSession (CView* view)
953 {
954 if (view->isAttached ())
955 {
956 #if DEBUG
957 DebugPrint ("the view must not be attached when used for beginModalViewSession");
958 #endif
959 return {};
960 }
961
962 if (!addView (view))
963 {
964 return {};
965 }
966
967 ModalViewSession session;
968 session.identifier = ++pImpl->modalViewSessionIDCounter;
969 session.view = view;
970 pImpl->modalViewSessionStack.push (session);
971
972 initModalViewSession (session);
973
974 return makeOptional (session.identifier);
975 }
976
977 //-----------------------------------------------------------------------------
endModalViewSession(ModalViewSessionID sessionID)978 bool CFrame::endModalViewSession (ModalViewSessionID sessionID)
979 {
980 if (pImpl->modalViewSessionStack.empty ())
981 return false;
982 if (pImpl->modalViewSessionStack.top ().identifier != sessionID)
983 return false;
984
985 auto view = pImpl->modalViewSessionStack.top ().view;
986 pImpl->modalViewSessionStack.pop ();
987
988 removeView (view);
989
990 if (!pImpl->modalViewSessionStack.empty ())
991 initModalViewSession (pImpl->modalViewSessionStack.top ());
992
993 return true;
994 }
995
996 //-----------------------------------------------------------------------------
beginEdit(int32_t index)997 void CFrame::beginEdit (int32_t index)
998 {
999 if (pImpl->editor)
1000 pImpl->editor->beginEdit (index);
1001 }
1002
1003 //-----------------------------------------------------------------------------
endEdit(int32_t index)1004 void CFrame::endEdit (int32_t index)
1005 {
1006 if (pImpl->editor)
1007 pImpl->editor->endEdit (index);
1008 }
1009
1010 //-----------------------------------------------------------------------------
1011 /**
1012 * @param where location of mouse
1013 * @return true on success
1014 */
getCurrentMouseLocation(CPoint & where) const1015 bool CFrame::getCurrentMouseLocation (CPoint &where) const
1016 {
1017 if (pImpl->platformFrame)
1018 {
1019 if (pImpl->platformFrame->getCurrentMousePosition (where))
1020 {
1021 getTransform().transform (where);
1022 return true;
1023 }
1024 }
1025 return false;
1026 }
1027
1028 //-----------------------------------------------------------------------------
1029 /**
1030 * @return mouse and modifier state
1031 */
getCurrentMouseButtons() const1032 CButtonState CFrame::getCurrentMouseButtons () const
1033 {
1034 CButtonState buttons = 0;
1035
1036 if (pImpl->platformFrame)
1037 pImpl->platformFrame->getCurrentMouseButtons (buttons);
1038
1039 return buttons;
1040 }
1041
1042 //-----------------------------------------------------------------------------
1043 /**
1044 * @param type cursor type see #CCursorType
1045 */
setCursor(CCursorType type)1046 void CFrame::setCursor (CCursorType type)
1047 {
1048 if (pImpl->platformFrame)
1049 pImpl->platformFrame->setMouseCursor (type);
1050 }
1051
1052 //-----------------------------------------------------------------------------
1053 /**
1054 * @param pView view which was removed
1055 */
onViewRemoved(CView * pView)1056 void CFrame::onViewRemoved (CView* pView)
1057 {
1058 removeFromMouseViews (pView);
1059
1060 if (pImpl->activeFocusView == pView)
1061 pImpl->activeFocusView = nullptr;
1062 if (pImpl->focusView == pView)
1063 {
1064 if (pImpl->active)
1065 setFocusView (nullptr);
1066 else
1067 pImpl->focusView = nullptr;
1068 }
1069 if (auto container = pView->asViewContainer ())
1070 {
1071 if (container->isChild (pImpl->focusView, true))
1072 setFocusView (nullptr);
1073 }
1074 if (getViewAddedRemovedObserver ())
1075 getViewAddedRemovedObserver ()->onViewRemoved (this, pView);
1076 if (pView->wantsWindowActiveStateChangeNotification ())
1077 pImpl->windowActiveStateChangeViews.remove (pView);
1078 if (pImpl->animator)
1079 pImpl->animator->removeAnimations (pView);
1080 }
1081
1082 //-----------------------------------------------------------------------------
1083 /**
1084 * @param pView view which was added
1085 */
onViewAdded(CView * pView)1086 void CFrame::onViewAdded (CView* pView)
1087 {
1088 if (getViewAddedRemovedObserver ())
1089 getViewAddedRemovedObserver ()->onViewAdded (this, pView);
1090 if (pView->wantsWindowActiveStateChangeNotification ())
1091 {
1092 pImpl->windowActiveStateChangeViews.add (pView);
1093 pView->onWindowActivate (pImpl->windowActive);
1094 }
1095 }
1096
1097 //-----------------------------------------------------------------------------
1098 /**
1099 * @param pView new focus view
1100 */
setFocusView(CView * pView)1101 void CFrame::setFocusView (CView *pView)
1102 {
1103 static bool recursion = false;
1104 if (pView == pImpl->focusView || (recursion && pImpl->focusView != nullptr))
1105 return;
1106
1107 if (pView && !pImpl->modalViewSessionStack.empty ())
1108 {
1109 if (auto modalContainer = pImpl->modalViewSessionStack.top ().view->asViewContainer ())
1110 {
1111 if (!modalContainer->isChild (pView, true))
1112 {
1113 #if DEBUG
1114 DebugPrint (
1115 "Could not set the focus view " \
1116 "as it is not a child of the currently displayed modal view\n");
1117 #endif
1118 return;
1119 }
1120 }
1121 }
1122
1123 if (!pImpl->active)
1124 {
1125 pImpl->activeFocusView = pView;
1126 return;
1127 }
1128
1129 recursion = true;
1130
1131 CView *pOldFocusView = pImpl->focusView;
1132 if (pView == nullptr || (pView && pView->isAttached () == false))
1133 pImpl->focusView = nullptr;
1134 else
1135 pImpl->focusView = pView;
1136 if (pImpl->focusView && pImpl->focusView->wantsFocus ())
1137 {
1138 pImpl->focusView->invalid ();
1139
1140 CView* receiver = pImpl->focusView->getParentView ();
1141 while (receiver != this && receiver != nullptr)
1142 {
1143 receiver->notify (pImpl->focusView, kMsgNewFocusView);
1144 receiver = receiver->getParentView ();
1145 }
1146 notify (pImpl->focusView, kMsgNewFocusView);
1147 }
1148
1149 if (pOldFocusView)
1150 {
1151 if (pOldFocusView->wantsFocus ())
1152 {
1153 pOldFocusView->invalid ();
1154
1155 CView* receiver = pOldFocusView->getParentView ();
1156 while (receiver != this && receiver != nullptr)
1157 {
1158 receiver->notify (pOldFocusView, kMsgOldFocusView);
1159 receiver = receiver->getParentView ();
1160 }
1161 notify (pOldFocusView, kMsgOldFocusView);
1162 }
1163 pOldFocusView->looseFocus ();
1164 }
1165 if (pImpl->focusView && pImpl->focusView->wantsFocus ())
1166 pImpl->focusView->takeFocus ();
1167
1168 pImpl->focusViewObservers.forEach ([&] (IFocusViewObserver* observer) {
1169 observer->onFocusViewChanged (this, pImpl->focusView, pOldFocusView);
1170 });
1171
1172 recursion = false;
1173 }
1174
1175 //-----------------------------------------------------------------------------
getFocusView() const1176 CView* CFrame::getFocusView () const
1177 {
1178 return pImpl->focusView;
1179 }
1180
1181 //-----------------------------------------------------------------------------
advanceNextFocusView(CView * oldFocus,bool reverse)1182 bool CFrame::advanceNextFocusView (CView* oldFocus, bool reverse)
1183 {
1184 if (auto modalView = getModalView ())
1185 {
1186 if (auto container = modalView->asViewContainer ())
1187 {
1188 if (oldFocus == nullptr || container->isChild (oldFocus, true) == false)
1189 return container->advanceNextFocusView (nullptr, reverse);
1190 else
1191 {
1192 if (auto* parentView = static_cast<CViewContainer*> (oldFocus->getParentView ()))
1193 {
1194 CView* tempOldFocus = oldFocus;
1195 while (parentView != container)
1196 {
1197 if (parentView->advanceNextFocusView (tempOldFocus, reverse))
1198 return true;
1199 else
1200 {
1201 tempOldFocus = parentView;
1202 parentView = static_cast<CViewContainer*> (parentView->getParentView ());
1203 }
1204 }
1205 if (container->advanceNextFocusView (tempOldFocus, reverse))
1206 return true;
1207 return container->advanceNextFocusView (nullptr, reverse);
1208 }
1209 }
1210 }
1211 else if (oldFocus != modalView)
1212 {
1213 setFocusView (modalView);
1214 return true;
1215 }
1216 return false; // currently not supported, but should be done sometime
1217 }
1218 if (oldFocus == nullptr)
1219 {
1220 if (pImpl->focusView == nullptr)
1221 return CViewContainer::advanceNextFocusView (nullptr, reverse);
1222 oldFocus = pImpl->focusView;
1223 }
1224 if (isChild (oldFocus))
1225 {
1226 if (CViewContainer::advanceNextFocusView (oldFocus, reverse))
1227 return true;
1228 else
1229 {
1230 setFocusView (nullptr);
1231 return false;
1232 }
1233 }
1234 if (auto* parentView = static_cast<CViewContainer*> (oldFocus->getParentView ()))
1235 {
1236 CView* tempOldFocus = oldFocus;
1237 while (parentView)
1238 {
1239 if (parentView->advanceNextFocusView (tempOldFocus, reverse))
1240 return true;
1241 else
1242 {
1243 tempOldFocus = parentView;
1244 parentView = static_cast<CViewContainer*> (parentView->getParentView ());
1245 }
1246 }
1247 }
1248 return CViewContainer::advanceNextFocusView (oldFocus, reverse);
1249 }
1250
1251 //-----------------------------------------------------------------------------
removeView(CView * pView,bool withForget)1252 bool CFrame::removeView (CView* pView, bool withForget)
1253 {
1254 #if DEBUG
1255 vstgui_assert (getModalView () != pView);
1256 #endif
1257 return CViewContainer::removeView (pView, withForget);
1258 }
1259
1260 //-----------------------------------------------------------------------------
removeAll(bool withForget)1261 bool CFrame::removeAll (bool withForget)
1262 {
1263 clearModalViewSessions ();
1264 if (pImpl->focusView)
1265 {
1266 pImpl->focusView->looseFocus ();
1267 pImpl->focusView = nullptr;
1268 }
1269 pImpl->activeFocusView = nullptr;
1270 clearMouseViews (CPoint (0, 0), 0, false);
1271 return CViewContainer::removeAll (withForget);
1272 }
1273
1274 //-----------------------------------------------------------------------------
getViewAt(const CPoint & where,const GetViewOptions & options) const1275 CView* CFrame::getViewAt (const CPoint& where, const GetViewOptions& options) const
1276 {
1277 if (auto modalView = getModalView ())
1278 {
1279 CPoint where2 (where);
1280 getTransform ().inverse ().transform (where2);
1281 if (modalView->getViewSize ().pointInside (where2))
1282 {
1283 if (options.getDeep ())
1284 {
1285 if (auto container = modalView->asViewContainer ())
1286 {
1287 return container->getViewAt (where2, options);
1288 }
1289 }
1290 return modalView;
1291 }
1292 return nullptr;
1293 }
1294 return CViewContainer::getViewAt (where, options);
1295 }
1296
1297 //-----------------------------------------------------------------------------
getContainerAt(const CPoint & where,const GetViewOptions & options) const1298 CViewContainer* CFrame::getContainerAt (const CPoint& where, const GetViewOptions& options) const
1299 {
1300 if (auto modalView = getModalView ())
1301 {
1302 CPoint where2 (where);
1303 getTransform ().inverse ().transform (where2);
1304 if (modalView->getViewSize ().pointInside (where2))
1305 {
1306 if (auto container = modalView->asViewContainer ())
1307 {
1308 if (options.getDeep ())
1309 return container->getContainerAt (where2, options);
1310 return container;
1311 }
1312 }
1313 return nullptr;
1314 }
1315 return CViewContainer::getContainerAt (where, options);
1316 }
1317
1318 //------------------------------------------------------------------------
getViewsAt(const CPoint & where,ViewList & views,const GetViewOptions & options) const1319 bool CFrame::getViewsAt (const CPoint& where, ViewList& views, const GetViewOptions& options) const
1320 {
1321 if (auto modalView = getModalView ())
1322 {
1323 CPoint where2 (where);
1324 getTransform ().inverse ().transform (where2);
1325 if (modalView->getViewSize ().pointInside (where2))
1326 {
1327 if (options.getDeep ())
1328 {
1329 if (auto container = modalView->asViewContainer ())
1330 {
1331 container->getViewsAt (where2, views, options);
1332 }
1333 }
1334 if (!options.getIncludeViewContainer () && modalView->asViewContainer ())
1335 return true;
1336 if (options.getMouseEnabled () && modalView->getMouseEnabled () == false)
1337 return true;
1338 if (!options.getIncludeInvisible () && !modalView->isVisible ())
1339 return true;
1340 views.emplace_back (modalView);
1341 return true;
1342 }
1343 return false;
1344 }
1345 return CViewContainer::getViewsAt (where, views, options);
1346 }
1347
1348 //-----------------------------------------------------------------------------
onActivate(bool state)1349 void CFrame::onActivate (bool state)
1350 {
1351 if (pImpl->active != state)
1352 {
1353 if (state)
1354 {
1355 pImpl->active = true;
1356 if (pImpl->activeFocusView)
1357 {
1358 setFocusView (pImpl->activeFocusView);
1359 pImpl->activeFocusView = nullptr;
1360 }
1361 else
1362 advanceNextFocusView (nullptr, false);
1363 }
1364 else
1365 {
1366 if (pImpl->tooltips)
1367 pImpl->tooltips->hideTooltip ();
1368 pImpl->activeFocusView = getFocusView ();
1369 setFocusView (nullptr);
1370 pImpl->active = false;
1371 }
1372 }
1373 }
1374
1375 //-----------------------------------------------------------------------------
focusDrawingEnabled() const1376 bool CFrame::focusDrawingEnabled () const
1377 {
1378 uint32_t attrSize;
1379 if (getAttributeSize ('vfde', attrSize))
1380 return true;
1381 return false;
1382 }
1383
1384 //-----------------------------------------------------------------------------
getFocusColor() const1385 CColor CFrame::getFocusColor () const
1386 {
1387 CColor focusColor (kRedCColor);
1388 getAttribute ('vfco', focusColor);
1389 return focusColor;
1390 }
1391
1392 //-----------------------------------------------------------------------------
getFocusWidth() const1393 CCoord CFrame::getFocusWidth () const
1394 {
1395 CCoord focusWidth = 2;
1396 getAttribute ('vfwi', focusWidth);
1397 return focusWidth;
1398 }
1399
1400 //-----------------------------------------------------------------------------
setFocusDrawingEnabled(bool state)1401 void CFrame::setFocusDrawingEnabled (bool state)
1402 {
1403 if (state)
1404 setAttribute ('vfde', state);
1405 else
1406 removeAttribute ('vfde');
1407 }
1408
1409 //-----------------------------------------------------------------------------
setFocusColor(const CColor & color)1410 void CFrame::setFocusColor (const CColor& color)
1411 {
1412 setAttribute ('vfco', color);
1413 }
1414
1415 //-----------------------------------------------------------------------------
setFocusWidth(CCoord width)1416 void CFrame::setFocusWidth (CCoord width)
1417 {
1418 setAttribute ('vfwi', width);
1419 }
1420
1421 //-----------------------------------------------------------------------------
1422 /**
1423 * @param src rect which to scroll
1424 * @param distance point of distance
1425 */
scrollRect(const CRect & src,const CPoint & distance)1426 void CFrame::scrollRect (const CRect& src, const CPoint& distance)
1427 {
1428 CRect rect (src);
1429 rect.offset (getViewSize ().left, getViewSize ().top);
1430
1431 if (pImpl->platformFrame)
1432 {
1433 if (pImpl->platformFrame->scrollRect (src, distance))
1434 return;
1435 }
1436 invalidRect (src);
1437 }
1438
1439 //-----------------------------------------------------------------------------
invalidate(const CRect & rect)1440 void CFrame::invalidate (const CRect &rect)
1441 {
1442 for (const auto& pV : getChildren ())
1443 {
1444 CRect rectView = pV->getViewSize ();
1445 if (rect.rectOverlap (rectView))
1446 pV->setDirty (true);
1447 }
1448 }
1449
1450 //-----------------------------------------------------------------------------
invalidRect(const CRect & rect)1451 void CFrame::invalidRect (const CRect& rect)
1452 {
1453 if (!isVisible () || !pImpl->platformFrame)
1454 return;
1455
1456 CRect _rect (rect);
1457 getTransform ().transform (_rect);
1458 _rect.makeIntegral ();
1459 if (pImpl->collectInvalidRects)
1460 pImpl->collectInvalidRects->addRect (_rect);
1461 else
1462 pImpl->platformFrame->invalidRect (_rect);
1463 }
1464
1465 //-----------------------------------------------------------------------------
getViewAddedRemovedObserver() const1466 IViewAddedRemovedObserver* CFrame::getViewAddedRemovedObserver () const
1467 {
1468 return pImpl->viewAddedRemovedObserver;
1469 }
1470
1471 //-----------------------------------------------------------------------------
setViewAddedRemovedObserver(IViewAddedRemovedObserver * observer)1472 void CFrame::setViewAddedRemovedObserver (IViewAddedRemovedObserver* observer)
1473 {
1474 pImpl->viewAddedRemovedObserver = observer;
1475 }
1476
1477 //-----------------------------------------------------------------------------
registerKeyboardHook(IKeyboardHook * hook)1478 void CFrame::registerKeyboardHook (IKeyboardHook* hook)
1479 {
1480 pImpl->keyboardHooks.add (hook);
1481 }
1482
1483 //-----------------------------------------------------------------------------
unregisterKeyboardHook(IKeyboardHook * hook)1484 void CFrame::unregisterKeyboardHook (IKeyboardHook* hook)
1485 {
1486 pImpl->keyboardHooks.remove (hook);
1487 }
1488
1489 //-----------------------------------------------------------------------------
keyboardHooksOnKeyDown(const VstKeyCode & key)1490 int32_t CFrame::keyboardHooksOnKeyDown (const VstKeyCode& key)
1491 {
1492 int32_t result = -1;
1493 pImpl->keyboardHooks.forEachReverse ([&] (IKeyboardHook* hook) {
1494 if (result <= 0)
1495 {
1496 result = hook->onKeyDown (key, this);
1497 }
1498 });
1499 return result;
1500 }
1501
1502 //-----------------------------------------------------------------------------
keyboardHooksOnKeyUp(const VstKeyCode & key)1503 int32_t CFrame::keyboardHooksOnKeyUp (const VstKeyCode& key)
1504 {
1505 int32_t result = -1;
1506 pImpl->keyboardHooks.forEachReverse ([&] (IKeyboardHook* hook) {
1507 if (result <= 0)
1508 {
1509 result = hook->onKeyUp (key, this);
1510 }
1511 });
1512 return result;
1513 }
1514
1515 //-----------------------------------------------------------------------------
registerScaleFactorChangedListeneer(IScaleFactorChangedListener * listener)1516 void CFrame::registerScaleFactorChangedListeneer (IScaleFactorChangedListener* listener)
1517 {
1518 pImpl->scaleFactorChangedListenerList.add (listener);
1519 }
1520
1521 //-----------------------------------------------------------------------------
unregisterScaleFactorChangedListeneer(IScaleFactorChangedListener * listener)1522 void CFrame::unregisterScaleFactorChangedListeneer (IScaleFactorChangedListener* listener)
1523 {
1524 pImpl->scaleFactorChangedListenerList.remove (listener);
1525 }
1526
1527 //-----------------------------------------------------------------------------
registerMouseObserver(IMouseObserver * observer)1528 void CFrame::registerMouseObserver (IMouseObserver* observer)
1529 {
1530 pImpl->mouseObservers.add (observer);
1531 }
1532
1533 //-----------------------------------------------------------------------------
registerFocusViewObserver(IFocusViewObserver * observer)1534 void CFrame::registerFocusViewObserver (IFocusViewObserver* observer)
1535 {
1536 pImpl->focusViewObservers.add (observer);
1537 }
1538
1539 //-----------------------------------------------------------------------------
unregisterFocusViewObserver(IFocusViewObserver * observer)1540 void CFrame::unregisterFocusViewObserver (IFocusViewObserver* observer)
1541 {
1542 pImpl->focusViewObservers.remove (observer);
1543 }
1544
1545 //-----------------------------------------------------------------------------
unregisterMouseObserver(IMouseObserver * observer)1546 void CFrame::unregisterMouseObserver (IMouseObserver* observer)
1547 {
1548 pImpl->mouseObservers.remove (observer);
1549 }
1550
1551 //-----------------------------------------------------------------------------
callMouseObserverMouseEntered(CView * view)1552 void CFrame::callMouseObserverMouseEntered (CView* view)
1553 {
1554 view->callMouseListenerEnteredExited (true);
1555 pImpl->mouseObservers.forEach ([&] (IMouseObserver* observer) {
1556 observer->onMouseEntered (view, this);
1557 });
1558 }
1559
1560 //-----------------------------------------------------------------------------
callMouseObserverMouseExited(CView * view)1561 void CFrame::callMouseObserverMouseExited (CView* view)
1562 {
1563 pImpl->mouseObservers.forEach ([&] (IMouseObserver* observer) {
1564 observer->onMouseExited (view, this);
1565 });
1566 view->callMouseListenerEnteredExited (false);
1567 }
1568
1569 //-----------------------------------------------------------------------------
callMouseObserverMouseDown(const CPoint & _where,const CButtonState & buttons)1570 CMouseEventResult CFrame::callMouseObserverMouseDown (const CPoint& _where, const CButtonState& buttons)
1571 {
1572 CMouseEventResult eventResult = kMouseEventNotHandled;
1573 if (pImpl->mouseObservers.empty ())
1574 return eventResult;
1575
1576 CPoint where (_where);
1577 getTransform ().inverse ().transform (where);
1578
1579 pImpl->mouseObservers.forEach ([&] (IMouseObserver* observer) {
1580 CMouseEventResult result2 = observer->onMouseDown (this, where, buttons);
1581 if (result2 != kMouseEventNotHandled)
1582 eventResult = result2;
1583 });
1584
1585 return eventResult;
1586 }
1587
1588 //-----------------------------------------------------------------------------
callMouseObserverMouseMoved(const CPoint & _where,const CButtonState & buttons)1589 CMouseEventResult CFrame::callMouseObserverMouseMoved (const CPoint& _where, const CButtonState& buttons)
1590 {
1591 CMouseEventResult eventResult = kMouseEventNotHandled;
1592 if (pImpl->mouseObservers.empty ())
1593 return eventResult;
1594
1595 CPoint where (_where);
1596 getTransform ().inverse ().transform (where);
1597
1598 pImpl->mouseObservers.forEach ([&] (IMouseObserver* observer) {
1599 CMouseEventResult result2 = observer->onMouseMoved (this, where, buttons);
1600 if (result2 == kMouseEventHandled)
1601 eventResult = kMouseEventHandled;
1602 });
1603
1604 return eventResult;
1605 }
1606
1607 //------------------------------------------------------------------------
performDrag(const DragDescription & desc,const SharedPointer<IDragCallback> & callback)1608 bool CFrame::performDrag (const DragDescription& desc, const SharedPointer<IDragCallback>& callback)
1609 {
1610 if (auto platformFrame = getPlatformFrame ())
1611 {
1612 if (platformFrame->doDrag (desc, callback))
1613 {
1614 setMouseDownView (nullptr);
1615 return true;
1616 }
1617 }
1618 return false;
1619 }
1620
1621 #if DEBUG
1622 //-----------------------------------------------------------------------------
dumpHierarchy()1623 void CFrame::dumpHierarchy ()
1624 {
1625 dumpInfo ();
1626 DebugPrint ("\n");
1627 CViewContainer::dumpHierarchy ();
1628 }
1629 #endif
1630
1631 //-----------------------------------------------------------------------------
getEditor() const1632 VSTGUIEditorInterface* CFrame::getEditor () const
1633 {
1634 return pImpl->editor;
1635 }
1636
1637 //-----------------------------------------------------------------------------
getPlatformFrame() const1638 IPlatformFrame* CFrame::getPlatformFrame () const
1639 {
1640 return pImpl->platformFrame;
1641 }
1642
1643 //-----------------------------------------------------------------------------
platformDrawRect(CDrawContext * context,const CRect & rect)1644 bool CFrame::platformDrawRect (CDrawContext* context, const CRect& rect)
1645 {
1646 drawRect (context, rect);
1647 return true;
1648 }
1649
1650 //-----------------------------------------------------------------------------
platformOnMouseDown(CPoint & where,const CButtonState & buttons)1651 CMouseEventResult CFrame::platformOnMouseDown (CPoint& where, const CButtonState& buttons)
1652 {
1653 if (!getMouseEnabled ())
1654 return kMouseEventNotHandled;
1655 Impl::PostEventHandler peh (*pImpl);
1656 CollectInvalidRects cir (this);
1657 return onMouseDown (where, buttons);
1658 }
1659
1660 //-----------------------------------------------------------------------------
platformOnMouseMoved(CPoint & where,const CButtonState & buttons)1661 CMouseEventResult CFrame::platformOnMouseMoved (CPoint& where, const CButtonState& buttons)
1662 {
1663 if (!getMouseEnabled ())
1664 return kMouseEventNotHandled;
1665 Impl::PostEventHandler peh (*pImpl);
1666 CollectInvalidRects cir (this);
1667 return onMouseMoved (where, buttons);
1668 }
1669
1670 //-----------------------------------------------------------------------------
platformOnMouseUp(CPoint & where,const CButtonState & buttons)1671 CMouseEventResult CFrame::platformOnMouseUp (CPoint& where, const CButtonState& buttons)
1672 {
1673 if (!getMouseEnabled ())
1674 return kMouseEventNotHandled;
1675 Impl::PostEventHandler peh (*pImpl);
1676 CollectInvalidRects cir (this);
1677 return onMouseUp (where, buttons);
1678 }
1679
1680 //-----------------------------------------------------------------------------
platformOnMouseExited(CPoint & where,const CButtonState & buttons)1681 CMouseEventResult CFrame::platformOnMouseExited (CPoint& where, const CButtonState& buttons)
1682 {
1683 if (!getMouseEnabled ())
1684 return kMouseEventNotHandled;
1685 Impl::PostEventHandler peh (*pImpl);
1686 CollectInvalidRects cir (this);
1687 return onMouseExited (where, buttons);
1688 }
1689
1690 //-----------------------------------------------------------------------------
platformOnMouseWheel(const CPoint & where,const CMouseWheelAxis & axis,const float & distance,const CButtonState & buttons)1691 bool CFrame::platformOnMouseWheel (const CPoint &where, const CMouseWheelAxis &axis, const float &distance, const CButtonState &buttons)
1692 {
1693 if (!getMouseEnabled ())
1694 return false;
1695 Impl::PostEventHandler peh (*pImpl);
1696 CollectInvalidRects cir (this);
1697 return onWheel (where, axis, distance, buttons);
1698 }
1699
1700 //-----------------------------------------------------------------------------
platformOnDragEnter(DragEventData data)1701 DragOperation CFrame::platformOnDragEnter (DragEventData data)
1702 {
1703 if (!getMouseEnabled ())
1704 return DragOperation::None;
1705 Impl::PostEventHandler peh (*pImpl);
1706 CollectInvalidRects cir (this);
1707 data.modifiers = data.modifiers.getModifierState ();
1708 return getDropTarget ()->onDragEnter (data);
1709 }
1710
1711 //-----------------------------------------------------------------------------
platformOnDragMove(DragEventData data)1712 DragOperation CFrame::platformOnDragMove (DragEventData data)
1713 {
1714 if (!getMouseEnabled ())
1715 return DragOperation::None;
1716 Impl::PostEventHandler peh (*pImpl);
1717 CollectInvalidRects cir (this);
1718 data.modifiers = data.modifiers.getModifierState ();
1719 return getDropTarget ()->onDragMove (data);
1720 }
1721
1722 //-----------------------------------------------------------------------------
platformOnDragLeave(DragEventData data)1723 void CFrame::platformOnDragLeave (DragEventData data)
1724 {
1725 if (!getMouseEnabled ())
1726 return;
1727 Impl::PostEventHandler peh (*pImpl);
1728 CollectInvalidRects cir (this);
1729 data.modifiers = data.modifiers.getModifierState ();
1730 getDropTarget ()->onDragLeave (data);
1731 }
1732
1733 //-----------------------------------------------------------------------------
platformOnDrop(DragEventData data)1734 bool CFrame::platformOnDrop (DragEventData data)
1735 {
1736 if (!getMouseEnabled ())
1737 return false;
1738 Impl::PostEventHandler peh (*pImpl);
1739 CollectInvalidRects cir (this);
1740 data.modifiers = data.modifiers.getModifierState ();
1741 return getDropTarget ()->onDrop (data);
1742 }
1743
1744 //-----------------------------------------------------------------------------
platformOnKeyDown(VstKeyCode & keyCode)1745 bool CFrame::platformOnKeyDown (VstKeyCode& keyCode)
1746 {
1747 if (!getMouseEnabled ())
1748 return false;
1749 Impl::PostEventHandler peh (*pImpl);
1750 CollectInvalidRects cir (this);
1751 return onKeyDown (keyCode) == 1;
1752 }
1753
1754 //-----------------------------------------------------------------------------
platformOnKeyUp(VstKeyCode & keyCode)1755 bool CFrame::platformOnKeyUp (VstKeyCode& keyCode)
1756 {
1757 if (!getMouseEnabled ())
1758 return false;
1759 Impl::PostEventHandler peh (*pImpl);
1760 CollectInvalidRects cir (this);
1761 return onKeyUp (keyCode) == 1;
1762 }
1763
1764 //-----------------------------------------------------------------------------
platformOnActivate(bool state)1765 void CFrame::platformOnActivate (bool state)
1766 {
1767 if (getFrame ())
1768 {
1769 CollectInvalidRects cir (this);
1770 onActivate (state);
1771 }
1772 }
1773
1774 //------------------------------------------------------------------------
platformOnWindowActivate(bool state)1775 void CFrame::platformOnWindowActivate (bool state)
1776 {
1777 if (pImpl->windowActive == state)
1778 return;
1779 pImpl->windowActive = state;
1780 CollectInvalidRects cir (this);
1781 pImpl->windowActiveStateChangeViews.forEach ([&] (CView* view) {
1782 view->onWindowActivate (state);
1783 });
1784 }
1785
1786 //-----------------------------------------------------------------------------
platformScaleFactorChanged(double newScaleFactor)1787 void CFrame::platformScaleFactorChanged (double newScaleFactor)
1788 {
1789 if (pImpl->platformScaleFactor == newScaleFactor)
1790 return;
1791 pImpl->platformScaleFactor = newScaleFactor;
1792 dispatchNewScaleFactor (getScaleFactor ());
1793 }
1794
1795 //-----------------------------------------------------------------------------
dispatchNewScaleFactor(double newScaleFactor)1796 void CFrame::dispatchNewScaleFactor (double newScaleFactor)
1797 {
1798 pImpl->scaleFactorChangedListenerList.forEach ([&] (IScaleFactorChangedListener* listener) {
1799 listener->onScaleFactorChanged (this, newScaleFactor);
1800 });
1801 }
1802
1803 #if VSTGUI_TOUCH_EVENT_HANDLING
1804 //-----------------------------------------------------------------------------
platformOnTouchEvent(ITouchEvent & event)1805 void CFrame::platformOnTouchEvent (ITouchEvent& event)
1806 {
1807 Impl::PostEventHandler peh (*pImpl);
1808 std::vector<CView*> targetDispatched;
1809 bool hasBeganTouch = false;
1810 for (const auto& e : event)
1811 {
1812 CView* target = e.second.target;
1813 if (target)
1814 {
1815 if (e.second.targetIsSingleTouch)
1816 {
1817 CButtonState buttons (kLButton);
1818 CPoint where (e.second.location);
1819 target->frameToLocal (where);
1820 switch (e.second.state)
1821 {
1822 case ITouchEvent::kMoved:
1823 {
1824 CMouseEventResult result = target->onMouseMoved (where, buttons);
1825 if (result == kMouseMoveEventHandledButDontNeedMoreEvents)
1826 {
1827 event.unsetTouchTarget(e.first, target);
1828 if (target->hitTest (where, buttons) == false)
1829 {
1830 // when the touch goes out of the target and it tells us to
1831 const_cast<ITouchEvent::Touch&> (e.second).state = ITouchEvent::kBegan;
1832 hasBeganTouch = true;
1833 }
1834 }
1835 break;
1836 }
1837 case ITouchEvent::kCanceled:
1838 {
1839 if (target->onMouseCancel () != kMouseEventHandled)
1840 target->onMouseUp (where, buttons);
1841 event.unsetTouchTarget (e.first, target);
1842 break;
1843 }
1844 case ITouchEvent::kEnded:
1845 {
1846 target->onMouseUp (where, buttons);
1847 event.unsetTouchTarget (e.first, target);
1848 break;
1849 }
1850 default:
1851 {
1852 // do nothing
1853 break;
1854 }
1855 }
1856 }
1857 else
1858 {
1859 if (std::find (targetDispatched.begin (), targetDispatched.end (), target) == targetDispatched.end ())
1860 {
1861 target->onTouchEvent (event);
1862 targetDispatched.emplace_back (target);
1863 }
1864 }
1865 }
1866 else if (e.second.state == ITouchEvent::kBegan)
1867 {
1868 hasBeganTouch = true;
1869 }
1870 }
1871 if (hasBeganTouch)
1872 {
1873 if (CView* focusView = getFocusView ())
1874 {
1875 if (dynamic_cast<CTextEdit*> (focusView))
1876 setFocusView (0);
1877 }
1878 for (const auto& e : event)
1879 {
1880 if (e.second.target == 0 && e.second.state == ITouchEvent::kBegan)
1881 {
1882 findSingleTouchEventTarget (const_cast<ITouchEvent::Touch&> (e.second));
1883 }
1884 }
1885 onTouchEvent (event);
1886 }
1887 }
1888
1889 #endif
1890
1891 //-----------------------------------------------------------------------------
doAfterEventProcessing(EventProcessingFunction && func)1892 bool CFrame::doAfterEventProcessing (EventProcessingFunction&& func)
1893 {
1894 if (pImpl->inEventHandling)
1895 pImpl->postEventFunctionQueue.push (std::move (func));
1896 return pImpl->inEventHandling;
1897 }
1898
1899 //-----------------------------------------------------------------------------
doAfterEventProcessing(const EventProcessingFunction & func)1900 bool CFrame::doAfterEventProcessing (const EventProcessingFunction& func)
1901 {
1902 if (pImpl->inEventHandling)
1903 pImpl->postEventFunctionQueue.push (func);
1904 return pImpl->inEventHandling;
1905 }
1906
1907 //-----------------------------------------------------------------------------
inEventProcessing() const1908 bool CFrame::inEventProcessing () const
1909 {
1910 return pImpl->inEventHandling;
1911 }
1912
1913 //-----------------------------------------------------------------------------
onStartLocalEventLoop()1914 void CFrame::onStartLocalEventLoop ()
1915 {
1916 if (pImpl->collectInvalidRects)
1917 {
1918 pImpl->collectInvalidRects->flush ();
1919 pImpl->collectInvalidRects = nullptr;
1920 }
1921 }
1922
1923 //-----------------------------------------------------------------------------
setCollectInvalidRects(CollectInvalidRects * cir)1924 void CFrame::setCollectInvalidRects (CollectInvalidRects* cir)
1925 {
1926 if (pImpl->collectInvalidRects)
1927 pImpl->collectInvalidRects->flush ();
1928 pImpl->collectInvalidRects = cir;
1929 }
1930
1931 //-----------------------------------------------------------------------------
CollectInvalidRects(CFrame * frame)1932 CFrame::CollectInvalidRects::CollectInvalidRects (CFrame* frame)
1933 : frame (frame)
1934 , lastTicks (frame->getTicks ())
1935 {
1936 #if VSTGUI_LOG_COLLECT_INVALID_RECTS
1937 numAddedRects = 0;
1938 #endif
1939 frame->setCollectInvalidRects (this);
1940 }
1941
1942 //-----------------------------------------------------------------------------
~CollectInvalidRects()1943 CFrame::CollectInvalidRects::~CollectInvalidRects () noexcept
1944 {
1945 frame->setCollectInvalidRects (nullptr);
1946 }
1947
1948 //-----------------------------------------------------------------------------
flush()1949 void CFrame::CollectInvalidRects::flush ()
1950 {
1951 if (!invalidRects.empty ())
1952 {
1953 if (frame->isVisible () && frame->pImpl->platformFrame)
1954 {
1955 for (auto& rect : invalidRects)
1956 frame->pImpl->platformFrame->invalidRect (rect);
1957 #if VSTGUI_LOG_COLLECT_INVALID_RECTS
1958 DebugPrint ("%d -> %d\n", numAddedRects, invalidRects.size ());
1959 numAddedRects = 0;
1960 #endif
1961 }
1962 invalidRects.clear ();
1963 }
1964 }
1965
1966 //-----------------------------------------------------------------------------
addRect(const CRect & rect)1967 void CFrame::CollectInvalidRects::addRect (const CRect& rect)
1968 {
1969 #if VSTGUI_LOG_COLLECT_INVALID_RECTS
1970 numAddedRects++;
1971 #endif
1972 bool add = true;
1973 for (auto it = invalidRects.begin (), end = invalidRects.end (); it != end; ++it)
1974 {
1975 if (it->rectInside (rect))
1976 {
1977 add = false;
1978 break;
1979 }
1980
1981 CRect r (rect);
1982 if (r.bound (*it) == rect)
1983 {
1984 add = false;
1985 break;
1986 }
1987 r = *it;
1988 if (r.bound (rect) == *it)
1989 {
1990 invalidRects.erase (it);
1991 break;
1992 }
1993 }
1994 if (add)
1995 invalidRects.emplace_back (rect);
1996 uint32_t now = frame->getTicks ();
1997 if (now - lastTicks > 16)
1998 {
1999 flush ();
2000 lastTicks = now;
2001 }
2002 }
2003
2004 } // VSTGUI
2005