Merge branch 'master' into features/menubutton
This commit is contained in:
commit
130bd3f9d2
|
@ -63,7 +63,8 @@ namespace
|
|||
Drawer( QQuickItem* parent = nullptr )
|
||||
: QskDrawer( parent )
|
||||
{
|
||||
auto box = new QskLinearBox( Qt::Vertical );
|
||||
auto box = new QskLinearBox( Qt::Vertical, this );
|
||||
|
||||
box->setSection( QskAspect::Header );
|
||||
box->setPanel( true );
|
||||
box->setPaddingHint( QskBox::Panel, 20 );
|
||||
|
@ -76,8 +77,6 @@ namespace
|
|||
|
||||
auto btn = new QskPushButton( "Close", box );
|
||||
connect( btn, &QskPushButton::clicked, this, &QskDrawer::close );
|
||||
|
||||
setContent( box );
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -211,19 +210,17 @@ namespace
|
|||
}
|
||||
|
||||
{
|
||||
auto drawer = new Drawer( parentItem() );
|
||||
drawer->setEdge( Qt::RightEdge );
|
||||
|
||||
auto burger = new QskPushButton( "≡", this );
|
||||
burger->setEmphasis( QskPushButton::LowEmphasis );
|
||||
|
||||
connect( burger, &QskPushButton::clicked,
|
||||
drawer, &QskPopup::open );
|
||||
this, &Header::drawerRequested );
|
||||
}
|
||||
}
|
||||
|
||||
Q_SIGNALS:
|
||||
void enabledToggled( bool );
|
||||
void drawerRequested();
|
||||
};
|
||||
|
||||
class MainView : public QskMainView
|
||||
|
@ -246,6 +243,12 @@ namespace
|
|||
connect( header, &Header::enabledToggled,
|
||||
tabView, &TabView::setPagesEnabled );
|
||||
|
||||
auto drawer = new Drawer( tabView );
|
||||
drawer->setEdge( Qt::RightEdge );
|
||||
|
||||
connect( header, &Header::drawerRequested,
|
||||
drawer, &QskPopup::toggle );
|
||||
|
||||
setHeader( header );
|
||||
setBody( tabView );
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
Definitions ( where possible ) taken from
|
||||
Definitions ( where possible ) taken from
|
||||
https://www.figma.com/file/NAWMapFlXnoOb86Q2H5GKr/Windows-UI-(Community)
|
||||
*/
|
||||
|
||||
|
@ -35,35 +35,18 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
The palette is made of a specific configurable colors and
|
||||
predefined semitransparent shades of gray. Both need to
|
||||
be resolved to opaque colors with the base colors of the sections.
|
||||
The palette is made of a couple of configurable base/accent colors and a
|
||||
predefined set of semitransparent shades of gray. These grays are used
|
||||
to create darkened/lightend colors from the configurable colors that can
|
||||
be used for borders etc.
|
||||
|
||||
Resolving the colors can be done in 2 ways:
|
||||
However borders need to be darkened for light base colors and lightened for
|
||||
dark ones. So we actually have 2 different sets of grays for light/dark
|
||||
colors schemes.
|
||||
|
||||
- render time
|
||||
|
||||
This actually means, that we do not create opaque colors and
|
||||
create the scene graph nodes with semitransparent colors.
|
||||
|
||||
- definition time
|
||||
|
||||
We create opaque colors for the base colors of the sections
|
||||
and set them as skin hints.
|
||||
|
||||
Resolving at render time sounds like the right solution as we
|
||||
background colors set in application code will just work.
|
||||
|
||||
Unfortunately we have 2 different sets of grays for light/dark
|
||||
base colors and when applications are setting a light color, where a
|
||||
dark color ( or v.v ) is expected we might end up with unacceptable
|
||||
results: ( white on light or black on dark ).
|
||||
|
||||
So there are pros and cons and we do not have a final opinion
|
||||
about waht to do. For the moment we implement resolving at definition
|
||||
time as an option to be able to play with both solutions.
|
||||
The main advantage of this concept is, that a working color schemes
|
||||
can be defined by setting the accent/base colors only.
|
||||
*/
|
||||
|
||||
#include "QskFluent2Skin.h"
|
||||
#include "QskFluent2Theme.h"
|
||||
|
||||
|
@ -139,9 +122,30 @@ namespace
|
|||
return qRgba( value, value, value, qRound( opacity * 255 ) );
|
||||
}
|
||||
|
||||
/*
|
||||
When application code is manipulating base colors manually the colors of
|
||||
the borders will be lightened/darkened from it like expected - as long
|
||||
as the application color matches the color scheme. Otherwise we end
|
||||
up with lightened borders on light backgrounds or v.v.
|
||||
|
||||
To avoid this problem we could resolve the grays with the background
|
||||
colors of the sections at definition time. This solves the problem with
|
||||
applications using backgrounds from the "wrong" color scheme, but requires
|
||||
more work for customizing controls hen using the "correct" scheme
|
||||
( -> border colors need to be set as well ).
|
||||
|
||||
When enabling QSK_RESOLVE_COLORS a code path is enabled that is intended
|
||||
to play with resolving the grays at definition time. But I'm not decided
|
||||
if it is worth to make a feature from it. TODO ...
|
||||
*/
|
||||
|
||||
#define QSK_RESOLVE_COLORS 0
|
||||
|
||||
#if QSK_RESOLVE_COLORS
|
||||
|
||||
inline constexpr QRgb rgbFlattened( QRgb foreground, QRgb background )
|
||||
{
|
||||
//Q_ASSERT( qAlpha( background ) == 255 );
|
||||
Q_ASSERT( qAlpha( background ) == 255 );
|
||||
|
||||
const auto r2 = qAlpha( foreground ) / 255.0;
|
||||
const auto r1 = 1.0 - r2;
|
||||
|
@ -160,15 +164,25 @@ namespace
|
|||
or without resolving the foreground alpha value
|
||||
*/
|
||||
|
||||
#if 0
|
||||
return rgbFlattened( foreground, background );
|
||||
#else
|
||||
//Q_ASSERT( qAlpha( background ) == 255 );
|
||||
}
|
||||
|
||||
#else // !QSK_RESOLVE_COLORS
|
||||
|
||||
inline QRgb rgbFlattened( QRgb foreground, QRgb background )
|
||||
{
|
||||
const auto alpha = qAlpha( foreground ) / 255.0;
|
||||
return QskRgb::interpolated( background, foreground, alpha );
|
||||
}
|
||||
|
||||
inline constexpr QRgb rgbSolid( QRgb foreground, QRgb background )
|
||||
{
|
||||
Q_UNUSED( background );
|
||||
return foreground;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
class Editor : private QskSkinHintTableEditor
|
||||
{
|
||||
public:
|
||||
|
@ -521,7 +535,8 @@ void Editor::setupComboBoxColors(
|
|||
|
||||
const auto& pal = theme.palette;
|
||||
|
||||
for ( const auto state : { QskAspect::NoState, Q::Hovered, Q::Focused, Q::Pressed, Q::Disabled } )
|
||||
for ( const auto state :
|
||||
{ QskAspect::NoState, Q::Hovered, Q::Focused, Q::Pressed, Q::Disabled } )
|
||||
{
|
||||
QRgb panelColor, borderColor1, borderColor2, textColor;
|
||||
|
||||
|
@ -606,21 +621,16 @@ void Editor::setupDialogButtonBoxColors(
|
|||
void Editor::setupDrawerMetrics()
|
||||
{
|
||||
using Q = QskDrawer;
|
||||
using A = QskAspect;
|
||||
|
||||
setPadding( Q::Panel, 5 );
|
||||
setHint( Q::Overlay | QskAspect::Style, false );
|
||||
|
||||
#if 1
|
||||
setAnimation( Q::Panel | QskAspect::Position, 200 );
|
||||
#endif
|
||||
setAnimation( Q::Panel | A::Position, 300, QEasingCurve::OutCubic );
|
||||
}
|
||||
|
||||
void Editor::setupDrawerColors(
|
||||
QskAspect::Section section, const QskFluent2Theme& theme )
|
||||
{
|
||||
using Q = QskDrawer;
|
||||
|
||||
setGradient( Q::Panel | section, theme.palette.background.solid.base );
|
||||
setGradient( QskDrawer::Panel | section,
|
||||
theme.palette.background.solid.base );
|
||||
}
|
||||
|
||||
void Editor::setupFocusIndicatorMetrics()
|
||||
|
@ -699,7 +709,7 @@ void Editor::setupListViewColors(
|
|||
{
|
||||
if ( state1 == Q::Hovered )
|
||||
cellColor = pal.fillColor.subtle.tertiary;
|
||||
else
|
||||
else
|
||||
cellColor = pal.fillColor.subtle.secondary;
|
||||
}
|
||||
|
||||
|
@ -735,6 +745,7 @@ void Editor::setupListViewColors(
|
|||
void Editor::setupMenuMetrics()
|
||||
{
|
||||
using Q = QskMenu;
|
||||
using A = QskAspect;
|
||||
|
||||
setPadding( Q::Panel, { 4, 6, 4, 6 } );
|
||||
setBoxBorderMetrics( Q::Panel, 1 );
|
||||
|
@ -748,6 +759,8 @@ void Editor::setupMenuMetrics()
|
|||
|
||||
setStrutSize( Q::Icon, 12, 12 );
|
||||
setPadding( Q::Icon, { 8, 8, 0, 8 } );
|
||||
|
||||
setAnimation( Q::Panel | A::Position, 100 );
|
||||
}
|
||||
|
||||
void Editor::setupMenuColors(
|
||||
|
@ -790,7 +803,8 @@ void Editor::setupMenuColors(
|
|||
setColor( Q::Text | Q::Selected | Q::Pressed, pal.fillColor.text.secondary );
|
||||
|
||||
setGraphicRole( Q::Icon, QskFluent2Skin::GraphicRoleFillColorTextPrimary );
|
||||
setGraphicRole( Q::Icon | Q::Selected | Q::Pressed, QskFluent2Skin::GraphicRoleFillColorTextSecondary );
|
||||
setGraphicRole( Q::Icon | Q::Selected | Q::Pressed,
|
||||
QskFluent2Skin::GraphicRoleFillColorTextSecondary );
|
||||
}
|
||||
|
||||
void Editor::setupPageIndicatorMetrics()
|
||||
|
@ -808,7 +822,7 @@ void Editor::setupPageIndicatorMetrics()
|
|||
|
||||
/*
|
||||
Pressed/Hovered are not yet implemented.
|
||||
Sizes would be:
|
||||
Sizes would be:
|
||||
|
||||
- Q::Pressed : 3
|
||||
- Q::Pressed | Q::Selected : 5
|
||||
|
@ -857,9 +871,11 @@ 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 );
|
||||
}
|
||||
|
||||
|
@ -1045,7 +1061,7 @@ void Editor::setupRadioBoxMetrics()
|
|||
However the colors of the inner side of the border are not solid for
|
||||
the selected states and we use a dummy indicator to get this done.
|
||||
|
||||
How to solve this in a better way, TODO ...
|
||||
How to solve this in a better way, TODO ...
|
||||
*/
|
||||
|
||||
setBoxShape( Q::CheckIndicator, 100, Qt::RelativeSize );
|
||||
|
@ -1095,7 +1111,7 @@ void Editor::setupRadioBoxColors(
|
|||
if ( states & Q::Disabled )
|
||||
textColor = pal.fillColor.text.disabled;
|
||||
|
||||
QRgb panelBorderColor;
|
||||
QRgb panelBorderColor;
|
||||
if ( states & ( Q::Disabled | Q::Pressed ) )
|
||||
panelBorderColor = pal.strokeColor.controlStrong.disabled;
|
||||
else
|
||||
|
@ -1408,7 +1424,7 @@ void Editor::setupSliderColors(
|
|||
setBoxBorderGradient( Q::Handle, pal.elevation.circle.border, handleColor );
|
||||
}
|
||||
|
||||
for ( auto state : { A::NoState , Q::Pressed , Q::Disabled } )
|
||||
for ( auto state : { A::NoState, Q::Pressed, Q::Disabled } )
|
||||
{
|
||||
QRgb grooveColor, fillColor, rippleColor;
|
||||
|
||||
|
@ -1568,7 +1584,7 @@ void Editor::setupTabButtonColors(
|
|||
using Q = QskTabButton;
|
||||
const auto& pal = theme.palette;
|
||||
|
||||
for ( const auto state : { QskAspect::NoState,
|
||||
for ( const auto state : { QskAspect::NoState,
|
||||
Q::Checked, Q::Hovered, Q::Pressed, Q::Disabled } )
|
||||
{
|
||||
QRgb panelColor, textColor;
|
||||
|
@ -1866,6 +1882,8 @@ void Editor::setupSwitchButtonColors(
|
|||
void Editor::setupSubWindow( const QskFluent2Theme& theme )
|
||||
{
|
||||
using Q = QskSubWindow;
|
||||
using A = QskAspect;
|
||||
|
||||
const auto& pal = theme.palette;
|
||||
|
||||
setPadding( Q::Panel, { 0, 31, 0, 0 } );
|
||||
|
@ -1883,6 +1901,8 @@ void Editor::setupSubWindow( const QskFluent2Theme& theme )
|
|||
setColor( Q::TitleBarText, pal.fillColor.text.primary );
|
||||
setAlignment( Q::TitleBarText, Qt::AlignLeft );
|
||||
setTextOptions( Q::TitleBarText, Qt::ElideRight, QskTextOptions::NoWrap );
|
||||
|
||||
setAnimation( Q::Panel | A::Position, 300, QEasingCurve::OutCubic );
|
||||
}
|
||||
|
||||
void Editor::setupVirtualKeyboardMetrics()
|
||||
|
|
|
@ -378,11 +378,9 @@ void Editor::setupMenu()
|
|||
setColor( Q::Text, m_pal.onSurface );
|
||||
setFontRole( Q::Text, QskMaterial3Skin::M3BodyMedium );
|
||||
|
||||
setPosition( Q::Panel, 0 );
|
||||
setPosition( Q::Panel | QskPopup::Closed, 1_dp );
|
||||
|
||||
setAnimation( Q::Panel | A::Metric, 150 );
|
||||
setAnimation( Q::Cursor | A::Position | A::Metric, 75, QEasingCurve::OutCubic );
|
||||
|
||||
setAnimation( Q::Panel | A::Position, 75 );
|
||||
}
|
||||
|
||||
void Editor::setupTextLabel()
|
||||
|
@ -809,12 +807,10 @@ void Editor::setupDialogButtonBox()
|
|||
void Editor::setupDrawer()
|
||||
{
|
||||
using Q = QskDrawer;
|
||||
using A = QskAspect;
|
||||
|
||||
setPadding( Q::Panel, 5_dp );
|
||||
setGradient( Q::Panel, m_pal.background );
|
||||
setHint( Q::Overlay | QskAspect::Style, false );
|
||||
|
||||
setAnimation( Q::Panel | QskAspect::Position, qskDuration );
|
||||
setAnimation( Q::Panel | A::Position, 300, QEasingCurve::OutCubic );
|
||||
}
|
||||
|
||||
void Editor::setupSlider()
|
||||
|
@ -1264,6 +1260,7 @@ void Editor::setupSubWindow()
|
|||
for ( auto subControl : { Q::Panel, Q::TitleBarPanel, Q::TitleBarText } )
|
||||
setAnimation( subControl | A::Color, qskDuration );
|
||||
|
||||
setAnimation( Q::Panel | A::Position, qskDuration, QEasingCurve::OutCubic );
|
||||
}
|
||||
|
||||
QskMaterial3Theme::QskMaterial3Theme( QskSkin::ColorScheme colorScheme )
|
||||
|
|
|
@ -409,7 +409,7 @@ 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 ) );
|
||||
}
|
||||
|
||||
void Editor::setupMenu()
|
||||
|
@ -446,11 +446,8 @@ void Editor::setupMenu()
|
|||
setGraphicRole( Q::Icon | Q::Disabled, DisabledSymbol );
|
||||
setGraphicRole( Q::Icon | Q::Selected, CursorSymbol );
|
||||
|
||||
setPosition( Q::Panel, 0 );
|
||||
setPosition( Q::Panel | QskPopup::Closed, 1 );
|
||||
|
||||
setAnimation( Q::Panel | A::Metric, 150 );
|
||||
setAnimation( Q::Cursor | A::Position | A::Metric, 75, QEasingCurve::OutCubic );
|
||||
setAnimation( Q::Panel | A::Position, 100 );
|
||||
}
|
||||
|
||||
void Editor::setupTextLabel()
|
||||
|
@ -759,13 +756,13 @@ void Editor::setupDialogButtonBox()
|
|||
setBoxShape( Q::Panel, 2 );
|
||||
}
|
||||
|
||||
void Editor::setupDrawer() {
|
||||
void Editor::setupDrawer()
|
||||
{
|
||||
using Q = QskDrawer;
|
||||
using A = QskAspect;
|
||||
|
||||
setPadding( Q::Panel, 5 );
|
||||
setGradient( Q::Panel, m_pal.darker125 );
|
||||
setAnimation( Q::Panel | QskAspect::Position, qskDuration );
|
||||
setHint( Q::Overlay | QskAspect::Style, false );
|
||||
setPanel( Q::Panel, Plain );
|
||||
setAnimation( Q::Panel | A::Position, 300, QEasingCurve::OutCubic );
|
||||
}
|
||||
|
||||
void Editor::setupTabButton()
|
||||
|
@ -1127,8 +1124,12 @@ void Editor::setupSubWindow()
|
|||
|
||||
setAlignment( Q::TitleBarText, Qt::AlignLeft | Qt::AlignVCenter );
|
||||
|
||||
#if 1
|
||||
for ( auto subControl : { Q::Panel, Q::TitleBarPanel, Q::TitleBarText } )
|
||||
setAnimation( subControl | A::Color, qskDuration );
|
||||
#endif
|
||||
|
||||
setAnimation( Q::Panel | A::Position, qskDuration, QEasingCurve::OutCubic );
|
||||
}
|
||||
|
||||
void Editor::setupSpinBox()
|
||||
|
|
|
@ -176,6 +176,7 @@ list(APPEND HEADERS
|
|||
controls/QskComboBoxSkinlet.h
|
||||
controls/QskControl.h
|
||||
controls/QskDrawer.h
|
||||
controls/QskDrawerSkinlet.h
|
||||
controls/QskEvent.h
|
||||
controls/QskFlickAnimator.h
|
||||
controls/QskFocusIndicator.h
|
||||
|
@ -280,6 +281,7 @@ list(APPEND SOURCES
|
|||
controls/QskControlPrivate.cpp
|
||||
controls/QskDirtyItemFilter.cpp
|
||||
controls/QskDrawer.cpp
|
||||
controls/QskDrawerSkinlet.cpp
|
||||
controls/QskEvent.cpp
|
||||
controls/QskFlickAnimator.cpp
|
||||
controls/QskFocusIndicator.cpp
|
||||
|
|
|
@ -915,10 +915,16 @@ void QskControl::itemChange( QQuickItem::ItemChange change,
|
|||
break;
|
||||
}
|
||||
case QQuickItem::ItemChildAddedChange:
|
||||
case QQuickItem::ItemChildRemovedChange:
|
||||
{
|
||||
if ( autoLayoutChildren() && qskIsAdjustableByLayout( value.item ) )
|
||||
polish();
|
||||
if ( autoLayoutChildren() )
|
||||
{
|
||||
if ( qskIsVisibleToLayout( value.item ) )
|
||||
resetImplicitSize();
|
||||
|
||||
if ( qskIsAdjustableByLayout( value.item ) )
|
||||
polish();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QQuickItem::ItemActiveFocusHasChanged:
|
||||
|
|
|
@ -1,48 +1,268 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskDrawer.h"
|
||||
#include "QskAspect.h"
|
||||
#include "QskControl.h"
|
||||
#include "QskQuick.h"
|
||||
#include "QskEvent.h"
|
||||
|
||||
#include <QskPopup.h>
|
||||
#include <QskBox.h>
|
||||
#include <QskAnimationHint.h>
|
||||
#include <QskQuick.h>
|
||||
#include "QskPanGestureRecognizer.h"
|
||||
#include "QskGesture.h"
|
||||
|
||||
#include <qguiapplication.h>
|
||||
#include <qstylehints.h>
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
#include <private/qquickitem_p.h>
|
||||
#include <private/qquickitemchangelistener_p.h>
|
||||
QSK_QT_PRIVATE_END
|
||||
|
||||
QSK_SUBCONTROL( QskDrawer, Panel )
|
||||
QSK_SUBCONTROL( QskDrawer, Overlay )
|
||||
|
||||
static inline qreal qskDefaultDragMargin()
|
||||
{
|
||||
// a skin hint ???
|
||||
return QGuiApplication::styleHints()->startDragDistance();
|
||||
}
|
||||
|
||||
static inline void qskCatchMouseEvents( QQuickItem* item )
|
||||
{
|
||||
#if 1
|
||||
// manipulating other items - do we really want to do this ?
|
||||
item->setAcceptedMouseButtons( Qt::LeftButton );
|
||||
item->setFiltersChildMouseEvents( true );
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool qskCheckDirection( Qt::Edge edge, const QskPanGesture* gesture )
|
||||
{
|
||||
const auto degrees = gesture->angle();
|
||||
|
||||
switch( edge )
|
||||
{
|
||||
case Qt::LeftEdge:
|
||||
return ( degrees < 90.0 ) || ( degrees ) > 270.0;
|
||||
|
||||
case Qt::RightEdge:
|
||||
return ( degrees > 90.0 ) && ( degrees < 270.0 );
|
||||
|
||||
case Qt::TopEdge:
|
||||
return degrees > 180.0;
|
||||
|
||||
case Qt::BottomEdge:
|
||||
return degrees < 180.0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline QRectF qskAlignedToEdge(
|
||||
const QRectF& r, const QSizeF& sz, Qt::Edge edge )
|
||||
{
|
||||
switch( edge )
|
||||
{
|
||||
case Qt::LeftEdge:
|
||||
return QRectF( r.left(), r.top(), sz.width(), r.height() );
|
||||
|
||||
case Qt::RightEdge:
|
||||
return QRectF( r.right() - sz.width(), r.top(), sz.width(), r.height() );
|
||||
|
||||
case Qt::TopEdge:
|
||||
return QRectF( r.left(), r.top(), r.width(), sz.height() );
|
||||
|
||||
case Qt::BottomEdge:
|
||||
return QRectF( r.left(), r.bottom() - sz.height(), r.width(), sz.height() );
|
||||
}
|
||||
|
||||
return QRectF();
|
||||
}
|
||||
|
||||
static QPointF qskDrawerTranslation( const QskDrawer* drawer, const QSizeF& size )
|
||||
{
|
||||
const auto ratio = 1.0 - drawer->fadingFactor();
|
||||
|
||||
auto dx = 0.0;
|
||||
auto dy = 0.0;
|
||||
|
||||
switch( drawer->edge() )
|
||||
{
|
||||
case Qt::LeftEdge:
|
||||
dx = -ratio * size.width();
|
||||
break;
|
||||
|
||||
case Qt::RightEdge:
|
||||
dx = ratio * size.width();
|
||||
break;
|
||||
|
||||
case Qt::TopEdge:
|
||||
dy = -ratio * size.height();
|
||||
break;
|
||||
|
||||
case Qt::BottomEdge:
|
||||
dy = ratio * size.height();
|
||||
break;
|
||||
}
|
||||
|
||||
return QPointF( dx, dy );
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
m_adjustedItem->polish();
|
||||
}
|
||||
|
||||
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 GestureRecognizer : public QskPanGestureRecognizer
|
||||
{
|
||||
using Inherited = QskPanGestureRecognizer;
|
||||
|
||||
public:
|
||||
GestureRecognizer( QskDrawer* drawer )
|
||||
: QskPanGestureRecognizer( drawer )
|
||||
{
|
||||
setWatchedItem( drawer->parentItem() );
|
||||
setTargetItem( drawer );
|
||||
}
|
||||
|
||||
protected:
|
||||
bool isAcceptedPos( const QPointF& pos ) const override
|
||||
{
|
||||
auto drawer = qobject_cast< const QskDrawer* >( targetItem() );
|
||||
if ( drawer->isFading() )
|
||||
return false;
|
||||
|
||||
auto rect = qskItemRect( watchedItem() );
|
||||
|
||||
if ( !drawer->isOpen() )
|
||||
{
|
||||
const auto dragMargin = drawer->dragMargin();
|
||||
if ( dragMargin <= 0.0 )
|
||||
return false;
|
||||
|
||||
switch( drawer->edge() )
|
||||
{
|
||||
case Qt::LeftEdge:
|
||||
rect.setRight( rect.left() + dragMargin );
|
||||
break;
|
||||
|
||||
case Qt::RightEdge:
|
||||
rect.setLeft( rect.right() - dragMargin );
|
||||
break;
|
||||
|
||||
case Qt::TopEdge:
|
||||
rect.setBottom( rect.top() + dragMargin );
|
||||
break;
|
||||
|
||||
case Qt::BottomEdge:
|
||||
rect.setTop( rect.bottom() - dragMargin );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rect.contains( pos );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class QskDrawer::PrivateData
|
||||
{
|
||||
public:
|
||||
QskControl* content = nullptr;
|
||||
QskBox* contentBox = nullptr;
|
||||
Qt::Edge edge = Qt::LeftEdge;
|
||||
PrivateData( Qt::Edge edge )
|
||||
: edge( edge )
|
||||
{
|
||||
}
|
||||
|
||||
inline void resetListener( QskDrawer* drawer )
|
||||
{
|
||||
delete listener;
|
||||
listener = nullptr;
|
||||
|
||||
if ( drawer->parentItem() && drawer->isVisible() )
|
||||
listener = new GeometryListener( drawer->parentItem(), drawer );
|
||||
}
|
||||
|
||||
GeometryListener* listener = nullptr;
|
||||
GestureRecognizer* gestureRecognizer = nullptr;
|
||||
|
||||
qreal dragMargin = qskDefaultDragMargin();
|
||||
Qt::Edge edge;
|
||||
};
|
||||
|
||||
QskDrawer::QskDrawer( QQuickItem* parentItem )
|
||||
: Inherited ( parentItem )
|
||||
, m_data( new PrivateData )
|
||||
: QskDrawer( Qt::LeftEdge, parentItem )
|
||||
{
|
||||
}
|
||||
|
||||
QskDrawer::QskDrawer( Qt::Edge edge, QQuickItem* parentItem )
|
||||
: Inherited ( parentItem )
|
||||
, m_data( new PrivateData( edge ) )
|
||||
{
|
||||
#if 1
|
||||
setZ( 1 );
|
||||
#endif
|
||||
|
||||
setPopupFlag( PopupFlag::CloseOnPressOutside, true );
|
||||
|
||||
m_data->contentBox = new QskBox(this);
|
||||
m_data->contentBox->setSubcontrolProxy( QskBox::Panel, Panel );
|
||||
m_data->contentBox->setPanel( true );
|
||||
/*
|
||||
A drawer 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 );
|
||||
|
||||
setSubcontrolProxy( Inherited::Overlay, Overlay );
|
||||
setAutoLayoutChildren( true );
|
||||
setInteractive( true );
|
||||
|
||||
setFaderAspect( Panel | QskAspect::Metric );
|
||||
|
||||
connect(this, &QskDrawer::closed, this, [this]() {
|
||||
startTransition( Panel | QskAspect::Metric,
|
||||
animationHint( Panel | QskAspect::Position ),
|
||||
0.0, 1.0 );
|
||||
});
|
||||
connect( this, &QskPopup::fadingChanged, this, &QQuickItem::setClip );
|
||||
}
|
||||
|
||||
QskDrawer::~QskDrawer()
|
||||
{
|
||||
delete m_data->listener;
|
||||
}
|
||||
|
||||
Qt::Edge QskDrawer::edge() const
|
||||
|
@ -60,79 +280,188 @@ void QskDrawer::setEdge( Qt::Edge edge )
|
|||
edgeChanged( edge );
|
||||
}
|
||||
|
||||
void QskDrawer::setContent( QskControl* content )
|
||||
void QskDrawer::setInteractive( bool on )
|
||||
{
|
||||
content->setParentItem( m_data->contentBox );
|
||||
if ( content->parent() == nullptr )
|
||||
content->setParent( m_data->contentBox );
|
||||
|
||||
m_data->content = content;
|
||||
}
|
||||
|
||||
void QskDrawer::updateLayout()
|
||||
{
|
||||
if ( !isOpen() && !isFading() )
|
||||
if ( on == isInteractive() )
|
||||
return;
|
||||
|
||||
const auto padding = paddingHint( Panel );
|
||||
|
||||
auto contentSize = m_data->content->preferredSize();
|
||||
contentSize = contentSize.grownBy( padding );
|
||||
|
||||
const auto parentSize = parentItem()->size();
|
||||
|
||||
switch( m_data->edge )
|
||||
if ( on )
|
||||
{
|
||||
case Qt::Edge::LeftEdge:
|
||||
{
|
||||
qreal x = metric( faderAspect() ) * contentSize.width() * -1.0;
|
||||
m_data->gestureRecognizer = new GestureRecognizer( this );
|
||||
if ( parentItem() )
|
||||
qskCatchMouseEvents( parentItem() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// how to revert qskCatchMouseEvents properly ???
|
||||
delete m_data->gestureRecognizer;
|
||||
m_data->gestureRecognizer = nullptr;
|
||||
}
|
||||
|
||||
qskSetItemGeometry( m_data->contentBox,
|
||||
x, 0, contentSize.width(), parentSize.height() );
|
||||
break;
|
||||
}
|
||||
case Qt::Edge::RightEdge:
|
||||
{
|
||||
qreal x = ( metric( faderAspect() ) * contentSize.width() )
|
||||
+ parentSize.width() - contentSize.width();
|
||||
Q_EMIT interactiveChanged( on );
|
||||
}
|
||||
|
||||
qskSetItemGeometry( m_data->contentBox,
|
||||
x, 0, contentSize.width(), parentSize.height() );
|
||||
break;
|
||||
bool QskDrawer::isInteractive() const
|
||||
{
|
||||
return m_data->gestureRecognizer != nullptr;
|
||||
}
|
||||
|
||||
void QskDrawer::setDragMargin( qreal margin )
|
||||
{
|
||||
margin = std::max( margin, 0.0 );
|
||||
|
||||
if ( margin != m_data->dragMargin )
|
||||
{
|
||||
m_data->dragMargin = margin;
|
||||
Q_EMIT dragMarginChanged( margin );
|
||||
}
|
||||
}
|
||||
|
||||
void QskDrawer::resetDragMargin()
|
||||
{
|
||||
setDragMargin( qskDefaultDragMargin() );
|
||||
}
|
||||
|
||||
qreal QskDrawer::dragMargin() const
|
||||
{
|
||||
return m_data->dragMargin;
|
||||
}
|
||||
|
||||
void QskDrawer::gestureEvent( QskGestureEvent* event )
|
||||
{
|
||||
if ( event->gesture()->type() == QskGesture::Pan )
|
||||
{
|
||||
/*
|
||||
For the moment we treat the gesture like a swipe gesture
|
||||
without dragging the drawer when moving the mouse. TODO ...
|
||||
*/
|
||||
const auto gesture = static_cast< const QskPanGesture* >( event->gesture().get() );
|
||||
if ( gesture->state() == QskGesture::Finished )
|
||||
{
|
||||
const auto forwards = qskCheckDirection( m_data->edge, gesture );
|
||||
if ( forwards != isOpen() )
|
||||
setOpen( forwards );
|
||||
}
|
||||
|
||||
case Qt::Edge::TopEdge:
|
||||
{
|
||||
qreal y = metric( faderAspect() ) * contentSize.height();
|
||||
return;
|
||||
}
|
||||
|
||||
qskSetItemGeometry( m_data->contentBox,
|
||||
0, -y, parentSize.width(), contentSize.height() );
|
||||
Inherited::gestureEvent( event );
|
||||
}
|
||||
|
||||
void QskDrawer::itemChange( QQuickItem::ItemChange change,
|
||||
const QQuickItem::ItemChangeData& value )
|
||||
{
|
||||
Inherited::itemChange( change, value );
|
||||
|
||||
switch( static_cast< int >( change ) )
|
||||
{
|
||||
case QQuickItem::ItemParentHasChanged:
|
||||
{
|
||||
if ( parentItem() && isInteractive() )
|
||||
qskCatchMouseEvents( parentItem() );
|
||||
|
||||
m_data->resetListener( this );
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::Edge::BottomEdge:
|
||||
case QQuickItem::ItemVisibleHasChanged:
|
||||
{
|
||||
qreal y = metric( faderAspect() ) * contentSize.height() + parentSize.height() -
|
||||
contentSize.height();
|
||||
|
||||
qskSetItemGeometry( m_data->contentBox,
|
||||
0, y, parentSize.width(), contentSize.height() );
|
||||
m_data->resetListener( this );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_data->content->setGeometry( QPointF( padding.left(), padding.top() ),
|
||||
m_data->contentBox->size().shrunkBy( padding ) );
|
||||
|
||||
Inherited::updateLayout();
|
||||
}
|
||||
|
||||
void QskDrawer::aboutToShow()
|
||||
void QskDrawer::updateResources()
|
||||
{
|
||||
startTransition( Panel | QskAspect::Metric,
|
||||
animationHint( Panel | QskAspect::Position ), 1.0, 0.0 );
|
||||
Inherited::updateResources();
|
||||
|
||||
Inherited::aboutToShow();
|
||||
/*
|
||||
Adjusting the geometry to the parent needs to be done before
|
||||
the layouting of the children ( -> autoLayoutChildren ) is done.
|
||||
So we are using this hook even if it is not about resources: TODO ...
|
||||
*/
|
||||
if ( const auto item = parentItem() )
|
||||
{
|
||||
auto r = qskItemRect( item );
|
||||
r = qskAlignedToEdge( r, sizeConstraint( Qt::PreferredSize ), edge() );
|
||||
|
||||
r.translate( qskDrawerTranslation( this, r.size() ) );
|
||||
setGeometry( r );
|
||||
}
|
||||
}
|
||||
|
||||
void QskDrawer::updateNode( QSGNode* node )
|
||||
{
|
||||
if ( isFading() && clip() )
|
||||
{
|
||||
if ( auto clipNode = QQuickItemPrivate::get( this )->clipNode() )
|
||||
{
|
||||
/*
|
||||
The clipRect is changing while fading. Couldn't
|
||||
find a way how to trigger updates - maybe be enabling/disabling
|
||||
the clip. So we do the updates manually. TODO ...
|
||||
*/
|
||||
const auto r = clipRect();
|
||||
if ( r != clipNode->rect() )
|
||||
{
|
||||
clipNode->setRect( r );
|
||||
clipNode->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Inherited::updateNode( node );
|
||||
}
|
||||
|
||||
QRectF QskDrawer::clipRect() const
|
||||
{
|
||||
if ( isFading() && parentItem() )
|
||||
{
|
||||
/*
|
||||
We might not fit into our parent and our children not
|
||||
into our rect. So we want to have a clip against the
|
||||
edge, where the drawer slides in/out only.
|
||||
Otherwise we would have unwanted effects, when clipping gets
|
||||
disabled once the transition is over.
|
||||
*/
|
||||
constexpr qreal d = 1e6;
|
||||
|
||||
QRectF r( -d, -d, 2.0 * d, 2.0 * d );
|
||||
|
||||
switch( edge() )
|
||||
{
|
||||
case Qt::LeftEdge:
|
||||
r.setLeft( -x() );
|
||||
break;
|
||||
|
||||
case Qt::RightEdge:
|
||||
r.setRight( parentItem()->width() - x() );
|
||||
break;
|
||||
|
||||
case Qt::TopEdge:
|
||||
r.setTop( -y() );
|
||||
break;
|
||||
|
||||
case Qt::BottomEdge:
|
||||
r.setBottom( parentItem()->height() - y() );
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
return Inherited::clipRect();
|
||||
}
|
||||
|
||||
QskAspect QskDrawer::fadingAspect() const
|
||||
{
|
||||
return QskDrawer::Panel | QskAspect::Position;
|
||||
}
|
||||
|
||||
QRectF QskDrawer::layoutRectForSize( const QSizeF& size ) const
|
||||
{
|
||||
return subControlContentsRect( size, Panel );
|
||||
}
|
||||
|
||||
#include "moc_QskDrawer.cpp"
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_DRAWER_H
|
||||
#define QSK_DRAWER_H
|
||||
|
||||
#include "QskPopup.h"
|
||||
#include <qnamespace.h>
|
||||
|
||||
class QSK_EXPORT QskDrawer : public QskPopup
|
||||
{
|
||||
|
@ -12,24 +16,46 @@ class QSK_EXPORT QskDrawer : public QskPopup
|
|||
|
||||
Q_PROPERTY( Qt::Edge edge READ edge WRITE setEdge NOTIFY edgeChanged )
|
||||
|
||||
Q_PROPERTY( qreal dragMargin READ dragMargin
|
||||
WRITE setDragMargin RESET resetDragMargin NOTIFY dragMarginChanged )
|
||||
|
||||
Q_PROPERTY( bool interactive READ isInteractive
|
||||
WRITE setInteractive NOTIFY interactiveChanged )
|
||||
|
||||
public:
|
||||
QSK_SUBCONTROLS( Panel, Overlay )
|
||||
QSK_SUBCONTROLS( Panel )
|
||||
|
||||
QskDrawer( QQuickItem* = nullptr );
|
||||
QskDrawer( Qt::Edge, QQuickItem* = nullptr );
|
||||
|
||||
~QskDrawer() override;
|
||||
|
||||
void setEdge( Qt::Edge );
|
||||
Qt::Edge edge() const;
|
||||
|
||||
void updateLayout() override;
|
||||
void setInteractive( bool );
|
||||
bool isInteractive() const;
|
||||
|
||||
void setContent( QskControl* );
|
||||
void setDragMargin( qreal );
|
||||
void resetDragMargin();
|
||||
qreal dragMargin() const;
|
||||
|
||||
QRectF clipRect() const override;
|
||||
QskAspect fadingAspect() const override;
|
||||
|
||||
QRectF layoutRectForSize( const QSizeF& ) const override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void edgeChanged( Qt::Edge );
|
||||
void dragMarginChanged( qreal );
|
||||
void interactiveChanged( bool );
|
||||
|
||||
protected:
|
||||
void aboutToShow() override;
|
||||
void gestureEvent( QskGestureEvent* ) override;
|
||||
void itemChange( ItemChange, const ItemChangeData& ) override;
|
||||
|
||||
void updateResources() override;
|
||||
void updateNode( QSGNode* ) override;
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskDrawerSkinlet.h"
|
||||
#include "QskDrawer.h"
|
||||
|
||||
QskDrawerSkinlet::QskDrawerSkinlet( QskSkin* skin )
|
||||
: Inherited( skin )
|
||||
{
|
||||
appendNodeRoles( { PanelRole } );
|
||||
}
|
||||
|
||||
QskDrawerSkinlet::~QskDrawerSkinlet() = default;
|
||||
|
||||
QRectF QskDrawerSkinlet::subControlRect(
|
||||
const QskSkinnable* skinnable, const QRectF& contentsRect,
|
||||
QskAspect::Subcontrol subControl ) const
|
||||
{
|
||||
if ( subControl == QskDrawer::Panel )
|
||||
return contentsRect;
|
||||
|
||||
return Inherited::subControlRect( skinnable, contentsRect, subControl );
|
||||
}
|
||||
|
||||
QSGNode* QskDrawerSkinlet::updateSubNode(
|
||||
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
|
||||
{
|
||||
if ( nodeRole == PanelRole )
|
||||
return updateBoxNode( skinnable, node, QskDrawer::Panel );
|
||||
|
||||
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
||||
}
|
||||
|
||||
QSizeF QskDrawerSkinlet::sizeHint( const QskSkinnable* skinnable,
|
||||
Qt::SizeHint which, const QSizeF& constraint ) const
|
||||
{
|
||||
if ( which == Qt::PreferredSize )
|
||||
return skinnable->strutSizeHint( QskDrawer::Panel );
|
||||
|
||||
return Inherited::sizeHint( skinnable, which, constraint );
|
||||
}
|
||||
|
||||
#include "moc_QskDrawerSkinlet.cpp"
|
|
@ -0,0 +1,40 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_DRAWER_SKINLET_H
|
||||
#define QSK_DRAWER_SKINLET_H
|
||||
|
||||
#include "QskPopupSkinlet.h"
|
||||
|
||||
class QSK_EXPORT QskDrawerSkinlet : public QskPopupSkinlet
|
||||
{
|
||||
Q_GADGET
|
||||
|
||||
using Inherited = QskPopupSkinlet;
|
||||
|
||||
public:
|
||||
enum NodeRole
|
||||
{
|
||||
ContentsRole = Inherited::RoleCount,
|
||||
PanelRole,
|
||||
|
||||
RoleCount
|
||||
};
|
||||
|
||||
Q_INVOKABLE QskDrawerSkinlet( QskSkin* = nullptr );
|
||||
~QskDrawerSkinlet() override;
|
||||
|
||||
QRectF subControlRect( const QskSkinnable*,
|
||||
const QRectF&, QskAspect::Subcontrol ) const override;
|
||||
|
||||
QSizeF sizeHint( const QskSkinnable*,
|
||||
Qt::SizeHint, const QSizeF& ) const override;
|
||||
|
||||
protected:
|
||||
QSGNode* updateSubNode( const QskSkinnable*,
|
||||
quint8 nodeRole, QSGNode* ) const override;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -68,7 +68,8 @@ class QskGestureRecognizer::PrivateData
|
|||
return watchedItem->acceptedMouseButtons();
|
||||
}
|
||||
|
||||
QQuickItem* watchedItem = nullptr;
|
||||
QPointer< QQuickItem > watchedItem = nullptr;
|
||||
QPointer< QQuickItem > targetItem = nullptr;
|
||||
|
||||
QVector< QMouseEvent* > pendingEvents;
|
||||
|
||||
|
@ -121,6 +122,16 @@ QQuickItem* QskGestureRecognizer::watchedItem() const
|
|||
return m_data->watchedItem;
|
||||
}
|
||||
|
||||
void QskGestureRecognizer::setTargetItem( QQuickItem* item )
|
||||
{
|
||||
m_data->targetItem = item;
|
||||
}
|
||||
|
||||
QQuickItem* QskGestureRecognizer::targetItem() const
|
||||
{
|
||||
return m_data->targetItem;
|
||||
}
|
||||
|
||||
void QskGestureRecognizer::setAcceptedMouseButtons( Qt::MouseButtons buttons )
|
||||
{
|
||||
m_data->buttons = buttons;
|
||||
|
@ -131,12 +142,9 @@ Qt::MouseButtons QskGestureRecognizer::acceptedMouseButtons() const
|
|||
return m_data->buttons;
|
||||
}
|
||||
|
||||
QRectF QskGestureRecognizer::gestureRect() const
|
||||
bool QskGestureRecognizer::isAcceptedPos( const QPointF& pos ) const
|
||||
{
|
||||
if ( m_data->watchedItem )
|
||||
return qskItemRect( m_data->watchedItem );
|
||||
|
||||
return QRectF( 0.0, 0.0, -1.0, -1.0 );
|
||||
return m_data->watchedItem && m_data->watchedItem->contains( pos );
|
||||
}
|
||||
|
||||
void QskGestureRecognizer::setRejectOnTimeout( bool on )
|
||||
|
@ -302,7 +310,7 @@ bool QskGestureRecognizer::processMouseEvent(
|
|||
|
||||
if ( event->type() == QEvent::MouseButtonPress )
|
||||
{
|
||||
if ( !gestureRect().contains( pos ) )
|
||||
if ( !isAcceptedPos( pos ) )
|
||||
return false;
|
||||
|
||||
if ( m_data->state != Idle )
|
||||
|
|
|
@ -22,6 +22,7 @@ class QSK_EXPORT QskGestureRecognizer : public QObject
|
|||
|
||||
Q_PROPERTY( State state READ state NOTIFY stateChanged )
|
||||
Q_PROPERTY( QQuickItem* watchedItem READ watchedItem WRITE setWatchedItem )
|
||||
Q_PROPERTY( QQuickItem* targetItem READ targetItem WRITE setTargetItem )
|
||||
|
||||
Q_PROPERTY( Qt::MouseButtons acceptedMouseButtons
|
||||
READ acceptedMouseButtons WRITE setAcceptedMouseButtons )
|
||||
|
@ -43,11 +44,16 @@ class QSK_EXPORT QskGestureRecognizer : public QObject
|
|||
QskGestureRecognizer( QObject* parent = nullptr );
|
||||
~QskGestureRecognizer() override;
|
||||
|
||||
bool eventFilter( QObject* object, QEvent* event) override;
|
||||
bool eventFilter( QObject*, QEvent* ) override;
|
||||
|
||||
// the item where the gesture happens
|
||||
void setWatchedItem( QQuickItem* );
|
||||
QQuickItem* watchedItem() const;
|
||||
|
||||
// the item processing the gesture events
|
||||
void setTargetItem( QQuickItem* );
|
||||
QQuickItem* targetItem() const;
|
||||
|
||||
// Qt::NoButton means: all buttons accepted
|
||||
void setAcceptedMouseButtons( Qt::MouseButtons );
|
||||
Qt::MouseButtons acceptedMouseButtons() const;
|
||||
|
@ -67,7 +73,7 @@ class QSK_EXPORT QskGestureRecognizer : public QObject
|
|||
|
||||
State state() const;
|
||||
|
||||
virtual QRectF gestureRect() const;
|
||||
virtual bool isAcceptedPos( const QPointF& ) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void stateChanged( State from, State to );
|
||||
|
|
|
@ -76,20 +76,28 @@ static inline QVariant qskAligned05( const QVariant& value )
|
|||
|
||||
#endif
|
||||
|
||||
static inline bool qskCheckReceiverThread( const QObject* receiver )
|
||||
static inline void qskSendAnimatorEvent(
|
||||
const QskAspect aspect, int index, bool on, QObject* receiver )
|
||||
{
|
||||
/*
|
||||
QskInputPanelSkinlet changes the skin state, what leads to
|
||||
sending events from the wrong thread. Until we have fixed it
|
||||
let's block sending the event to avoid running into assertions
|
||||
in QCoreApplication::sendEvent
|
||||
*/
|
||||
const auto state = on ? QskAnimatorEvent::Started : QskAnimatorEvent::Terminated;
|
||||
|
||||
const QThread* thread = receiver->thread();
|
||||
if ( thread == nullptr )
|
||||
return true;
|
||||
|
||||
return ( thread == QThread::currentThread() );
|
||||
const auto thread = receiver->thread();
|
||||
if ( thread && ( thread != QThread::currentThread() ) )
|
||||
{
|
||||
/*
|
||||
QskInputPanelSkinlet changes the skin state, what leads to
|
||||
sending events from the wrong thread. We can't use
|
||||
QCoreApplication::sendEvent then, TODO ...
|
||||
*/
|
||||
|
||||
auto event = new QskAnimatorEvent( aspect, index, state );
|
||||
QCoreApplication::postEvent( receiver, event );
|
||||
}
|
||||
else
|
||||
{
|
||||
QskAnimatorEvent event( aspect, index, state );
|
||||
QCoreApplication::sendEvent( receiver, &event );
|
||||
}
|
||||
}
|
||||
|
||||
QskHintAnimator::QskHintAnimator() noexcept
|
||||
|
@ -141,7 +149,7 @@ void QskHintAnimator::advance( qreal progress )
|
|||
{
|
||||
if ( m_updateFlags == QskAnimationHint::UpdateAuto )
|
||||
{
|
||||
if ( m_aspect.isMetric() )
|
||||
if ( !m_aspect.isColor() )
|
||||
{
|
||||
m_control->resetImplicitSize();
|
||||
|
||||
|
@ -338,11 +346,7 @@ void QskHintAnimatorTable::start( QskControl* control,
|
|||
|
||||
animator->start();
|
||||
|
||||
if ( qskCheckReceiverThread( control ) )
|
||||
{
|
||||
QskAnimatorEvent event( aspect, index, QskAnimatorEvent::Started );
|
||||
QCoreApplication::sendEvent( control, &event );
|
||||
}
|
||||
qskSendAnimatorEvent( aspect, index, true, control );
|
||||
}
|
||||
|
||||
const QskHintAnimator* QskHintAnimatorTable::animator( QskAspect aspect, int index ) const
|
||||
|
@ -390,15 +394,7 @@ bool QskHintAnimatorTable::cleanup()
|
|||
it = animators.erase( it );
|
||||
|
||||
if ( control )
|
||||
{
|
||||
if ( qskCheckReceiverThread( control ) )
|
||||
{
|
||||
auto event = new QskAnimatorEvent(
|
||||
aspect, index, QskAnimatorEvent::Terminated );
|
||||
|
||||
QCoreApplication::postEvent( control, event );
|
||||
}
|
||||
}
|
||||
qskSendAnimatorEvent( aspect, index, false, control );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -24,7 +24,7 @@ class QSK_EXPORT QskListViewSkinlet : public QskScrollViewSkinlet
|
|||
public:
|
||||
enum NodeRole
|
||||
{
|
||||
TextRole,
|
||||
TextRole = Inherited::RoleCount,
|
||||
GraphicRole,
|
||||
|
||||
RoleCount
|
||||
|
|
|
@ -103,7 +103,7 @@ void QskMainView::focusInEvent( QFocusEvent* event )
|
|||
{
|
||||
if ( auto focusItem = nextItemInFocusChain( true ) )
|
||||
{
|
||||
if ( qskIsItemComplete( focusItem )
|
||||
if ( !qskIsItemInDestructor( focusItem )
|
||||
&& qskIsAncestorOf( this, focusItem ) )
|
||||
{
|
||||
focusItem->setFocus( true );
|
||||
|
|
|
@ -18,7 +18,10 @@
|
|||
#include <qvariant.h>
|
||||
#include <qeventloop.h>
|
||||
|
||||
QSK_SUBCONTROL( QskMenu, Overlay )
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
#include <private/qquickitem_p.h>
|
||||
QSK_QT_PRIVATE_END
|
||||
|
||||
QSK_SUBCONTROL( QskMenu, Panel )
|
||||
QSK_SUBCONTROL( QskMenu, Segment )
|
||||
QSK_SUBCONTROL( QskMenu, Cursor )
|
||||
|
@ -58,20 +61,23 @@ QskMenu::QskMenu( QQuickItem* parent )
|
|||
, m_data( new PrivateData )
|
||||
{
|
||||
setModal( true );
|
||||
setFaderAspect( QskMenu::Panel | QskAspect::Position | QskAspect::Metric );
|
||||
|
||||
setPopupFlag( QskPopup::CloseOnPressOutside, true );
|
||||
setPopupFlag( QskPopup::DeleteOnClose, true );
|
||||
|
||||
setPlacementPolicy( QskPlacementPolicy::Ignore );
|
||||
setSubcontrolProxy( Inherited::Overlay, Overlay );
|
||||
|
||||
initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
|
||||
|
||||
// we hide the focus indicator while fading
|
||||
connect( this, &QskMenu::fadingChanged, this,
|
||||
&QskControl::focusIndicatorRectChanged );
|
||||
// we hide the focus indicator while sliding
|
||||
connect( this, &QskPopup::fadingChanged,
|
||||
this, &QskControl::focusIndicatorRectChanged );
|
||||
|
||||
connect( this, &QskMenu::opened, this,
|
||||
connect( this, &QskPopup::fadingChanged,
|
||||
this, &QQuickItem::setClip );
|
||||
|
||||
connect( this, &QskPopup::opened, this,
|
||||
[this]() { m_data->triggeredIndex = -1; } );
|
||||
|
||||
setAcceptHoverEvents( true );
|
||||
|
@ -81,6 +87,17 @@ QskMenu::~QskMenu()
|
|||
{
|
||||
}
|
||||
|
||||
QRectF QskMenu::clipRect() const
|
||||
{
|
||||
if ( isFading() )
|
||||
{
|
||||
constexpr qreal d = 1e6;
|
||||
return QRectF( -d, m_data->origin.y() - y(), 2.0 * d, d );
|
||||
}
|
||||
|
||||
return Inherited::clipRect();
|
||||
}
|
||||
|
||||
#if 1
|
||||
|
||||
// has no effect as we do not offer submenus yet. TODO ...
|
||||
|
@ -263,25 +280,57 @@ QString QskMenu::triggeredText() const
|
|||
return optionAt( m_data->triggeredIndex ).text();
|
||||
}
|
||||
|
||||
void QskMenu::updateResources()
|
||||
{
|
||||
qreal dy = 0.0;
|
||||
if ( isFading() )
|
||||
dy = ( 1.0 - fadingFactor() ) * height();
|
||||
|
||||
setPosition( m_data->origin.x(), m_data->origin.y() - dy );
|
||||
|
||||
Inherited::updateResources();
|
||||
}
|
||||
|
||||
void QskMenu::updateNode( QSGNode* node )
|
||||
{
|
||||
if ( isFading() && clip() )
|
||||
{
|
||||
if ( auto clipNode = QQuickItemPrivate::get( this )->clipNode() )
|
||||
{
|
||||
/*
|
||||
The clipRect is changing while fading. Couldn't
|
||||
find a way how to trigger updates - maybe be enabling/disabling
|
||||
the clip. So we do the updates manually. TODO ...
|
||||
*/
|
||||
const auto r = clipRect();
|
||||
if ( r != clipNode->rect() )
|
||||
{
|
||||
clipNode->setRect( r );
|
||||
clipNode->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Inherited::updateNode( node );
|
||||
}
|
||||
|
||||
void QskMenu::keyPressEvent( QKeyEvent* event )
|
||||
{
|
||||
if( m_data->currentIndex < 0 )
|
||||
return;
|
||||
|
||||
int key = event->key();
|
||||
|
||||
switch( key )
|
||||
switch( event->key() )
|
||||
{
|
||||
case Qt::Key_Up:
|
||||
{
|
||||
traverse( -1 );
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
case Qt::Key_Down:
|
||||
{
|
||||
traverse( 1 );
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
case Qt::Key_Select:
|
||||
|
@ -293,19 +342,17 @@ void QskMenu::keyPressEvent( QKeyEvent* event )
|
|||
return;
|
||||
}
|
||||
|
||||
case Qt::Key_Escape:
|
||||
case Qt::Key_Cancel:
|
||||
{
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if ( const int steps = qskFocusChainIncrement( event ) )
|
||||
{
|
||||
traverse( steps );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Inherited::keyPressEvent( event );
|
||||
}
|
||||
|
||||
void QskMenu::keyReleaseEvent( QKeyEvent* )
|
||||
|
@ -439,7 +486,7 @@ void QskMenu::mouseReleaseEvent( QMouseEvent* event )
|
|||
|
||||
void QskMenu::aboutToShow()
|
||||
{
|
||||
setGeometry( QRectF( m_data->origin, sizeConstraint() ) );
|
||||
setSize( sizeConstraint() );
|
||||
|
||||
if ( m_data->currentIndex < 0 )
|
||||
{
|
||||
|
@ -496,6 +543,11 @@ void QskMenu::trigger( int index )
|
|||
}
|
||||
}
|
||||
|
||||
QskAspect QskMenu::fadingAspect() const
|
||||
{
|
||||
return QskMenu::Panel | QskAspect::Position;
|
||||
}
|
||||
|
||||
int QskMenu::exec()
|
||||
{
|
||||
(void) execPopup();
|
||||
|
|
|
@ -37,7 +37,7 @@ class QSK_EXPORT QskMenu : public QskPopup
|
|||
using Inherited = QskPopup;
|
||||
|
||||
public:
|
||||
QSK_SUBCONTROLS( Overlay, Panel, Segment, Cursor, Text, Icon, Separator )
|
||||
QSK_SUBCONTROLS( Panel, Segment, Cursor, Text, Icon, Separator )
|
||||
QSK_STATES( Selected, Pressed )
|
||||
|
||||
QskMenu( QQuickItem* parentItem = nullptr );
|
||||
|
@ -81,6 +81,9 @@ class QSK_EXPORT QskMenu : public QskPopup
|
|||
|
||||
bool isPressed() const;
|
||||
|
||||
QRectF clipRect() const override;
|
||||
QskAspect fadingAspect() const override;
|
||||
|
||||
Q_INVOKABLE int exec();
|
||||
|
||||
Q_SIGNALS:
|
||||
|
@ -115,6 +118,9 @@ class QSK_EXPORT QskMenu : public QskPopup
|
|||
void aboutToShow() override;
|
||||
void trigger( int );
|
||||
|
||||
void updateResources() override;
|
||||
void updateNode( QSGNode* ) override;
|
||||
|
||||
private:
|
||||
void traverse( int steps );
|
||||
|
||||
|
|
|
@ -9,12 +9,13 @@
|
|||
#include "QskGraphic.h"
|
||||
#include "QskColorFilter.h"
|
||||
#include "QskTextOptions.h"
|
||||
#include "QskSGNode.h"
|
||||
#include "QskFunctions.h"
|
||||
#include "QskMargins.h"
|
||||
#include "QskFunctions.h"
|
||||
#include "QskLabelData.h"
|
||||
|
||||
#include "QskSGNode.h"
|
||||
|
||||
#include <qfontmetrics.h>
|
||||
#include <qmath.h>
|
||||
|
||||
|
@ -209,11 +210,31 @@ QskMenuSkinlet::QskMenuSkinlet( QskSkin* skin )
|
|||
: Inherited( skin )
|
||||
, m_data( new PrivateData() )
|
||||
{
|
||||
appendNodeRoles( { PanelRole } );
|
||||
appendNodeRoles( { ContentsRole, PanelRole } );
|
||||
}
|
||||
|
||||
QskMenuSkinlet::~QskMenuSkinlet() = default;
|
||||
|
||||
QSGNode* QskMenuSkinlet::updateSubNode(
|
||||
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
|
||||
{
|
||||
switch ( nodeRole )
|
||||
{
|
||||
case ContentsRole:
|
||||
{
|
||||
const auto popup = static_cast< const QskPopup* >( skinnable );
|
||||
|
||||
auto rect = popup->contentsRect();
|
||||
if ( rect.isEmpty() )
|
||||
return nullptr;
|
||||
|
||||
return updateContentsNode( popup, node );
|
||||
}
|
||||
}
|
||||
|
||||
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
||||
}
|
||||
|
||||
QRectF QskMenuSkinlet::cursorRect(
|
||||
const QskSkinnable* skinnable, const QRectF& contentsRect, int index ) const
|
||||
{
|
||||
|
@ -407,7 +428,8 @@ QskAspect::States QskMenuSkinlet::sampleStates(
|
|||
}
|
||||
}
|
||||
|
||||
const auto cursorPos = menu->effectiveSkinHint( Q::Segment | Q::Hovered | A::Metric | A::Position ).toPointF();
|
||||
const auto cursorPos = menu->effectiveSkinHint(
|
||||
Q::Segment | Q::Hovered | A::Metric | A::Position ).toPointF();
|
||||
|
||||
if( !cursorPos.isNull() && menu->indexAtPosition( cursorPos ) == index )
|
||||
{
|
||||
|
|
|
@ -20,7 +20,9 @@ class QSK_EXPORT QskMenuSkinlet : public QskPopupSkinlet
|
|||
public:
|
||||
enum NodeRole
|
||||
{
|
||||
PanelRole = QskPopupSkinlet::RoleCount,
|
||||
ContentsRole = Inherited::RoleCount,
|
||||
PanelRole,
|
||||
|
||||
RoleCount
|
||||
};
|
||||
|
||||
|
@ -48,7 +50,10 @@ class QSK_EXPORT QskMenuSkinlet : public QskPopupSkinlet
|
|||
Qt::SizeHint, const QSizeF& ) const override;
|
||||
|
||||
protected:
|
||||
QSGNode* updateContentsNode( const QskPopup*, QSGNode* ) const override;
|
||||
QSGNode* updateSubNode( const QskSkinnable*,
|
||||
quint8 nodeRole, QSGNode* ) const override;
|
||||
|
||||
QSGNode* updateContentsNode( const QskPopup*, QSGNode* ) const;
|
||||
QSGNode* updateMenuNode( const QskSkinnable*, QSGNode* ) const;
|
||||
|
||||
QSGNode* updateSampleNode( const QskSkinnable*,
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
#include "QskEvent.h"
|
||||
#include "QskGesture.h"
|
||||
|
||||
#include <qcoreapplication.h>
|
||||
#include <qline.h>
|
||||
#include <qmath.h>
|
||||
#include <qquickitem.h>
|
||||
#include <qguiapplication.h>
|
||||
#include <qstylehints.h>
|
||||
|
||||
static inline bool qskIsInOrientation(
|
||||
const QPointF& from, const QPointF& to, Qt::Orientations orientations )
|
||||
|
@ -60,9 +61,14 @@ static inline qreal qskAngle(
|
|||
}
|
||||
|
||||
static void qskSendPanGestureEvent(
|
||||
QQuickItem* item, QskGesture::State state, qreal velocity, qreal angle,
|
||||
const QPointF& origin, const QPointF& lastPosition, const QPointF& position )
|
||||
QskGestureRecognizer* recognizer, QskGesture::State state,
|
||||
qreal velocity, qreal angle, const QPointF& origin,
|
||||
const QPointF& lastPosition, const QPointF& position )
|
||||
{
|
||||
auto item = recognizer->targetItem();
|
||||
if ( item == nullptr )
|
||||
item = recognizer->watchedItem();
|
||||
|
||||
auto gesture = std::make_shared< QskPanGesture >();
|
||||
gesture->setState( state );
|
||||
|
||||
|
@ -146,7 +152,7 @@ class QskPanGestureRecognizer::PrivateData
|
|||
public:
|
||||
Qt::Orientations orientations = Qt::Horizontal | Qt::Vertical;
|
||||
|
||||
int minDistance = 15;
|
||||
int minDistance = QGuiApplication::styleHints()->startDragDistance() + 5;
|
||||
|
||||
quint64 timestampVelocity = 0.0; // timestamp of the last mouse event
|
||||
qreal angle = 0.0;
|
||||
|
@ -243,12 +249,12 @@ void QskPanGestureRecognizer::processMove( const QPointF& pos, quint64 timestamp
|
|||
|
||||
if ( started )
|
||||
{
|
||||
qskSendPanGestureEvent( watchedItem(), QskGesture::Started,
|
||||
qskSendPanGestureEvent( this, QskGesture::Started,
|
||||
velocity, m_data->angle, m_data->origin, m_data->origin, m_data->pos );
|
||||
}
|
||||
else
|
||||
{
|
||||
qskSendPanGestureEvent( watchedItem(), QskGesture::Updated,
|
||||
qskSendPanGestureEvent( this, QskGesture::Updated,
|
||||
velocity, m_data->angle, m_data->origin, oldPos, m_data->pos );
|
||||
}
|
||||
}
|
||||
|
@ -261,7 +267,7 @@ void QskPanGestureRecognizer::processRelease( const QPointF&, quint64 timestamp
|
|||
const ulong elapsedTotal = timestamp - timestampStarted();
|
||||
const qreal velocity = m_data->velocityTracker.velocity( elapsedTotal );
|
||||
|
||||
qskSendPanGestureEvent( watchedItem(), QskGesture::Finished,
|
||||
qskSendPanGestureEvent( this, QskGesture::Finished,
|
||||
velocity, m_data->angle, m_data->origin, m_data->pos, m_data->pos );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,11 +23,12 @@ class QSK_EXPORT QskPanGestureRecognizer : public QskGestureRecognizer
|
|||
void setOrientations( Qt::Orientations );
|
||||
Qt::Orientations orientations() const;
|
||||
|
||||
private:
|
||||
protected:
|
||||
void processPress( const QPointF&, quint64 timestamp, bool isFinal ) override;
|
||||
void processMove( const QPointF&, quint64 timestamp ) override;
|
||||
void processRelease( const QPointF&, quint64 timestamp ) override;
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
};
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "QskWindow.h"
|
||||
#include "QskEvent.h"
|
||||
#include "QskPlatform.h"
|
||||
#include "QskHintAnimator.h"
|
||||
|
||||
#include <qpa/qplatformintegration.h>
|
||||
|
||||
|
@ -75,6 +76,23 @@ static bool qskReplayMousePress()
|
|||
return false;
|
||||
}
|
||||
|
||||
static void qskStartFading( QskPopup* popup, bool on )
|
||||
{
|
||||
const auto aspect = popup->fadingAspect();
|
||||
|
||||
auto hint = popup->animationHint( aspect );
|
||||
|
||||
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
|
||||
|
@ -130,7 +148,6 @@ class QskPopup::PrivateData
|
|||
PrivateData()
|
||||
: flags( 0 )
|
||||
, isModal( false )
|
||||
, hasFaderEffect( true )
|
||||
, autoGrabFocus( true )
|
||||
, handoverFocus( true )
|
||||
{
|
||||
|
@ -139,11 +156,9 @@ class QskPopup::PrivateData
|
|||
InputGrabber* inputGrabber = nullptr;
|
||||
|
||||
uint priority = 0;
|
||||
QskAspect faderAspect;
|
||||
|
||||
int flags : 4;
|
||||
bool isModal : 1;
|
||||
bool hasFaderEffect : 1;
|
||||
|
||||
const bool autoGrabFocus : 1;
|
||||
const bool handoverFocus : 1;
|
||||
|
@ -196,6 +211,11 @@ void QskPopup::close()
|
|||
setOpen( false );
|
||||
}
|
||||
|
||||
void QskPopup::toggle()
|
||||
{
|
||||
setOpen( !isOpen() );
|
||||
}
|
||||
|
||||
void QskPopup::setOpen( bool on )
|
||||
{
|
||||
if ( on == isOpen() )
|
||||
|
@ -213,6 +233,8 @@ void QskPopup::setOpen( bool on )
|
|||
else
|
||||
Q_EMIT closed();
|
||||
|
||||
qskStartFading( this, on );
|
||||
|
||||
if ( isFading() )
|
||||
{
|
||||
Q_EMIT fadingChanged( true );
|
||||
|
@ -234,15 +256,22 @@ bool QskPopup::isOpen() const
|
|||
return !hasSkinState( QskPopup::Closed );
|
||||
}
|
||||
|
||||
QskAspect QskPopup::fadingAspect() const
|
||||
{
|
||||
return QskAspect();
|
||||
}
|
||||
|
||||
bool QskPopup::isFading() const
|
||||
{
|
||||
if ( m_data->faderAspect.value() == 0 )
|
||||
return false;
|
||||
return runningHintAnimator( fadingAspect() ) != nullptr;
|
||||
}
|
||||
|
||||
QskSkinHintStatus status;
|
||||
(void) effectiveSkinHint( m_data->faderAspect, &status );
|
||||
qreal QskPopup::fadingFactor() const
|
||||
{
|
||||
if ( auto animator = runningHintAnimator( fadingAspect() ) )
|
||||
return animator->currentValue().value< qreal >();
|
||||
|
||||
return status.source == QskSkinHintStatus::Animator;
|
||||
return isOpen() ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
QRectF QskPopup::overlayRect() const
|
||||
|
@ -293,44 +322,23 @@ void QskPopup::updateInputGrabber()
|
|||
}
|
||||
}
|
||||
|
||||
QskAspect QskPopup::faderAspect() const
|
||||
{
|
||||
return m_data->faderAspect;
|
||||
}
|
||||
|
||||
void QskPopup::setFaderAspect( QskAspect aspect )
|
||||
{
|
||||
auto faderAspect = aspect;
|
||||
faderAspect.clearStates(); // animated values are always stateless
|
||||
|
||||
if ( faderAspect == m_data->faderAspect )
|
||||
return;
|
||||
|
||||
if ( isFading() )
|
||||
{
|
||||
// stop the running animation TODO ...
|
||||
}
|
||||
|
||||
m_data->faderAspect = faderAspect;
|
||||
}
|
||||
|
||||
bool QskPopup::isTransitionAccepted( QskAspect aspect ) const
|
||||
{
|
||||
if ( isVisible() && m_data->hasFaderEffect )
|
||||
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->faderAspect )
|
||||
return true;
|
||||
|
||||
if ( aspect.isColor() )
|
||||
{
|
||||
if ( aspect.subControl() == effectiveSubcontrol( QskPopup::Overlay ) )
|
||||
return true;
|
||||
}
|
||||
if ( aspect.subControl() == effectiveSubcontrol( fadingAspect().subControl() ) )
|
||||
return true;
|
||||
|
||||
if ( aspect.subControl() == effectiveSubcontrol( QskPopup::Overlay ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return Inherited::isTransitionAccepted( aspect );
|
||||
|
@ -366,20 +374,6 @@ bool QskPopup::isModal() const
|
|||
return m_data->isModal;
|
||||
}
|
||||
|
||||
void QskPopup::setFaderEffect( bool on )
|
||||
{
|
||||
if ( on != m_data->hasFaderEffect )
|
||||
{
|
||||
m_data->hasFaderEffect = on;
|
||||
Q_EMIT faderEffectChanged( on );
|
||||
}
|
||||
}
|
||||
|
||||
bool QskPopup::hasFaderEffect() const
|
||||
{
|
||||
return m_data->hasFaderEffect;
|
||||
}
|
||||
|
||||
void QskPopup::setPopupFlags( PopupFlags flags )
|
||||
{
|
||||
const auto newFlags = static_cast< int >( flags );
|
||||
|
@ -488,10 +482,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->faderAspect ) )
|
||||
if ( ( animatorEvent->state() == QskAnimatorEvent::Terminated )
|
||||
&& ( animatorEvent->aspect() == fadingAspect() ) )
|
||||
{
|
||||
if ( !isOpen() )
|
||||
{
|
||||
|
@ -523,6 +517,17 @@ bool QskPopup::event( QEvent* event )
|
|||
return ok;
|
||||
}
|
||||
|
||||
void QskPopup::keyPressEvent( QKeyEvent* event )
|
||||
{
|
||||
if ( qskIsStandardKeyInput( event, QKeySequence::Cancel ) )
|
||||
{
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
return Inherited::keyPressEvent( event );
|
||||
}
|
||||
|
||||
void QskPopup::focusInEvent( QFocusEvent* event )
|
||||
{
|
||||
Inherited::focusInEvent( event );
|
||||
|
@ -543,7 +548,7 @@ void QskPopup::focusInEvent( QFocusEvent* event )
|
|||
|
||||
if ( auto focusItem = nextItemInFocusChain( true ) )
|
||||
{
|
||||
if ( qskIsItemComplete( focusItem )
|
||||
if ( !qskIsItemInDestructor( focusItem )
|
||||
&& qskIsAncestorOf( this, focusItem ) )
|
||||
{
|
||||
focusItem->setFocus( true );
|
||||
|
|
|
@ -14,13 +14,11 @@ class QSK_EXPORT QskPopup : public QskControl
|
|||
|
||||
Q_PROPERTY( bool open READ isOpen WRITE setOpen NOTIFY openChanged )
|
||||
Q_PROPERTY( bool modal READ isModal WRITE setModal NOTIFY modalChanged )
|
||||
Q_PROPERTY( bool fading READ isFading NOTIFY fadingChanged )
|
||||
|
||||
Q_PROPERTY( bool overlay READ hasOverlay
|
||||
WRITE setOverlay RESET resetOverlay NOTIFY overlayChanged )
|
||||
|
||||
Q_PROPERTY( bool faderEffect READ hasFaderEffect
|
||||
WRITE setFaderEffect NOTIFY faderEffectChanged )
|
||||
|
||||
Q_PROPERTY( uint priority READ priority WRITE setPriority NOTIFY priorityChanged )
|
||||
|
||||
using Inherited = QskControl;
|
||||
|
@ -58,20 +56,20 @@ class QSK_EXPORT QskPopup : public QskControl
|
|||
void setPriority( uint );
|
||||
uint priority() const;
|
||||
|
||||
void setFaderEffect( bool );
|
||||
bool hasFaderEffect() const;
|
||||
bool isOpen() const;
|
||||
bool isClosed() const;
|
||||
|
||||
QskAspect faderAspect() const;
|
||||
void setFaderAspect( QskAspect );
|
||||
bool isFading() const;
|
||||
qreal fadingFactor() const;
|
||||
virtual QskAspect fadingAspect() const;
|
||||
|
||||
virtual QRectF overlayRect() const;
|
||||
|
||||
bool isOpen() const;
|
||||
bool isFading() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void open();
|
||||
void close();
|
||||
void toggle();
|
||||
|
||||
void setOpen( bool );
|
||||
|
||||
Q_SIGNALS:
|
||||
|
@ -83,7 +81,6 @@ class QSK_EXPORT QskPopup : public QskControl
|
|||
void modalChanged( bool );
|
||||
void overlayChanged( bool );
|
||||
void priorityChanged( uint );
|
||||
void faderEffectChanged( bool );
|
||||
|
||||
protected:
|
||||
void aboutToShow() override;
|
||||
|
@ -92,6 +89,7 @@ class QSK_EXPORT QskPopup : public QskControl
|
|||
bool event( QEvent* ) override;
|
||||
void focusInEvent( QFocusEvent* ) override;
|
||||
void focusOutEvent( QFocusEvent* ) override;
|
||||
void keyPressEvent( QKeyEvent* ) override;
|
||||
void windowChangeEvent( QskWindowChangeEvent* ) override;
|
||||
|
||||
void itemChange( QQuickItem::ItemChange,
|
||||
|
@ -113,6 +111,11 @@ class QSK_EXPORT QskPopup : public QskControl
|
|||
std::unique_ptr< PrivateData > m_data;
|
||||
};
|
||||
|
||||
inline bool QskPopup::isClosed() const
|
||||
{
|
||||
return !isOpen();
|
||||
}
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( QskPopup::PopupFlags )
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,108 +5,17 @@
|
|||
|
||||
#include "QskPopupSkinlet.h"
|
||||
#include "QskPopup.h"
|
||||
#include "QskSGNode.h"
|
||||
#include "QskRgbValue.h"
|
||||
|
||||
#include <qtransform.h>
|
||||
#include <qsgnode.h>
|
||||
#include <qquickwindow.h>
|
||||
|
||||
namespace
|
||||
static inline QRgb qskInterpolatedRgb( QRgb rgb, qreal factor )
|
||||
{
|
||||
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;
|
||||
};
|
||||
return QskRgb::toTransparent( rgb, qRound( factor * qAlpha( rgb ) ) );
|
||||
}
|
||||
|
||||
QskPopupSkinlet::QskPopupSkinlet( QskSkin* skin )
|
||||
: Inherited( skin )
|
||||
{
|
||||
appendNodeRoles( { OverlayRole, ContentsRole } );
|
||||
appendNodeRoles( { OverlayRole } );
|
||||
}
|
||||
|
||||
QskPopupSkinlet::~QskPopupSkinlet() = default;
|
||||
|
@ -130,49 +39,38 @@ QSGNode* QskPopupSkinlet::updateSubNode(
|
|||
switch ( nodeRole )
|
||||
{
|
||||
case OverlayRole:
|
||||
return updateBoxNode( skinnable, node, QskPopup::Overlay );
|
||||
|
||||
case ContentsRole:
|
||||
return updateExtraNode( popup, node );
|
||||
return updateOverlayNode( popup, node );
|
||||
}
|
||||
|
||||
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
||||
}
|
||||
|
||||
QSGNode* QskPopupSkinlet::updateExtraNode( const QskPopup* popup, QSGNode* node ) const
|
||||
QSGNode* QskPopupSkinlet::updateOverlayNode(
|
||||
const QskPopup* popup, QSGNode* node ) const
|
||||
{
|
||||
auto cr = popup->contentsRect();
|
||||
if ( cr.isEmpty() )
|
||||
using Q = QskPopup;
|
||||
|
||||
const auto factor = popup->fadingFactor();
|
||||
if ( factor <= 0.0 )
|
||||
return nullptr;
|
||||
|
||||
auto rootNode = QskSGNode::ensureNode< RootNode >( node );
|
||||
const auto rect = popup->subControlRect( Q::Overlay );
|
||||
if ( rect.isEmpty() )
|
||||
return nullptr;
|
||||
|
||||
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() );
|
||||
auto gradient = popup->gradientHint( Q::Overlay );
|
||||
|
||||
rootNode->setClipRect( clipRect );
|
||||
}
|
||||
else
|
||||
if ( gradient.isVisible() && factor != 1.0 )
|
||||
{
|
||||
rootNode->resetClip();
|
||||
auto stops = gradient.stops();
|
||||
|
||||
for ( auto& stop : stops )
|
||||
stop.setRgb( qskInterpolatedRgb( stop.rgb(), factor ) );
|
||||
|
||||
gradient.setStops( stops );
|
||||
}
|
||||
|
||||
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;
|
||||
return updateBoxNode( popup, node, rect, gradient, QskPopup::Overlay );
|
||||
}
|
||||
|
||||
#include "moc_QskPopupSkinlet.cpp"
|
||||
|
|
|
@ -20,8 +20,6 @@ class QSK_EXPORT QskPopupSkinlet : public QskSkinlet
|
|||
enum NodeRole
|
||||
{
|
||||
OverlayRole,
|
||||
ContentsRole,
|
||||
|
||||
RoleCount
|
||||
};
|
||||
|
||||
|
@ -35,10 +33,7 @@ class QSK_EXPORT QskPopupSkinlet : public QskSkinlet
|
|||
QSGNode* updateSubNode( const QskSkinnable*,
|
||||
quint8 nodeRole, QSGNode* ) const override;
|
||||
|
||||
virtual QSGNode* updateContentsNode( const QskPopup*, QSGNode* ) const;
|
||||
|
||||
private:
|
||||
QSGNode* updateExtraNode( const QskPopup*, QSGNode* ) const;
|
||||
QSGNode* updateOverlayNode( const QskPopup*, QSGNode* ) const;
|
||||
};
|
||||
|
||||
|
|
|
@ -47,6 +47,21 @@ bool qskIsItemComplete( const QQuickItem* item )
|
|||
return QQuickItemPrivate::get( item )->componentComplete;
|
||||
}
|
||||
|
||||
bool qskIsItemInDestructor( const QQuickItem* item )
|
||||
{
|
||||
auto d = QQuickItemPrivate::get( item );
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK( 6, 5, 0 )
|
||||
return d->inDestructor;
|
||||
#else
|
||||
/*
|
||||
QskQuickItem sets componentComplete to false in its destructor,
|
||||
but for other items we will will return the wrong information
|
||||
*/
|
||||
return !d->componentComplete;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool qskIsAncestorOf( const QQuickItem* item, const QQuickItem* child )
|
||||
{
|
||||
if ( item == nullptr || child == nullptr )
|
||||
|
@ -356,7 +371,7 @@ QList< QQuickItem* > qskPaintOrderChildItems( const QQuickItem* item )
|
|||
return QList< QQuickItem* >();
|
||||
}
|
||||
|
||||
const QSGNode* qskItemNode( const QQuickItem* item )
|
||||
const QSGTransformNode* qskItemNode( const QQuickItem* item )
|
||||
{
|
||||
if ( item == nullptr )
|
||||
return nullptr;
|
||||
|
|
|
@ -16,6 +16,7 @@ class QskSizePolicy;
|
|||
|
||||
class QQuickItem;
|
||||
class QSGNode;
|
||||
class QSGTransformNode;
|
||||
class QRectF;
|
||||
template< typename T > class QList;
|
||||
|
||||
|
@ -24,6 +25,7 @@ template< typename T > class QList;
|
|||
of QQuickItem.
|
||||
*/
|
||||
|
||||
QSK_EXPORT bool qskIsItemInDestructor( const QQuickItem* );
|
||||
QSK_EXPORT bool qskIsItemComplete( const QQuickItem* );
|
||||
QSK_EXPORT bool qskIsAncestorOf( const QQuickItem* item, const QQuickItem* child );
|
||||
QSK_EXPORT bool qskIsTabFence( const QQuickItem* );
|
||||
|
@ -66,7 +68,7 @@ QSK_EXPORT QList< QQuickItem* > qskPaintOrderChildItems( const QQuickItem* );
|
|||
QSK_EXPORT void qskUpdateInputMethod( const QQuickItem*, Qt::InputMethodQueries );
|
||||
QSK_EXPORT void qskInputMethodSetVisible( const QQuickItem*, bool );
|
||||
|
||||
QSK_EXPORT const QSGNode* qskItemNode( const QQuickItem* );
|
||||
QSK_EXPORT const QSGTransformNode* qskItemNode( const QQuickItem* );
|
||||
QSK_EXPORT const QSGNode* qskPaintNode( const QQuickItem* );
|
||||
|
||||
QSK_EXPORT void qskItemUpdateRecursive( QQuickItem* );
|
||||
|
|
|
@ -180,6 +180,11 @@ QskQuickItem::~QskQuickItem()
|
|||
We set componentComplete to false, so that operations
|
||||
that are triggered by detaching the item from its parent
|
||||
can be aware of the about-to-delete state.
|
||||
|
||||
Note, that since Qt >= 6.5 this information is stored
|
||||
in QQuickItemPrivate::inDestructor.
|
||||
|
||||
s.a: qskIsItemInDestructor
|
||||
*/
|
||||
d_func()->componentComplete = false;
|
||||
|
||||
|
|
|
@ -136,15 +136,15 @@ namespace
|
|||
setOrientations( Qt::Horizontal | Qt::Vertical );
|
||||
}
|
||||
|
||||
QRectF gestureRect() const override
|
||||
bool isAcceptedPos( const QPointF& pos ) const override
|
||||
{
|
||||
if ( auto scrollBox = qobject_cast< const QskScrollBox* >( watchedItem() ) )
|
||||
{
|
||||
if ( qskIsScrollable( scrollBox, orientations() ) )
|
||||
return scrollBox->viewContentsRect();
|
||||
return scrollBox->viewContentsRect().contains( pos );
|
||||
}
|
||||
|
||||
return QRectF( 0.0, 0.0, -1.0, -1.0 ); // empty
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
#include "QskComboBox.h"
|
||||
#include "QskComboBoxSkinlet.h"
|
||||
|
||||
#include "QskDrawer.h"
|
||||
#include "QskDrawerSkinlet.h"
|
||||
|
||||
#include "QskFocusIndicator.h"
|
||||
#include "QskFocusIndicatorSkinlet.h"
|
||||
|
||||
|
@ -160,6 +163,7 @@ QskSkin::QskSkin( QObject* parent )
|
|||
declareSkinlet< QskBox, QskBoxSkinlet >();
|
||||
declareSkinlet< QskCheckBox, QskCheckBoxSkinlet >();
|
||||
declareSkinlet< QskComboBox, QskComboBoxSkinlet >();
|
||||
declareSkinlet< QskDrawer, QskDrawerSkinlet >();
|
||||
declareSkinlet< QskFocusIndicator, QskFocusIndicatorSkinlet >();
|
||||
declareSkinlet< QskGraphicLabel, QskGraphicLabelSkinlet >();
|
||||
declareSkinlet< QskListView, QskListViewSkinlet >();
|
||||
|
|
|
@ -121,7 +121,7 @@ namespace
|
|||
scheme = Qt::ColorScheme::Unknown;
|
||||
}
|
||||
|
||||
const auto systemScheme = qGuiApp->styleHints()->colorScheme();
|
||||
const auto systemScheme = QGuiApplication::styleHints()->colorScheme();
|
||||
|
||||
if( scheme == systemScheme )
|
||||
{
|
||||
|
|
|
@ -988,6 +988,23 @@ bool QskSkinnable::moveSkinHint( QskAspect aspect, const QVariant& value )
|
|||
return moveSkinHint( aspect, effectiveSkinHint( aspect ), value );
|
||||
}
|
||||
|
||||
const QskHintAnimator* QskSkinnable::runningHintAnimator(
|
||||
QskAspect aspect, int index ) const
|
||||
{
|
||||
const auto& animators = m_data->animators;
|
||||
|
||||
if ( animators.isEmpty() )
|
||||
return nullptr;
|
||||
|
||||
aspect = qskAnimatorAspect( aspect );
|
||||
|
||||
auto animator = animators.animator( aspect, index );
|
||||
if ( animator == nullptr && index >= 0 )
|
||||
animator = animators.animator( aspect, -1 );
|
||||
|
||||
return animator;
|
||||
}
|
||||
|
||||
QVariant QskSkinnable::animatedHint(
|
||||
QskAspect aspect, QskSkinHintStatus* status ) const
|
||||
{
|
||||
|
@ -1259,13 +1276,19 @@ bool QskSkinnable::isTransitionAccepted( QskAspect aspect ) const
|
|||
{
|
||||
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() ) )
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ class QQuickItem;
|
|||
class QskArcMetrics;
|
||||
class QskControl;
|
||||
class QskAnimationHint;
|
||||
class QskHintAnimator;
|
||||
class QskColorFilter;
|
||||
class QskBoxShapeMetrics;
|
||||
class QskBoxBorderMetrics;
|
||||
|
@ -262,6 +263,8 @@ class QSK_EXPORT QskSkinnable
|
|||
bool startHintTransitions( const QVector< QskAspect::Subcontrol >&,
|
||||
QskAspect::States, QskAspect::States, int index = -1 );
|
||||
|
||||
const QskHintAnimator* runningHintAnimator( QskAspect, int index = -1 ) const;
|
||||
|
||||
protected:
|
||||
virtual void updateNode( QSGNode* );
|
||||
virtual bool isTransitionAccepted( QskAspect ) const;
|
||||
|
|
|
@ -253,4 +253,15 @@ void QskSubWindow::itemChange( QQuickItem::ItemChange change,
|
|||
}
|
||||
}
|
||||
|
||||
void QskSubWindow::updateResources()
|
||||
{
|
||||
setOpacity( fadingFactor() );
|
||||
Inherited::updateResources();
|
||||
}
|
||||
|
||||
QskAspect QskSubWindow::fadingAspect() const
|
||||
{
|
||||
return QskSubWindow::Panel | QskAspect::Position;
|
||||
}
|
||||
|
||||
#include "moc_QskSubWindow.cpp"
|
||||
|
|
|
@ -83,6 +83,7 @@ class QSK_EXPORT QskSubWindow : public QskPopup
|
|||
QRectF titleBarRect() const;
|
||||
|
||||
QRectF layoutRectForSize( const QSizeF& ) const override;
|
||||
QskAspect fadingAspect() const override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void decorationsChanged( Decorations );
|
||||
|
@ -95,6 +96,8 @@ class QSK_EXPORT QskSubWindow : public QskPopup
|
|||
bool event( QEvent* ) override;
|
||||
|
||||
void updateLayout() override;
|
||||
void updateResources() override;
|
||||
|
||||
QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override;
|
||||
|
||||
void itemChange( QQuickItem::ItemChange,
|
||||
|
|
|
@ -94,6 +94,18 @@ QSGNode* QskSubWindowSkinlet::updateSubNode(
|
|||
|
||||
return nullptr;
|
||||
}
|
||||
case OverlayRole:
|
||||
{
|
||||
/*
|
||||
Overloading QskPopupSkinlet: as the opacity of the subwindow already
|
||||
depends on the fadingFactor we do not want the additional opacity
|
||||
adjustments for the overlay node.
|
||||
Maybe we should have a flag that indicates if the popup does
|
||||
opacity or geometry transitions, when fading TODO ...
|
||||
*/
|
||||
updateBoxNode( subWindow, node, Q::Overlay );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
||||
|
|
|
@ -424,8 +424,18 @@ void QskWindow::exposeEvent( QExposeEvent* event )
|
|||
|
||||
void QskWindow::resizeEvent( QResizeEvent* event )
|
||||
{
|
||||
auto rootItem = contentItem();
|
||||
|
||||
const auto oldRect = qskItemGeometry( rootItem );
|
||||
Inherited::resizeEvent( event );
|
||||
|
||||
const auto newRect = qskItemGeometry( rootItem );
|
||||
if ( newRect != oldRect )
|
||||
{
|
||||
QskGeometryChangeEvent event( newRect, oldRect );
|
||||
QCoreApplication::sendEvent( rootItem, &event );
|
||||
}
|
||||
|
||||
if ( isExposed() )
|
||||
layoutItems();
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ static void qskSetupSubWindow(
|
|||
const QString& title, QskDialog::Actions actions,
|
||||
QskDialog::Action defaultAction, QskDialogSubWindow* subWindow )
|
||||
{
|
||||
subWindow->setPopupFlag( QskPopup::DeleteOnClose );
|
||||
subWindow->setModal( true );
|
||||
subWindow->setWindowTitle( title );
|
||||
subWindow->setDialogActions( actions );
|
||||
|
@ -128,14 +129,14 @@ static QskDialog::Action qskMessageSubWindow(
|
|||
const QString& text, int symbolType, QskDialog::Actions actions,
|
||||
QskDialog::Action defaultAction )
|
||||
{
|
||||
QskMessageSubWindow subWindow( window->contentItem() );
|
||||
subWindow.setSymbolType( symbolType );
|
||||
subWindow.setText( text );
|
||||
auto subWindow = new QskMessageSubWindow( window->contentItem() );
|
||||
subWindow->setSymbolType( symbolType );
|
||||
subWindow->setText( text );
|
||||
|
||||
qskSetupSubWindow( title, actions, defaultAction, &subWindow );
|
||||
( void ) subWindow.exec();
|
||||
qskSetupSubWindow( title, actions, defaultAction, subWindow );
|
||||
( void ) subWindow->exec();
|
||||
|
||||
auto clickedAction = subWindow.clickedAction();
|
||||
auto clickedAction = subWindow->clickedAction();
|
||||
if ( clickedAction == QskDialog::NoAction )
|
||||
{
|
||||
// dialog might have been closed by the window menu
|
||||
|
@ -172,16 +173,16 @@ static QString qskSelectSubWindow(
|
|||
QskDialog::Actions actions, QskDialog::Action defaultAction,
|
||||
const QStringList& entries, int selectedRow )
|
||||
{
|
||||
QskSelectionSubWindow subWindow( window->contentItem() );
|
||||
subWindow.setInfoText( text );
|
||||
subWindow.setEntries( entries );
|
||||
subWindow.setSelectedRow( selectedRow );
|
||||
auto subWindow = new QskSelectionSubWindow( window->contentItem() );
|
||||
subWindow->setInfoText( text );
|
||||
subWindow->setEntries( entries );
|
||||
subWindow->setSelectedRow( selectedRow );
|
||||
|
||||
QString selectedEntry;
|
||||
|
||||
qskSetupSubWindow( title, actions, defaultAction, &subWindow );
|
||||
if ( subWindow.exec() == QskDialog::Accepted )
|
||||
selectedEntry = subWindow.selectedEntry();
|
||||
qskSetupSubWindow( title, actions, defaultAction, subWindow );
|
||||
if ( subWindow->exec() == QskDialog::Accepted )
|
||||
selectedEntry = subWindow->selectedEntry();
|
||||
|
||||
return selectedEntry;
|
||||
}
|
||||
|
|
|
@ -278,15 +278,10 @@ void QskDialogSubWindow::keyPressEvent( QKeyEvent* event )
|
|||
{
|
||||
auto button = m_data->buttonBox->defaultButton();
|
||||
if ( button && button->isEnabled() )
|
||||
{
|
||||
button->click();
|
||||
}
|
||||
|
||||
if ( qskIsStandardKeyInput( event, QKeySequence::Cancel ) )
|
||||
{
|
||||
// using shortcuts instead ???
|
||||
|
||||
reject();
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Inherited::keyPressEvent( event );
|
||||
|
|
Loading…
Reference in New Issue