implementation with basic functionality
This commit is contained in:
parent
48c170bfbf
commit
79d0f08eb6
|
@ -24,33 +24,34 @@ namespace
|
|||
: QskDrawer( parent )
|
||||
{
|
||||
#if 1
|
||||
setAnimationHint( Panel | QskAspect::Position, 1000 );
|
||||
setAnimationHint( faderAspect(), 1000 );
|
||||
#endif
|
||||
|
||||
setEdge( edge );
|
||||
setOverlay( true );
|
||||
|
||||
auto content = new QskControl( this );
|
||||
content->setObjectName( "Content" );
|
||||
|
||||
switch( edge )
|
||||
{
|
||||
case Qt::LeftEdge:
|
||||
content->setBackgroundColor( QskRgb::Tomato );
|
||||
setFixedWidth( 100 );
|
||||
content->setFixedWidth( 100 );
|
||||
break;
|
||||
|
||||
case Qt::RightEdge:
|
||||
setFixedWidth( 200 );
|
||||
content->setFixedWidth( 200 );
|
||||
content->setBackgroundColor( QskRgb::Orchid );
|
||||
break;
|
||||
|
||||
case Qt::TopEdge:
|
||||
setFixedHeight( 100 );
|
||||
content->setBackgroundColor( QskRgb::Wheat );
|
||||
content->setFixedHeight( 100 );
|
||||
content->setBackgroundColor( QskRgb::Chartreuse );
|
||||
break;
|
||||
|
||||
case Qt::BottomEdge:
|
||||
setFixedHeight( 200 );
|
||||
content->setFixedHeight( 200 );
|
||||
content->setBackgroundColor( QskRgb::Wheat );
|
||||
break;
|
||||
}
|
||||
|
@ -65,16 +66,26 @@ namespace
|
|||
{
|
||||
setBackgroundColor( QskRgb::LightSteelBlue );
|
||||
|
||||
setMargins( 50 );
|
||||
setMargins( 10 );
|
||||
setAutoLayoutChildren( true );
|
||||
|
||||
(void) new QskPushButton( this );
|
||||
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
const auto edge = static_cast< Qt::Edge >( 1 << i );
|
||||
m_drawers[i] = new Drawer( edge, this );
|
||||
|
||||
auto dragMargin = 30; // the default setting is pretty small
|
||||
if ( edge == Qt::TopEdge )
|
||||
{
|
||||
// to check if dragging works above the button
|
||||
dragMargin = 120;
|
||||
}
|
||||
|
||||
m_drawers[i]->setDragMargin( dragMargin );
|
||||
}
|
||||
|
||||
auto button = new QskPushButton( "Push Me", this );
|
||||
button->setPreferredHeight( 100 );
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -87,7 +98,6 @@ namespace
|
|||
MainBox( QQuickItem* parent = nullptr )
|
||||
: QskControl( parent )
|
||||
{
|
||||
setBackgroundColor( QskRgb::LemonChiffon );
|
||||
setMargins( 40 );
|
||||
setAutoLayoutChildren( true );
|
||||
|
||||
|
|
|
@ -606,21 +606,15 @@ void Editor::setupDialogButtonBoxColors(
|
|||
void Editor::setupDrawerMetrics()
|
||||
{
|
||||
using Q = QskDrawer;
|
||||
|
||||
setPadding( Q::Panel, 5 );
|
||||
setHint( Q::Overlay | QskAspect::Style, false );
|
||||
using A = QskAspect;
|
||||
|
||||
#if 1
|
||||
setAnimation( Q::Panel | QskAspect::Position, 200 );
|
||||
setAnimation( Q::Panel | A::Metric | A::Position, 200 );
|
||||
#endif
|
||||
}
|
||||
|
||||
void Editor::setupDrawerColors(
|
||||
QskAspect::Section section, const QskFluent2Theme& theme )
|
||||
void Editor::setupDrawerColors( QskAspect::Section, const QskFluent2Theme& )
|
||||
{
|
||||
using Q = QskDrawer;
|
||||
|
||||
setGradient( Q::Panel | section, theme.palette.background.solid.base );
|
||||
}
|
||||
|
||||
void Editor::setupFocusIndicatorMetrics()
|
||||
|
@ -735,6 +729,7 @@ void Editor::setupListViewColors(
|
|||
void Editor::setupMenuMetrics()
|
||||
{
|
||||
using Q = QskMenu;
|
||||
using A = QskAspect;
|
||||
|
||||
setPadding( Q::Panel, { 4, 6, 4, 6 } );
|
||||
setBoxBorderMetrics( Q::Panel, 1 );
|
||||
|
@ -748,6 +743,14 @@ void Editor::setupMenuMetrics()
|
|||
|
||||
setStrutSize( Q::Icon, 12, 12 );
|
||||
setPadding( Q::Icon, { 8, 8, 0, 8 } );
|
||||
|
||||
#if 1
|
||||
setPosition( Q::Panel, 0 );
|
||||
setPosition( Q::Panel | QskPopup::Closed, 1 );
|
||||
|
||||
// copied from Mat3 - what are the correct values for Fluent2 ???
|
||||
setAnimation( Q::Panel | A::Metric, 150 );
|
||||
#endif
|
||||
}
|
||||
|
||||
void Editor::setupMenuColors(
|
||||
|
|
|
@ -379,7 +379,7 @@ void Editor::setupMenu()
|
|||
setFontRole( Q::Text, QskMaterial3Skin::M3BodyMedium );
|
||||
|
||||
setPosition( Q::Panel, 0 );
|
||||
setPosition( Q::Panel | QskPopup::Closed, 1_dp );
|
||||
setPosition( Q::Panel | QskPopup::Closed, 1 );
|
||||
|
||||
setAnimation( Q::Panel | A::Metric, 150 );
|
||||
setAnimation( Q::Cursor | A::Position | A::Metric, 75, QEasingCurve::OutCubic );
|
||||
|
@ -809,12 +809,9 @@ void Editor::setupDialogButtonBox()
|
|||
void Editor::setupDrawer()
|
||||
{
|
||||
using Q = QskDrawer;
|
||||
using A = QskAspect;
|
||||
|
||||
setPadding( Q::Panel, 5_dp );
|
||||
setGradient( Q::Panel, m_pal.background );
|
||||
setHint( Q::Overlay | QskAspect::Style, false );
|
||||
|
||||
setAnimation( Q::Panel | QskAspect::Position, qskDuration );
|
||||
setAnimation( Q::Panel | A::Metric | A::Position, qskDuration );
|
||||
}
|
||||
|
||||
void Editor::setupSlider()
|
||||
|
|
|
@ -759,13 +759,12 @@ void Editor::setupDialogButtonBox()
|
|||
setBoxShape( Q::Panel, 2 );
|
||||
}
|
||||
|
||||
void Editor::setupDrawer() {
|
||||
void Editor::setupDrawer()
|
||||
{
|
||||
using A = QskAspect;
|
||||
using Q = QskDrawer;
|
||||
|
||||
setPadding( Q::Panel, 5 );
|
||||
setGradient( Q::Panel, m_pal.darker125 );
|
||||
setAnimation( Q::Panel | QskAspect::Position, qskDuration );
|
||||
setHint( Q::Overlay | QskAspect::Style, false );
|
||||
setAnimation( Q::Panel | A::Metric | A::Position, qskDuration );
|
||||
}
|
||||
|
||||
void Editor::setupTabButton()
|
||||
|
|
|
@ -115,6 +115,7 @@ list(APPEND HEADERS
|
|||
nodes/QskRichTextRenderer.h
|
||||
nodes/QskScaleRenderer.h
|
||||
nodes/QskSGNode.h
|
||||
nodes/QskSlideInNode.h
|
||||
nodes/QskStrokeNode.h
|
||||
nodes/QskStippledLineRenderer.h
|
||||
nodes/QskShapeNode.h
|
||||
|
@ -146,6 +147,7 @@ list(APPEND SOURCES
|
|||
nodes/QskRichTextRenderer.cpp
|
||||
nodes/QskScaleRenderer.cpp
|
||||
nodes/QskSGNode.cpp
|
||||
nodes/QskSlideInNode.cpp
|
||||
nodes/QskStrokeNode.cpp
|
||||
nodes/QskStippledLineRenderer.cpp
|
||||
nodes/QskShapeNode.cpp
|
||||
|
|
|
@ -12,48 +12,88 @@
|
|||
#include "QskPanGestureRecognizer.h"
|
||||
#include "QskGesture.h"
|
||||
|
||||
#include <qguiapplication.h>
|
||||
#include <qstylehints.h>
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
#include <private/qquickitem_p.h>
|
||||
#include <private/qquickitemchangelistener_p.h>
|
||||
QSK_QT_PRIVATE_END
|
||||
|
||||
// we need a skinlet to draw the panel TODO ...
|
||||
/*
|
||||
Only used for the sliding in animation. Do we want to
|
||||
introduce a specific panel as background ???
|
||||
*/
|
||||
QSK_SUBCONTROL( QskDrawer, Panel )
|
||||
|
||||
static QRectF qskDrawerRect( const QRectF& rect,
|
||||
Qt::Edge edge, qreal pos, const QSizeF& size )
|
||||
static void qskCatchMouseEvents( QQuickItem* item )
|
||||
{
|
||||
QRectF r( 0.0, 0.0, size.width(), size.height() );
|
||||
#if 1
|
||||
// manipulating other items - do we really want to do this ?
|
||||
item->setAcceptedMouseButtons( Qt::LeftButton );
|
||||
item->setFiltersChildMouseEvents( true );
|
||||
#endif
|
||||
}
|
||||
|
||||
const auto progress = pos = 1.0 - pos;
|
||||
static bool qskCheckDirection( Qt::Edge edge, const QskPanGesture* gesture )
|
||||
{
|
||||
const auto degrees = gesture->angle();
|
||||
|
||||
switch( edge )
|
||||
{
|
||||
case Qt::LeftEdge:
|
||||
return ( degrees < 90.0 ) || ( degrees ) > 270.0;
|
||||
|
||||
case Qt::RightEdge:
|
||||
return ( degrees > 90.0 ) && ( degrees < 270.0 );
|
||||
|
||||
case Qt::TopEdge:
|
||||
return degrees > 180.0;
|
||||
|
||||
case Qt::BottomEdge:
|
||||
return degrees < 180.0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void qskLayoutDrawer( const QRectF& rect, QskDrawer* drawer )
|
||||
{
|
||||
r.moveRight( rect.left() + progress * size.width() );
|
||||
const auto size = qskSizeConstraint( drawer, Qt::PreferredSize );
|
||||
|
||||
QRectF r( 0.0, 0.0, size.width(), size.height() );
|
||||
|
||||
switch( drawer->edge() )
|
||||
{
|
||||
case Qt::LeftEdge:
|
||||
{
|
||||
r.setHeight( rect.height() );
|
||||
r.moveRight( rect.left() + size.width() );
|
||||
break;
|
||||
}
|
||||
case Qt::RightEdge:
|
||||
{
|
||||
r.moveLeft( rect.right() - progress * size.width() );
|
||||
r.setHeight( rect.height() );
|
||||
r.moveLeft( rect.right() - size.width() );
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::TopEdge:
|
||||
{
|
||||
r.moveBottom( rect.top() + progress * size.height() );
|
||||
r.setWidth( rect.width() );
|
||||
r.moveBottom( rect.top() + size.height() );
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::BottomEdge:
|
||||
{
|
||||
r.moveTop( rect.bottom() - progress * size.height() );
|
||||
r.setWidth( rect.width() );
|
||||
r.moveTop( rect.bottom() - size.height() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
drawer->setGeometry( r );
|
||||
}
|
||||
|
||||
namespace
|
||||
|
@ -61,10 +101,11 @@ namespace
|
|||
class GeometryListener final : public QQuickItemChangeListener
|
||||
{
|
||||
public:
|
||||
GeometryListener( QskDrawer* drawer )
|
||||
: m_drawer( drawer )
|
||||
, m_parent( drawer->parentItem() )
|
||||
GeometryListener( QQuickItem* item, QQuickItem* adjustedItem )
|
||||
: m_item( item )
|
||||
, m_adjustedItem( adjustedItem )
|
||||
{
|
||||
adjust();
|
||||
setEnabled( true );
|
||||
}
|
||||
|
||||
|
@ -77,28 +118,40 @@ namespace
|
|||
void itemGeometryChanged( QQuickItem*,
|
||||
QQuickGeometryChange, const QRectF& ) override
|
||||
{
|
||||
m_drawer->polish();
|
||||
adjust();
|
||||
}
|
||||
|
||||
private:
|
||||
void setEnabled( bool on )
|
||||
void adjust()
|
||||
{
|
||||
if ( m_parent )
|
||||
#if 0
|
||||
const auto pos = m_adjustedItem->mapFromItem( m_item, QPointF() );
|
||||
qskSetItemGeometry( m_adjustedItem,
|
||||
pos.x(), pos.y(), m_item->width(), m_item->height() );
|
||||
#else
|
||||
qskLayoutDrawer( QRectF( QPointF(), m_item->size() ),
|
||||
qobject_cast< QskDrawer* >( m_adjustedItem ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
void setEnabled( bool on )
|
||||
{
|
||||
const auto changeTypes = QQuickItemPrivate::Geometry;
|
||||
|
||||
auto d = QQuickItemPrivate::get( m_parent );
|
||||
auto d = QQuickItemPrivate::get( m_item );
|
||||
if ( on )
|
||||
d->addItemChangeListener( this, changeTypes );
|
||||
else
|
||||
d->removeItemChangeListener( this, changeTypes );
|
||||
}
|
||||
|
||||
QQuickItem* m_item;
|
||||
QQuickItem* m_adjustedItem;
|
||||
};
|
||||
}
|
||||
|
||||
QskDrawer* m_drawer = nullptr;
|
||||
QQuickItem* m_parent = nullptr;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
class GestureRecognizer : public QskPanGestureRecognizer
|
||||
{
|
||||
using Inherited = QskPanGestureRecognizer;
|
||||
|
@ -112,33 +165,36 @@ namespace
|
|||
}
|
||||
|
||||
protected:
|
||||
QRectF gestureRect() const override
|
||||
bool isAcceptedPos( const QPointF& pos ) const override
|
||||
{
|
||||
auto drawer = qobject_cast< QskDrawer* >( parent() );
|
||||
auto drawer = qobject_cast< const QskDrawer* >( targetItem() );
|
||||
|
||||
const auto dragMargin = drawer->dragMargin();
|
||||
if ( dragMargin <= 0.0 )
|
||||
return false;
|
||||
|
||||
const auto dist = 50;
|
||||
auto rect = qskItemRect( watchedItem() );
|
||||
|
||||
switch( drawer->edge() )
|
||||
{
|
||||
case Qt::LeftEdge:
|
||||
rect.setRight( rect.left() + dist );
|
||||
rect.setRight( rect.left() + dragMargin );
|
||||
break;
|
||||
|
||||
case Qt::RightEdge:
|
||||
rect.setLeft( rect.right() - dist );
|
||||
rect.setLeft( rect.right() - dragMargin );
|
||||
break;
|
||||
|
||||
case Qt::TopEdge:
|
||||
rect.setBottom( rect.top() + dist );
|
||||
rect.setBottom( rect.top() + dragMargin );
|
||||
break;
|
||||
|
||||
case Qt::BottomEdge:
|
||||
rect.setTop( rect.bottom() - dist );
|
||||
rect.setTop( rect.bottom() - dragMargin );
|
||||
break;
|
||||
}
|
||||
|
||||
return rect;
|
||||
return rect.contains( pos );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -147,23 +203,26 @@ class QskDrawer::PrivateData
|
|||
{
|
||||
public:
|
||||
Qt::Edge edge = Qt::LeftEdge;
|
||||
GestureRecognizer* gestureRecognizer = nullptr;
|
||||
GeometryListener* listener = nullptr;
|
||||
|
||||
// a skin hint ???
|
||||
qreal dragMargin = QGuiApplication::styleHints()->startDragDistance();
|
||||
};
|
||||
|
||||
QskDrawer::QskDrawer( QQuickItem* parentItem )
|
||||
: Inherited ( parentItem )
|
||||
, m_data( new PrivateData )
|
||||
{
|
||||
#if 1
|
||||
setZ( 1 );
|
||||
#endif
|
||||
|
||||
setAutoLayoutChildren( true );
|
||||
setPolishOnResize( true );
|
||||
|
||||
setPopupFlag( PopupFlag::CloseOnPressOutside, true );
|
||||
setFaderAspect( Panel | QskAspect::Position | QskAspect::Metric );
|
||||
|
||||
connect( this, &QskDrawer::closed,
|
||||
this, [this]() { startFading( false ); } );
|
||||
|
||||
/*
|
||||
The drawer wants to be on top of the parent - not being
|
||||
layouted into its layoutRect(). So we opt out and do
|
||||
|
@ -172,17 +231,22 @@ QskDrawer::QskDrawer( QQuickItem* parentItem )
|
|||
setPlacementPolicy( QskPlacementPolicy::Ignore );
|
||||
if ( parentItem )
|
||||
{
|
||||
/*
|
||||
QskPopup has an internal QskInputGrabber, that does something
|
||||
very similar. Maybe we can make use of it ... TODO
|
||||
*/
|
||||
m_data->listener = new GeometryListener( this );
|
||||
m_data->listener = new GeometryListener( parentItem, this );
|
||||
qskCatchMouseEvents( parentItem );
|
||||
}
|
||||
|
||||
(void) new GestureRecognizer( this );
|
||||
#if 1
|
||||
parentItem->setAcceptedMouseButtons( Qt::LeftButton );
|
||||
#endif
|
||||
m_data->gestureRecognizer = new GestureRecognizer( this );
|
||||
|
||||
|
||||
connect( this, &QskPopup::openChanged, this, &QskDrawer::setFading );
|
||||
|
||||
/*
|
||||
When the content of the parentItem does not fit we will have
|
||||
a difference between fading and normal state. To overcome this problem
|
||||
we need to expand the rectangle of the QQuickDefaultClipNode manually to
|
||||
the window borders: TODO ...
|
||||
*/
|
||||
connect( this, &QskPopup::fadingChanged, parentItem, &QQuickItem::setClip );
|
||||
}
|
||||
|
||||
QskDrawer::~QskDrawer()
|
||||
|
@ -205,13 +269,36 @@ void QskDrawer::setEdge( Qt::Edge edge )
|
|||
edgeChanged( edge );
|
||||
}
|
||||
|
||||
void QskDrawer::setDragMargin( qreal margin )
|
||||
{
|
||||
margin = std::max( margin, 0.0 );
|
||||
|
||||
if ( margin != m_data->dragMargin )
|
||||
{
|
||||
m_data->dragMargin = margin;
|
||||
Q_EMIT dragMarginChanged( margin );
|
||||
}
|
||||
}
|
||||
|
||||
qreal QskDrawer::dragMargin() const
|
||||
{
|
||||
return m_data->dragMargin;
|
||||
}
|
||||
|
||||
void QskDrawer::gestureEvent( QskGestureEvent* event )
|
||||
{
|
||||
if ( event->gesture()->type() == QskGesture::Pan )
|
||||
{
|
||||
/*
|
||||
For the moment we treat the gesture like a swipe gesture
|
||||
without dragging the drawer when moving the mouse. TODO ...
|
||||
*/
|
||||
const auto gesture = static_cast< const QskPanGesture* >( event->gesture().get() );
|
||||
if ( gesture->state() == QskGesture::Finished )
|
||||
{
|
||||
if ( qskCheckDirection( m_data->edge, gesture ) )
|
||||
open();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -219,30 +306,89 @@ void QskDrawer::gestureEvent( QskGestureEvent* event )
|
|||
Inherited::gestureEvent( event );
|
||||
}
|
||||
|
||||
QRectF QskDrawer::layoutRectForSize( const QSizeF& size ) const
|
||||
QSizeF QskDrawer::layoutSizeHint(
|
||||
Qt::SizeHint which, const QSizeF& constraint ) const
|
||||
{
|
||||
return Inherited::layoutRectForSize( size );
|
||||
if ( which == Qt::MaximumSize )
|
||||
return QSizeF();
|
||||
|
||||
qreal w = -1.0;
|
||||
qreal h = -1.0;
|
||||
|
||||
const auto children = childItems();
|
||||
|
||||
for ( const auto child : children )
|
||||
{
|
||||
if ( !qskIsVisibleToLayout( child ) )
|
||||
continue;
|
||||
|
||||
const auto policy = qskSizePolicy( child );
|
||||
|
||||
if ( constraint.width() >= 0.0 && policy.isConstrained( Qt::Vertical ) )
|
||||
{
|
||||
const auto hint = qskSizeConstraint( child, which, constraint );
|
||||
h = qMax( h, hint.height() );
|
||||
}
|
||||
else if ( constraint.height() >= 0.0 && policy.isConstrained( Qt::Horizontal ) )
|
||||
{
|
||||
const auto hint = qskSizeConstraint( child, which, constraint );
|
||||
w = qMax( w, hint.width() );
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto hint = qskSizeConstraint( child, which );
|
||||
|
||||
w = qMax( w, hint.width() );
|
||||
h = qMax( h, hint.height() );
|
||||
}
|
||||
}
|
||||
|
||||
return QSizeF( w, h );
|
||||
}
|
||||
|
||||
void QskDrawer::updateLayout()
|
||||
{
|
||||
if ( !( isOpen() || isFading() ) )
|
||||
if ( !( isOpen() || isFading() ) || size().isEmpty() )
|
||||
return;
|
||||
|
||||
const auto targetRect = qskItemRect( parentItem() );
|
||||
const auto size = qskConstrainedItemSize( this, targetRect.size() );
|
||||
auto dx = 0.0;
|
||||
auto dy = 0.0;
|
||||
|
||||
const auto rect = qskDrawerRect( targetRect,
|
||||
m_data->edge, metric( faderAspect() ), size );
|
||||
if ( isFading() )
|
||||
{
|
||||
const auto f = metric( faderAspect() );
|
||||
|
||||
qskSetItemGeometry( this, rect );
|
||||
Inherited::updateLayout();
|
||||
switch( m_data->edge )
|
||||
{
|
||||
case Qt::LeftEdge:
|
||||
dx = -f * width();
|
||||
break;
|
||||
|
||||
case Qt::RightEdge:
|
||||
dx = f * width();
|
||||
break;
|
||||
|
||||
case Qt::TopEdge:
|
||||
dy = -f * height();
|
||||
break;
|
||||
|
||||
case Qt::BottomEdge:
|
||||
dy = f * height();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QskDrawer::aboutToShow()
|
||||
const QRectF layoutRect( dx, dy, width(), height() );
|
||||
|
||||
const auto children = childItems();
|
||||
for ( auto child : children )
|
||||
{
|
||||
startFading( true );
|
||||
Inherited::aboutToShow();
|
||||
if ( qskIsAdjustableByLayout( child ) )
|
||||
{
|
||||
const auto r = qskConstrainedItemRect( child, layoutRect );
|
||||
qskSetItemGeometry( child, r );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QskDrawer::itemChange( QQuickItem::ItemChange change,
|
||||
|
@ -250,23 +396,39 @@ void QskDrawer::itemChange( QQuickItem::ItemChange change,
|
|||
{
|
||||
Inherited::itemChange( change, value );
|
||||
|
||||
if ( change == QQuickItem::ItemParentHasChanged )
|
||||
switch( static_cast< int >( change ) )
|
||||
{
|
||||
case QQuickItem::ItemParentHasChanged:
|
||||
{
|
||||
if ( parentItem() )
|
||||
qskCatchMouseEvents( parentItem() );
|
||||
|
||||
Q_FALLTHROUGH();
|
||||
}
|
||||
case QQuickItem::ItemVisibleHasChanged:
|
||||
{
|
||||
delete m_data->listener;
|
||||
m_data->listener = nullptr;
|
||||
|
||||
if ( parentItem() )
|
||||
m_data->listener = new GeometryListener( this );
|
||||
if ( parentItem() && isVisible() )
|
||||
m_data->listener = new GeometryListener( parentItem(), this );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QskDrawer::startFading( bool open )
|
||||
void QskDrawer::setFading( bool on )
|
||||
{
|
||||
const auto from = open ? 1.0 : 0.0;
|
||||
const auto to = open ? 0.0 : 1.0;
|
||||
const qreal from = on ? 1.0 : 0.0;
|
||||
const qreal to = on ? 0.0 : 1.0;
|
||||
|
||||
const auto hint = animationHint( Panel | QskAspect::Position );
|
||||
startTransition( faderAspect(), hint, from, to );
|
||||
const auto aspect = faderAspect();
|
||||
|
||||
auto hint = animationHint( aspect );
|
||||
hint.updateFlags = QskAnimationHint::UpdatePolish;
|
||||
|
||||
startTransition( aspect, hint, from, to );
|
||||
}
|
||||
|
||||
#include "moc_QskDrawer.cpp"
|
||||
|
|
|
@ -17,6 +17,9 @@ class QSK_EXPORT QskDrawer : public QskPopup
|
|||
|
||||
Q_PROPERTY( Qt::Edge edge READ edge WRITE setEdge NOTIFY edgeChanged )
|
||||
|
||||
Q_PROPERTY( qreal dragMargin READ dragMargin
|
||||
WRITE setDragMargin NOTIFY dragMarginChanged )
|
||||
|
||||
public:
|
||||
QSK_SUBCONTROLS( Panel )
|
||||
|
||||
|
@ -26,20 +29,23 @@ class QSK_EXPORT QskDrawer : public QskPopup
|
|||
void setEdge( Qt::Edge );
|
||||
Qt::Edge edge() const;
|
||||
|
||||
QRectF layoutRectForSize( const QSizeF& ) const override;
|
||||
void setDragMargin( qreal );
|
||||
qreal dragMargin() const;
|
||||
|
||||
void updateLayout() override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void edgeChanged( Qt::Edge );
|
||||
void dragMarginChanged( qreal );
|
||||
|
||||
protected:
|
||||
void aboutToShow() override;
|
||||
void itemChange( ItemChange, const ItemChangeData& ) override;
|
||||
|
||||
QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override;
|
||||
void gestureEvent( QskGestureEvent* ) override;
|
||||
|
||||
private:
|
||||
void startFading( bool );
|
||||
void setFading( bool );
|
||||
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
|
|
|
@ -142,12 +142,9 @@ Qt::MouseButtons QskGestureRecognizer::acceptedMouseButtons() const
|
|||
return m_data->buttons;
|
||||
}
|
||||
|
||||
QRectF QskGestureRecognizer::gestureRect() const
|
||||
bool QskGestureRecognizer::isAcceptedPos( const QPointF& pos ) const
|
||||
{
|
||||
if ( m_data->watchedItem )
|
||||
return qskItemRect( m_data->watchedItem );
|
||||
|
||||
return QRectF( 0.0, 0.0, -1.0, -1.0 );
|
||||
return m_data->watchedItem && m_data->watchedItem->contains( pos );
|
||||
}
|
||||
|
||||
void QskGestureRecognizer::setRejectOnTimeout( bool on )
|
||||
|
@ -313,7 +310,7 @@ bool QskGestureRecognizer::processMouseEvent(
|
|||
|
||||
if ( event->type() == QEvent::MouseButtonPress )
|
||||
{
|
||||
if ( !gestureRect().contains( pos ) )
|
||||
if ( !isAcceptedPos( pos ) )
|
||||
return false;
|
||||
|
||||
if ( m_data->state != Idle )
|
||||
|
|
|
@ -73,7 +73,7 @@ class QSK_EXPORT QskGestureRecognizer : public QObject
|
|||
|
||||
State state() const;
|
||||
|
||||
virtual QRectF gestureRect() const;
|
||||
virtual bool isAcceptedPos( const QPointF& ) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void stateChanged( State from, State to );
|
||||
|
|
|
@ -24,7 +24,7 @@ class QSK_EXPORT QskListViewSkinlet : public QskScrollViewSkinlet
|
|||
public:
|
||||
enum NodeRole
|
||||
{
|
||||
TextRole,
|
||||
TextRole = Inherited::RoleCount,
|
||||
GraphicRole,
|
||||
|
||||
RoleCount
|
||||
|
|
|
@ -9,12 +9,14 @@
|
|||
#include "QskGraphic.h"
|
||||
#include "QskColorFilter.h"
|
||||
#include "QskTextOptions.h"
|
||||
#include "QskSGNode.h"
|
||||
#include "QskFunctions.h"
|
||||
#include "QskMargins.h"
|
||||
#include "QskFunctions.h"
|
||||
#include "QskLabelData.h"
|
||||
|
||||
#include "QskSGNode.h"
|
||||
#include "QskSlideInNode.h"
|
||||
|
||||
#include <qfontmetrics.h>
|
||||
#include <qmath.h>
|
||||
|
||||
|
@ -209,11 +211,44 @@ QskMenuSkinlet::QskMenuSkinlet( QskSkin* skin )
|
|||
: Inherited( skin )
|
||||
, m_data( new PrivateData() )
|
||||
{
|
||||
appendNodeRoles( { PanelRole } );
|
||||
appendNodeRoles( { ContentsRole, PanelRole } );
|
||||
}
|
||||
|
||||
QskMenuSkinlet::~QskMenuSkinlet() = default;
|
||||
|
||||
QSGNode* QskMenuSkinlet::updateSubNode(
|
||||
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
|
||||
{
|
||||
switch ( nodeRole )
|
||||
{
|
||||
case ContentsRole:
|
||||
{
|
||||
/*
|
||||
QskSlideInNode works for controls made of nodes - not for
|
||||
containers of other quick items. TODO ...
|
||||
*/
|
||||
|
||||
const auto popup = static_cast< const QskPopup* >( skinnable );
|
||||
|
||||
auto rect = popup->contentsRect();
|
||||
if ( rect.isEmpty() )
|
||||
return nullptr;
|
||||
|
||||
auto slideInNode = QskSGNode::ensureNode< QskSlideInNode >( node );
|
||||
|
||||
const auto progress = popup->metric( popup->faderAspect() );
|
||||
slideInNode->updateTranslation( rect, Qt::TopEdge, progress );
|
||||
|
||||
auto contentsNode = updateContentsNode( popup, slideInNode->contentsNode() );
|
||||
slideInNode->setContentsNode( contentsNode );
|
||||
|
||||
return slideInNode;
|
||||
}
|
||||
}
|
||||
|
||||
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
||||
}
|
||||
|
||||
QRectF QskMenuSkinlet::cursorRect(
|
||||
const QskSkinnable* skinnable, const QRectF& contentsRect, int index ) const
|
||||
{
|
||||
|
@ -407,7 +442,8 @@ QskAspect::States QskMenuSkinlet::sampleStates(
|
|||
}
|
||||
}
|
||||
|
||||
const auto cursorPos = menu->effectiveSkinHint( Q::Segment | Q::Hovered | A::Metric | A::Position ).toPointF();
|
||||
const auto cursorPos = menu->effectiveSkinHint(
|
||||
Q::Segment | Q::Hovered | A::Metric | A::Position ).toPointF();
|
||||
|
||||
if( !cursorPos.isNull() && menu->indexAtPosition( cursorPos ) == index )
|
||||
{
|
||||
|
|
|
@ -20,7 +20,9 @@ class QSK_EXPORT QskMenuSkinlet : public QskPopupSkinlet
|
|||
public:
|
||||
enum NodeRole
|
||||
{
|
||||
PanelRole = QskPopupSkinlet::RoleCount,
|
||||
ContentsRole = Inherited::RoleCount,
|
||||
PanelRole,
|
||||
|
||||
RoleCount
|
||||
};
|
||||
|
||||
|
@ -48,7 +50,10 @@ class QSK_EXPORT QskMenuSkinlet : public QskPopupSkinlet
|
|||
Qt::SizeHint, const QSizeF& ) const override;
|
||||
|
||||
protected:
|
||||
QSGNode* updateContentsNode( const QskPopup*, QSGNode* ) const override;
|
||||
QSGNode* updateSubNode( const QskSkinnable*,
|
||||
quint8 nodeRole, QSGNode* ) const override;
|
||||
|
||||
QSGNode* updateContentsNode( const QskPopup*, QSGNode* ) const;
|
||||
QSGNode* updateMenuNode( const QskSkinnable*, QSGNode* ) const;
|
||||
|
||||
QSGNode* updateSampleNode( const QskSkinnable*,
|
||||
|
|
|
@ -5,108 +5,11 @@
|
|||
|
||||
#include "QskPopupSkinlet.h"
|
||||
#include "QskPopup.h"
|
||||
#include "QskSGNode.h"
|
||||
|
||||
#include <qtransform.h>
|
||||
#include <qsgnode.h>
|
||||
#include <qquickwindow.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
class RootNode : public QSGNode
|
||||
{
|
||||
public:
|
||||
~RootNode() override
|
||||
{
|
||||
delete m_clipNode;
|
||||
delete m_transformNode;
|
||||
delete m_contentsNode;
|
||||
}
|
||||
|
||||
void setClipRect( const QRectF& rect )
|
||||
{
|
||||
if ( m_clipNode == nullptr )
|
||||
{
|
||||
m_clipNode = new QSGClipNode();
|
||||
m_clipNode->setFlag( QSGNode::OwnedByParent, false );
|
||||
m_clipNode->setIsRectangular( true );
|
||||
}
|
||||
|
||||
m_clipNode->setClipRect( rect );
|
||||
}
|
||||
|
||||
void resetClip()
|
||||
{
|
||||
delete m_clipNode;
|
||||
m_clipNode = nullptr;
|
||||
}
|
||||
|
||||
void setTranslation( qreal dx, qreal dy )
|
||||
{
|
||||
if ( dx != 0.0 || dy != 0.0 )
|
||||
{
|
||||
if ( m_transformNode == nullptr )
|
||||
{
|
||||
m_transformNode = new QSGTransformNode();
|
||||
m_transformNode->setFlag( QSGNode::OwnedByParent, false );
|
||||
}
|
||||
|
||||
QTransform transform;
|
||||
transform.translate( dx, dy );
|
||||
|
||||
m_transformNode->setMatrix( transform );
|
||||
}
|
||||
else
|
||||
{
|
||||
delete m_transformNode;
|
||||
m_transformNode = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void setContentsNode( QSGNode* contentsNode )
|
||||
{
|
||||
if ( m_contentsNode != contentsNode )
|
||||
{
|
||||
if ( contentsNode )
|
||||
contentsNode->setFlag( QSGNode::OwnedByParent, false );
|
||||
|
||||
delete m_contentsNode;
|
||||
m_contentsNode = contentsNode;
|
||||
}
|
||||
}
|
||||
|
||||
void rearrangeNodes()
|
||||
{
|
||||
const std::initializer_list< QSGNode* > nodes =
|
||||
{ m_clipNode, m_transformNode, m_contentsNode };
|
||||
|
||||
QSGNode* parentNode = this;
|
||||
for ( auto node : nodes )
|
||||
{
|
||||
if ( node )
|
||||
{
|
||||
QskSGNode::setParentNode( node, parentNode );
|
||||
parentNode = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline QSGNode* contentsNode()
|
||||
{
|
||||
return m_contentsNode;
|
||||
}
|
||||
|
||||
private:
|
||||
QSGClipNode* m_clipNode = nullptr;
|
||||
QSGTransformNode* m_transformNode = nullptr;
|
||||
QSGNode* m_contentsNode = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
QskPopupSkinlet::QskPopupSkinlet( QskSkin* skin )
|
||||
: Inherited( skin )
|
||||
{
|
||||
appendNodeRoles( { OverlayRole, ContentsRole } );
|
||||
appendNodeRoles( { OverlayRole } );
|
||||
}
|
||||
|
||||
QskPopupSkinlet::~QskPopupSkinlet() = default;
|
||||
|
@ -125,54 +28,13 @@ QRectF QskPopupSkinlet::subControlRect( const QskSkinnable* skinnable,
|
|||
QSGNode* QskPopupSkinlet::updateSubNode(
|
||||
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
|
||||
{
|
||||
const auto popup = static_cast< const QskPopup* >( skinnable );
|
||||
|
||||
switch ( nodeRole )
|
||||
{
|
||||
case OverlayRole:
|
||||
return updateBoxNode( skinnable, node, QskPopup::Overlay );
|
||||
|
||||
case ContentsRole:
|
||||
return updateExtraNode( popup, node );
|
||||
}
|
||||
|
||||
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
||||
}
|
||||
|
||||
QSGNode* QskPopupSkinlet::updateExtraNode( const QskPopup* popup, QSGNode* node ) const
|
||||
{
|
||||
auto cr = popup->contentsRect();
|
||||
if ( cr.isEmpty() )
|
||||
return nullptr;
|
||||
|
||||
auto rootNode = QskSGNode::ensureNode< RootNode >( node );
|
||||
|
||||
const auto faderProgress = popup->metric( popup->faderAspect() );
|
||||
if ( faderProgress > 0.0 && faderProgress <= 1.0 )
|
||||
{
|
||||
auto clipRect = QRectF( popup->mapFromScene( QPointF() ), popup->window()->size() );
|
||||
clipRect.setTop( cr.top() );
|
||||
|
||||
rootNode->setClipRect( clipRect );
|
||||
}
|
||||
else
|
||||
{
|
||||
rootNode->resetClip();
|
||||
}
|
||||
|
||||
rootNode->setTranslation( 0.0, -faderProgress * cr.height() );
|
||||
|
||||
auto contentsNode = updateContentsNode( popup, rootNode->contentsNode() );
|
||||
rootNode->setContentsNode( contentsNode );
|
||||
|
||||
rootNode->rearrangeNodes();
|
||||
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
QSGNode* QskPopupSkinlet::updateContentsNode( const QskPopup*, QSGNode* ) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#include "moc_QskPopupSkinlet.cpp"
|
||||
|
|
|
@ -20,8 +20,6 @@ class QSK_EXPORT QskPopupSkinlet : public QskSkinlet
|
|||
enum NodeRole
|
||||
{
|
||||
OverlayRole,
|
||||
ContentsRole,
|
||||
|
||||
RoleCount
|
||||
};
|
||||
|
||||
|
@ -35,10 +33,7 @@ class QSK_EXPORT QskPopupSkinlet : public QskSkinlet
|
|||
QSGNode* updateSubNode( const QskSkinnable*,
|
||||
quint8 nodeRole, QSGNode* ) const override;
|
||||
|
||||
virtual QSGNode* updateContentsNode( const QskPopup*, QSGNode* ) const;
|
||||
|
||||
private:
|
||||
QSGNode* updateExtraNode( const QskPopup*, QSGNode* ) const;
|
||||
QSGNode* updateOverlayNode( const QskPopup*, QSGNode* ) const;
|
||||
};
|
||||
|
||||
|
|
|
@ -136,15 +136,15 @@ namespace
|
|||
setOrientations( Qt::Horizontal | Qt::Vertical );
|
||||
}
|
||||
|
||||
QRectF gestureRect() const override
|
||||
bool isAcceptedPos( const QPointF& pos ) const override
|
||||
{
|
||||
if ( auto scrollBox = qobject_cast< const QskScrollBox* >( watchedItem() ) )
|
||||
{
|
||||
if ( qskIsScrollable( scrollBox, orientations() ) )
|
||||
return scrollBox->viewContentsRect();
|
||||
return scrollBox->viewContentsRect().contains( pos );
|
||||
}
|
||||
|
||||
return QRectF( 0.0, 0.0, -1.0, -1.0 ); // empty
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1259,14 +1259,20 @@ bool QskSkinnable::isTransitionAccepted( QskAspect aspect ) const
|
|||
{
|
||||
Q_UNUSED( aspect )
|
||||
|
||||
if ( auto control = qskControlCast( owningItem() ) )
|
||||
{
|
||||
/*
|
||||
Usually we only need smooth transitions, when state changes
|
||||
happen while the skinnable is visible. There are few exceptions
|
||||
like QskPopup::Closed, that is used to slide/fade in.
|
||||
*/
|
||||
if ( auto control = qskControlCast( owningItem() ) )
|
||||
|
||||
if ( control->flags() & QQuickItem::ItemHasContents )
|
||||
return control->isInitiallyPainted();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskSlideInNode.h"
|
||||
#include "QskSGNode.h"
|
||||
#include <qtransform.h>
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
#include <private/qsgnode_p.h>
|
||||
QSK_QT_PRIVATE_END
|
||||
|
||||
class QskSlideInNodePrivate final : public QSGNodePrivate
|
||||
{
|
||||
public:
|
||||
~QskSlideInNodePrivate()
|
||||
{
|
||||
delete clipNode;
|
||||
delete transformNode;
|
||||
delete contentsNode;
|
||||
}
|
||||
|
||||
void reparentContentNode( QskSlideInNode* node )
|
||||
{
|
||||
if ( contentsNode )
|
||||
{
|
||||
QSGNode* parentNode = transformNode;
|
||||
|
||||
if ( parentNode == nullptr )
|
||||
parentNode = clipNode;
|
||||
|
||||
if ( parentNode == nullptr )
|
||||
parentNode = node;
|
||||
|
||||
QskSGNode::setParentNode( contentsNode, parentNode );
|
||||
}
|
||||
}
|
||||
|
||||
QSGClipNode* clipNode = nullptr;
|
||||
QSGTransformNode* transformNode = nullptr;
|
||||
QSGNode* contentsNode = nullptr;
|
||||
};
|
||||
|
||||
QskSlideInNode::QskSlideInNode()
|
||||
: QSGNode( *new QskSlideInNodePrivate, QSGNode::BasicNodeType )
|
||||
{
|
||||
}
|
||||
|
||||
QskSlideInNode::~QskSlideInNode() = default;
|
||||
|
||||
void QskSlideInNode::updateTranslation( const QRectF& rect,
|
||||
Qt::Edge edge, qreal progress )
|
||||
{
|
||||
Q_UNUSED( edge ); // TODO ...
|
||||
|
||||
Q_D( QskSlideInNode );
|
||||
|
||||
{
|
||||
// clipping
|
||||
|
||||
if ( progress > 0.0 && progress <= 1.0 )
|
||||
{
|
||||
if ( d->clipNode == nullptr )
|
||||
{
|
||||
d->clipNode = new QSGClipNode();
|
||||
d->clipNode->setFlag( QSGNode::OwnedByParent, false );
|
||||
d->clipNode->setIsRectangular( true );
|
||||
}
|
||||
|
||||
d->clipNode->setClipRect( rect );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
delete d->clipNode;
|
||||
d->clipNode = nullptr;
|
||||
}
|
||||
|
||||
if ( d->clipNode )
|
||||
QskSGNode::setParentNode( d->clipNode, this );
|
||||
}
|
||||
|
||||
{
|
||||
// translation
|
||||
|
||||
qreal dx = 0.0;
|
||||
qreal dy = -progress* rect.height();
|
||||
|
||||
if ( dx != 0.0 || dy != 0.0 )
|
||||
{
|
||||
if ( d->transformNode == nullptr )
|
||||
{
|
||||
d->transformNode = new QSGTransformNode();
|
||||
d->transformNode->setFlag( QSGNode::OwnedByParent, false );
|
||||
}
|
||||
|
||||
QTransform transform;
|
||||
transform.translate( dx, dy );
|
||||
|
||||
d->transformNode->setMatrix( transform );
|
||||
}
|
||||
else
|
||||
{
|
||||
delete d->transformNode;
|
||||
d->transformNode = nullptr;
|
||||
}
|
||||
|
||||
if ( d->transformNode )
|
||||
{
|
||||
QSGNode* parentNode = d->clipNode;
|
||||
if ( parentNode == nullptr )
|
||||
parentNode = this;
|
||||
|
||||
QskSGNode::setParentNode( d->transformNode, parentNode );
|
||||
}
|
||||
}
|
||||
|
||||
d->reparentContentNode( this );
|
||||
}
|
||||
|
||||
void QskSlideInNode::setContentsNode( QSGNode* node )
|
||||
{
|
||||
Q_D( QskSlideInNode );
|
||||
|
||||
if ( d->contentsNode == node )
|
||||
return;
|
||||
|
||||
if ( node )
|
||||
node->setFlag( QSGNode::OwnedByParent, false );
|
||||
|
||||
delete d->contentsNode;
|
||||
d->contentsNode = node;
|
||||
|
||||
d->reparentContentNode( this );
|
||||
}
|
||||
|
||||
QSGNode* QskSlideInNode::contentsNode()
|
||||
{
|
||||
return d_func()->contentsNode;
|
||||
}
|
||||
|
||||
const QSGNode* QskSlideInNode::contentsNode() const
|
||||
{
|
||||
return d_func()->contentsNode;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_SLIDE_IN_NODE_H
|
||||
#define QSK_SLIDE_IN_NODE_H
|
||||
|
||||
#include "QskGlobal.h"
|
||||
|
||||
#include <qsgnode.h>
|
||||
#include <qnamespace.h>
|
||||
|
||||
class QskSlideInNodePrivate;
|
||||
|
||||
class QSK_EXPORT QskSlideInNode : public QSGNode
|
||||
{
|
||||
public:
|
||||
QskSlideInNode();
|
||||
~QskSlideInNode() override;
|
||||
|
||||
void updateTranslation( const QRectF&, Qt::Edge, qreal progress );
|
||||
|
||||
void setContentsNode( QSGNode* );
|
||||
|
||||
QSGNode* contentsNode();
|
||||
const QSGNode* contentsNode() const;
|
||||
|
||||
private:
|
||||
Q_DECLARE_PRIVATE( QskSlideInNode )
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue