Squashed commit of the following:

commit c6aec22cbdbed31955e70ea73fc6863d9369ba22
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Tue Oct 24 11:34:55 2023 +0200

    wip

commit 473946633e150129a3ba67ea321bda23fcd0f5a7
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Tue Oct 24 11:28:23 2023 +0200

    wip

commit 368f6edac32457d6a060c2f2e8a722c0d15bf35c
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Tue Oct 24 11:26:46 2023 +0200

    wip

commit eccffafec006d471cc691f3d10143219ec263c63
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Tue Oct 24 11:22:01 2023 +0200

    wip

commit c5ae5025d4ed0ea7184fb8b4fa97df7f3ca54c0e
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Tue Oct 24 10:53:09 2023 +0200

    wip

commit 174b1d946067c5b5c0bf4a9982d7b3f7f717d263
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Tue Oct 24 10:51:54 2023 +0200

    wip

commit 3e89f17ea971adc19c89cca0eb38dc3e973a090e
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Tue Oct 24 10:15:17 2023 +0200

    wip

commit 499a13ab74501c24f1e0effe56dfb9cf9ff9bf63
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Tue Oct 24 10:03:55 2023 +0200

    wip

commit 935ffc6d23dcd20a2c70898f28063fcdffea0795
Merge: 82f44d41 0cf60b41
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Mon Oct 23 10:49:32 2023 +0200

    Merge branch 'drawer' into Overlay

commit 0cf60b414cee9a26fa5a53f05938e69ab39294d7
Merge: da76eb6d 2013338d
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Mon Oct 23 10:49:13 2023 +0200

    Merge branch 'features/drawer' into drawer

commit 82f44d41c03f8cedab8b1bf3f1c164dfa65200cf
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Sun Oct 22 10:44:50 2023 +0200

    wip

commit 3b254ff4551d457e1581b5dbb85fae2dcf55e2cc
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Sun Oct 22 10:43:15 2023 +0200

    wip

commit 81e2bd8b35fb4a361e67f8a56870d99ea05ffa4d
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Sun Oct 22 09:50:07 2023 +0200

    wip

commit 916f5ca888f675bdded0b97b763de02c8c6c12ff
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Fri Oct 20 17:08:53 2023 +0200

    wip

commit b3e8fd4d7cf4eab710b7781bb1e9dc730548d51b
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Fri Oct 20 17:03:12 2023 +0200

    wip

commit da76eb6df5353029856084e6306db32cb2712b6b
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Fri Oct 20 16:05:19 2023 +0200

    wip

commit 72fbd0b6fad4b33e09643e5a2c67833f6e2c4abd
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Fri Oct 20 15:21:14 2023 +0200

    wip

commit 7f899d67d6c8f7f98212030ac0e83e86581cefff
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Fri Oct 20 15:00:42 2023 +0200

    wip

commit 72872cad2a0749afe9c901775c18459ac4cd956a
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Fri Oct 20 13:49:05 2023 +0200

    wip

commit f16572e29a5fe8851479e2be6e04ff2d991e9ebd
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Fri Oct 20 13:40:47 2023 +0200

    wip

commit 4300a2cf225554f93cb492062f89af51dcc5df64
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Fri Oct 20 13:34:37 2023 +0200

    wip

commit c85150bcb98934b144e4453f12fbe37c4900049f
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Fri Oct 20 13:32:44 2023 +0200

    wip

commit 00d069d134319b0c3fb6d192cba32c31640e161f
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Fri Oct 20 13:21:45 2023 +0200

    wip

commit 36b4a203a3d761d4a3a5e17e1ba2deb7f9b37740
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Fri Oct 20 12:52:52 2023 +0200

    wip

commit e27fa8af6ddc233862ec431e2c129299e24f4ee0
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Fri Oct 20 11:12:42 2023 +0200

    wip

commit 579a45149a92ffef72c569c79456a3a2c753e37c
Author: Uwe Rathmann <Uwe.Rathmann@tigertal.de>
Date:   Fri Oct 20 10:57:51 2023 +0200

    QskSlideIn added
