Files
hot-step-cpp-ROCm/engine/vendor/vst3sdk/vstgui4/vstgui/uidescription/editing/uieditview.cpp
T
2026-08-16 18:24:52 +07:00

1468 lines
43 KiB
C++

// 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 "uieditview.h"
#if VSTGUI_LIVE_EDITING
#include "uiundomanager.h"
#include "uiactions.h"
#include "uicrosslines.h"
#include "igridprocessor.h"
#include "uiselection.h"
#include "uioverlayview.h"
#include "../icontroller.h"
#include "../uiattributes.h"
#include "../uidescription.h"
#include "../iviewfactory.h"
#include "../cstream.h"
#include "../detail/uiviewcreatorattributes.h"
#include "../../lib/cvstguitimer.h"
#include "../../lib/cexternalview.h"
#include "../../lib/cframe.h"
#include "../../lib/cscrollview.h"
#include "../../lib/cdropsource.h"
#include "../../lib/coffscreencontext.h"
#include "../../lib/clayeredviewcontainer.h"
#include "../../lib/dragging.h"
#include "../../lib/events.h"
#include "../../lib/idatapackage.h"
#include "../../lib/controls/ctextedit.h"
#include <cassert>
namespace VSTGUI {
namespace UIEditViewInternal {
//----------------------------------------------------------------------------------------------------
class UISelectionView : public UIOverlayView, public UISelectionListenerAdapter
//----------------------------------------------------------------------------------------------------
{
public:
UISelectionView (CViewContainer* editView, UISelection* selection, const CColor& selectionColor, CCoord handleSize);
~UISelectionView () override;
private:
void draw (CDrawContext* pContext) override;
void drawResizeHandle (const CPoint& p, CDrawContext* pContext);
void selectionWillChange (UISelection*) override { onSelectionChanged (); }
void selectionDidChange (UISelection*) override { onSelectionChanged (); }
void selectionViewsWillChange (UISelection*) override { onSelectionChanged (); }
void selectionViewsDidChange (UISelection*) override { onSelectionChanged (); }
void onSelectionChanged ();
SharedPointer<UISelection> selection;
CColor selectionColor;
CCoord handleInset;
};
//----------------------------------------------------------------------------------------------------
UISelectionView::UISelectionView (CViewContainer* editView, UISelection* selection, const CColor& selectionColor, CCoord handleSize)
: UIOverlayView (editView)
, selection (selection)
, selectionColor (selectionColor)
, handleInset (handleSize / 2.)
{
selection->registerListener (this);
}
//----------------------------------------------------------------------------------------------------
UISelectionView::~UISelectionView ()
{
selection->unregisterListener (this);
}
//----------------------------------------------------------------------------------------------------
void UISelectionView::drawResizeHandle (const CPoint& p, CDrawContext* pContext)
{
CRect r (p.x, p.y, p.x, p.y);
r.inset (-handleInset, -handleInset);
pContext->drawRect (r, kDrawFilledAndStroked);
}
//----------------------------------------------------------------------------------------------------
void UISelectionView::draw (CDrawContext* pContext)
{
auto lineWidth = pContext->getHairlineSize ();
CRect r (getVisibleViewSize ());
ConcatClip cc (*pContext, r);
pContext->setDrawMode (kAliasing);
pContext->setLineStyle (kLineSolid);
pContext->setLineWidth (lineWidth);
CColor lightColor (kWhiteCColor);
lightColor.alpha = 140;
pContext->setFillColor (lightColor);
CView* mainView = getTargetView ()->getView (0);
CPoint p;
frameToLocal (p);
for (auto view : *selection)
{
CRect vs = selection->getGlobalViewCoordinates (view);
vs.offsetInverse (p);
vs.extend (lineWidth, lineWidth);
pContext->setFrameColor (lightColor);
pContext->drawRect (vs);
vs.inset (lineWidth, lineWidth);
pContext->setFrameColor (selectionColor);
pContext->drawRect (vs);
if (vs.getWidth () > handleInset * 2. && vs.getHeight () > handleInset * 2.)
{
drawResizeHandle (vs.getBottomRight (), pContext);
if (view != mainView)
{
drawResizeHandle (vs.getTopLeft (), pContext);
drawResizeHandle (vs.getBottomLeft (), pContext);
drawResizeHandle (vs.getTopRight (), pContext);
}
if (vs.getHeight () > handleInset * 4)
{
drawResizeHandle (vs.getRightCenter (), pContext);
if (view != mainView)
drawResizeHandle (vs.getLeftCenter (), pContext);
}
if (vs.getWidth () > handleInset * 4)
{
drawResizeHandle (vs.getBottomCenter (), pContext);
if (view != mainView)
drawResizeHandle (vs.getTopCenter (), pContext);
}
}
}
}
//----------------------------------------------------------------------------------------------------
void UISelectionView::onSelectionChanged ()
{
CPoint p;
frameToLocal (p);
for (auto view : *selection)
{
CRect vs = selection->getGlobalViewCoordinates (view);
vs.offsetInverse (p);
vs.extend (handleInset + 2, handleInset + 2);
invalidRect (vs);
}
}
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
class UIHighlightView : public UIOverlayView
{
public:
UIHighlightView (CViewContainer* editView, const CColor& viewHighlightColor);
void setHighlightView (CView* view);
private:
void draw (CDrawContext* pContext) override;
CView* highlightView;
CColor strokeColor;
CColor fillColor;
};
//----------------------------------------------------------------------------------------------------
UIHighlightView::UIHighlightView (CViewContainer* editView, const CColor& viewHighlightColor)
: UIOverlayView (editView)
, highlightView (nullptr)
, strokeColor (viewHighlightColor)
{
double h,s,l;
strokeColor.toHSL (h, s, l);
l /= 2.;
fillColor.fromHSL (h, s, l);
fillColor.alpha = strokeColor.alpha;
}
//----------------------------------------------------------------------------------------------------
void UIHighlightView::setHighlightView (CView* view)
{
if (highlightView != view)
{
highlightView = view;
invalid ();
}
}
//----------------------------------------------------------------------------------------------------
void UIHighlightView::draw (CDrawContext* pContext)
{
if (highlightView == nullptr)
return;
CRect r = UISelection::getGlobalViewCoordinates (highlightView);
CPoint p;
frameToLocal (p);
r.offsetInverse (p);
r.inset (2, 2);
pContext->setFillColor (fillColor);
pContext->setFrameColor (strokeColor);
pContext->setLineStyle (kLineSolid);
pContext->setLineWidth (3);
pContext->drawRect (r, kDrawFilledAndStroked);
}
//------------------------------------------------------------------------
template<typename T>
void collectExternalViewsOnInlineEditing (CViewContainer* container, T& array)
{
container->forEachChild ([&] (auto view) {
if (view.template cast<ExternalView::IViewEmbedder> ())
array.emplace_back (view);
else if (auto c = view->asViewContainer ())
collectExternalViewsOnInlineEditing (c, array);
});
}
} // UIEditViewInternal
//------------------------------------------------------------------------
struct UIEditView::ViewAddedObserver : IViewAddedRemovedObserver,
ViewListenerAdapter
{
ViewAddedObserver (CViewContainer* root) : root (root) {}
~ViewAddedObserver () override
{
for (auto view : views)
{
if (auto viewEmbedder = dynamic_cast<ExternalView::IViewEmbedder*> (view))
{
if (auto ev = viewEmbedder->getExternalView ())
ev->setMouseEnabled (view->getMouseEnabled ());
}
view->unregisterViewListener (this);
}
}
bool isViewSubViewOfRoot (CView* view)
{
CView* parent = view->getParentView ();
if (parent == nullptr || parent == root->getFrame ())
return false;
if (parent->asViewContainer () == root)
return true;
return isViewSubViewOfRoot (parent);
}
void onViewAdded (CFrame* frame, CView* view) override
{
if (auto viewEmbedder = dynamic_cast<ExternalView::IViewEmbedder*> (view))
{
if (!isViewSubViewOfRoot (view))
return;
if (auto ev = viewEmbedder->getExternalView ())
ev->setMouseEnabled (false);
view->registerViewListener (this);
views.emplace_back (view);
}
}
void onViewRemoved (CFrame* frame, CView* view) override {}
void viewWillDelete (CView* view) override
{
view->unregisterViewListener (this);
auto it = std::find (views.begin (), views.end (), view);
if (it != views.end ())
views.erase (it);
}
void viewOnMouseEnabled (CView* view, bool state) override
{
if (auto viewEmbedder = dynamic_cast<ExternalView::IViewEmbedder*> (view))
{
if (auto ev = viewEmbedder->getExternalView ())
ev->setMouseEnabled (false);
}
}
CViewContainer* root;
std::vector<CView*> views;
};
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
IdStringPtr UIEditView::kMsgAttached = "UIEditView::kMsgAttached";
IdStringPtr UIEditView::kMsgRemoved = "UIEditView::kMsgRemoved";
static constexpr auto kResizeHandleSize = 6.;
static constexpr auto UIEditViewMargin = 8.;
//----------------------------------------------------------------------------------------------------
UIEditView::UIEditView (const CRect& size, UIDescription* uidescription)
: CViewContainer (size)
, description (uidescription)
, gridProcessor (nullptr)
{
setScale (1.);
setWantsFocus (true);
}
//----------------------------------------------------------------------------------------------------
UIEditView::~UIEditView ()
{
editTimer = nullptr;
setUndoManager (nullptr);
setSelection (nullptr);
}
//------------------------------------------------------------------------
void UIEditView::updateSize ()
{
if (CView* view = getEditView ())
{
CRect r (getViewSize ());
CPoint size (view->getWidth (), view->getHeight ());
getTransform ().transform (size);
r.setSize (size);
r.right += UIEditViewMargin;
r.bottom += UIEditViewMargin;
if (r != getViewSize ())
{
setAutosizingEnabled (false);
setViewSize (r);
setMouseableArea (getViewSize ());
setAutosizingEnabled (true);
getParentView ()->invalid ();
}
}
}
//----------------------------------------------------------------------------------------------------
void UIEditView::setScale (double scale)
{
scale = std::round (scale * 100) / 100.;
setTransform (CGraphicsTransform ().scale (scale, scale));
updateSize ();
}
//----------------------------------------------------------------------------------------------------
void UIEditView::enableEditing (bool state)
{
if (editing != state)
{
editing = state;
invalid ();
CFrame* parent = getFrame ();
if (parent == nullptr)
return;
if (editing)
{
CRect r = parent->getViewSize ();
r.originize ();
vstgui_assert (overlayView == nullptr);
overlayView = new CLayeredViewContainer (r);
overlayView->setAutosizeFlags (kAutosizeAll);
overlayView->setMouseEnabled (false);
overlayView->setTransparency (true);
overlayView->setZIndex (1000);
parent->addView (overlayView);
highlightView = new UIEditViewInternal::UIHighlightView (this, viewHighlightColor);
overlayView->addView (highlightView);
auto selectionView = new UIEditViewInternal::UISelectionView (this, getSelection (), viewSelectionColor, kResizeHandleSize);
overlayView->addView (selectionView);
}
else
{
parent->removeView (overlayView);
overlayView = nullptr;
highlightView = nullptr;
lines = nullptr;
}
disableExternalViewsOnInlineEditing (editing);
}
}
//------------------------------------------------------------------------
void UIEditView::disableExternalViewsOnInlineEditing (bool state)
{
CFrame* parent = getFrame ();
if (editingViewAddedObserver)
parent->setViewAddedRemovedObserver (nullptr);
editingViewAddedObserver.reset ();
if (state)
{
editingViewAddedObserver = std::make_unique<ViewAddedObserver> (this);
std::vector<CView*> views;
UIEditViewInternal::collectExternalViewsOnInlineEditing (this, views);
for (auto* v : views)
editingViewAddedObserver->onViewAdded (parent, v);
parent->setViewAddedRemovedObserver (editingViewAddedObserver.get ());
}
}
//----------------------------------------------------------------------------------------------------
void UIEditView::enableAutosizing (bool state)
{
autosizing = state;
}
//----------------------------------------------------------------------------------------------------
void UIEditView::setUndoManager (UIUndoManager* manager)
{
undoManger = manager;
}
//----------------------------------------------------------------------------------------------------
UIUndoManager* UIEditView::getUndoManager ()
{
if (undoManger == nullptr)
undoManger = makeOwned<UIUndoManager> ();
return undoManger;
}
//----------------------------------------------------------------------------------------------------
void UIEditView::setSelection (UISelection* inSelection)
{
selection = inSelection;
}
//----------------------------------------------------------------------------------------------------
UISelection* UIEditView::getSelection ()
{
if (selection == nullptr)
{
selection = makeOwned<UISelection> ();
}
return selection;
}
//----------------------------------------------------------------------------------------------------
void UIEditView::setGridProcessor (IGridProcessor* inGrid)
{
gridProcessor = inGrid;
}
//----------------------------------------------------------------------------------------------------
void UIEditView::setEditView (CView* view)
{
if (view != getEditView ())
{
disableExternalViewsOnInlineEditing (false);
invalid ();
removeAll ();
CRect vs (getViewSize ());
if (view)
{
addView (view);
updateSize ();
}
else
{
vs.setWidth (0);
vs.setHeight (0);
setMouseableArea (vs);
setViewSize (vs);
}
disableExternalViewsOnInlineEditing (editing);
invalid ();
}
}
//----------------------------------------------------------------------------------------------------
CView* UIEditView::getEditView () const
{
return getView (0);
}
//----------------------------------------------------------------------------------------------------
CMessageResult UIEditView::notify (CBaseObject* sender, IdStringPtr message)
{
if (message == CVSTGUITimer::kMsgTimer)
{
if (sender == editTimer)
{
if (lines == nullptr)
{
lines = new UICrossLines (this, UICrossLines::kSelectionStyle, crosslineBackgroundColor, crosslineForegroundColor);
overlayView->addView (lines);
lines->update (selection);
getFrame ()->setCursor (kCursorMoveObject);
}
editTimer = nullptr;
}
return kMessageNotified;
}
else if (message == kMsgViewSizeChanged)
{
CView* view = dynamic_cast<CView*> (sender);
if (view && view == getEditView ())
{
updateSize ();
}
}
return CViewContainer::notify (sender, message);
}
//----------------------------------------------------------------------------------------------------
void UIEditView::draw (CDrawContext *pContext)
{
drawRect (pContext, getViewSize ());
}
//----------------------------------------------------------------------------------------------------
void UIEditView::drawRect (CDrawContext *pContext, const CRect& updateRect)
{
// disable focus drawing
bool focusDrawing = getFrame ()->focusDrawingEnabled ();
if (!editing && focusDrawing)
getFrame ()->setFocusDrawingEnabled (false);
CViewContainer::drawRect (pContext, updateRect);
if (!editing && focusDrawing)
getFrame ()->setFocusDrawingEnabled (focusDrawing);
pContext->setClipRect (updateRect);
CDrawContext::Transform transform (*pContext, CGraphicsTransform ().translate (getViewSize ().left, getViewSize ().top));
const CCoord dashLength[] = {5, 5};
const CLineStyle lineDash (CLineStyle::kLineCapButt, CLineStyle::kLineJoinMiter, 0, 2, dashLength);
pContext->setLineStyle (lineDash);
pContext->setLineWidth (1);
pContext->setDrawMode (kAliasing);
pContext->setFrameColor (kBlueCColor);
pContext->drawRect (
CRect (0, 0, getWidth () - UIEditViewMargin, getHeight () - UIEditViewMargin),
kDrawStroked);
}
//----------------------------------------------------------------------------------------------------
CView* UIEditView::getViewAt (const CPoint& p, const GetViewOptions& options) const
{
CView* view = CViewContainer::getViewAt (p, options);
if (editing)
{
while (view && IViewFactory::getViewName (view) == nullptr)
{
view = view->getParentView ();
}
}
return view;
}
//----------------------------------------------------------------------------------------------------
CViewContainer* UIEditView::getContainerAt (const CPoint& p, const GetViewOptions& options) const
{
CViewContainer* view = CViewContainer::getContainerAt (p, options);
if (editing)
{
while (view && IViewFactory::getViewName (view) == nullptr)
{
view = view->getParentView ()->asViewContainer ();
}
}
return view;
}
//----------------------------------------------------------------------------------------------------
bool UIEditView::advanceNextFocusView (CView* oldFocus, bool reverse)
{
if (editing)
return false;
return CViewContainer::advanceNextFocusView (oldFocus, reverse);
}
//----------------------------------------------------------------------------------------------------
void UIEditView::onMouseWheelEvent (MouseWheelEvent& event)
{
if (!editing)
CViewContainer::onMouseWheelEvent (event);
}
//------------------------------------------------------------------------
void UIEditView::onZoomGestureEvent (ZoomGestureEvent& event)
{
if (editing)
{
auto scale = getTransform ().m11;
auto newScale = scale + scale * event.zoom;
setScale (newScale);
event.consumed = true;
}
}
//----------------------------------------------------------------------------------------------------
void UIEditView::invalidSelection ()
{
getSelection ()->invalidRects ();
}
namespace UIEditViewInternal {
//----------------------------------------------------------------------------------------------------
static bool pointInResizeHandleRect (const CPoint& where, const CPoint& handle)
{
CRect r (handle.x, handle.y, handle.x, handle.y);
r.extend (kResizeHandleSize/2., kResizeHandleSize/2.);
return r.pointInside (where);
}
} // UIEditViewInternal
//----------------------------------------------------------------------------------------------------
UIEditView::MouseSizeMode UIEditView::selectionHitTest (const CPoint& _where, CView** resultView)
{
CPoint where (_where);
where.offset (-getViewSize ().left, -getViewSize ().top);
CPoint p;
frameToLocal (p);
CView* mainView = getEditView ();
for (auto it = getSelection ()->rbegin (), end = getSelection ()->rend (); it != end; ++it)
{
auto view = (*it);
CRect r = getSelection ()->getGlobalViewCoordinates (view);
bool isMainView = (mainView == view) ? true : false;
r.offset (p);
r.extend (kResizeHandleSize, kResizeHandleSize);
if (r.pointInside (where))
{
if (resultView)
*resultView = view;
r.inset (kResizeHandleSize, kResizeHandleSize);
if (UIEditViewInternal::pointInResizeHandleRect (where, r.getBottomRight ()))
return MouseSizeMode::BottomRight;
if (UIEditViewInternal::pointInResizeHandleRect (where, r.getRightCenter ()))
return MouseSizeMode::Right;
if (UIEditViewInternal::pointInResizeHandleRect (where, r.getBottomCenter ()))
return MouseSizeMode::Bottom;
if (!isMainView)
{
if (UIEditViewInternal::pointInResizeHandleRect (where, r.getLeftCenter ()))
return MouseSizeMode::Left;
if (UIEditViewInternal::pointInResizeHandleRect (where, r.getTopCenter ()))
return MouseSizeMode::Top;
if (UIEditViewInternal::pointInResizeHandleRect (where, r.getBottomLeft ()))
return MouseSizeMode::BottomLeft;
if (UIEditViewInternal::pointInResizeHandleRect (where, r.getTopLeft ()))
return MouseSizeMode::TopLeft;
if (UIEditViewInternal::pointInResizeHandleRect (where, r.getTopRight ()))
return MouseSizeMode::TopRight;
if (r.pointInside (where))
return MouseSizeMode::None;
}
if (resultView)
*resultView = nullptr;
}
}
if (resultView)
*resultView = nullptr;
return MouseSizeMode::None;
}
//----------------------------------------------------------------------------------------------------
bool UIEditView::hitTestSubViews (const CPoint& where, const Event& event)
{
return hitTest (where, event);
}
//----------------------------------------------------------------------------------------------------
CMouseEventResult UIEditView::onMouseDown (CPoint &where, const CButtonState& buttons)
{
if (!editing)
return CViewContainer::onMouseDown (where, buttons);
if (!buttons.isLeftButton ())
return kMouseEventHandled;
getFrame ()->setFocusView (this);
CPoint where2 (where);
where2.offset (-getViewSize ().left, -getViewSize ().top);
getTransform ().inverse ().transform (where2);
if (buttons.isShiftSet ())
{
if (!buttons.isControlSet ())
getSelection ()->clear ();
mouseEditMode = MouseEditMode::WaitLasso;
dragStartMouseObserver.init (where);
mouseStartPoint = where2;
return kMouseEventHandled;
}
CView* selectionHitView = nullptr;
MouseSizeMode sizeMode = selectionHitTest (where, &selectionHitView);
CView* mouseHitView = getViewAt (where, GetViewOptions ().deep ().includeViewContainer ().includeInvisible ());
if (selectionHitView == nullptr && mouseHitView == nullptr)
{
getSelection ()->clear ();
return kMouseEventHandled;
}
if (getSelection ()->contains (mouseHitView))
{
if (buttons.isControlSet ())
{
getSelection ()->remove (mouseHitView);
onMouseMoved (where, CButtonState (buttons.getModifierState ()));
return kMouseEventHandled;
}
}
else if (mouseHitView && sizeMode == MouseSizeMode::None)
{
if (buttons.isControlSet ())
{
getSelection ()->add (mouseHitView);
selectionHitView = mouseHitView;
onMouseMoved (where, CButtonState (buttons.getModifierState ()));
}
else if (selectionHitView == nullptr || selectionHitView == getEditView ())
{
getSelection ()->setExclusive (mouseHitView);
selectionHitView = mouseHitView;
onMouseMoved (where, CButtonState (buttons.getModifierState ()));
}
}
if (selectionHitView)
{
if (buttons.isDoubleClick ())
{
onDoubleClickEditing (selectionHitView);
return kMouseEventHandled;
}
if (buttons.isAltSet () && !getSelection ()->contains (getEditView ()))
{
mouseEditMode = MouseEditMode::WaitDrag;
dragStartMouseObserver.init (where);
return kMouseEventHandled;
}
if (sizeMode == MouseSizeMode::None)
{
if (getSelection ()->contains (getEditView ()))
{
return kMouseEventHandled;
}
mouseEditMode = MouseEditMode::DragEditing;
mouseStartPoint = where2;
if (gridProcessor)
gridProcessor->process (mouseStartPoint);
editTimer = owned (new CVSTGUITimer (this, 500));
editTimer->start ();
return kMouseEventHandled;
}
else
{
mouseEditMode = MouseEditMode::SizeEditing;
mouseStartPoint = where2;
if (gridProcessor)
gridProcessor->process (mouseStartPoint);
mouseSizeMode = sizeMode;
if (true)
{
int32_t crossLineMode = 0;
switch (sizeMode)
{
case MouseSizeMode::Left:
case MouseSizeMode::Right:
case MouseSizeMode::Top:
case MouseSizeMode::Bottom: crossLineMode = UICrossLines::kSelectionStyle; break;
default : crossLineMode = UICrossLines::kDragStyle; break;
}
lines = new UICrossLines (this, crossLineMode, crosslineBackgroundColor, crosslineForegroundColor);
overlayView->addView (lines);
if (crossLineMode == UICrossLines::kSelectionStyle)
lines->update (selection);
else
lines->update (CPoint (mouseStartPoint.x, mouseStartPoint.y));
}
return kMouseEventHandled;
}
}
return kMouseEventHandled;
}
//----------------------------------------------------------------------------------------------------
CMouseEventResult UIEditView::onMouseUp (CPoint &where, const CButtonState& buttons)
{
if (!editing)
return CViewContainer::onMouseUp (where, buttons);
editTimer = nullptr;
if (mouseEditMode == MouseEditMode::LassoSelection)
{
CPoint where2 (where);
where2.offset (-getViewSize ().left, -getViewSize ().top);
getTransform ().inverse ().transform (where2);
CRect area;
area.setTopLeft (mouseStartPoint);
area.setBottomRight (where2);
area.normalize ();
auto result = findChildsInArea (getEditView ()->asViewContainer (), area);
for (auto& view : result)
{
if (IViewFactory::getViewName (view) && !getSelection ()->contains (view))
getSelection ()->add (view);
}
}
else if (mouseEditMode != MouseEditMode::NoEditing && !moveSizeOperation && buttons == kLButton && !lines)
{
CView* view = getViewAt (where, GetViewOptions ().deep ().includeViewContainer ().includeInvisible ());
if (view == this)
view = nullptr;
if (view)
{
getSelection ()->setExclusive (view);
}
}
if (lines)
{
overlayView->removeView (lines);
lines = nullptr;
}
mouseEditMode = MouseEditMode::NoEditing;
if (moveSizeOperation)
{
if (moveSizeOperation->didChange ())
getUndoManager ()->pushAndPerform (moveSizeOperation);
else
delete moveSizeOperation;
moveSizeOperation = nullptr;
}
onMouseMoved (where, CButtonState (buttons.getModifierState ()));
return kMouseEventHandled;
}
//----------------------------------------------------------------------------------------------------
CMouseEventResult UIEditView::onMouseMoved (CPoint &where, const CButtonState& buttons)
{
if (!editing)
return CViewContainer::onMouseMoved (where, buttons);
if (inlineAttrTextEditOpen)
return kMouseEventHandled;
CPoint where2 (where);
where2.offset (-getViewSize ().left, -getViewSize ().top);
getTransform ().inverse ().transform (where2);
if (buttons & kLButton)
{
if (mouseEditMode == MouseEditMode::LassoSelection)
{
if (lines)
{
CRect r;
r.setTopLeft (mouseStartPoint);
r.setBottomRight (where2);
r.normalize ();
lines->update (r);
}
getFrame ()->setCursor (kCursorDefault);
}
else if (mouseEditMode == MouseEditMode::WaitLasso && buttons.isShiftSet ())
{
if (dragStartMouseObserver.shouldStartDrag (where))
{
mouseEditMode = MouseEditMode::LassoSelection;
lines = new UICrossLines (this, UICrossLines::kLassoStyle, lassoFrameColor,
lassoFillColor);
overlayView->addView (lines);
getFrame ()->setCursor (kCursorDefault);
CViewContainer::onMouseMoved (where, buttons);
}
}
else if (getSelection ()->total () > 0)
{
if (mouseEditMode == MouseEditMode::DragEditing)
{
doDragEditingMove (where2);
}
else if (mouseEditMode == MouseEditMode::SizeEditing)
{
doSizeEditingMove (where2);
}
else if (mouseEditMode == MouseEditMode::WaitDrag)
{
if (dragStartMouseObserver.shouldStartDrag (where))
{
mouseEditMode = MouseEditMode::DragEditing;
invalidSelection ();
startDrag (where);
mouseEditMode = MouseEditMode::NoEditing;
invalidSelection ();
}
}
}
CScrollView* scrollView = dynamic_cast<CScrollView*>(getParentView ()->getParentView ());
if (scrollView)
{
scrollView->makeRectVisible (CRect (where, CPoint (1, 1)));
}
return kMouseEventHandled;
}
else if (buttons.getButtonState () == 0 && !buttons.isShiftSet ())
{
CView* view = nullptr;
CCursorType ctype = kCursorDefault;
auto mode = selectionHitTest (where, &view);
if (view)
{
switch (mode)
{
case MouseSizeMode::Right:
case MouseSizeMode::Left: ctype = kCursorHSize; break;
case MouseSizeMode::Top:
case MouseSizeMode::Bottom: ctype = kCursorVSize; break;
case MouseSizeMode::TopLeft:
case MouseSizeMode::BottomRight: ctype = kCursorNWSESize; break;
case MouseSizeMode::TopRight:
case MouseSizeMode::BottomLeft: ctype = kCursorNESWSize; break;
case MouseSizeMode::None:
{
if (getSelection ()->contains (getEditView ()) == false)
ctype = kCursorMovableObject;
break;
}
default: ctype = kCursorDefault; break;
}
}
getFrame ()->setCursor (ctype);
}
else
getFrame ()->setCursor (kCursorDefault);
return kMouseEventHandled;
}
//------------------------------------------------------------------------
void UIEditView::onKeyboardEvent (KeyboardEvent& event)
{
if (mouseEditMode != MouseEditMode::NoEditing && event.virt == VirtualKey::Escape &&
event.type == EventType::KeyDown)
{
if (lines)
{
overlayView->removeView (lines);
lines = nullptr;
}
if (moveSizeOperation)
{
moveSizeOperation->undo ();
delete moveSizeOperation;
moveSizeOperation = nullptr;
}
mouseEditMode = MouseEditMode::NoEditing;
getFrame ()->setCursor (kCursorDefault);
event.consumed = true;
return;
}
CViewContainer::onKeyboardEvent (event);
}
//-----------------------------------------------------------------------------
void UIEditView::doKeyMove (const CPoint& delta)
{
if (delta.x != 0. || delta.y != 0.)
{
if (getSelection ()->contains (getEditView ()))
return;
if (!moveSizeOperation)
moveSizeOperation = new ViewSizeChangeOperation (selection, false, autosizing);
getSelection ()->moveBy (delta);
if (moveSizeOperation)
{
getUndoManager ()->pushAndPerform (moveSizeOperation);
moveSizeOperation = nullptr;
}
}
}
//-----------------------------------------------------------------------------
void UIEditView::doKeySize (const CPoint& delta)
{
if (delta.x != 0. || delta.y != 0.)
{
if (!moveSizeOperation)
moveSizeOperation = new ViewSizeChangeOperation (selection, true, autosizing);
getSelection ()->viewsWillChange ();
for (auto view : *selection)
{
CRect viewSize = view->getViewSize ();
CPoint bottomRight = viewSize.getBottomRight ();
bottomRight += delta;
viewSize.setBottomRight (bottomRight);
view->setViewSize (viewSize);
view->setMouseableArea (viewSize);
}
getSelection ()->viewsDidChange ();
getUndoManager ()->pushAndPerform (moveSizeOperation);
moveSizeOperation = nullptr;
}
}
//----------------------------------------------------------------------------------------------------
std::vector<CView*> UIEditView::findChildsInArea (CViewContainer* view, CRect r) const
{
std::vector<CView*> views;
view->forEachChild ([&] (CView* child) {
if (r.rectOverlap (child->getViewSize ()))
{
if (auto container = child->asViewContainer ())
{
auto r2 = r;
auto viewSize = container->getViewSize ();
r2.bound (viewSize);
if (!r2.isEmpty ())
{
r2.offsetInverse (viewSize.getTopLeft ());
auto res2 = findChildsInArea (container, r2);
std::move (res2.begin (), res2.end (), std::back_inserter (views));
}
}
else
{
views.push_back (child);
}
}
});
return views;
}
//----------------------------------------------------------------------------------------------------
void UIEditView::doDragEditingMove (CPoint& where)
{
if (gridProcessor)
gridProcessor->process (where);
CPoint diff (where.x - mouseStartPoint.x, where.y - mouseStartPoint.y);
if (diff.x != 0. || diff.y != 0.)
{
if (!moveSizeOperation)
moveSizeOperation = new ViewSizeChangeOperation (selection, false, autosizing);
getSelection ()->moveBy (diff);
mouseStartPoint = where;
if (editTimer)
{
editTimer = nullptr;
if (!lines)
{
lines = new UICrossLines (this, UICrossLines::kSelectionStyle, crosslineBackgroundColor, crosslineForegroundColor);
overlayView->addView (lines);
lines->update (selection);
}
getFrame ()->setCursor (kCursorMoveObject);
}
if (lines)
lines->update (selection);
}
}
//----------------------------------------------------------------------------------------------------
void UIEditView::doSizeEditingMove (CPoint& where)
{
if (!moveSizeOperation)
moveSizeOperation = new ViewSizeChangeOperation (selection, true, autosizing);
if (gridProcessor)
gridProcessor->process (where);
if (mouseStartPoint == where)
return;
CRect diff;
switch (mouseSizeMode)
{
case MouseSizeMode::Left:
{
diff.left = where.x - mouseStartPoint.x;
break;
}
case MouseSizeMode::Right:
{
diff.right = where.x - mouseStartPoint.x;
break;
}
case MouseSizeMode::Top:
{
diff.top = where.y - mouseStartPoint.y;
break;
}
case MouseSizeMode::Bottom:
{
diff.bottom = where.y - mouseStartPoint.y;
break;
}
case MouseSizeMode::TopLeft:
{
diff.left = where.x - mouseStartPoint.x;
diff.top = where.y - mouseStartPoint.y;
break;
}
case MouseSizeMode::TopRight:
{
diff.right = where.x - mouseStartPoint.x;
diff.top = where.y - mouseStartPoint.y;
break;
}
case MouseSizeMode::BottomRight:
{
diff.right = where.x - mouseStartPoint.x;
diff.bottom = where.y - mouseStartPoint.y;
break;
}
case MouseSizeMode::BottomLeft:
{
diff.left = where.x - mouseStartPoint.x;
diff.bottom = where.y - mouseStartPoint.y;
break;
}
default: break;
}
std::vector<bool> oldAutosizeState;
if (!autosizing)
{
for (auto& view : *selection)
{
if (auto container = view->asViewContainer ())
{
oldAutosizeState.emplace_back (container->getAutosizingEnabled ());
container->setAutosizingEnabled (false);
}
}
}
selection->sizeBy (diff);
if (!autosizing)
{
size_t index = 0;
for (auto& view : *selection)
{
if (auto container = view->asViewContainer ())
{
container->setAutosizingEnabled (oldAutosizeState[index]);
++index;
}
}
}
mouseStartPoint = where;
if (lines)
{
if (lines->getStyle () == UICrossLines::kSelectionStyle)
lines->update (selection);
else
lines->update (mouseStartPoint);
}
}
//----------------------------------------------------------------------------------------------------
CMouseEventResult UIEditView::onMouseExited (CPoint& where, const CButtonState& buttons)
{
getFrame()->setCursor (kCursorDefault);
return kMouseEventHandled;
}
//----------------------------------------------------------------------------------------------------
void UIEditView::startDrag (CPoint& where)
{
auto bitmap = createBitmapFromSelection (selection, getFrame (), this);
if (bitmap == nullptr)
return;
where.makeIntegral ();
CRect selectionBounds = getSelection ()->getBounds ();
CPoint p;
getParentView ()->localToFrame (p);
selectionBounds.offsetInverse (p);
CPoint offset;
offset.x = (selectionBounds.left - where.x);
offset.y = (selectionBounds.top - where.y);
getSelection ()->setDragOffset (CPoint (offset.x, offset.y));
std::string templateName;
if (description->getTemplateNameFromView (getEditView (), templateName))
description->updateViewDescription (templateName.c_str (), getEditView ());
CMemoryStream stream (1024, 1024, false);
if (!getSelection ()->store (stream, description))
return;
stream.end ();
auto callback = makeOwned<DragCallbackFunctions> ();
callback->endedFunc = [this] (IDraggingSession*, CPoint pos, DragOperation) {
frameToLocal (pos);
onMouseMoved (pos, 0);
};
auto dropSource = CDropSource::create (stream.getBuffer (), static_cast<uint32_t>(stream.tell ()), CDropSource::kText);
doDrag (DragDescription (dropSource, offset, bitmap), callback);
}
//----------------------------------------------------------------------------------------------------
SharedPointer<UISelection> UIEditView::getSelectionOutOfDrag (IDataPackage* drag) const
{
IDataPackage::Type type;
const void* dragData;
uint32_t size;
if ((size = drag->getData (0, dragData, type)) > 0 && type == IDataPackage::kText)
{
auto oldController = description->getController ();
if (auto* controller = getEditor () ? dynamic_cast<IController*> (getEditor ()) : nullptr)
description->setController (controller);
CMemoryStream stream (static_cast<const int8_t*> (dragData), size, false);
auto newSelection = makeOwned<UISelection> ();
if (newSelection->restore (stream, description))
{
description->setController (oldController);
return newSelection;
}
description->setController (oldController);
}
return nullptr;
}
//----------------------------------------------------------------------------------------------------
SharedPointer<IDropTarget> UIEditView::getDropTarget ()
{
if (editing)
return this;
return CViewContainer::getDropTarget ();
}
//----------------------------------------------------------------------------------------------------
bool UIEditView::onDrop (DragEventData data)
{
if (lines)
{
overlayView->removeView (lines);
lines = nullptr;
}
if (dragSelection)
{
if (highlightView)
{
highlightView->setHighlightView (nullptr);
}
CPoint where2 (data.pos);
where2.offset (dragSelection->getDragOffset ().x, dragSelection->getDragOffset ().y);
if (gridProcessor)
{
getTransform ().inverse ().transform (where2);
gridProcessor->process (where2);
getTransform ().transform (where2);
}
CViewContainer* viewContainer = getContainerAt (where2, GetViewOptions ().deep ());
if (viewContainer && viewContainer != this)
{
where2.offset (-getViewSize ().left, -getViewSize ().top);
getTransform ().inverse ().transform (where2);
CPoint containerOffset;
viewContainer->localToFrame (containerOffset);
frameToLocal (containerOffset);
where2.offset (-containerOffset.x, -containerOffset.y);
where2.makeIntegral ();
IAction* action = new ViewCopyOperation (dragSelection, getSelection (), viewContainer, where2, description);
getUndoManager()->pushAndPerform (action);
}
dragSelection = nullptr;
}
return true;
}
//----------------------------------------------------------------------------------------------------
DragOperation UIEditView::onDragEnter (DragEventData data)
{
dragSelection = getSelectionOutOfDrag (data.drag);
if (dragSelection)
{
if (!lines)
{
lines = new UICrossLines (this, UICrossLines::kDragStyle, crosslineBackgroundColor, crosslineForegroundColor);
overlayView->addView (lines);
}
return onDragMove (data);
}
return DragOperation::None;
}
//----------------------------------------------------------------------------------------------------
void UIEditView::onDragLeave (DragEventData data)
{
dragSelection = nullptr;
if (highlightView)
{
highlightView->setHighlightView (nullptr);
}
if (lines)
{
overlayView->removeView (lines);
lines = nullptr;
}
}
//----------------------------------------------------------------------------------------------------
DragOperation UIEditView::onDragMove (DragEventData data)
{
if (editing)
{
if (lines)
{
if (dragSelection)
{
CPoint where2 (data.pos);
where2.offset (dragSelection->getDragOffset ().x, dragSelection->getDragOffset ().y);
where2.offset (-getViewSize ().left, -getViewSize ().top);
if (gridProcessor)
{
getTransform ().inverse ().transform (where2);
gridProcessor->process (where2);
getTransform ().transform (where2);
}
CPoint where3 (where2);
getTransform ().inverse ().transform (where3);
lines->update (where3);
if (highlightView)
{
CRect visibleRect = getVisibleViewSize ();
where2.offset (getViewSize ().left, getViewSize ().top);
where2.offset (-visibleRect.left, -visibleRect.top);
auto container = getContainerAt (where2, GetViewOptions ().deep ());
if (container == this)
{
container = nullptr;
highlightView->setHighlightView (nullptr);
return DragOperation::None;
}
highlightView->setHighlightView (container);
}
return DragOperation::Copy;
}
}
}
return DragOperation::None;
}
//-----------------------------------------------------------------------------
void UIEditView::onDoubleClickEditing (CView* view)
{
struct AttributeInlineEditorController : ViewListenerAdapter
{
using Callback = std::function<void ()>;
AttributeInlineEditorController (CTextEdit* edit, Callback&& callback)
: edit (edit), callback (std::move (callback))
{
edit->registerViewListener (this);
}
void viewWillDelete (CView*) override
{
edit->unregisterViewListener (this);
delete this;
}
void viewLostFocus (CView*) override
{
callback ();
}
private:
CTextEdit* edit;
Callback callback;
};
const auto* factory = description->getViewFactory ();
vstgui_assert (factory);
std::string attrValue;
if (!factory ||
!factory->getAttributeValue (view, UIViewCreator::kAttrTitle, attrValue, description))
return;
auto frame = getFrame ();
frame->setCursor (kCursorDefault);
auto r = selection->getGlobalViewCoordinates (view);
r.offsetInverse (getViewSize ().getTopLeft ());
translateToLocal (r, true);
auto textEdit = new CTextEdit (r, nullptr, 0);
textEdit->setText (attrValue.data ());
addView (textEdit);
new AttributeInlineEditorController (textEdit, [this, textEdit, attrValue] () {
const auto& text = textEdit->getText ();
if (text != attrValue)
{
auto action = new AttributeChangeAction (description, selection,
UIViewCreator::kAttrTitle, text.getString ());
getUndoManager ()->pushAndPerform (action);
}
textEdit->getParentView ()->asViewContainer ()->removeView (textEdit);
inlineAttrTextEditOpen = false;
});
frame->setFocusView (textEdit);
inlineAttrTextEditOpen = true;
}
//-----------------------------------------------------------------------------
void UIEditView::looseFocus ()
{
if (editing == false)
CViewContainer::looseFocus ();
}
//-----------------------------------------------------------------------------
void UIEditView::takeFocus ()
{
if (editing == false)
CViewContainer::takeFocus ();
}
//-----------------------------------------------------------------------------
bool UIEditView::attached (CView* parent)
{
if (CViewContainer::attached (parent))
{
editing = !editing;
enableEditing (!editing);
IController* controller = getViewController (this, true);
if (controller)
{
CBaseObject* obj = dynamic_cast<CBaseObject*>(controller);
if (obj)
obj->notify (this, kMsgAttached);
}
return true;
}
return false;
}
//-----------------------------------------------------------------------------
bool UIEditView::removed (CView* parent)
{
auto frame = getFrame ();
if (editingViewAddedObserver)
{
frame->setViewAddedRemovedObserver (nullptr);
editingViewAddedObserver.reset ();
}
IController* controller = getViewController (this, true);
if (controller)
{
CBaseObject* obj = dynamic_cast<CBaseObject*>(controller);
if (obj)
obj->notify (this, kMsgRemoved);
}
if (overlayView)
{
frame->removeView (overlayView);
overlayView = nullptr;
}
frame->setCursor (kCursorDefault);
return CViewContainer::removed (parent);
}
//-----------------------------------------------------------------------------
void UIEditView::setupColors (const IUIDescription* desc)
{
desc->getColor ("editView.crosslines.background", crosslineBackgroundColor);
desc->getColor ("editView.crosslines.foreground", crosslineForegroundColor);
desc->getColor ("editView.lasso.fill", lassoFillColor);
desc->getColor ("editView.lasso.frame", lassoFrameColor);
desc->getColor ("editView.view.highlight", viewHighlightColor);
desc->getColor ("editView.view.selection", viewSelectionColor);
}
} // VSTGUI
#endif // VSTGUI_LIVE_EDITING