implementation with basic functionality

This commit is contained in:
Uwe Rathmann 2023-10-17 11:55:50 +02:00
parent 48c170bfbf
commit 79d0f08eb6
18 changed files with 533 additions and 274 deletions

View File

@ -24,33 +24,34 @@ namespace
: QskDrawer( parent ) : QskDrawer( parent )
{ {
#if 1 #if 1
setAnimationHint( Panel | QskAspect::Position, 1000 ); setAnimationHint( faderAspect(), 1000 );
#endif #endif
setEdge( edge ); setEdge( edge );
setOverlay( true ); setOverlay( true );
auto content = new QskControl( this ); auto content = new QskControl( this );
content->setObjectName( "Content" );
switch( edge ) switch( edge )
{ {
case Qt::LeftEdge: case Qt::LeftEdge:
content->setBackgroundColor( QskRgb::Tomato ); content->setBackgroundColor( QskRgb::Tomato );
setFixedWidth( 100 ); content->setFixedWidth( 100 );
break; break;
case Qt::RightEdge: case Qt::RightEdge:
setFixedWidth( 200 ); content->setFixedWidth( 200 );
content->setBackgroundColor( QskRgb::Orchid ); content->setBackgroundColor( QskRgb::Orchid );
break; break;
case Qt::TopEdge: case Qt::TopEdge:
setFixedHeight( 100 ); content->setFixedHeight( 100 );
content->setBackgroundColor( QskRgb::Wheat ); content->setBackgroundColor( QskRgb::Chartreuse );
break; break;
case Qt::BottomEdge: case Qt::BottomEdge:
setFixedHeight( 200 ); content->setFixedHeight( 200 );
content->setBackgroundColor( QskRgb::Wheat ); content->setBackgroundColor( QskRgb::Wheat );
break; break;
} }
@ -65,16 +66,26 @@ namespace
{ {
setBackgroundColor( QskRgb::LightSteelBlue ); setBackgroundColor( QskRgb::LightSteelBlue );
setMargins( 50 ); setMargins( 10 );
setAutoLayoutChildren( true ); setAutoLayoutChildren( true );
(void) new QskPushButton( this );
for ( int i = 0; i < 4; i++ ) for ( int i = 0; i < 4; i++ )
{ {
const auto edge = static_cast< Qt::Edge >( 1 << i ); const auto edge = static_cast< Qt::Edge >( 1 << i );
m_drawers[i] = new Drawer( edge, this ); 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: private:
@ -87,7 +98,6 @@ namespace
MainBox( QQuickItem* parent = nullptr ) MainBox( QQuickItem* parent = nullptr )
: QskControl( parent ) : QskControl( parent )
{ {
setBackgroundColor( QskRgb::LemonChiffon );
setMargins( 40 ); setMargins( 40 );
setAutoLayoutChildren( true ); setAutoLayoutChildren( true );

View File

@ -606,21 +606,15 @@ void Editor::setupDialogButtonBoxColors(
void Editor::setupDrawerMetrics() void Editor::setupDrawerMetrics()
{ {
using Q = QskDrawer; using Q = QskDrawer;
using A = QskAspect;
setPadding( Q::Panel, 5 );
setHint( Q::Overlay | QskAspect::Style, false );
#if 1 #if 1
setAnimation( Q::Panel | QskAspect::Position, 200 ); setAnimation( Q::Panel | A::Metric | A::Position, 200 );
#endif #endif
} }
void Editor::setupDrawerColors( void Editor::setupDrawerColors( QskAspect::Section, const QskFluent2Theme& )
QskAspect::Section section, const QskFluent2Theme& theme )
{ {
using Q = QskDrawer;
setGradient( Q::Panel | section, theme.palette.background.solid.base );
} }
void Editor::setupFocusIndicatorMetrics() void Editor::setupFocusIndicatorMetrics()
@ -735,6 +729,7 @@ void Editor::setupListViewColors(
void Editor::setupMenuMetrics() void Editor::setupMenuMetrics()
{ {
using Q = QskMenu; using Q = QskMenu;
using A = QskAspect;
setPadding( Q::Panel, { 4, 6, 4, 6 } ); setPadding( Q::Panel, { 4, 6, 4, 6 } );
setBoxBorderMetrics( Q::Panel, 1 ); setBoxBorderMetrics( Q::Panel, 1 );
@ -748,6 +743,14 @@ void Editor::setupMenuMetrics()
setStrutSize( Q::Icon, 12, 12 ); setStrutSize( Q::Icon, 12, 12 );
setPadding( Q::Icon, { 8, 8, 0, 8 } ); 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( void Editor::setupMenuColors(

View File

@ -379,7 +379,7 @@ void Editor::setupMenu()
setFontRole( Q::Text, QskMaterial3Skin::M3BodyMedium ); setFontRole( Q::Text, QskMaterial3Skin::M3BodyMedium );
setPosition( Q::Panel, 0 ); 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::Panel | A::Metric, 150 );
setAnimation( Q::Cursor | A::Position | A::Metric, 75, QEasingCurve::OutCubic ); setAnimation( Q::Cursor | A::Position | A::Metric, 75, QEasingCurve::OutCubic );
@ -809,12 +809,9 @@ void Editor::setupDialogButtonBox()
void Editor::setupDrawer() void Editor::setupDrawer()
{ {
using Q = QskDrawer; using Q = QskDrawer;
using A = QskAspect;
setPadding( Q::Panel, 5_dp ); setAnimation( Q::Panel | A::Metric | A::Position, qskDuration );
setGradient( Q::Panel, m_pal.background );
setHint( Q::Overlay | QskAspect::Style, false );
setAnimation( Q::Panel | QskAspect::Position, qskDuration );
} }
void Editor::setupSlider() void Editor::setupSlider()

View File

@ -759,13 +759,12 @@ void Editor::setupDialogButtonBox()
setBoxShape( Q::Panel, 2 ); setBoxShape( Q::Panel, 2 );
} }
void Editor::setupDrawer() { void Editor::setupDrawer()
{
using A = QskAspect;
using Q = QskDrawer; using Q = QskDrawer;
setPadding( Q::Panel, 5 ); setAnimation( Q::Panel | A::Metric | A::Position, qskDuration );
setGradient( Q::Panel, m_pal.darker125 );
setAnimation( Q::Panel | QskAspect::Position, qskDuration );
setHint( Q::Overlay | QskAspect::Style, false );
} }
void Editor::setupTabButton() void Editor::setupTabButton()

View File

@ -115,6 +115,7 @@ list(APPEND HEADERS
nodes/QskRichTextRenderer.h nodes/QskRichTextRenderer.h
nodes/QskScaleRenderer.h nodes/QskScaleRenderer.h
nodes/QskSGNode.h nodes/QskSGNode.h
nodes/QskSlideInNode.h
nodes/QskStrokeNode.h nodes/QskStrokeNode.h
nodes/QskStippledLineRenderer.h nodes/QskStippledLineRenderer.h
nodes/QskShapeNode.h nodes/QskShapeNode.h
@ -146,6 +147,7 @@ list(APPEND SOURCES
nodes/QskRichTextRenderer.cpp nodes/QskRichTextRenderer.cpp
nodes/QskScaleRenderer.cpp nodes/QskScaleRenderer.cpp
nodes/QskSGNode.cpp nodes/QskSGNode.cpp
nodes/QskSlideInNode.cpp
nodes/QskStrokeNode.cpp nodes/QskStrokeNode.cpp
nodes/QskStippledLineRenderer.cpp nodes/QskStippledLineRenderer.cpp
nodes/QskShapeNode.cpp nodes/QskShapeNode.cpp

View File

@ -12,48 +12,88 @@
#include "QskPanGestureRecognizer.h" #include "QskPanGestureRecognizer.h"
#include "QskGesture.h" #include "QskGesture.h"
#include <qguiapplication.h>
#include <qstylehints.h>
QSK_QT_PRIVATE_BEGIN QSK_QT_PRIVATE_BEGIN
#include <private/qquickitem_p.h> #include <private/qquickitem_p.h>
#include <private/qquickitemchangelistener_p.h> #include <private/qquickitemchangelistener_p.h>
QSK_QT_PRIVATE_END 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 ) QSK_SUBCONTROL( QskDrawer, Panel )
static QRectF qskDrawerRect( const QRectF& rect, static void qskCatchMouseEvents( QQuickItem* item )
Qt::Edge edge, qreal pos, const QSizeF& size )
{ {
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 ) switch( edge )
{ {
case Qt::LeftEdge: 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 )
{
const auto size = qskSizeConstraint( drawer, Qt::PreferredSize );
QRectF r( 0.0, 0.0, size.width(), size.height() );
switch( drawer->edge() )
{ {
r.moveRight( rect.left() + progress * size.width() ); case Qt::LeftEdge:
{
r.setHeight( rect.height() );
r.moveRight( rect.left() + size.width() );
break; break;
} }
case Qt::RightEdge: case Qt::RightEdge:
{ {
r.moveLeft( rect.right() - progress * size.width() ); r.setHeight( rect.height() );
r.moveLeft( rect.right() - size.width() );
break; break;
} }
case Qt::TopEdge: case Qt::TopEdge:
{ {
r.moveBottom( rect.top() + progress * size.height() ); r.setWidth( rect.width() );
r.moveBottom( rect.top() + size.height() );
break; break;
} }
case Qt::BottomEdge: case Qt::BottomEdge:
{ {
r.moveTop( rect.bottom() - progress * size.height() ); r.setWidth( rect.width() );
r.moveTop( rect.bottom() - size.height() );
break; break;
} }
} }
return r; drawer->setGeometry( r );
} }
namespace namespace
@ -61,10 +101,11 @@ namespace
class GeometryListener final : public QQuickItemChangeListener class GeometryListener final : public QQuickItemChangeListener
{ {
public: public:
GeometryListener( QskDrawer* drawer ) GeometryListener( QQuickItem* item, QQuickItem* adjustedItem )
: m_drawer( drawer ) : m_item( item )
, m_parent( drawer->parentItem() ) , m_adjustedItem( adjustedItem )
{ {
adjust();
setEnabled( true ); setEnabled( true );
} }
@ -77,28 +118,40 @@ namespace
void itemGeometryChanged( QQuickItem*, void itemGeometryChanged( QQuickItem*,
QQuickGeometryChange, const QRectF& ) override QQuickGeometryChange, const QRectF& ) override
{ {
m_drawer->polish(); adjust();
} }
private: 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; const auto changeTypes = QQuickItemPrivate::Geometry;
auto d = QQuickItemPrivate::get( m_parent ); auto d = QQuickItemPrivate::get( m_item );
if ( on ) if ( on )
d->addItemChangeListener( this, changeTypes ); d->addItemChangeListener( this, changeTypes );
else else
d->removeItemChangeListener( this, changeTypes ); d->removeItemChangeListener( this, changeTypes );
} }
}
QskDrawer* m_drawer = nullptr; QQuickItem* m_item;
QQuickItem* m_parent = nullptr; QQuickItem* m_adjustedItem;
}; };
}
namespace
{
class GestureRecognizer : public QskPanGestureRecognizer class GestureRecognizer : public QskPanGestureRecognizer
{ {
using Inherited = QskPanGestureRecognizer; using Inherited = QskPanGestureRecognizer;
@ -112,33 +165,36 @@ namespace
} }
protected: 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() ); auto rect = qskItemRect( watchedItem() );
switch( drawer->edge() ) switch( drawer->edge() )
{ {
case Qt::LeftEdge: case Qt::LeftEdge:
rect.setRight( rect.left() + dist ); rect.setRight( rect.left() + dragMargin );
break; break;
case Qt::RightEdge: case Qt::RightEdge:
rect.setLeft( rect.right() - dist ); rect.setLeft( rect.right() - dragMargin );
break; break;
case Qt::TopEdge: case Qt::TopEdge:
rect.setBottom( rect.top() + dist ); rect.setBottom( rect.top() + dragMargin );
break; break;
case Qt::BottomEdge: case Qt::BottomEdge:
rect.setTop( rect.bottom() - dist ); rect.setTop( rect.bottom() - dragMargin );
break; break;
} }
return rect; return rect.contains( pos );
} }
}; };
} }
@ -147,23 +203,26 @@ class QskDrawer::PrivateData
{ {
public: public:
Qt::Edge edge = Qt::LeftEdge; Qt::Edge edge = Qt::LeftEdge;
GestureRecognizer* gestureRecognizer = nullptr;
GeometryListener* listener = nullptr; GeometryListener* listener = nullptr;
// a skin hint ???
qreal dragMargin = QGuiApplication::styleHints()->startDragDistance();
}; };
QskDrawer::QskDrawer( QQuickItem* parentItem ) QskDrawer::QskDrawer( QQuickItem* parentItem )
: Inherited ( parentItem ) : Inherited ( parentItem )
, m_data( new PrivateData ) , m_data( new PrivateData )
{ {
#if 1
setZ( 1 ); setZ( 1 );
#endif
setAutoLayoutChildren( true ); setPolishOnResize( true );
setPopupFlag( PopupFlag::CloseOnPressOutside, true ); setPopupFlag( PopupFlag::CloseOnPressOutside, true );
setFaderAspect( Panel | QskAspect::Position | QskAspect::Metric ); 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 The drawer wants to be on top of the parent - not being
layouted into its layoutRect(). So we opt out and do layouted into its layoutRect(). So we opt out and do
@ -172,17 +231,22 @@ QskDrawer::QskDrawer( QQuickItem* parentItem )
setPlacementPolicy( QskPlacementPolicy::Ignore ); setPlacementPolicy( QskPlacementPolicy::Ignore );
if ( parentItem ) if ( parentItem )
{ {
/* m_data->listener = new GeometryListener( parentItem, this );
QskPopup has an internal QskInputGrabber, that does something qskCatchMouseEvents( parentItem );
very similar. Maybe we can make use of it ... TODO
*/
m_data->listener = new GeometryListener( this );
} }
(void) new GestureRecognizer( this ); m_data->gestureRecognizer = new GestureRecognizer( this );
#if 1
parentItem->setAcceptedMouseButtons( Qt::LeftButton );
#endif 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() QskDrawer::~QskDrawer()
@ -205,13 +269,36 @@ void QskDrawer::setEdge( Qt::Edge edge )
edgeChanged( 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 ) void QskDrawer::gestureEvent( QskGestureEvent* event )
{ {
if ( event->gesture()->type() == QskGesture::Pan ) 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() ); const auto gesture = static_cast< const QskPanGesture* >( event->gesture().get() );
if ( gesture->state() == QskGesture::Finished ) if ( gesture->state() == QskGesture::Finished )
{
if ( qskCheckDirection( m_data->edge, gesture ) )
open(); open();
}
return; return;
} }
@ -219,30 +306,89 @@ void QskDrawer::gestureEvent( QskGestureEvent* event )
Inherited::gestureEvent( 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() void QskDrawer::updateLayout()
{ {
if ( !( isOpen() || isFading() ) ) if ( !( isOpen() || isFading() ) || size().isEmpty() )
return; return;
const auto targetRect = qskItemRect( parentItem() ); auto dx = 0.0;
const auto size = qskConstrainedItemSize( this, targetRect.size() ); auto dy = 0.0;
const auto rect = qskDrawerRect( targetRect, if ( isFading() )
m_data->edge, metric( faderAspect() ), size ); {
const auto f = metric( faderAspect() );
qskSetItemGeometry( this, rect ); switch( m_data->edge )
Inherited::updateLayout(); {
} case Qt::LeftEdge:
dx = -f * width();
break;
void QskDrawer::aboutToShow() case Qt::RightEdge:
{ dx = f * width();
startFading( true ); break;
Inherited::aboutToShow();
case Qt::TopEdge:
dy = -f * height();
break;
case Qt::BottomEdge:
dy = f * height();
break;
}
}
const QRectF layoutRect( dx, dy, width(), height() );
const auto children = childItems();
for ( auto child : children )
{
if ( qskIsAdjustableByLayout( child ) )
{
const auto r = qskConstrainedItemRect( child, layoutRect );
qskSetItemGeometry( child, r );
}
}
} }
void QskDrawer::itemChange( QQuickItem::ItemChange change, void QskDrawer::itemChange( QQuickItem::ItemChange change,
@ -250,23 +396,39 @@ void QskDrawer::itemChange( QQuickItem::ItemChange change,
{ {
Inherited::itemChange( change, value ); 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; delete m_data->listener;
m_data->listener = nullptr; m_data->listener = nullptr;
if ( parentItem() ) if ( parentItem() && isVisible() )
m_data->listener = new GeometryListener( this ); 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 qreal from = on ? 1.0 : 0.0;
const auto to = open ? 0.0 : 1.0; const qreal to = on ? 0.0 : 1.0;
const auto hint = animationHint( Panel | QskAspect::Position ); const auto aspect = faderAspect();
startTransition( faderAspect(), hint, from, to );
auto hint = animationHint( aspect );
hint.updateFlags = QskAnimationHint::UpdatePolish;
startTransition( aspect, hint, from, to );
} }
#include "moc_QskDrawer.cpp" #include "moc_QskDrawer.cpp"

View File

@ -17,6 +17,9 @@ class QSK_EXPORT QskDrawer : public QskPopup
Q_PROPERTY( Qt::Edge edge READ edge WRITE setEdge NOTIFY edgeChanged ) Q_PROPERTY( Qt::Edge edge READ edge WRITE setEdge NOTIFY edgeChanged )
Q_PROPERTY( qreal dragMargin READ dragMargin
WRITE setDragMargin NOTIFY dragMarginChanged )
public: public:
QSK_SUBCONTROLS( Panel ) QSK_SUBCONTROLS( Panel )
@ -26,20 +29,23 @@ class QSK_EXPORT QskDrawer : public QskPopup
void setEdge( Qt::Edge ); void setEdge( Qt::Edge );
Qt::Edge edge() const; Qt::Edge edge() const;
QRectF layoutRectForSize( const QSizeF& ) const override; void setDragMargin( qreal );
qreal dragMargin() const;
void updateLayout() override; void updateLayout() override;
Q_SIGNALS: Q_SIGNALS:
void edgeChanged( Qt::Edge ); void edgeChanged( Qt::Edge );
void dragMarginChanged( qreal );
protected: protected:
void aboutToShow() override;
void itemChange( ItemChange, const ItemChangeData& ) override; void itemChange( ItemChange, const ItemChangeData& ) override;
QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override;
void gestureEvent( QskGestureEvent* ) override; void gestureEvent( QskGestureEvent* ) override;
private: private:
void startFading( bool ); void setFading( bool );
class PrivateData; class PrivateData;
std::unique_ptr< PrivateData > m_data; std::unique_ptr< PrivateData > m_data;

View File

@ -142,12 +142,9 @@ Qt::MouseButtons QskGestureRecognizer::acceptedMouseButtons() const
return m_data->buttons; return m_data->buttons;
} }
QRectF QskGestureRecognizer::gestureRect() const bool QskGestureRecognizer::isAcceptedPos( const QPointF& pos ) const
{ {
if ( m_data->watchedItem ) return m_data->watchedItem && m_data->watchedItem->contains( pos );
return qskItemRect( m_data->watchedItem );
return QRectF( 0.0, 0.0, -1.0, -1.0 );
} }
void QskGestureRecognizer::setRejectOnTimeout( bool on ) void QskGestureRecognizer::setRejectOnTimeout( bool on )
@ -313,7 +310,7 @@ bool QskGestureRecognizer::processMouseEvent(
if ( event->type() == QEvent::MouseButtonPress ) if ( event->type() == QEvent::MouseButtonPress )
{ {
if ( !gestureRect().contains( pos ) ) if ( !isAcceptedPos( pos ) )
return false; return false;
if ( m_data->state != Idle ) if ( m_data->state != Idle )

View File

@ -73,7 +73,7 @@ class QSK_EXPORT QskGestureRecognizer : public QObject
State state() const; State state() const;
virtual QRectF gestureRect() const; virtual bool isAcceptedPos( const QPointF& ) const;
Q_SIGNALS: Q_SIGNALS:
void stateChanged( State from, State to ); void stateChanged( State from, State to );

View File

@ -24,7 +24,7 @@ class QSK_EXPORT QskListViewSkinlet : public QskScrollViewSkinlet
public: public:
enum NodeRole enum NodeRole
{ {
TextRole, TextRole = Inherited::RoleCount,
GraphicRole, GraphicRole,
RoleCount RoleCount

View File

@ -9,12 +9,14 @@
#include "QskGraphic.h" #include "QskGraphic.h"
#include "QskColorFilter.h" #include "QskColorFilter.h"
#include "QskTextOptions.h" #include "QskTextOptions.h"
#include "QskSGNode.h"
#include "QskFunctions.h" #include "QskFunctions.h"
#include "QskMargins.h" #include "QskMargins.h"
#include "QskFunctions.h" #include "QskFunctions.h"
#include "QskLabelData.h" #include "QskLabelData.h"
#include "QskSGNode.h"
#include "QskSlideInNode.h"
#include <qfontmetrics.h> #include <qfontmetrics.h>
#include <qmath.h> #include <qmath.h>
@ -209,11 +211,44 @@ QskMenuSkinlet::QskMenuSkinlet( QskSkin* skin )
: Inherited( skin ) : Inherited( skin )
, m_data( new PrivateData() ) , m_data( new PrivateData() )
{ {
appendNodeRoles( { PanelRole } ); appendNodeRoles( { ContentsRole, PanelRole } );
} }
QskMenuSkinlet::~QskMenuSkinlet() = default; 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( QRectF QskMenuSkinlet::cursorRect(
const QskSkinnable* skinnable, const QRectF& contentsRect, int index ) const 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 ) if( !cursorPos.isNull() && menu->indexAtPosition( cursorPos ) == index )
{ {

View File

@ -20,7 +20,9 @@ class QSK_EXPORT QskMenuSkinlet : public QskPopupSkinlet
public: public:
enum NodeRole enum NodeRole
{ {
PanelRole = QskPopupSkinlet::RoleCount, ContentsRole = Inherited::RoleCount,
PanelRole,
RoleCount RoleCount
}; };
@ -48,7 +50,10 @@ class QSK_EXPORT QskMenuSkinlet : public QskPopupSkinlet
Qt::SizeHint, const QSizeF& ) const override; Qt::SizeHint, const QSizeF& ) const override;
protected: 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* updateMenuNode( const QskSkinnable*, QSGNode* ) const;
QSGNode* updateSampleNode( const QskSkinnable*, QSGNode* updateSampleNode( const QskSkinnable*,

View File

@ -5,108 +5,11 @@
#include "QskPopupSkinlet.h" #include "QskPopupSkinlet.h"
#include "QskPopup.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 ) QskPopupSkinlet::QskPopupSkinlet( QskSkin* skin )
: Inherited( skin ) : Inherited( skin )
{ {
appendNodeRoles( { OverlayRole, ContentsRole } ); appendNodeRoles( { OverlayRole } );
} }
QskPopupSkinlet::~QskPopupSkinlet() = default; QskPopupSkinlet::~QskPopupSkinlet() = default;
@ -125,54 +28,13 @@ QRectF QskPopupSkinlet::subControlRect( const QskSkinnable* skinnable,
QSGNode* QskPopupSkinlet::updateSubNode( QSGNode* QskPopupSkinlet::updateSubNode(
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
{ {
const auto popup = static_cast< const QskPopup* >( skinnable );
switch ( nodeRole ) switch ( nodeRole )
{ {
case OverlayRole: case OverlayRole:
return updateBoxNode( skinnable, node, QskPopup::Overlay ); return updateBoxNode( skinnable, node, QskPopup::Overlay );
case ContentsRole:
return updateExtraNode( popup, node );
} }
return Inherited::updateSubNode( skinnable, nodeRole, 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" #include "moc_QskPopupSkinlet.cpp"

View File

@ -20,8 +20,6 @@ class QSK_EXPORT QskPopupSkinlet : public QskSkinlet
enum NodeRole enum NodeRole
{ {
OverlayRole, OverlayRole,
ContentsRole,
RoleCount RoleCount
}; };
@ -35,10 +33,7 @@ class QSK_EXPORT QskPopupSkinlet : public QskSkinlet
QSGNode* updateSubNode( const QskSkinnable*, QSGNode* updateSubNode( const QskSkinnable*,
quint8 nodeRole, QSGNode* ) const override; quint8 nodeRole, QSGNode* ) const override;
virtual QSGNode* updateContentsNode( const QskPopup*, QSGNode* ) const;
private: private:
QSGNode* updateExtraNode( const QskPopup*, QSGNode* ) const;
QSGNode* updateOverlayNode( const QskPopup*, QSGNode* ) const; QSGNode* updateOverlayNode( const QskPopup*, QSGNode* ) const;
}; };

View File

@ -136,15 +136,15 @@ namespace
setOrientations( Qt::Horizontal | Qt::Vertical ); 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 ( auto scrollBox = qobject_cast< const QskScrollBox* >( watchedItem() ) )
{ {
if ( qskIsScrollable( scrollBox, orientations() ) ) 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;
} }
}; };
} }

View File

@ -1259,14 +1259,20 @@ bool QskSkinnable::isTransitionAccepted( QskAspect aspect ) const
{ {
Q_UNUSED( aspect ) Q_UNUSED( aspect )
if ( auto control = qskControlCast( owningItem() ) )
{
/* /*
Usually we only need smooth transitions, when state changes Usually we only need smooth transitions, when state changes
happen while the skinnable is visible. There are few exceptions happen while the skinnable is visible. There are few exceptions
like QskPopup::Closed, that is used to slide/fade in. like QskPopup::Closed, that is used to slide/fade in.
*/ */
if ( auto control = qskControlCast( owningItem() ) )
if ( control->flags() & QQuickItem::ItemHasContents )
return control->isInitiallyPainted(); return control->isInitiallyPainted();
return true;
}
return false; return false;
} }

View File

@ -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;
}

View File

@ -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