This commit is contained in:
Uwe Rathmann 2023-10-24 11:39:32 +02:00
parent 2013338dd4
commit e4b9b8bd1b
14 changed files with 411 additions and 313 deletions

View File

@ -23,10 +23,6 @@ namespace
Drawer( Qt::Edge edge, QQuickItem* parent )
: QskDrawer( parent )
{
#if 1
setAnimationHint( transitionAspect(), 1000 );
#endif
setEdge( edge );
auto content = new QskControl( this );

View File

@ -620,12 +620,6 @@ void Editor::setupDialogButtonBoxColors(
void Editor::setupDrawerMetrics()
{
using Q = QskDrawer;
using A = QskAspect;
#if 1
setAnimation( Q::Panel | A::Metric | A::Position, 200 );
#endif
}
void Editor::setupDrawerColors( QskAspect::Section, const QskFluent2Theme& )
@ -744,7 +738,6 @@ void Editor::setupListViewColors(
void Editor::setupMenuMetrics()
{
using Q = QskMenu;
using A = QskAspect;
setPadding( Q::Panel, { 4, 6, 4, 6 } );
setBoxBorderMetrics( Q::Panel, 1 );
@ -758,14 +751,6 @@ void Editor::setupMenuMetrics()
setStrutSize( Q::Icon, 12, 12 );
setPadding( Q::Icon, { 8, 8, 0, 8 } );
#if 1
setPosition( Q::Panel, 1 );
setPosition( Q::Panel | QskPopup::Closed, 0 );
// copied from Mat3 - what are the correct values for Fluent2 ???
setAnimation( Q::Panel | A::Metric, 150 );
#endif
}
void Editor::setupMenuColors(
@ -876,10 +861,14 @@ void Editor::setupPageIndicatorColors(
void Editor::setupPopup( const QskFluent2Theme& theme )
{
using Q = QskPopup;
using A = QskAspect;
const auto& pal = theme.palette;
setHint( Q::Overlay | A::Style, true );
setGradient( Q::Overlay, pal.background.overlay.defaultColor );
setAnimation( Q::Popup, 200 );
}
void Editor::setupProgressBarMetrics()

View File

@ -331,6 +331,8 @@ void Editor::setupPopup()
setHint( Q::Overlay | A::Style, true );
setGradient( Q::Overlay, stateLayerColor( m_pal.outline, 0.8 ) );
setAnimation( Q::Popup, qskDuration );
}
void Editor::setupMenu()
@ -378,10 +380,6 @@ void Editor::setupMenu()
setColor( Q::Text, m_pal.onSurface );
setFontRole( Q::Text, QskMaterial3Skin::M3BodyMedium );
setPosition( Q::Panel, 1 );
setPosition( Q::Panel | QskPopup::Closed, 0 );
setAnimation( Q::Panel | A::Metric, 150 );
setAnimation( Q::Cursor | A::Position | A::Metric, 75, QEasingCurve::OutCubic );
}
@ -808,10 +806,6 @@ void Editor::setupDialogButtonBox()
void Editor::setupDrawer()
{
using Q = QskDrawer;
using A = QskAspect;
setAnimation( Q::Panel | A::Metric | A::Position, qskDuration );
}
void Editor::setupSlider()

View File

@ -409,7 +409,9 @@ void Editor::setupPopup()
using Q = QskPopup;
setHint( Q::Overlay | A::Style, true );
setGradient( Q::Overlay, QColor( 220, 220, 220, 150 ) );
setGradient( Q::Overlay, qRgba( 220, 220, 220, 150 ) );
setAnimation( Q::Popup, 200 );
}
void Editor::setupMenu()
@ -446,10 +448,6 @@ void Editor::setupMenu()
setGraphicRole( Q::Icon | Q::Disabled, DisabledSymbol );
setGraphicRole( Q::Icon | Q::Selected, CursorSymbol );
setPosition( Q::Panel, 1 );
setPosition( Q::Panel | QskPopup::Closed, 0 );
setAnimation( Q::Panel | A::Metric, 150 );
setAnimation( Q::Cursor | A::Position | A::Metric, 75, QEasingCurve::OutCubic );
}
@ -761,10 +759,6 @@ void Editor::setupDialogButtonBox()
void Editor::setupDrawer()
{
using A = QskAspect;
using Q = QskDrawer;
setAnimation( Q::Panel | A::Metric | A::Position, qskDuration );
}
void Editor::setupTabButton()

View File

@ -210,6 +210,7 @@ list(APPEND HEADERS
controls/QskQuickItem.h
controls/QskRadioBox.h
controls/QskRadioBoxSkinlet.h
controls/QskSlideIn.h
controls/QskScrollArea.h
controls/QskScrollBox.h
controls/QskScrollView.h
@ -316,6 +317,7 @@ list(APPEND SOURCES
controls/QskScrollBox.cpp
controls/QskScrollView.cpp
controls/QskScrollViewSkinlet.cpp
controls/QskSlideIn.cpp
controls/QskRadioBox.cpp
controls/QskRadioBoxSkinlet.cpp
controls/QskSegmentedBar.cpp

View File

@ -5,7 +5,6 @@
#include "QskDrawer.h"
#include "QskAspect.h"
#include "QskAnimationHint.h"
#include "QskQuick.h"
#include "QskEvent.h"
@ -15,24 +14,13 @@
#include <qguiapplication.h>
#include <qstylehints.h>
QSK_QT_PRIVATE_BEGIN
#include <private/qquickitem_p.h>
#include <private/qquickitemchangelistener_p.h>
QSK_QT_PRIVATE_END
/*
Only used for the sliding in animation. Do we want to
introduce a specific panel as background ???
*/
QSK_SUBCONTROL( QskDrawer, Panel )
static inline qreal qskDefaultDragMargin()
{
// a skin hint ???
return QGuiApplication::styleHints()->startDragDistance();
}
static void qskCatchMouseEvents( QQuickItem* item )
static inline void qskCatchMouseEvents( QQuickItem* item )
{
#if 1
// manipulating other items - do we really want to do this ?
@ -63,13 +51,12 @@ static bool qskCheckDirection( Qt::Edge edge, const QskPanGesture* gesture )
return false;
}
static void qskLayoutDrawer( const QRectF& rect, QskDrawer* drawer )
static inline QRectF qskAlignedToEdge(
const QRectF& rect, const QSizeF& size, Qt::Edge edge )
{
const auto size = qskSizeConstraint( drawer, Qt::PreferredSize );
QRectF r( 0.0, 0.0, size.width(), size.height() );
switch( drawer->edge() )
switch( edge )
{
case Qt::LeftEdge:
{
@ -99,91 +86,7 @@ static void qskLayoutDrawer( const QRectF& rect, QskDrawer* drawer )
}
}
drawer->setGeometry( r );
}
static inline QRectF qskSlidingRect(
const QSizeF& size, Qt::Edge edge, qreal ratio )
{
auto x = 0.0;
auto y = 0.0;
ratio = 1.0 - ratio;
switch( edge )
{
case Qt::LeftEdge:
x = -ratio * size.width();
break;
case Qt::RightEdge:
x = ratio * size.width();
break;
case Qt::TopEdge:
y = -ratio * size.height();
break;
case Qt::BottomEdge:
y = ratio * size.height();
break;
}
return QRectF( x, y, size.width(), size.height() );
}
namespace
{
class GeometryListener final : public QQuickItemChangeListener
{
public:
GeometryListener( QQuickItem* item, QQuickItem* adjustedItem )
: m_item( item )
, m_adjustedItem( adjustedItem )
{
adjust();
setEnabled( true );
}
~GeometryListener()
{
setEnabled( false );
}
private:
void itemGeometryChanged( QQuickItem*,
QQuickGeometryChange, const QRectF& ) override
{
adjust();
}
private:
void adjust()
{
#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_item );
if ( on )
d->addItemChangeListener( this, changeTypes );
else
d->removeItemChangeListener( this, changeTypes );
}
QQuickItem* m_item;
QQuickItem* m_adjustedItem;
};
return r;
}
namespace
@ -243,18 +146,8 @@ namespace
class QskDrawer::PrivateData
{
public:
inline void resetListener( QskDrawer* drawer )
{
delete listener;
listener = nullptr;
if ( drawer->parentItem() && drawer->isVisible() )
listener = new GeometryListener( drawer->parentItem(), drawer );
}
Qt::Edge edge = Qt::LeftEdge;
GestureRecognizer* gestureRecognizer = nullptr;
GeometryListener* listener = nullptr;
qreal dragMargin = qskDefaultDragMargin();
};
@ -269,25 +162,11 @@ QskDrawer::QskDrawer( QQuickItem* parentItem )
setAutoLayoutChildren( true );
setInteractive( true );
setPopupFlag( PopupFlag::CloseOnPressOutside, true );
setTransitionAspect( Panel | QskAspect::Position | QskAspect::Metric );
/*
The drawer wants to be on top of the parent - not being
layouted into its layoutRect(). So we opt out and do
the layout updates manually.
*/
setPlacementPolicy( QskPlacementPolicy::Ignore );
m_data->resetListener( this );
connect( this, &QskPopup::openChanged, this, &QskDrawer::setSliding );
connect( this, &QskPopup::transitioningChanged, this, &QskDrawer::setIntermediate );
setAdjustingToParentGeometry( true );
}
QskDrawer::~QskDrawer()
{
delete m_data->listener;
}
Qt::Edge QskDrawer::edge() const
@ -352,6 +231,24 @@ qreal QskDrawer::dragMargin() const
return m_data->dragMargin;
}
bool QskDrawer::event( QEvent* event )
{
if ( event->type() == QEvent::PolishRequest )
{
if ( isAdjustingToParentGeometry() && parentItem() )
{
auto r = qskItemRect( parentItem() );
r = qskAlignedToEdge( r, sizeConstraint( Qt::PreferredSize ), edge() );
setGeometry( r );
return true;
}
}
return Inherited::event( event );
}
void QskDrawer::keyPressEvent( QKeyEvent* event )
{
if ( isOpen() )
@ -432,18 +329,6 @@ void QskDrawer::gestureEvent( QskGestureEvent* event )
Inherited::gestureEvent( event );
}
QRectF QskDrawer::layoutRectForSize( const QSizeF& size ) const
{
qreal ratio;
if ( isTransitioning() )
ratio = metric( transitionAspect() );
else
ratio = isOpen() ? 1.0 : 0.0;
return qskSlidingRect( size, m_data->edge, ratio );
}
void QskDrawer::itemChange( QQuickItem::ItemChange change,
const QQuickItem::ItemChangeData& value )
{
@ -456,85 +341,9 @@ void QskDrawer::itemChange( QQuickItem::ItemChange change,
if ( parentItem() && isInteractive() )
qskCatchMouseEvents( parentItem() );
m_data->resetListener( this );
break;
}
case QQuickItem::ItemVisibleHasChanged:
{
m_data->resetListener( this );
break;
}
}
}
void QskDrawer::setSliding( bool on )
{
const qreal from = on ? 0.0 : 1.0;
const qreal to = on ? 1.0 : 0.0;
const auto aspect = transitionAspect();
auto hint = animationHint( aspect );
hint.updateFlags = QskAnimationHint::UpdatePolish;
startTransition( aspect, hint, from, to );
}
QRectF QskDrawer::clipRect() const
{
if ( !isTransitioning() )
return Inherited::clipRect();
/*
When fading we want to clip against the edge, where the drawer
slides in/out. However the size of the drawer is often smaller than the
one of the parent and we would clip the overlay node
and all content, that is located outside the drawer geometry.
So we expand the clip rectangle to "unbounded" at the other edges.
Note, that clipping against "rounded" rectangles can't be done
properly by overloading clipRect. We would have to manipulate the clip node
manually - like it is done in QskScrollArea. TODO ..
*/
constexpr qreal d = std::numeric_limits< short >::max();
QRectF r( -d, -d, 2.0 * d, 2.0 * d );
switch( m_data->edge )
{
case Qt::LeftEdge:
r.setLeft( 0.0 );
break;
case Qt::RightEdge:
r.setRight( width() );
break;
case Qt::TopEdge:
r.setTop( 0.0 );
break;
case Qt::BottomEdge:
r.setBottom( height() );
break;
}
return r;
}
void QskDrawer::setIntermediate( bool on )
{
setClip( on );
Q_EMIT focusIndicatorRectChanged();
}
QRectF QskDrawer::focusIndicatorRect() const
{
if ( isTransitioning() )
return QRectF();
return Inherited::focusIndicatorRect();
}
#include "moc_QskDrawer.cpp"

