// This file is part of VSTGUI. It is subject to the license terms // in the LICENSE file found in the top-level directory of this // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE #include "cexternalview.h" #include "cframe.h" #include "platform/iplatformframe.h" //------------------------------------------------------------------------ namespace VSTGUI { //------------------------------------------------------------------------ struct CExternalViewBaseImpl { private: using ExternalViewPtr = std::shared_ptr; ExternalViewPtr view; bool isAttached {false}; static ExternalView::IntRect fromCRect (const CRect& r) { ExternalView::IntRect res; res.origin.x = static_cast (std::ceil (r.left)); res.origin.y = static_cast (std::ceil (r.top)); res.size.width = static_cast (std::floor (r.getWidth ())); res.size.height = static_cast (std::floor (r.getHeight ())); return res; } static CRect calculateSize (CViewContainer* parent, CRect newSize) { CFrame* frame = parent ? parent->getFrame () : nullptr; while (parent && parent != frame) { CRect parentSize = parent->getViewSize (); parent->getTransform ().transform (newSize); newSize.offset (parentSize.left, parentSize.top); newSize.bound (parentSize); parent = static_cast (parent->getParentView ()); } if (frame) frame->getTransform ().transform (newSize); return newSize; } public: CExternalViewBaseImpl (const ExternalViewPtr& v) : view (v) {} void updateSize (CViewContainer* parent, CRect localSize, CRect globalSize) { if (!view) return; localSize = calculateSize (parent, localSize); view->setViewSize (fromCRect (globalSize), fromCRect (localSize)); } void attach (CFrame* frame) { if (!frame || !view) return; auto platformFrame = frame->getPlatformFrame (); if (!platformFrame) return; ExternalView::PlatformViewType viewType = {}; switch (platformFrame->getPlatformType ()) { case PlatformType::kHWND: viewType = ExternalView::PlatformViewType::HWND; break; case PlatformType::kNSView: viewType = ExternalView::PlatformViewType::NSView; break; default: return; } if (!view->platformViewTypeSupported (viewType)) return; isAttached = view->attach (platformFrame->getPlatformRepresentation (), viewType); } void remove () { if (view && isAttached) { view->remove (); isAttached = false; } } void scaleFactorChanged (double scaleFactor) { if (view) view->setContentScaleFactor (scaleFactor); } void takeFocus () { if (view) view->takeFocus (); } void looseFocus () { if (view) view->looseFocus (); } void enableMouse (bool state) { if (view) view->setMouseEnabled (state); } ExternalView::IView* getView () const { return view.get (); } }; //------------------------------------------------------------------------ struct CExternalView::Impl : CExternalViewBaseImpl { using CExternalViewBaseImpl::CExternalViewBaseImpl; }; //------------------------------------------------------------------------ CExternalView::CExternalView (const CRect& r, const ExternalViewPtr& view) : CView (r) { impl = std::make_unique (view); impl->getView ()->setTookFocusCallback ([this] () { if (auto frame = getFrame ()) frame->setFocusView (this); }); } //------------------------------------------------------------------------ CExternalView::~CExternalView () noexcept { impl->getView ()->setTookFocusCallback (nullptr); } //------------------------------------------------------------------------ bool CExternalView::attached (CView* parent) { if (CView::attached (parent)) { auto frame = parent->getFrame (); impl->updateSize (parent->asViewContainer (), getViewSize (), translateToGlobal (getViewSize ())); impl->scaleFactorChanged (frame->getScaleFactor ()); impl->attach (frame); frame->registerScaleFactorChangedListener (this); return true; } return false; } //------------------------------------------------------------------------ bool CExternalView::removed (CView* parent) { if (auto frame = parent->getFrame ()) { frame->unregisterScaleFactorChangedListener (this); } impl->remove (); return CView::removed (parent); } //------------------------------------------------------------------------ void CExternalView::takeFocus () { impl->takeFocus (); } //------------------------------------------------------------------------ void CExternalView::looseFocus () { impl->looseFocus (); } //------------------------------------------------------------------------ void CExternalView::setViewSize (const CRect& rect, bool invalid) { CView::setViewSize (rect, invalid); impl->updateSize (getParentView () ? getParentView ()->asViewContainer () : nullptr, getViewSize (), translateToGlobal (getViewSize ())); } //------------------------------------------------------------------------ void CExternalView::parentSizeChanged () { impl->updateSize (getParentView () ? getParentView ()->asViewContainer () : nullptr, getViewSize (), translateToGlobal (getViewSize ())); } //------------------------------------------------------------------------ void CExternalView::onScaleFactorChanged (CFrame* frame, double newScaleFactor) { impl->scaleFactorChanged (newScaleFactor); } //------------------------------------------------------------------------ void CExternalView::setMouseEnabled (bool enable) { impl->enableMouse (enable); CView::setMouseEnabled (enable); } //------------------------------------------------------------------------ ExternalView::IView* CExternalView::getExternalView () const { return impl->getView (); } //------------------------------------------------------------------------ //------------------------------------------------------------------------ //------------------------------------------------------------------------ //------------------------------------------------------------------------ struct CExternalControl::Impl : CExternalViewBaseImpl { using CExternalViewBaseImpl::CExternalViewBaseImpl; }; //------------------------------------------------------------------------ CExternalControl::CExternalControl (const CRect& r, const ExternalControlPtr& view) : CControl (r, nullptr) { impl = std::make_unique (view); impl->getView ()->setTookFocusCallback ([this] () { if (auto frame = getFrame ()) frame->setFocusView (this); }); auto control = dynamic_cast (impl->getView ()); vstgui_assert ( control, "Please provide an object that inherits from ExternalView::IControlViewExtension"); control->setEditCallbacks ({ [this] () { beginEdit (); }, [this] (double newValue) { auto old = getValue (); setValueNormalized (static_cast (newValue)); if (old != getValue ()) valueChanged (); }, [this] () { endEdit (); }, }); setWantsFocus (true); } //------------------------------------------------------------------------ CExternalControl::~CExternalControl () noexcept { impl->getView ()->setTookFocusCallback (nullptr); auto control = dynamic_cast (impl->getView ()); control->setEditCallbacks ({}); } //------------------------------------------------------------------------ void CExternalControl::setValue (float val) { CControl::setValue (val); auto control = dynamic_cast (impl->getView ()); control->setValue (getValueNormalized ()); } //------------------------------------------------------------------------ bool CExternalControl::attached (CView* parent) { if (CControl::attached (parent)) { auto frame = parent->getFrame (); impl->updateSize (parent->asViewContainer (), getViewSize (), translateToGlobal (getViewSize ())); impl->scaleFactorChanged (frame->getScaleFactor ()); impl->attach (frame); frame->registerScaleFactorChangedListener (this); return true; } return false; } //------------------------------------------------------------------------ bool CExternalControl::removed (CView* parent) { if (auto frame = parent->getFrame ()) { frame->unregisterScaleFactorChangedListener (this); } impl->remove (); return CControl::removed (parent); } //------------------------------------------------------------------------ void CExternalControl::takeFocus () { impl->takeFocus (); } //------------------------------------------------------------------------ void CExternalControl::looseFocus () { impl->looseFocus (); } //------------------------------------------------------------------------ void CExternalControl::setViewSize (const CRect& rect, bool invalid) { CControl::setViewSize (rect, invalid); impl->updateSize (getParentView () ? getParentView ()->asViewContainer () : nullptr, getViewSize (), translateToGlobal (getViewSize ())); } //------------------------------------------------------------------------ void CExternalControl::parentSizeChanged () { impl->updateSize (getParentView () ? getParentView ()->asViewContainer () : nullptr, getViewSize (), translateToGlobal (getViewSize ())); } //------------------------------------------------------------------------ void CExternalControl::onScaleFactorChanged (CFrame* frame, double newScaleFactor) { impl->scaleFactorChanged (newScaleFactor); } //------------------------------------------------------------------------ void CExternalControl::setMouseEnabled (bool enable) { impl->enableMouse (enable); CControl::setMouseEnabled (enable); } //------------------------------------------------------------------------ ExternalView::IView* CExternalControl::getExternalView () const { return impl->getView (); } //------------------------------------------------------------------------ bool CExternalControl::getFocusPath (CGraphicsPath& outPath) { return true; } //------------------------------------------------------------------------ } // VSTGUI