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:
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() )
{ {
case Qt::LeftEdge: case Qt::LeftEdge:
{ {
r.moveRight( rect.left() + progress * size.width() ); 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 );
} }
@ -74,31 +115,43 @@ namespace
} }
private: private:
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() );
const auto changeTypes = QQuickItemPrivate::Geometry; qskSetItemGeometry( m_adjustedItem,
pos.x(), pos.y(), m_item->width(), m_item->height() );
auto d = QQuickItemPrivate::get( m_parent ); #else
if ( on ) qskLayoutDrawer( QRectF( QPointF(), m_item->size() ),
d->addItemChangeListener( this, changeTypes ); qobject_cast< QskDrawer* >( m_adjustedItem ) );
else #endif
d->removeItemChangeListener( this, changeTypes );
}
} }
QskDrawer* m_drawer = nullptr; void setEnabled( bool on )
QQuickItem* m_parent = nullptr; {
}; const auto changeTypes = QQuickItemPrivate::Geometry;
auto d = QQuickItemPrivate::get( m_item );
if ( on )
d->addItemChangeListener( this, changeTypes );
else
d->removeItemChangeListener( this, changeTypes );
}
QQuickItem* m_item;
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 )
open(); {
if ( qskCheckDirection( m_data->edge, gesture ) )
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 ) )
{ {
delete m_data->listener; case QQuickItem::ItemParentHasChanged:
m_data->listener = nullptr; {
if ( parentItem() )
qskCatchMouseEvents( parentItem() );
if ( parentItem() ) Q_FALLTHROUGH();
m_data->listener = new GeometryListener( this ); }
case QQuickItem::ItemVisibleHasChanged:
{
delete m_data->listener;
m_data->listener = nullptr;
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 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,13 +1259,19 @@ bool QskSkinnable::isTransitionAccepted( QskAspect aspect ) const
{ {
Q_UNUSED( aspect ) Q_UNUSED( aspect )
/*
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 ( auto control = qskControlCast( owningItem() ) )
return control->isInitiallyPainted(); {
/*
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 ( control->flags() & QQuickItem::ItemHasContents )
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