View File

@ -6,14 +6,13 @@
#ifndef QSK_DRAWER_H
#define QSK_DRAWER_H
#include "QskPopup.h"
#include <qnamespace.h>
#include "QskSlideIn.h"
class QSK_EXPORT QskDrawer : public QskPopup
class QSK_EXPORT QskDrawer : public QskSlideIn
{
Q_OBJECT
using Inherited = QskPopup;
using Inherited = QskSlideIn;
Q_PROPERTY( Qt::Edge edge READ edge WRITE setEdge NOTIFY edgeChanged )
@ -24,13 +23,11 @@ class QSK_EXPORT QskDrawer : public QskPopup
WRITE setInteractive NOTIFY interactiveChanged )
public:
QSK_SUBCONTROLS( Panel )
QskDrawer( QQuickItem* = nullptr );
~QskDrawer() override;
void setEdge( Qt::Edge );
Qt::Edge edge() const;
Qt::Edge edge() const override final;
void setInteractive( bool );
bool isInteractive() const;
@ -39,26 +36,19 @@ class QSK_EXPORT QskDrawer : public QskPopup
void resetDragMargin();
qreal dragMargin() const;
QRectF layoutRectForSize( const QSizeF& ) const override;
QRectF clipRect() const override;
QRectF focusIndicatorRect() const override;
Q_SIGNALS:
void edgeChanged( Qt::Edge );
void dragMarginChanged( qreal );
void interactiveChanged( bool );
protected:
bool event( QEvent* ) override;
void itemChange( ItemChange, const ItemChangeData& ) override;
void gestureEvent( QskGestureEvent* ) override;
void keyPressEvent( QKeyEvent* ) override;
private:
void setSliding( bool );
void setIntermediate( bool );
class PrivateData;
std::unique_ptr< PrivateData > m_data;
};

