Files
2026-08-16 18:24:52 +07:00

357 lines
12 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
#pragma once
#include "vstguifwd.h"
#include "cview.h"
#include "cdrawdefs.h"
#if VSTGUI_TOUCH_EVENT_HANDLING
#include "itouchevent.h"
#endif
#include <list>
#include <memory>
#include <optional>
namespace VSTGUI {
/** Message of a view loosing focus (only CTextEdit and COptionMenu send this) */
extern IdStringPtr kMsgLooseFocus;
//-----------------------------------------------------------------------------
struct GetViewOptions
{
enum {
kNone = 0,
kDeep = 1 << 0,
kMouseEnabled = 1 << 1,
kIncludeViewContainer = 1 << 2,
kIncludeInvisible = 1 << 3
};
explicit GetViewOptions (uint32_t options = kNone) : flags (options) {}
GetViewOptions& deep (bool state = true) { setBit (flags, kDeep, state); return *this; }
GetViewOptions& mouseEnabled (bool state = true) { setBit (flags, kMouseEnabled, state); return *this; }
GetViewOptions& includeViewContainer (bool state = true) { setBit (flags, kIncludeViewContainer, state); return *this; }
GetViewOptions& includeInvisible (bool state = true) { setBit (flags, kIncludeInvisible, state); return *this; }
bool getDeep () const { return hasBit (flags, kDeep); }
bool getMouseEnabled () const { return hasBit (flags, kMouseEnabled); }
bool getIncludeViewContainer () const { return hasBit (flags, kIncludeViewContainer); }
bool getIncludeInvisible () const { return hasBit (flags, kIncludeInvisible); }
private:
uint32_t flags;
};
//-----------------------------------------------------------------------------
// CViewContainer Declaration
//! @brief Container Class of CView objects
/// @ingroup containerviews
//-----------------------------------------------------------------------------
class CViewContainer : public CView
{
public:
using ViewList = std::list<SharedPointer<CView>>;
explicit CViewContainer (const CRect& size);
CViewContainer (const CViewContainer& viewContainer);
//-----------------------------------------------------------------------------
/// @name Sub View Methods
//-----------------------------------------------------------------------------
//@{
/** add a child view */
bool addView (CView* pView, const CRect& mouseableArea, bool mouseEnabled = true);
/** add a child view before another view */
virtual bool addView (CView* pView, CView* pBefore = nullptr);
/** remove a child view */
virtual bool removeView (CView* pView, bool withForget = true);
/** remove all child views */
virtual bool removeAll (bool withForget = true);
/** check if pView is a child view of this container */
bool isChild (CView* pView) const;
/** check if pView is a child view of this container */
virtual bool isChild (CView* pView, bool deep) const;
/** check if container has child views */
virtual bool hasChildren () const;
/** get the number of child views */
virtual uint32_t getNbViews () const;
/** get the child view at index */
virtual CView* getView (uint32_t index) const;
/** get the view at point where */
virtual CView* getViewAt (const CPoint& where, const GetViewOptions& options = GetViewOptions ()) const;
/** get the container at point where */
virtual CViewContainer* getContainerAt (const CPoint& where, const GetViewOptions& options = GetViewOptions ().deep ()) const;
/** get all views at point where, top->down */
virtual bool getViewsAt (const CPoint& where, ViewList& views, const GetViewOptions& options = GetViewOptions ().deep ()) const;
/** change view z order position */
virtual bool changeViewZOrder (CView* view, uint32_t newIndex);
virtual bool hitTestSubViews (const CPoint& where, const Event& event);
/** enable or disable autosizing subviews. Per default this is enabled. */
virtual void setAutosizingEnabled (bool state);
bool getAutosizingEnabled () const { return hasViewFlag (kAutosizeSubviews); }
/** get child views of type ViewClass. ContainerClass must be a stdc++ container */
template<class ViewClass, class ContainerClass>
uint32_t getChildViewsOfType (ContainerClass& result, bool deep = false) const;
/** execute proc for each child view */
template<typename Proc>
void forEachChild (Proc proc) const;
template<typename Proc>
CView* findFirstViewIf (Proc filter) const;
//@}
//-----------------------------------------------------------------------------
/// @name View Layouter Methods
//-----------------------------------------------------------------------------
//@{
/** set a view layouter
*
* Per default the view container has an AutoSizeLayouter set.
* Use this method to set a custom layouter.
* To reset the layouter to the default AutoSizeLayouter use setViewLayouter (nullptr).
*/
void setViewLayouter (const SharedPointer<IViewLayouter>& layouter);
/** get the current view layouter */
SharedPointer<IViewLayouter> getViewLayouter () const;
/** calculate the view layout for the new size */
std::optional<ViewLayout> calculateViewLayout (const CRect& newSize) const;
/** apply a previously calculated view layout */
bool applyViewLayout (const ViewLayout& layout);
/** check if a view layout is currently applied */
bool inApplyViewLayout () const;
//@}
//-----------------------------------------------------------------------------
/// @name Background Methods
//-----------------------------------------------------------------------------
//@{
/** set the background color (will only be drawn if this container is not set to transparent and does not have a background bitmap) */
virtual void setBackgroundColor (const CColor& color);
/** get the background color */
virtual CColor getBackgroundColor () const;
/** set the offset of the background bitmap */
virtual void setBackgroundOffset (const CPoint& p);
/** get the offset of the background bitmap */
virtual CPoint getBackgroundOffset () const;
/** draw the background */
virtual void drawBackgroundRect (CDrawContext* pContext, const CRect& _updateRect);
virtual void setBackgroundColorDrawStyle (CDrawStyle style);
CDrawStyle getBackgroundColorDrawStyle () const;
//@}
/** set custom initial focus view
* which is first focused when advanceNextFocusView is called without oldFocus view
*/
void setInitialFocusView (CView* view);
/** get custom initial focus view */
CView* getInitialFocusView () const;
virtual bool advanceNextFocusView (CView* oldFocus, bool reverse = false);
virtual bool invalidateDirtyViews ();
virtual CRect getVisibleSize (const CRect& rect) const;
void setTransform (const CGraphicsTransform& t);
const CGraphicsTransform& getTransform () const;
void registerViewContainerListener (IViewContainerListener* listener);
void unregisterViewContainerListener (IViewContainerListener* listener);
// CView
void draw (CDrawContext* pContext) override;
void drawRect (CDrawContext* pContext, const CRect& updateRect) override;
void onMouseDownEvent (MouseDownEvent& event) override;
void onMouseMoveEvent (MouseMoveEvent& event) override;
void onMouseUpEvent (MouseUpEvent& event) override;
void onMouseCancelEvent (MouseCancelEvent& event) override;
void onMouseWheelEvent (MouseWheelEvent& event) override;
void onZoomGestureEvent (ZoomGestureEvent& event) override;
CMessageResult notify (CBaseObject* sender, IdStringPtr message) override;
#if VSTGUI_ENABLE_DEPRECATED_METHODS
bool onWheel (const CPoint& where, const CMouseWheelAxis& axis, const float& distance,
const CButtonState& buttons) final;
#endif
#if VSTGUI_TOUCH_EVENT_HANDLING
virtual void onTouchEvent (ITouchEvent& event) override;
virtual bool wantsMultiTouchEvents () const override { return true; }
virtual bool findSingleTouchEventTarget (ITouchEvent::Touch& event);
#endif
SharedPointer<IDropTarget> getDropTarget () override;
void looseFocus () override;
void takeFocus () override;
bool isDirty () const override;
void invalid () override;
void invalidRect (const CRect& rect) override;
void setViewSize (const CRect& rect, bool invalid = true) override;
void parentSizeChanged () override;
bool sizeToFit () override;
bool removed (CView* parent) override;
bool attached (CView* parent) override;
CPoint& frameToLocal (CPoint& point) const override;
CPoint& localToFrame (CPoint& point) const override;
//-----------------------------------------------------------------------------
using ChildViewConstIterator = ViewList::const_iterator;
using ChildViewConstReverseIterator = ViewList::const_reverse_iterator;
//-----------------------------------------------------------------------------
template<bool reverse>
class Iterator
{
public:
using IteratorType = typename std::conditional<reverse, ChildViewConstReverseIterator,
ChildViewConstIterator>::type;
explicit Iterator (const CViewContainer* container) : children (container->getChildren ())
{
if constexpr (reverse)
iterator = children.rbegin ();
else
iterator = children.begin ();
}
explicit Iterator (const Iterator<reverse>& vi)
: children (vi.children), iterator (vi.iterator)
{
}
Iterator (Iterator<reverse>&& o) : children (o.children), iterator (std::move (o.iterator))
{
}
Iterator<reverse>& operator++ ()
{
++iterator;
return *this;
}
Iterator<reverse> operator++ (int)
{
Iterator<reverse> old (*this);
++iterator;
return old;
}
Iterator<reverse>& operator-- ()
{
--iterator;
return *this;
}
CView* operator* () const
{
if constexpr (reverse)
return (iterator == children.rend ()) ? nullptr : *iterator;
else
return (iterator == children.end ()) ? nullptr : *iterator;
}
protected:
const ViewList& children;
IteratorType iterator;
};
//-------------------------------------------
CLASS_METHODS(CViewContainer, CView)
#if DEBUG
void dumpInfo () override;
virtual void dumpHierarchy ();
#endif
CViewContainer* asViewContainer () final { return this; }
const CViewContainer* asViewContainer () const final { return this; }
protected:
enum
{
kAutosizeSubviews = 1 << (CView::kLastCViewFlag + 1),
kInApplyLayout = 1 << (CView::kLastCViewFlag + 2),
};
~CViewContainer () noexcept override;
void beforeDelete () override;
virtual bool checkUpdateRect (CView* view, const CRect& rect);
void setMouseDownView (CView* view);
CView* getMouseDownView () const;
const ViewList& getChildren () const;
private:
static constexpr CViewAttributeID kInitialFocusViewAttribute = 'cifv';
void dispatchEventToSubViews (Event& event);
void clearMouseDownView ();
CRect getLastDrawnFocus () const;
void setLastDrawnFocus (CRect r);
struct Impl;
std::unique_ptr<Impl> pImpl;
};
using ViewIterator = CViewContainer::Iterator<false>;
using ReverseViewIterator = CViewContainer::Iterator<true>;
//-----------------------------------------------------------------------------
template<class ViewClass, class ContainerClass>
inline uint32_t CViewContainer::getChildViewsOfType (ContainerClass& result, bool deep) const
{
for (auto& child : getChildren ())
{
auto vObj = child.cast<ViewClass> ();
if (vObj)
{
result.push_back (vObj);
}
if (deep)
{
if (auto container = child->asViewContainer ())
{
container->getChildViewsOfType<ViewClass, ContainerClass> (result, deep);
}
}
}
return static_cast<uint32_t> (result.size ());
}
//-----------------------------------------------------------------------------
template <typename Proc>
inline void CViewContainer::forEachChild (Proc proc) const
{
for (auto& child : getChildren ())
{
proc (child);
}
}
template<typename Proc>
inline CView* CViewContainer::findFirstViewIf (Proc filter) const
{
for (const auto& child : getChildren ())
{
if (filter (child))
return child;
}
return nullptr;
}
} // VSTGUI