View File

@ -58,7 +58,6 @@ QskMenu::QskMenu( QQuickItem* parent )
, m_data( new PrivateData )
{
setModal( true );
setTransitionAspect( QskMenu::Panel | QskAspect::Position | QskAspect::Metric );
setPopupFlag( QskPopup::CloseOnPressOutside, true );
setPopupFlag( QskPopup::DeleteOnClose, true );

View File

@ -236,8 +236,8 @@ QSGNode* QskMenuSkinlet::updateSubNode(
auto slideInNode = QskSGNode::ensureNode< QskSlideInNode >( node );
const auto progress = popup->metric( popup->transitionAspect() );
slideInNode->updateTranslation( rect, Qt::TopEdge, progress );
slideInNode->updateTranslation(
rect, Qt::TopEdge, popup->transitioningFactor() );
auto contentsNode = updateContentsNode( popup, slideInNode->contentsNode() );
slideInNode->setContentsNode( contentsNode );

View File

@ -19,9 +19,16 @@ QSK_QT_PRIVATE_BEGIN
#include <private/qquickitem_p.h>
QSK_QT_PRIVATE_END
QSK_SUBCONTROL( QskPopup, Popup )
QSK_SUBCONTROL( QskPopup, Overlay )
QSK_SYSTEM_STATE( QskPopup, Closed, QskAspect::FirstSystemState << 1 )
static QskAspect qskTransitioningAspect()
{
return QskPopup::Popup | QskAspect::Metric;
}
static void qskSetFocus( QQuickItem* item, bool on )
{
if ( item->window() == nullptr )
@ -76,6 +83,23 @@ static bool qskReplayMousePress()
return false;
}
static void qskStartTransition( QskPopup* popup, bool on )
{
const auto aspect = qskTransitioningAspect();
auto hint = popup->animationHint( aspect.subControl() );
if ( hint.isValid() )
{
hint.updateFlags = QskAnimationHint::UpdatePolish | QskAnimationHint::UpdateNode;
const qreal from = on ? 0.0 : 1.0;
const qreal to = on ? 1.0 : 0.0;
popup->startTransition( aspect, hint, from, to );
}
}
namespace
{
class InputGrabber final : public QskInputGrabber
@ -139,7 +163,6 @@ class QskPopup::PrivateData
InputGrabber* inputGrabber = nullptr;
uint priority = 0;
QskAspect transitionAspect;
int flags : 4;
bool isModal : 1;
@ -217,6 +240,8 @@ void QskPopup::setOpen( bool on )
else
Q_EMIT closed();
qskStartTransition( this, on );
if ( isTransitioning() )
{
Q_EMIT transitioningChanged( true );
@ -240,7 +265,15 @@ bool QskPopup::isOpen() const
bool QskPopup::isTransitioning() const
{
return runningHintAnimator( m_data->transitionAspect ) != nullptr;
return runningHintAnimator( qskTransitioningAspect() ) != nullptr;
}
qreal QskPopup::transitioningFactor() const
{
if ( auto animator = runningHintAnimator( qskTransitioningAspect() ) )
return animator->currentValue().value< qreal >();
return isOpen() ? 1.0 : 0.0;
}
QRectF QskPopup::overlayRect() const
@ -291,44 +324,23 @@ void QskPopup::updateInputGrabber()
}
}
QskAspect QskPopup::transitionAspect() const
{
return m_data->transitionAspect;
}
void QskPopup::setTransitionAspect( QskAspect aspect )
{
auto transitionAspect = aspect;
transitionAspect.clearStates(); // animated values are always stateless
if ( transitionAspect == m_data->transitionAspect )
return;
if ( isTransitioning() )
{
// stop the running animation TODO ...
}
m_data->transitionAspect = transitionAspect;
}
bool QskPopup::isTransitionAccepted( QskAspect aspect ) const
{
if ( isVisible() )
if ( isVisible() && !isInitiallyPainted() )
{
/*
Usually we suppress transitions, when a control has never been
painted before as there is no valid starting point. Popups are
different as we want to have smooth fade/slide appearances.
*/
if ( ( aspect.value() == 0 ) )
{
return true;
}
if ( aspect == m_data->transitionAspect )
return true;
if ( aspect.isColor() )
{
if ( aspect.subControl() == effectiveSubcontrol( QskPopup::Overlay ) )
return true;
}
if ( aspect.subControl() == effectiveSubcontrol( QskPopup::Popup ) )
return true;
if ( aspect.subControl() == effectiveSubcontrol( QskPopup::Overlay ) )
return true;
}
return Inherited::isTransitionAccepted( aspect );
@ -472,10 +484,10 @@ bool QskPopup::event( QEvent* event )
}
case QskEvent::Animator:
{
const auto animtorEvent = static_cast< QskAnimatorEvent* >( event );
const auto animatorEvent = static_cast< QskAnimatorEvent* >( event );
if ( ( animtorEvent->state() == QskAnimatorEvent::Terminated )
&& ( animtorEvent->aspect() == m_data->transitionAspect ) )
if ( ( animatorEvent->state() == QskAnimatorEvent::Terminated )
&& ( animatorEvent->aspect() == qskTransitioningAspect() ) )
{
if ( !isOpen() )
{

View File

@ -24,7 +24,7 @@ class QSK_EXPORT QskPopup : public QskControl
using Inherited = QskControl;
public:
QSK_SUBCONTROLS( Overlay )
QSK_SUBCONTROLS( Popup, Overlay )
QSK_STATES( Closed )
enum PopupFlag
@ -56,11 +56,8 @@ class QSK_EXPORT QskPopup : public QskControl
void setPriority( uint );
uint priority() const;
// transitions between open/closed states
QskAspect transitionAspect() const;
void setTransitionAspect( QskAspect );
bool isTransitioning() const;
qreal transitioningFactor() const;
bool isOpen() const;
bool isClosed() const;

View File

@ -5,6 +5,12 @@
#include "QskPopupSkinlet.h"
#include "QskPopup.h"
#include "QskRgbValue.h"
static inline QRgb qskInterpolatedRgb( QRgb rgb, qreal factor )
{
return QskRgb::toTransparent( rgb, qRound( factor * qAlpha( rgb ) ) );
}
QskPopupSkinlet::QskPopupSkinlet( QskSkin* skin )
: Inherited( skin )
@ -28,13 +34,43 @@ 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 );
return updateOverlayNode( popup, node );
}
return Inherited::updateSubNode( skinnable, nodeRole, node );
}
QSGNode* QskPopupSkinlet::updateOverlayNode(
const QskPopup* popup, QSGNode* node ) const
{
using Q = QskPopup;
const auto factor = popup->transitioningFactor();
if ( factor <= 0.0 )
return nullptr;
const auto rect = popup->subControlRect( Q::Overlay );
if ( rect.isEmpty() )
return nullptr;
auto gradient = popup->gradientHint( Q::Overlay );
if ( gradient.isVisible() && factor != 1.0 )
{
auto stops = gradient.stops();
for ( auto& stop : stops )
stop.setRgb( qskInterpolatedRgb( stop.rgb(), factor ) );
gradient.setStops( stops );
}
return updateBoxNode( popup, node, rect, gradient, QskPopup::Overlay );
}
#include "moc_QskPopupSkinlet.cpp"

236
src/controls/QskSlideIn.cpp Normal file
View File

@ -0,0 +1,236 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskSlideIn.h"
#include "QskAnimationHint.h"
QSK_QT_PRIVATE_BEGIN
#include <private/qquickitem_p.h>
#include <private/qquickitemchangelistener_p.h>
QSK_QT_PRIVATE_END
namespace
{
// Using an eventFilter for QskEvent::GeometryChange instead ???
class GeometryListener final : public QQuickItemChangeListener
{
public:
GeometryListener( QQuickItem* item, QQuickItem* adjustedItem )
: m_item( item )
, m_adjustedItem( adjustedItem )
{
adjust();
setEnabled( true );
}
~GeometryListener()
{
setEnabled( false );
}
private:
void itemGeometryChanged( QQuickItem*,
QQuickGeometryChange, const QRectF& ) override
{
adjust();
}
private:
void adjust()
{
QEvent event( QEvent::PolishRequest );
QCoreApplication::sendEvent( m_adjustedItem, &event );
}
void setEnabled( bool on )
{
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;
};
}
class QskSlideIn::PrivateData
{
public:
inline void resetListener( QskSlideIn* slideIn )
{
delete listener;
listener = nullptr;
if ( adjustingToParentGeometry )
{
if ( slideIn->parentItem() && slideIn->isVisible() )
listener = new GeometryListener( slideIn->parentItem(), slideIn );
}
}
bool adjustingToParentGeometry = false;
GeometryListener* listener = nullptr;
};
QskSlideIn::QskSlideIn( QQuickItem* parentItem )
: Inherited ( parentItem )
, m_data( new PrivateData )
{
setPopupFlag( PopupFlag::CloseOnPressOutside, true );
/*
A slider wants to be on top of its parent - not being
layouted into its layoutRect(). So we opt out and do
the layout updates manually.
*/
setPlacementPolicy( QskPlacementPolicy::Ignore );
connect( this, &QskPopup::transitioningChanged,
this, &QskSlideIn::setIntermediate );
}
QskSlideIn::~QskSlideIn()
{
delete m_data->listener;
}
void QskSlideIn::setAdjustingToParentGeometry( bool on )
{
if ( on != m_data->adjustingToParentGeometry )
{
m_data->adjustingToParentGeometry = on;
m_data->resetListener( this );
}
}
bool QskSlideIn::isAdjustingToParentGeometry() const
{
return m_data->adjustingToParentGeometry;
}
void QskSlideIn::itemChange( QQuickItem::ItemChange change,
const QQuickItem::ItemChangeData& value )
{
Inherited::itemChange( change, value );
switch( static_cast< int >( change ) )
{
case QQuickItem::ItemParentHasChanged:
case QQuickItem::ItemVisibleHasChanged:
{
m_data->resetListener( this );
break;
}
}
}
bool QskSlideIn::event( QEvent* event )
{
if ( event->type() == QEvent::PolishRequest )
{
// isVisible ???
if ( m_data->adjustingToParentGeometry && parentItem() )
{
setSize( parentItem()->size() );
return true;
}
}
return Inherited::event( event );
}
void QskSlideIn::setIntermediate( bool on )
{
setClip( on );
Q_EMIT focusIndicatorRectChanged();
}
QRectF QskSlideIn::focusIndicatorRect() const
{
if ( isTransitioning() )
return QRectF();
return Inherited::focusIndicatorRect();
}
QRectF QskSlideIn::clipRect() const
{
if ( !isTransitioning() )
return Inherited::clipRect();
/*
When sliding we want to clip against the edge, where the drawer
slides in/out. However the size of the slidein is often smaller than the
one of the parent and we would clip the overlay node
and all content, that is located outside the drawer geometry.
So we expand the clip rectangle to "unbounded" at the other edges.
Note, that clipping against "rounded" rectangles can't be done
properly by overloading clipRect. We would have to manipulate the clip node
manually - like it is done in QskScrollArea. TODO ..
*/
constexpr qreal d = std::numeric_limits< short >::max();
QRectF r( -d, -d, 2.0 * d, 2.0 * d );
switch( edge() )
{
case Qt::LeftEdge:
r.setLeft( 0.0 );
break;
case Qt::RightEdge:
r.setRight( width() );
break;
case Qt::TopEdge:
r.setTop( 0.0 );
break;
case Qt::BottomEdge:
r.setBottom( height() );
break;
}
return r;
}
QRectF QskSlideIn::layoutRectForSize( const QSizeF& size ) const
{
const auto ratio = 1.0 - transitioningFactor();
auto x = 0.0;
auto y = 0.0;
switch( edge() )
{
case Qt::LeftEdge:
x = -ratio * size.width();
break;
case Qt::RightEdge:
x = ratio * size.width();
break;
case Qt::TopEdge:
y = -ratio * size.height();
break;
case Qt::BottomEdge:
y = ratio * size.height();
break;
}
return QRectF( x, y, size.width(), size.height() );
}
#include "moc_QskSlideIn.cpp"

44
src/controls/QskSlideIn.h Normal file
View File

@ -0,0 +1,44 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_SLIDE_IN_H
#define QSK_SLIDE_IN_H
#include "QskPopup.h"
#include <qnamespace.h>
class QSK_EXPORT QskSlideIn : public QskPopup
{
Q_OBJECT
using Inherited = QskPopup;
public:
~QskSlideIn() override;
virtual Qt::Edge edge() const = 0;
QRectF focusIndicatorRect() const override;
QRectF clipRect() const override;
void setAdjustingToParentGeometry( bool on );
bool isAdjustingToParentGeometry() const;
QRectF layoutRectForSize( const QSizeF& ) const override;
protected:
QskSlideIn( QQuickItem* = nullptr );
bool event( QEvent* ) override;
void itemChange( ItemChange, const ItemChangeData& ) override;
private:
void setIntermediate( bool );
class PrivateData;
std::unique_ptr< PrivateData > m_data;
};
#endif