Merge branch 'master' into features/menubutton

This commit is contained in:
Uwe Rathmann 2023-09-27 11:17:07 +02:00
commit b273264629
57 changed files with 1771 additions and 687 deletions

View File

@ -108,6 +108,6 @@ SpacesInSquareBrackets: true
Standard: Cpp11
TabWidth: 4
UseTab: Never
UseCRLF: Always
UseCRLF: true
...

View File

@ -4,13 +4,18 @@
*****************************************************************************/
#include "ProgressBarPage.h"
#include <QskProgressBar.h>
#include <QskAnimator.h>
#include <QskGraphicProvider.h>
#include <QskGraphic.h>
#include <QskGradient.h>
#include <QskHctColor.h>
#include <QskProgressBar.h>
#include <QskProgressRing.h>
#include <QskRgbValue.h>
#include <QQuickWindow>
namespace
{
class ProgressBar : public QskProgressBar
@ -35,9 +40,32 @@ namespace
colors += hctColor.toned( 45 ).rgb();
colors += hctColor.toned( 30 ).rgb();
setBarGradient( qskBuildGradientStops( colors, true ) );
setFillGradient( qskBuildGradientStops( colors, true ) );
}
};
class DeterminateIndicatorsAnimator : public QskAnimator
{
public:
DeterminateIndicatorsAnimator( const QVector< QskProgressIndicator* >& indicators )
: QskAnimator()
, m_indicators( indicators )
{
setAutoRepeat( true );
setDuration( 3000 );
}
void advance( qreal value ) override
{
for( auto* indicator : m_indicators )
{
indicator->setValueAsRatio( value );
}
}
private:
const QVector< QskProgressIndicator* > m_indicators;
};
}
ProgressBarPage::ProgressBarPage( QQuickItem* parent )
@ -53,10 +81,7 @@ void ProgressBarPage::populate()
hBox->setSizePolicy( Qt::Horizontal, QskSizePolicy::Fixed );
hBox->setSpacing( 20 );
{
auto bar = new ProgressBar( hBox );
bar->setValue( 35 );
}
QVector< QskProgressIndicator* > determinateIndicators;
{
auto bar = new ProgressBar( hBox );
@ -77,6 +102,11 @@ void ProgressBarPage::populate()
bar->setValue( 25 );
}
{
auto bar = new ProgressBar( hBox );
determinateIndicators.append( bar );
}
{
auto bar = new ProgressBar( hBox );
bar->setIndeterminate( true );
@ -106,8 +136,55 @@ void ProgressBarPage::populate()
bar->setValue( 10 );
}
{
auto bar = new ProgressBar( vBox );
determinateIndicators.append( bar );
}
{
auto bar = new ProgressBar( vBox );
bar->setIndeterminate( true );
}
const auto sizes = { QskProgressRing::SmallSize, QskProgressRing::NormalSize,
QskProgressRing::LargeSize };
auto determinateRingsHBox = new QskLinearBox( Qt::Horizontal, vBox );
auto indeterminateRingsHBox = new QskLinearBox( Qt::Horizontal, vBox );
for( const auto size : sizes )
{
for( const auto indeterminate : { true, false } )
{
auto* ring = new QskProgressRing( determinateRingsHBox );
ring->setSize( size );
QQuickItem* parentItem;
if( indeterminate )
{
parentItem = indeterminateRingsHBox;
ring->setIndeterminate( true );
}
else
{
parentItem = determinateRingsHBox;
determinateIndicators.append( ring );
}
ring->setParent( parentItem );
ring->setParentItem( parentItem );
}
}
connect( this, &QskQuickItem::windowChanged, this, [this, determinateIndicators]( QQuickWindow* window )
{
if( window )
{
m_determinateIndicatorsAnimator.reset( new DeterminateIndicatorsAnimator( determinateIndicators ) );
m_determinateIndicatorsAnimator->setWindow( window );
m_determinateIndicatorsAnimator->start();
}
} );
}

View File

@ -7,6 +7,8 @@
#include "Page.h"
class QskAnimator;
class ProgressBarPage : public Page
{
public:
@ -14,4 +16,6 @@ class ProgressBarPage : public Page
private:
void populate();
std::unique_ptr< QskAnimator > m_determinateIndicatorsAnimator;
};

View File

@ -193,35 +193,6 @@ void Cube::switchToPosition( const Position position )
doSwitch( direction, nextPosition );
}
void Cube::keyPressEvent( QKeyEvent* event )
{
Qsk::Direction direction;
switch( event->key() )
{
case Qt::Key_Up:
direction = Qsk::TopToBottom;
break;
case Qt::Key_Down:
direction = Qsk::BottomToTop;
break;
case Qt::Key_Left:
direction = Qsk::LeftToRight;
break;
case Qt::Key_Right:
direction = Qsk::RightToLeft;
break;
default:
return;
}
switchPosition( direction );
}
Cube::Position Cube::currentPosition() const
{
return static_cast< Position >( currentIndex() );
@ -304,8 +275,6 @@ MainItem::MainItem( QQuickItem* parent )
// the current item needs to be the one at the Front:
m_cube->setCurrentItem( dashboardPage );
installEventFilter( this );
}
void MainItem::gestureEvent( QskGestureEvent* event )
@ -332,33 +301,48 @@ void MainItem::gestureEvent( QskGestureEvent* event )
}
}
bool MainItem::eventFilter( QObject* object, QEvent* event )
void MainItem::keyPressEvent( QKeyEvent* event )
{
if ( event->type() == QEvent::KeyPress )
{
QCoreApplication::sendEvent( m_cube, event );
return true;
}
else
{
return QObject::eventFilter( object, event );
}
}
// maybe using shortcuts ?
bool MainItem::gestureFilter( QQuickItem* item, QEvent* event )
Qsk::Direction direction;
switch( event->key() )
{
case Qt::Key_Up:
direction = Qsk::TopToBottom;
break;
case Qt::Key_Down:
direction = Qsk::BottomToTop;
break;
case Qt::Key_Left:
direction = Qsk::LeftToRight;
break;
case Qt::Key_Right:
direction = Qsk::RightToLeft;
break;
default:
return;
}
m_cube->switchPosition( direction );
}
bool MainItem::gestureFilter( const QQuickItem* item, const QEvent* event )
{
auto& recognizer = m_panRecognizer;
if( event->type() == QEvent::MouseButtonPress )
{
const auto mouseEvent = static_cast< QMouseEvent* >( event );
auto mouseEvent = static_cast< const QMouseEvent* >( event );
if( ( item != this ) || ( recognizer.timeout() < 0 ) )
{
if( recognizer.hasProcessedBefore( mouseEvent ) )
{
return false;
}
}
recognizer.setTimeout( ( item == this ) ? -1 : 100 );

View File

@ -40,22 +40,19 @@ class Cube : public QskStackBox
explicit Cube( QQuickItem* parent = nullptr );
public Q_SLOTS:
void switchPosition( const Qsk::Direction direction );
void switchToPosition( const Cube::Position position );
void switchPosition( const Qsk::Direction );
void switchToPosition( const Cube::Position );
Q_SIGNALS:
// might be different from indexChanged:
void cubeIndexChanged( const int index );
protected:
void keyPressEvent( QKeyEvent* event ) override;
private:
Position currentPosition() const;
Position neighbor( const Position position, const Qsk::Direction direction ) const;
Position neighbor( const Position, const Qsk::Direction ) const;
Qsk::Direction direction( const Position from, const Position to ) const;
void updateEdge( Qsk::Direction direction, Position position );
void doSwitch( Qsk::Direction direction, Position position );
void updateEdge( Qsk::Direction, Position );
void doSwitch( Qsk::Direction, Position );
Position m_destination;
Edge m_currentEdge;
@ -73,8 +70,9 @@ class MainItem : public QskControl
MainItem( QQuickItem* parent = nullptr );
protected:
bool eventFilter(QObject* obj, QEvent* event) override final;
bool gestureFilter( QQuickItem*, QEvent* ) override final;
void keyPressEvent( QKeyEvent* ) override final;
bool gestureFilter( const QQuickItem*, const QEvent* ) override final;
void gestureEvent( QskGestureEvent* ) override final;
private:

View File

@ -33,7 +33,6 @@
#include <QskBoxShapeMetrics.h>
#include <QskColorFilter.h>
#include <QskFunctions.h>
#include <QskProgressBar.h>
#include <QskShadowMetrics.h>
#include <QskSkinHintTableEditor.h>
#include <QskStateCombination.h>

View File

@ -5,9 +5,6 @@
#include "StoragePage.h"
#include "Box.h"
#include "CircularProgressBar.h"
#include "Diagram.h"
#include "EnergyMeter.h"
#include "StorageBar.h"
#include "StorageMeter.h"
#include <QTimer>
@ -17,7 +14,6 @@
#include <QskGradient.h>
#include <QskGradientStop.h>
#include <QskGraphicLabel.h>
#include <QskProgressBar.h>
#include <QskPushButton.h>
#include <QskSkin.h>
#include <QskStackBox.h>

View File

@ -11,6 +11,7 @@ set(SOURCES
LinearLayoutPage.h LinearLayoutPage.cpp
DynamicConstraintsPage.h DynamicConstraintsPage.cpp
StackLayoutPage.h StackLayoutPage.cpp
SwipeViewPage.h SwipeViewPage.cpp
main.cpp
)
qt_add_resources(SOURCES layouts.qrc)

View File

@ -101,7 +101,7 @@ namespace
void incrementScrolling( Qt::Orientation orientation, int offset )
{
auto animator = dynamic_cast< QskStackBoxAnimator1* >( this->animator() );
auto animator = qobject_cast< QskStackBoxAnimator1* >( this->animator() );
if ( animator == nullptr )
{
@ -109,7 +109,11 @@ namespace
animator->setDuration( 1000 );
}
animator->setOrientation( orientation );
if ( orientation == Qt::Horizontal )
animator->setDirection( offset > 0 ? Qsk::LeftToRight : Qsk::RightToLeft );
else
animator->setDirection( offset > 0 ? Qsk::TopToBottom : Qsk::BottomToTop );
setAnimator( animator );
setCurrentIndex( incrementedIndex( offset ) );

View File

@ -0,0 +1,62 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "SwipeViewPage.h"
#include "TestRectangle.h"
#include <QskRgbValue.h>
#include <QskSwipeView.h>
namespace
{
class SwipeView : public QskSwipeView
{
Q_OBJECT
public:
SwipeView( QQuickItem* parent = nullptr )
: QskSwipeView( parent )
{
setObjectName( "SwipeView" );
setBackgroundColor( Qt::white );
setDefaultAlignment( Qt::AlignCenter );
setOrientation( Qt::Horizontal );
addRectangle( "Gold" );
addRectangle( "SeaGreen" );
addRectangle( "SlateBlue" );
addRectangle( "Peru" );
for ( int i = 0; i < itemCount(); i += 2 )
{
if ( auto control = qskControlCast( itemAtIndex( i ) ) )
control->setFixedSize( 200, 200 );
}
}
private:
void addRectangle( const char* colorName )
{
auto rect = new TestRectangle( colorName );
rect->setText( QString::number( itemCount() + 1 ) );
addItem( rect );
}
};
}
SwipeViewPage::SwipeViewPage( QQuickItem* parent )
: QskLinearBox( Qt::Vertical, parent )
{
setObjectName( "SwipeViewPage" );
setMargins( 10 );
setBackgroundColor( QskRgb::LightSteelBlue );
auto swipeView = new SwipeView();
addItem( swipeView );
}
#include "SwipeViewPage.moc"

View File

@ -0,0 +1,14 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskLinearBox.h>
class SwipeViewPage : public QskLinearBox
{
public:
SwipeViewPage( QQuickItem* parent = nullptr );
};

View File

@ -8,6 +8,7 @@
#include "LinearLayoutPage.h"
#include "GridLayoutPage.h"
#include "StackLayoutPage.h"
#include "SwipeViewPage.h"
#include "TestRectangle.h"
#include <SkinnyShortcut.h>
@ -37,7 +38,8 @@ namespace
addTab( "Linear Layout", new LinearLayoutPage() );
addTab( "Dynamic\nConstraints", new DynamicConstraintsPage() );
addTab( "Stack Layout", new StackLayoutPage() );
addTab( "Swipe View", new SwipeViewPage() );
setCurrentIndex( 0 );
}
};

View File

@ -79,6 +79,17 @@ class Thumbnail : public QskPushButton
setStrutSizeHint( QskPushButton::Icon, -1, -1 );
}
#if 0
void mousePressEvent( QMouseEvent* event ) override
{
/*
rgnore events: to check if the pae gesture recoognizer of the scroll
area becomes active without timeout ( see QskScrollBox::mousePressEvent )
*/
event->setAccepted( false );
}
#endif
private:
QskGraphic thumbnailGraphic( const QColor& color,
int shape, const QSizeF& size ) const

View File

@ -105,6 +105,6 @@ inline void ChartSample::setSample(
#ifndef QT_NO_DEBUG_STREAM
class QDebug;
QSK_EXPORT QDebug operator<<( QDebug, const ChartSample& );
QDebug operator<<( QDebug, const ChartSample& );
#endif

View File

@ -33,6 +33,7 @@
#include <QskPlacementPolicy.h>
#include <QskPopup.h>
#include <QskProgressBar.h>
#include <QskProgressRing.h>
#include <QskPushButton.h>
#include <QskRadioBox.h>
#include <QskScrollArea.h>
@ -220,6 +221,7 @@ void QskQml::registerTypes()
registerObject< QskFocusIndicator >();
registerObject< QskSeparator >();
registerObject< QskProgressBar >();
registerObject< QskProgressRing >();
registerObject< QskPushButton >();
registerObject< QskScrollView >();
registerObject< QskScrollArea >();

View File

@ -73,6 +73,7 @@
#include <QskCheckBox.h>
#include <QskComboBox.h>
#include <QskDialogButtonBox.h>
#include <QskDrawer.h>
#include <QskFocusIndicator.h>
#include <QskGraphicLabel.h>
#include <QskListView.h>
@ -80,6 +81,7 @@
#include <QskPageIndicator.h>
#include <QskPushButton.h>
#include <QskProgressBar.h>
#include <QskProgressRing.h>
#include <QskRadioBox.h>
#include <QskScrollView.h>
#include <QskSegmentedBar.h>
@ -194,6 +196,9 @@ namespace
void setupDialogButtonBoxMetrics();
void setupDialogButtonBoxColors( QskAspect::Section, const QskFluent2Theme& );
void setupDrawerMetrics();
void setupDrawerColors( QskAspect::Section, const QskFluent2Theme& );
void setupFocusIndicatorMetrics();
void setupFocusIndicatorColors( QskAspect::Section, const QskFluent2Theme& );
@ -212,6 +217,9 @@ namespace
void setupProgressBarMetrics();
void setupProgressBarColors( QskAspect::Section, const QskFluent2Theme& );
void setupProgressRingMetrics();
void setupProgressRingColors( QskAspect::Section, const QskFluent2Theme& );
void setupPushButtonMetrics();
void setupPushButtonColors( QskAspect::Section, const QskFluent2Theme& );
@ -285,12 +293,14 @@ void Editor::setupMetrics()
setupCheckBoxMetrics();
setupComboBoxMetrics();
setupDialogButtonBoxMetrics();
setupDrawerMetrics();
setupFocusIndicatorMetrics();
setupGraphicLabelMetrics();
setupListViewMetrics();
setupMenuMetrics();
setupPageIndicatorMetrics();
setupProgressBarMetrics();
setupProgressRingMetrics();
setupPushButtonMetrics();
setupRadioBoxMetrics();
setupScrollViewMetrics();
@ -320,6 +330,7 @@ void Editor::setupColors( QskAspect::Section section, const QskFluent2Theme& the
setupCheckBoxColors( section, theme );
setupComboBoxColors( section, theme );
setupDialogButtonBoxColors( section, theme );
setupDrawerColors( section, theme );
setupFocusIndicatorColors( section, theme );
setupGraphicLabelColors( section, theme );
setupGraphicLabelMetrics();
@ -327,6 +338,7 @@ void Editor::setupColors( QskAspect::Section section, const QskFluent2Theme& the
setupMenuColors( section, theme );
setupPageIndicatorColors( section, theme );
setupProgressBarColors( section, theme );
setupProgressRingColors( section, theme );
setupPushButtonColors( section, theme );
setupRadioBoxColors( section, theme );
setupScrollViewColors( section, theme );
@ -591,6 +603,26 @@ void Editor::setupDialogButtonBoxColors(
theme.palette.background.solid.base );
}
void Editor::setupDrawerMetrics()
{
using Q = QskDrawer;
setPadding( Q::Panel, 5 );
setHint( Q::Overlay | QskAspect::Style, false );
#if 1
setAnimation( Q::Panel | QskAspect::Position, 200 );
#endif
}
void Editor::setupDrawerColors(
QskAspect::Section section, const QskFluent2Theme& theme )
{
using Q = QskDrawer;
setGradient( Q::Panel | section, theme.palette.background.solid.base );
}
void Editor::setupFocusIndicatorMetrics()
{
using Q = QskFocusIndicator;
@ -612,8 +644,10 @@ void Editor::setupFocusIndicatorColors(
void Editor::setupListViewMetrics()
{
using Q = QskListView;
using A = QskAspect;
setBoxBorderMetrics( Q::Cell | Q::Selected, { 3, 0, 0, 0 } );
for ( auto state : { A::NoState, Q::Hovered, Q::Pressed } )
setBoxBorderMetrics( Q::Cell | state | Q::Selected, { 3, 0, 0, 0 } );
#if 1
// taken from M3 - what are the actual values, TODO ...
setPadding( Q::Cell, { 16, 12, 16, 12 } );
@ -637,7 +671,7 @@ void Editor::setupListViewColors(
textColor = pal.fillColor.text.disabled;
indicatorColor = pal.fillColor.accent.disabled;
}
if ( state1 == Q::Pressed )
else if ( state1 == Q::Pressed )
{
textColor = pal.fillColor.text.secondary;
indicatorColor = pal.fillColor.accent.defaultColor;
@ -673,7 +707,7 @@ void Editor::setupListViewColors(
const auto text = Q::Text | section | state1 | state2;
setGradient( cell, cellColor );
{
/*
We are using a section of the left border to display a
@ -693,6 +727,9 @@ void Editor::setupListViewColors(
setColor( text, textColor );
}
}
setAnimation( Q::Cell | A::Color, 100 );
setAnimation( Q::Text | A::Color, 100 );
}
void Editor::setupMenuMetrics()
@ -834,8 +871,8 @@ void Editor::setupProgressBarMetrics()
setMetric( Q::Groove | A::Size, 1 );
setBoxShape( Q::Groove, 100, Qt::RelativeSize );
setMetric( Q::Bar | A::Size, 3 );
setBoxShape( Q::Bar, 100, Qt::RelativeSize );
setMetric( Q::Fill | A::Size, 3 );
setBoxShape( Q::Fill, 100, Qt::RelativeSize );
}
void Editor::setupProgressBarColors(
@ -846,7 +883,36 @@ void Editor::setupProgressBarColors(
const auto& pal = theme.palette;
setGradient( Q::Groove | section, pal.strokeColor.controlStrong.defaultColor );
setGradient( Q::Bar | section, pal.fillColor.accent.defaultColor );
setGradient( Q::Fill | section, pal.fillColor.accent.defaultColor );
}
void Editor::setupProgressRingMetrics()
{
using Q = QskProgressRing;
using A = QskAspect;
static constexpr QskAspect::Variation SmallSize = A::Small;
static constexpr QskAspect::Variation NormalSize = A::NoVariation;
static constexpr QskAspect::Variation LargeSize = A::Large;
setStrutSize( Q::Fill | SmallSize, { 16, 16 } );
setStrutSize( Q::Fill | NormalSize, { 32, 32 } );
setStrutSize( Q::Fill | LargeSize, { 64, 64 } );
const auto startAngle = 90, spanAngle = -360;
setArcMetrics( Q::Fill | SmallSize, startAngle, spanAngle, 1.5 );
setArcMetrics( Q::Fill | NormalSize, startAngle, spanAngle, 3 );
setArcMetrics( Q::Fill | LargeSize, startAngle, spanAngle, 6 );
}
void Editor::setupProgressRingColors(
QskAspect::Section section, const QskFluent2Theme& theme )
{
using Q = QskProgressRing;
const auto& pal = theme.palette;
setGradient( Q::Fill | section, pal.fillColor.accent.defaultColor );
}
void Editor::setupPushButtonMetrics()

View File

@ -23,6 +23,7 @@
#include <QskPageIndicator.h>
#include <QskPushButton.h>
#include <QskProgressBar.h>
#include <QskProgressRing.h>
#include <QskRadioBox.h>
#include <QskScrollView.h>
#include <QskSegmentedBar.h>
@ -94,6 +95,7 @@ namespace
void setupPageIndicator();
void setupPopup();
void setupProgressBar();
void setupProgressRing();
void setupRadioBox();
void setupPushButton();
void setupScrollView();
@ -161,6 +163,7 @@ void Editor::setup()
setupPageIndicator();
setupPopup();
setupProgressBar();
setupProgressRing();
setupPushButton();
setupRadioBox();
setupScrollView();
@ -431,9 +434,9 @@ void Editor::setupProgressBar()
using A = QskAspect;
using Q = QskProgressBar;
auto size = 5_dp;
auto size = 4_dp;
for ( auto subControl : { Q::Groove, Q::Bar } )
for ( auto subControl : { Q::Groove, Q::Fill } )
{
setMetric( subControl | A::Size, size );
setPadding( subControl, 0 );
@ -443,12 +446,21 @@ void Editor::setupProgressBar()
}
setMetric( Q::Groove | A::Size, size );
setGradient( Q::Groove, m_pal.primaryContainer );
setGradient( Q::Groove, m_pal.surfaceContainerHighest );
setGradient( Q::Groove | Q::Disabled, m_pal.onSurface12 );
setGradient( Q::Bar, m_pal.primary );
setGradient( Q::Bar | Q::Disabled, m_pal.onSurface38 );
setGradient( Q::Fill, m_pal.primary );
setGradient( Q::Fill | Q::Disabled, m_pal.onSurface38 );
}
void Editor::setupProgressRing()
{
using Q = QskProgressRing;
setStrutSize( Q::Fill, { 48_dp, 48_dp } );
setGradient( Q::Fill, m_pal.primary );
setArcMetrics( Q::Fill, 90, -360, 4_dp );
}
void Editor::setupRadioBox()
@ -538,7 +550,7 @@ void Editor::setupSegmentedBar()
setGradient( Q::Segment | Q::Selected | Q::Hovered,
flattenedColor( m_pal.onSurface, m_pal.secondaryContainer, m_pal.hoverOpacity ) );
setGradient( Q::Segment | Q::Selected | Q::Focused,
flattenedColor( m_pal.onSurface, m_pal.secondaryContainer, m_pal.focusOpacity ) );
@ -800,8 +812,9 @@ void Editor::setupDrawer()
setPadding( Q::Panel, 5_dp );
setGradient( Q::Panel, m_pal.background );
setAnimation( Q::Panel | QskAspect::Position, qskDuration );
setHint( Q::Overlay | QskAspect::Style, false );
setAnimation( Q::Panel | QskAspect::Position, qskDuration );
}
void Editor::setupSlider()
@ -1151,15 +1164,71 @@ void Editor::setupScrollView()
void Editor::setupListView()
{
using Q = QskListView;
using A = QskAspect;
setStrutSize( Q::Cell, { -1, 56 } );
setPadding( Q::Cell, { 16_dp, 12_dp, 16_dp, 12_dp } );
setStrutSize( Q::Cell, { -1, 56_dp } );
setPadding( Q::Cell, { 16_dp, 8_dp, 24_dp, 8_dp } );
setBoxBorderColors( Q::Cell, m_pal.outline );
setGradient( Q::Cell, m_pal.surface );
setGradient( Q::Cell | Q::Selected, m_pal.primary12 );
for ( const auto state1 : { A::NoState, Q::Hovered, Q::Focused, Q::Pressed, Q::Disabled } )
{
for ( const auto state2 : { A::NoState, Q::Selected } )
{
QRgb cellColor;
if ( state2 == A::NoState )
{
if ( state1 == Q::Hovered )
{
cellColor = flattenedColor( m_pal.onSurface,
m_pal.surface, m_pal.hoverOpacity );
}
else if ( state1 == Q::Pressed )
{
cellColor = flattenedColor( m_pal.onSurface,
m_pal.primary12, m_pal.pressedOpacity );
}
else
{
cellColor = m_pal.surface;
}
}
else
{
if ( state1 == Q::Hovered )
{
cellColor = flattenedColor( m_pal.onSurface,
m_pal.primary12, m_pal.focusOpacity );
}
else if ( state1 == Q::Focused )
{
cellColor = flattenedColor( m_pal.onSurface,
m_pal.primary12, m_pal.focusOpacity );
}
else if ( state1 == Q::Disabled )
{
cellColor = m_pal.surfaceVariant;
}
else
{
cellColor = m_pal.primary12;
}
}
setGradient( Q::Cell | state1 | state2, cellColor );
}
}
setFontRole( Q::Text, QskMaterial3Skin::M3BodyMedium );
setColor( Q::Text, m_pal.onSurface );
setColor( Q::Text | Q::Disabled, m_pal.onSurface38 );
#if 1
setAnimation( Q::Cell | A::Color, 100 );
setAnimation( Q::Text | A::Color, 100 );
#endif
}
void Editor::setupSubWindow()
@ -1246,6 +1315,8 @@ QskMaterial3Theme::QskMaterial3Theme( QskSkin::ColorScheme colorScheme,
outline = m_palettes[ NeutralVariant ].toned( 50 ).rgb();
outlineVariant = m_palettes[ NeutralVariant ].toned( 80 ).rgb();
surfaceContainerHighest = m_palettes[ NeutralVariant ].toned( 90 ).rgb();
shadow = m_palettes[ Neutral ].toned( 0 ).rgb();
}
else if ( colorScheme == QskSkin::DarkScheme )
@ -1280,6 +1351,8 @@ QskMaterial3Theme::QskMaterial3Theme( QskSkin::ColorScheme colorScheme,
outline = m_palettes[ NeutralVariant ].toned( 60 ).rgb();
outlineVariant = m_palettes[ NeutralVariant ].toned( 30 ).rgb();
surfaceContainerHighest = m_palettes[ NeutralVariant ].toned( 22 ).rgb();
shadow = m_palettes[ Neutral ].toned( 0 ).rgb();
}

View File

@ -79,6 +79,8 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Theme
QRgb outline;
QRgb outlineVariant;
QRgb surfaceContainerHighest;
QRgb shadow;
QskShadowMetrics elevation0;

View File

@ -20,6 +20,7 @@
#include <QskPageIndicator.h>
#include <QskPopup.h>
#include <QskProgressBar.h>
#include <QskProgressRing.h>
#include <QskPushButton.h>
#include <QskRadioBox.h>
#include <QskScrollView.h>
@ -162,6 +163,7 @@ namespace
void setupPageIndicator();
void setupPopup();
void setupProgressBar();
void setupProgressRing();
void setupPushButton();
void setupRadioBox();
void setupScrollView();
@ -287,6 +289,7 @@ void Editor::setup()
setupPageIndicator();
setupPopup();
setupProgressBar();
setupProgressRing();
setupPushButton();
setupRadioBox();
setupScrollView();
@ -521,15 +524,35 @@ void Editor::setupProgressBar()
using A = QskAspect;
using Q = QskProgressBar;
for ( auto subControl : { Q::Groove, Q::Bar } )
for ( auto subControl : { Q::Groove, Q::Fill } )
{
setMetric( subControl | A::Size, 6 );
setPadding( subControl, 0 );
setBoxShape( subControl, 4 );
}
setGradient( Q::Groove, m_pal.darker200 );
setGradient( Q::Bar, m_pal.highlighted );
setGradient( Q::Groove, m_pal.lighter110 );
setGradient( Q::Fill, m_pal.highlighted );
}
void Editor::setupProgressRing()
{
using A = QskAspect;
using Q = QskProgressRing;
for ( auto subControl : { Q::Groove, Q::Fill } )
{
setMetric( subControl | A::Size, 6 );
setPadding( subControl, 0 );
setBoxShape( subControl, 4 );
}
setArcMetrics( Q::Groove, 90, -360, 6 );
setGradient( Q::Groove, m_pal.lighter110 );
setStrutSize( Q::Fill, { 60, 60 } );
setGradient( Q::Fill, m_pal.highlighted );
setArcMetrics( Q::Fill, 90, -360, 6 );
}
void Editor::setupFocusIndicator()
@ -1054,15 +1077,13 @@ void Editor::setupListView()
setPadding( Q::Cell, QskMargins( 4, 8 ) );
setColor( Q::Text, m_pal.themeForeground );
setColor( Q::Cell, Qt::white );
// alternating row colors
setColor( Q::Cell | A::Lower, Qt::white );
setColor( Q::Cell | Q::Selected | A::Lower, m_pal.highlighted );
setColor( Q::Cell | A::Upper, m_pal.contrasted );
setColor( Q::Cell | Q::Selected | A::Upper, m_pal.highlighted );
setColor( Q::Text | Q::Selected, m_pal.highlightedText );
for ( auto state : { A::NoState, Q::Hovered, Q::Pressed } )
{
setColor( Q::Cell | state | Q::Selected, m_pal.highlighted );
setColor( Q::Text | state | Q::Selected, m_pal.highlightedText );
}
}
void Editor::setupSubWindow()

View File

@ -197,10 +197,14 @@ list(APPEND HEADERS
controls/QskPanGestureRecognizer.h
controls/QskPopup.h
controls/QskPopupSkinlet.h
controls/QskPushButton.h
controls/QskPushButtonSkinlet.h
controls/QskProgressBar.h
controls/QskProgressBarSkinlet.h
controls/QskProgressIndicator.h
controls/QskProgressIndicatorSkinlet.h
controls/QskProgressRing.h
controls/QskProgressRingSkinlet.h
controls/QskPushButton.h
controls/QskPushButtonSkinlet.h
controls/QskQuick.h
controls/QskQuickItem.h
controls/QskRadioBox.h
@ -237,6 +241,7 @@ list(APPEND HEADERS
controls/QskSubWindowSkinlet.h
controls/QskSwitchButton.h
controls/QskSwitchButtonSkinlet.h
controls/QskSwipeView.h
controls/QskTabBar.h
controls/QskTabButton.h
controls/QskTabButtonSkinlet.h
@ -296,10 +301,14 @@ list(APPEND SOURCES
controls/QskPanGestureRecognizer.cpp
controls/QskPopup.cpp
controls/QskPopupSkinlet.cpp
controls/QskPushButton.cpp
controls/QskPushButtonSkinlet.cpp
controls/QskProgressBar.cpp
controls/QskProgressBarSkinlet.cpp
controls/QskProgressIndicator.cpp
controls/QskProgressIndicatorSkinlet.cpp
controls/QskProgressRing.cpp
controls/QskProgressRingSkinlet.cpp
controls/QskPushButton.cpp
controls/QskPushButtonSkinlet.cpp
controls/QskQuick.cpp
controls/QskQuickItem.cpp
controls/QskQuickItemPrivate.cpp
@ -336,6 +345,7 @@ list(APPEND SOURCES
controls/QskSubWindowSkinlet.cpp
controls/QskSwitchButton.cpp
controls/QskSwitchButtonSkinlet.cpp
controls/QskSwipeView.cpp
controls/QskTabBar.cpp
controls/QskTabButton.cpp
controls/QskTabButtonSkinlet.cpp

View File

@ -31,6 +31,20 @@ static inline void qskSendEventTo( QObject* object, QEvent::Type type )
QCoreApplication::sendEvent( object, &event );
}
static inline bool qskMaybeGesture( QQuickItem* item,
const QQuickItem* child, const QEvent* event )
{
if ( qskIsTouchOrMouseEvent( event->type() ) )
{
QskGestureFilterEvent ev( child, event );
QCoreApplication::sendEvent( item, &ev );
return ev.maybeGesture();
}
return false;
}
QskControl::QskControl( QQuickItem* parent )
: QskQuickItem( *( new QskControlPrivate() ), parent )
{
@ -791,6 +805,33 @@ bool QskControl::event( QEvent* event )
break;
}
case QskEvent::GestureFilter:
{
/*
qskMaybeGesture is sending an event, so that it can be manipulated
by event filters. F.e QskDrawer wants to add a gesture to
some other control to initiate its appearance.
*/
auto ev = static_cast< QskGestureFilterEvent* >( event );
if ( ev->event()->type() == QEvent::MouseButtonPress )
{
auto mouseEvent = static_cast< const QMouseEvent* >( ev->event() );
const auto pos =
mapFromItem( ev->item(), qskMousePosition( mouseEvent ) );
if ( !gestureRect().contains( pos ) )
{
ev->setMaybeGesture( false );
break;
}
}
ev->setMaybeGesture( gestureFilter( ev->item(), ev->event() ) );
break;
}
case QskEvent::Gesture:
{
gestureEvent( static_cast< QskGestureEvent* >( event ) );
@ -798,18 +839,18 @@ bool QskControl::event( QEvent* event )
}
}
if ( d_func()->maybeGesture( this, event ) )
if ( qskMaybeGesture( this, this, event ) )
return true;
return Inherited::event( event );
}
bool QskControl::childMouseEventFilter( QQuickItem* item, QEvent* event )
bool QskControl::childMouseEventFilter( QQuickItem* child, QEvent* event )
{
return d_func()->maybeGesture( item, event );
return qskMaybeGesture( this, child, event );
}
bool QskControl::gestureFilter( QQuickItem*, QEvent* )
bool QskControl::gestureFilter( const QQuickItem*, const QEvent* )
{
return false;
}

View File

@ -196,7 +196,7 @@ class QSK_EXPORT QskControl : public QskQuickItem, public QskSkinnable
void hoverLeaveEvent( QHoverEvent* ) override;
bool childMouseEventFilter( QQuickItem*, QEvent* ) override;
virtual bool gestureFilter( QQuickItem*, QEvent* );
virtual bool gestureFilter( const QQuickItem*, const QEvent* );
void itemChange( ItemChange, const ItemChangeData& ) override;
void geometryChange( const QRectF&, const QRectF& ) override;

View File

@ -8,6 +8,7 @@
#include "QskLayoutMetrics.h"
#include "QskObjectTree.h"
#include "QskWindow.h"
#include "QskEvent.h"
static inline void qskSendEventTo( QObject* object, QEvent::Type type )
{
@ -15,15 +16,6 @@ static inline void qskSendEventTo( QObject* object, QEvent::Type type )
QCoreApplication::sendEvent( object, &event );
}
static inline QPointF qskScenePosition( const QMouseEvent* event )
{
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
return event->scenePosition();
#else
return event->windowPos();
#endif
}
extern bool qskInheritLocale( QskWindow*, const QLocale& );
namespace
@ -309,41 +301,6 @@ QSizeF QskControlPrivate::explicitSizeHint( Qt::SizeHint whichHint ) const
return QSizeF();
}
bool QskControlPrivate::maybeGesture( QQuickItem* child, QEvent* event )
{
Q_Q( QskControl );
switch ( event->type() )
{
case QEvent::MouseButtonPress:
{
const auto mouseEvent = static_cast< const QMouseEvent* >( event );
auto pos = qskScenePosition( mouseEvent );
pos = q->mapFromScene( pos );
if ( !q->gestureRect().contains( pos ) )
return false;
break;
}
case QEvent::MouseMove:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::UngrabMouse:
case QEvent::TouchBegin:
case QEvent::TouchCancel:
case QEvent::TouchUpdate:
break;
default:
return false;
}
return q->gestureFilter( child, event );
}
bool QskControlPrivate::inheritLocale( QskControl* control, const QLocale& locale )
{
auto d = static_cast< QskControlPrivate* >( QQuickItemPrivate::get( control ) );

View File

@ -36,8 +36,6 @@ class QskControlPrivate : public QskQuickItemPrivate
void implicitSizeChanged() override final;
void layoutConstraintChanged() override final;
bool maybeGesture( QQuickItem*, QEvent* );
QskPlacementPolicy::Policy placementPolicy( bool visible ) const noexcept;
void setPlacementPolicy( bool visible, QskPlacementPolicy::Policy );

View File

@ -15,15 +15,15 @@ class QSK_EXPORT QskDrawer : public QskPopup
public:
QSK_SUBCONTROLS( Panel, Overlay )
QskDrawer( QQuickItem* parentItem = nullptr );
QskDrawer( QQuickItem* = nullptr );
~QskDrawer() override;
void setEdge( Qt::Edge edge );
void setEdge( Qt::Edge );
Qt::Edge edge() const;
void updateLayout() override;
void setContent( QskControl* t );
void setContent( QskControl* );
Q_SIGNALS:
void edgeChanged( Qt::Edge );

View File

@ -154,6 +154,28 @@ bool qskIsButtonPressKey( const QKeyEvent* event )
#endif
}
bool qskIsTouchOrMouseEvent( QEvent::Type type )
{
switch ( type )
{
case QEvent::MouseButtonPress:
case QEvent::MouseMove:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::UngrabMouse:
case QEvent::TouchBegin:
case QEvent::TouchCancel:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
return true;
default:
return false;
}
}
QskEvent::QskEvent( QskEvent::Type type )
: QEvent( static_cast< QEvent::Type >( type ) )
{
@ -249,3 +271,19 @@ QskAnimatorEvent* QskAnimatorEvent::clone() const
{
return new QskAnimatorEvent( *this );
}
// -- QskGestureFilterEvent
QskGestureFilterEvent::QskGestureFilterEvent(
const QQuickItem* item, const QEvent* event )
: QskEvent( QskEvent::GestureFilter )
, m_item( item )
, m_event( event )
, m_maybeGesture( false )
{
}
QskGestureFilterEvent* QskGestureFilterEvent::clone() const
{
return new QskGestureFilterEvent( *this );
}

View File

@ -47,6 +47,7 @@ class QSK_EXPORT QskEvent : public QEvent
PopupRemoved,
Gesture,
GestureFilter,
Animator,
@ -118,6 +119,29 @@ class QSK_EXPORT QskPopupEvent : public QskEvent
QskPopup* m_popup;
};
class QSK_EXPORT QskGestureFilterEvent : public QskEvent
{
public:
QskGestureFilterEvent( const QQuickItem*, const QEvent* );
inline const QQuickItem* item() const { return m_item; }
inline const QEvent* event() const { return m_event; }
inline void setMaybeGesture( bool on ) { m_maybeGesture = on; }
inline bool maybeGesture() const { return m_maybeGesture; }
QskGestureFilterEvent* clone() const override;
protected:
QSK_EVENT_DISABLE_COPY( QskGestureFilterEvent )
private:
const QQuickItem* m_item;
const QEvent* m_event;
bool m_maybeGesture;
};
class QSK_EXPORT QskGestureEvent : public QskEvent
{
public:
@ -178,4 +202,6 @@ QSK_EXPORT qreal qskWheelIncrement( const QWheelEvent* );
QSK_EXPORT bool qskIsStandardKeyInput( const QKeyEvent*, QKeySequence::StandardKey );
QSK_EXPORT bool qskIsButtonPressKey( const QKeyEvent* );
QSK_EXPORT bool qskIsTouchOrMouseEvent( QEvent::Type );
#endif

View File

@ -295,7 +295,7 @@ QskGestureRecognizer::State QskGestureRecognizer::state() const
}
bool QskGestureRecognizer::processEvent(
QQuickItem* item, QEvent* event, bool blockReplayedEvents )
const QQuickItem* item, const QEvent* event, bool blockReplayedEvents )
{
if ( m_data->isReplayingEvents && blockReplayedEvents )
{
@ -331,7 +331,7 @@ bool QskGestureRecognizer::processEvent(
if ( buttons == Qt::NoButton )
buttons = watchedItem->acceptedMouseButtons();
auto mouseEvent = static_cast< QMouseEvent* >( event );
auto mouseEvent = static_cast< const QMouseEvent* >( event );
if ( !( buttons & mouseEvent->button() ) )
return false;
@ -383,7 +383,7 @@ bool QskGestureRecognizer::processEvent(
{
case QEvent::MouseButtonPress:
{
auto mouseEvent = static_cast< QMouseEvent* >( event );
auto mouseEvent = static_cast< const QMouseEvent* >( event );
m_data->pendingEvents += qskClonedMouseEvent( mouseEvent );
pressEvent( mouseEvent );
@ -392,7 +392,7 @@ bool QskGestureRecognizer::processEvent(
case QEvent::MouseMove:
{
auto mouseEvent = static_cast< QMouseEvent* >( event );
auto mouseEvent = static_cast< const QMouseEvent* >( event );
m_data->pendingEvents += qskClonedMouseEvent( mouseEvent );
moveEvent( mouseEvent );
@ -401,7 +401,7 @@ bool QskGestureRecognizer::processEvent(
case QEvent::MouseButtonRelease:
{
auto mouseEvent = static_cast< QMouseEvent* >( event );
auto mouseEvent = static_cast< const QMouseEvent* >( event );
m_data->pendingEvents += qskClonedMouseEvent( mouseEvent );
if ( m_data->state == Pending )

View File

@ -41,7 +41,7 @@ class QSK_EXPORT QskGestureRecognizer
// timestamp, when the Idle state had been left
ulong timestamp() const;
bool processEvent( QQuickItem*, QEvent*, bool blockReplayedEvents = true );
bool processEvent( const QQuickItem*, const QEvent*, bool blockReplayedEvents = true );
void reject();
void accept();

View File

@ -46,6 +46,43 @@ class QskListView::PrivateData
{
}
void setRowState( QskListView* listView, int row, QskAspect::State state )
{
using Q = QskListView;
auto& storedRow = ( state == Q::Hovered )
? hoveredRow : ( ( state == Q::Pressed ) ? pressedRow : selectedRow );
if ( row == storedRow )
return;
if ( storedRow >= 0 )
{
const auto states = listView->rowStates( storedRow );
startTransitions( listView, storedRow, states, states & ~state );
}
if ( row >= 0 )
{
const auto states = listView->rowStates( row );
startTransitions( listView, row, states, states | state );
}
storedRow = row;
listView->update();
}
private:
inline void startTransitions( QskListView* listView, int row,
QskAspect::States oldStates, QskAspect::States newStates )
{
using Q = QskListView;
listView->startHintTransitions(
{ Q::Cell, Q::Text }, oldStates, newStates, row );
}
public:
/*
Currently we only support single selection. We can't navigate
the current item ( = focus ) without changing the selection.
@ -55,6 +92,8 @@ class QskListView::PrivateData
bool preferredWidthFromColumns : 1;
SelectionMode selectionMode : 4;
int hoveredRow = -1;
int pressedRow = -1;
int selectedRow = -1;
};
@ -131,7 +170,8 @@ void QskListView::setSelectedRow( int row )
if ( row != m_data->selectedRow )
{
m_data->selectedRow = row;
m_data->setRowState( this, row, Selected );
Q_EMIT selectedRowChanged( row );
Q_EMIT focusIndicatorRectChanged();
@ -280,6 +320,7 @@ void QskListView::mousePressEvent( QMouseEvent* event )
const int row = qskRowAt( this, qskMousePosition( event ) );
if ( row >= 0 )
{
m_data->setRowState( this, row, Pressed );
setSelectedRow( row );
return;
}
@ -290,9 +331,44 @@ void QskListView::mousePressEvent( QMouseEvent* event )
void QskListView::mouseReleaseEvent( QMouseEvent* event )
{
m_data->setRowState( this, -1, Pressed );
Inherited::mouseReleaseEvent( event );
}
void QskListView::mouseUngrabEvent()
{
m_data->setRowState( this, -1, Pressed );
Inherited::mouseUngrabEvent();
}
void QskListView::hoverEnterEvent( QHoverEvent* event )
{
if ( m_data->selectionMode != NoSelection )
{
const int row = qskRowAt( this, qskHoverPosition( event ) );
m_data->setRowState( this, row, Hovered );
}
Inherited::hoverEnterEvent( event );
}
void QskListView::hoverMoveEvent( QHoverEvent* event )
{
if ( m_data->selectionMode != NoSelection )
{
const int row = qskRowAt( this, qskHoverPosition( event ) );
m_data->setRowState( this, row, Hovered );
}
Inherited::hoverMoveEvent( event );
}
void QskListView::hoverLeaveEvent( QHoverEvent* event )
{
m_data->setRowState( this, -1, Hovered );
Inherited::hoverLeaveEvent( event );
}
void QskListView::changeEvent( QEvent* event )
{
if ( event->type() == QEvent::StyleChange )
@ -301,6 +377,25 @@ void QskListView::changeEvent( QEvent* event )
Inherited::changeEvent( event );
}
QskAspect::States QskListView::rowStates( int row ) const
{
auto states = skinStates();
if ( row >= 0 )
{
if ( row == m_data->selectedRow )
states |= Selected;
if ( row == m_data->hoveredRow )
states |= Hovered;
if ( row == m_data->pressedRow )
states |= Pressed;
}
return states;
}
#ifndef QT_NO_WHEELEVENT
static qreal qskAlignedToRows( const qreal y0, qreal dy,

View File

@ -54,6 +54,7 @@ class QSK_EXPORT QskListView : public QskScrollView
QskTextOptions textOptions() const;
Q_INVOKABLE int selectedRow() const;
QskAspect::States rowStates( int ) const;
virtual int rowCount() const = 0;
virtual int columnCount() const = 0;
@ -83,6 +84,11 @@ class QSK_EXPORT QskListView : public QskScrollView
void mousePressEvent( QMouseEvent* ) override;
void mouseReleaseEvent( QMouseEvent* ) override;
void mouseUngrabEvent() override;
void hoverEnterEvent( QHoverEvent* ) override;
void hoverMoveEvent( QHoverEvent* ) override;
void hoverLeaveEvent( QHoverEvent* ) override;
#ifndef QT_NO_WHEELEVENT
virtual QPointF scrollOffset( const QWheelEvent* ) const override;

View File

@ -196,7 +196,6 @@ void QskListViewSkinlet::updateBackgroundNodes(
const QskListView* listView, QSGNode* backgroundNode ) const
{
using Q = QskListView;
using A = QskAspect;
auto listViewNode = static_cast< const ListViewNode* >( backgroundNode->parent() );
@ -205,14 +204,11 @@ void QskListViewSkinlet::updateBackgroundNodes(
for ( int row = listViewNode->rowMin(); row <= listViewNode->rowMax(); row++ )
{
QskSkinStateChanger stateChanger( listView );
stateChanger.setStates( sampleStates( listView, Q::Cell, row ) );
stateChanger.setStates( sampleStates( listView, Q::Cell, row ), row );
const auto rect = sampleRect( listView, listView->contentsRect(), Q::Cell, row );
const QskAspect aspect = Q::Cell | ( ( row % 2 ) ? A::Upper : A::Lower );
const auto boxHints = listView->boxHints( aspect );
auto newNode = updateBoxNode( listView, rowNode, rect, boxHints );
auto newNode = updateBoxNode( listView, rowNode, rect, Q::Cell );
if ( newNode )
{
if ( newNode->parent() != backgroundNode )
@ -395,7 +391,7 @@ QSGNode* QskListViewSkinlet::updateCellNode( const QskListView* listView,
using namespace QskSGNode;
QskSkinStateChanger stateChanger( listView );
stateChanger.setStates( sampleStates( listView, Q::Cell, row ) );
stateChanger.setStates( sampleStates( listView, Q::Cell, row ), row );
QSGNode* newNode = nullptr;
@ -470,12 +466,7 @@ QskAspect::States QskListViewSkinlet::sampleStates( const QskSkinnable* skinnabl
if ( subControl == Q::Cell || subControl == Q::Text || subControl == Q::Graphic )
{
const auto listView = static_cast< const QskListView* >( skinnable );
auto states = listView->skinStates();
if ( index == listView->selectedRow() )
states |= Q::Selected;
return states;
return listView->rowStates( index );
}
return Inherited::sampleStates( skinnable, subControl, index );

View File

@ -6,91 +6,30 @@
#include "QskProgressBar.h"
#include "QskIntervalF.h"
#include "QskFunctions.h"
#include "QskAnimator.h"
#include "QskAspect.h"
QSK_SUBCONTROL( QskProgressBar, Groove )
QSK_SUBCONTROL( QskProgressBar, Bar )
namespace
{
class PositionAnimator : public QskAnimator
{
public:
PositionAnimator( QskProgressBar* progressBar )
: m_progressBar( progressBar )
{
setAutoRepeat( true );
setDuration( 1300 );
setWindow( progressBar->window() );
}
void advance( qreal value ) override
{
if ( m_progressBar->setPositionHint( QskProgressBar::Bar, value ) )
m_progressBar->update();
}
private:
QskProgressBar* m_progressBar;
};
}
QSK_SUBCONTROL( QskProgressBar, Fill )
class QskProgressBar::PrivateData
{
public:
void updateIndeterminateAnimator( QskProgressBar* progressBar )
{
if ( !isIndeterminate )
{
delete animator;
animator = nullptr;
return;
}
if ( progressBar->window() && progressBar->isVisible() )
{
if ( animator == nullptr )
animator = new PositionAnimator( progressBar );
animator->start();
}
else
{
if ( animator )
animator->stop();
}
}
PositionAnimator* animator = nullptr;
qreal value = 0.0;
qreal origin = 0.0;
bool hasOrigin = false;
bool isIndeterminate = false;
Qt::Orientation orientation;
};
QskProgressBar::QskProgressBar( Qt::Orientation orientation,
qreal min, qreal max, QQuickItem* parent )
: QskBoundedControl( min, max, parent )
: Inherited( min, max, parent )
, m_data( new PrivateData )
{
m_data->orientation = orientation;
m_data->value = minimum();
if ( orientation == Qt::Horizontal )
initSizePolicy( QskSizePolicy::MinimumExpanding, QskSizePolicy::Fixed );
else
initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::MinimumExpanding );
connect( this, &QskBoundedControl::boundariesChanged,
this, &QskProgressBar::adjustValue );
setSubcontrolProxy( Inherited::Groove, Groove );
setSubcontrolProxy( Inherited::Fill, Fill );
}
QskProgressBar::QskProgressBar( Qt::Orientation orientation, QQuickItem* parent )
@ -115,7 +54,12 @@ QskProgressBar::QskProgressBar( QQuickItem* parent )
QskProgressBar::~QskProgressBar()
{
delete m_data->animator;
}
QskAspect::Variation QskProgressBar::effectiveVariation() const
{
// so you can define different hints depending on the orientation
return static_cast< QskAspect::Variation >( m_data->orientation );
}
Qt::Orientation QskProgressBar::orientation() const
@ -137,163 +81,4 @@ void QskProgressBar::setOrientation( Qt::Orientation orientation )
}
}
bool QskProgressBar::isIndeterminate() const
{
return m_data->isIndeterminate;
}
void QskProgressBar::setIndeterminate( bool on )
{
if ( on == m_data->isIndeterminate )
return;
m_data->isIndeterminate = on;
m_data->updateIndeterminateAnimator( this );
update();
Q_EMIT indeterminateChanged( on );
}
QskAspect::Variation QskProgressBar::effectiveVariation() const
{
// so you can define different hints depending on the orientation
return static_cast< QskAspect::Variation >( m_data->orientation );
}
void QskProgressBar::setBarGradient( const QskGradient& gradient )
{
setGradientHint( Bar, gradient );
}
void QskProgressBar::resetBarGradient()
{
resetColor( Bar );
}
QskGradient QskProgressBar::barGradient() const
{
return gradientHint( QskProgressBar::Bar );
}
void QskProgressBar::setExtent( qreal extent )
{
if ( extent < 0.0 )
extent = 0.0;
if ( setMetric( Groove | QskAspect::Size, extent ) )
Q_EMIT extentChanged( extent );
}
void QskProgressBar::resetExtent()
{
if ( resetMetric( Groove | QskAspect::Size ) )
Q_EMIT extentChanged( extent() );
}
qreal QskProgressBar::extent() const
{
auto grooveSize = metric( Groove | QskAspect::Size );
auto barSize = metric( Bar | QskAspect::Size );
return qMax( grooveSize, barSize );
}
void QskProgressBar::setOrigin( qreal origin )
{
if ( isComponentComplete() )
origin = boundedValue( origin );
if( !m_data->hasOrigin || !qskFuzzyCompare( m_data->origin, origin ) )
{
m_data->hasOrigin = true;
m_data->origin = origin;
update();
Q_EMIT originChanged( origin );
}
}
void QskProgressBar::resetOrigin()
{
if ( m_data->hasOrigin )
{
m_data->hasOrigin = false;
update();
Q_EMIT originChanged( origin() );
}
}
qreal QskProgressBar::origin() const
{
if ( m_data->hasOrigin )
{
return boundedValue( m_data->origin );
}
return minimum();
}
void QskProgressBar::setValue( qreal value )
{
if ( isComponentComplete() )
value = boundedValue( value );
setValueInternal( value );
}
qreal QskProgressBar::value() const
{
return m_data->value;
}
void QskProgressBar::setValueAsRatio( qreal ratio )
{
ratio = qBound( 0.0, ratio, 1.0 );
setValue( minimum() + ratio * boundaryLength() );
}
qreal QskProgressBar::valueAsRatio() const
{
return valueAsRatio( m_data->value );
}
void QskProgressBar::componentComplete()
{
Inherited::componentComplete();
adjustValue();
}
void QskProgressBar::adjustValue()
{
if ( isComponentComplete() )
setValueInternal( boundedValue( m_data->value ) );
}
void QskProgressBar::setValueInternal( qreal value )
{
if ( !qskFuzzyCompare( value, m_data->value ) )
{
m_data->value = value;
Q_EMIT valueChanged( value );
update();
}
}
void QskProgressBar::itemChange( QQuickItem::ItemChange change,
const QQuickItem::ItemChangeData& value )
{
switch( static_cast< int >( change ) )
{
case QQuickItem::ItemVisibleHasChanged:
case QQuickItem::ItemSceneChange:
{
m_data->updateIndeterminateAnimator( this );
break;
}
}
Inherited::itemChange( change, value );
}
#include "moc_QskProgressBar.cpp"

View File

@ -6,34 +6,19 @@
#ifndef QSK_PROGRESS_BAR_H
#define QSK_PROGRESS_BAR_H
#include "QskBoundedControl.h"
#include "QskProgressIndicator.h"
class QskIntervalF;
class QSK_EXPORT QskProgressBar : public QskBoundedControl
class QSK_EXPORT QskProgressBar : public QskProgressIndicator
{
Q_OBJECT
Q_PROPERTY( Qt::Orientation orientation READ orientation
WRITE setOrientation NOTIFY orientationChanged )
Q_PROPERTY( qreal extent READ extent
WRITE setExtent RESET resetExtent NOTIFY extentChanged )
Q_PROPERTY( bool indeterminate READ isIndeterminate
WRITE setIndeterminate NOTIFY indeterminateChanged )
Q_PROPERTY( qreal origin READ origin
WRITE setOrigin RESET resetOrigin NOTIFY originChanged )
Q_PROPERTY( qreal value READ value WRITE setValue NOTIFY valueChanged )
Q_PROPERTY( qreal valueAsRatio READ valueAsRatio
WRITE setValueAsRatio NOTIFY valueChanged )
using Inherited = QskBoundedControl;
using Inherited = QskProgressIndicator;
public:
QSK_SUBCONTROLS( Groove, Bar )
QSK_SUBCONTROLS( Groove, Fill )
QskProgressBar( Qt::Orientation, QQuickItem* parent = nullptr );
QskProgressBar( Qt::Orientation, qreal min, qreal max, QQuickItem* parent = nullptr );
@ -43,50 +28,15 @@ class QSK_EXPORT QskProgressBar : public QskBoundedControl
~QskProgressBar() override;
QskAspect::Variation effectiveVariation() const override;
Qt::Orientation orientation() const;
void setOrientation( Qt::Orientation orientation );
bool isIndeterminate() const;
void setIndeterminate( bool on = true );
QskAspect::Variation effectiveVariation() const override;
void setBarGradient( const QskGradient& );
void resetBarGradient();
QskGradient barGradient() const;
void setExtent( qreal );
void resetExtent();
qreal extent() const;
void resetOrigin();
qreal origin() const;
qreal value() const;
qreal valueAsRatio() const; // [0.0, 1.0]
using QskBoundedControl::valueAsRatio;
public Q_SLOTS:
void setValue( qreal );
void setValueAsRatio( qreal );
void setOrigin( qreal );
Q_SIGNALS:
void orientationChanged( Qt::Orientation );
void extentChanged( qreal );
void indeterminateChanged( bool );
void valueChanged( qreal );
void originChanged( qreal );
protected:
void componentComplete() override;
void itemChange( ItemChange, const ItemChangeData& ) override;
private:
void setValueInternal( qreal value );
void adjustBoundaries( bool increasing );
void adjustValue();
class PrivateData;
std::unique_ptr< PrivateData > m_data;
};

View File

@ -7,51 +7,54 @@
#include "QskProgressBar.h"
#include "QskIntervalF.h"
#include "QskBoxBorderMetrics.h"
#include "QskGradientDirection.h"
#include <qeasingcurve.h>
#include <cmath>
static inline QskIntervalF qskBarInterval( const QskProgressBar* bar )
using Q = QskProgressBar;
namespace
{
qreal pos1, pos2;
if ( bar->isIndeterminate() )
QskIntervalF qskFillInterval( const Q* bar )
{
const auto pos = bar->positionHint( QskProgressBar::Bar );
qreal pos1, pos2;
static const QEasingCurve curve( QEasingCurve::InOutCubic );
const qreal off = 0.15;
pos1 = curve.valueForProgress( qMax( pos - off, 0.0 ) );
pos2 = curve.valueForProgress( qMin( pos + off, 1.0 ) );
}
else
{
pos1 = bar->valueAsRatio( bar->origin() );
pos2 = bar->valueAsRatio( bar->value() );
}
if( bar->orientation() == Qt::Horizontal )
{
if ( bar->layoutMirroring() )
if ( bar->isIndeterminate() )
{
pos1 = 1.0 - pos1;
pos2 = 1.0 - pos2;
const auto pos = bar->positionHint( QskProgressIndicator::Fill );
static const QEasingCurve curve( QEasingCurve::InOutCubic );
const qreal off = 0.15;
pos1 = curve.valueForProgress( qMax( pos - off, 0.0 ) );
pos2 = curve.valueForProgress( qMin( pos + off, 1.0 ) );
}
else
{
pos1 = bar->valueAsRatio( bar->origin() );
pos2 = bar->valueAsRatio( bar->value() );
}
if( bar->orientation() == Qt::Horizontal )
{
if ( bar->layoutMirroring() )
{
pos1 = 1.0 - pos1;
pos2 = 1.0 - pos2;
}
}
if ( pos1 > pos2 )
std::swap( pos1, pos2 );
return QskIntervalF( pos1, pos2 );
}
if ( pos1 > pos2 )
std::swap( pos1, pos2 );
return QskIntervalF( pos1, pos2 );
}
QskProgressBarSkinlet::QskProgressBarSkinlet( QskSkin* skin )
: QskSkinlet( skin )
: Inherited( skin )
{
setNodeRoles( { GrooveRole, BarRole } );
}
QskProgressBarSkinlet::~QskProgressBarSkinlet()
@ -62,7 +65,6 @@ QRectF QskProgressBarSkinlet::subControlRect(
const QskSkinnable* skinnable, const QRectF& contentsRect,
QskAspect::Subcontrol subControl ) const
{
using Q = QskProgressBar;
const auto bar = static_cast< const Q* >( skinnable );
if( subControl == Q::Groove )
@ -84,7 +86,7 @@ QRectF QskProgressBarSkinlet::subControlRect(
return rect;
}
if( subControl == Q::Bar )
if( subControl == Q::Fill )
{
return barRect( bar );
}
@ -92,30 +94,18 @@ QRectF QskProgressBarSkinlet::subControlRect(
return Inherited::subControlRect( skinnable, contentsRect, subControl );
}
QSGNode* QskProgressBarSkinlet::updateSubNode(
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
QSGNode* QskProgressBarSkinlet::updateGrooveNode(
const QskProgressIndicator* indicator, QSGNode* node ) const
{
switch( nodeRole )
{
case GrooveRole:
{
return updateBoxNode( skinnable, node, QskProgressBar::Groove );
}
case BarRole:
{
const auto bar = static_cast< const QskProgressBar* >( skinnable );
return updateBarNode( bar, node );
}
}
return Inherited::updateSubNode( skinnable, nodeRole, node );
return updateBoxNode( indicator, node, Q::Groove );
}
QSGNode* QskProgressBarSkinlet::updateBarNode(
const QskProgressBar* bar, QSGNode* node ) const
QSGNode* QskProgressBarSkinlet::updateFillNode(
const QskProgressIndicator* indicator, QSGNode* node ) const
{
const auto subControl = QskProgressBar::Bar;
const auto bar = static_cast< const Q* >( indicator );
const auto subControl = Q::Fill;
const auto rect = bar->subControlRect( subControl );
if ( rect.isEmpty() )
@ -139,26 +129,27 @@ QSGNode* QskProgressBarSkinlet::updateBarNode(
not supporting this yet. TODO ...
*/
const auto intv = qskBarInterval( bar );
const auto intv = qskFillInterval( bar );
const auto stops = qskExtractedGradientStops( gradient.stops(),
intv.lowerBound(), intv.upperBound() );
gradient.setStops( stops );
gradient.setLinearDirection( bar->orientation() );
gradient.setLinearDirection( static_cast< Qt::Orientation >( bar->orientation() ) );
if ( bar->orientation() == Qt::Vertical || bar->layoutMirroring() )
gradient.reverse();
}
return updateBoxNode( bar, node, rect, gradient, subControl );
return updateBoxNode( indicator, node, rect, gradient, subControl );
}
QRectF QskProgressBarSkinlet::barRect( const QskProgressBar* bar ) const
QRectF QskProgressBarSkinlet::barRect( const Q* bar ) const
{
using Q = QskProgressBar;
const auto subControl = Q::Groove;
const auto barSize = bar->metric( Q::Bar | QskAspect::Size );
const auto barSize = bar->metric( Q::Fill | QskAspect::Size );
auto rect = bar->subControlRect( subControl );
if ( bar->orientation() == Qt::Horizontal )
@ -179,7 +170,7 @@ QRectF QskProgressBarSkinlet::barRect( const QskProgressBar* bar ) const
rect = rect.marginsRemoved( m );
const auto intv = qskBarInterval( bar );
const auto intv = qskFillInterval( bar );
if( bar->orientation() == Qt::Horizontal )
{
@ -205,7 +196,7 @@ QSizeF QskProgressBarSkinlet::sizeHint( const QskSkinnable* skinnable,
if ( which != Qt::PreferredSize )
return QSizeF();
const auto bar = static_cast< const QskProgressBar* >( skinnable );
const auto bar = static_cast< const Q* >( skinnable );
const auto extent = bar->extent();

View File

@ -6,25 +6,17 @@
#ifndef QSK_PROGRESS_BAR_SKINLET_H
#define QSK_PROGRESS_BAR_SKINLET_H
#include "QskSkinlet.h"
#include "QskProgressIndicatorSkinlet.h"
class QskProgressBar;
class QSK_EXPORT QskProgressBarSkinlet : public QskSkinlet
class QSK_EXPORT QskProgressBarSkinlet : public QskProgressIndicatorSkinlet
{
Q_GADGET
using Inherited = QskSkinlet;
using Inherited = QskProgressIndicatorSkinlet;
public:
enum NodeRole
{
GrooveRole,
BarRole,
RoleCount
};
Q_INVOKABLE QskProgressBarSkinlet( QskSkin* = nullptr );
~QskProgressBarSkinlet() override;
@ -35,11 +27,10 @@ class QSK_EXPORT QskProgressBarSkinlet : public QskSkinlet
Qt::SizeHint, const QSizeF& ) const override;
protected:
QSGNode* updateSubNode( const QskSkinnable*,
quint8 nodeRole, QSGNode* ) const override;
QSGNode* updateGrooveNode( const QskProgressIndicator*, QSGNode* ) const override;
QSGNode* updateFillNode( const QskProgressIndicator*, QSGNode* ) const override;
private:
QSGNode* updateBarNode( const QskProgressBar*, QSGNode* ) const;
QRectF barRect( const QskProgressBar* ) const;
};

View File

@ -0,0 +1,255 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskProgressIndicator.h"
#include "QskIntervalF.h"
#include "QskFunctions.h"
#include "QskAnimator.h"
#include "QskAspect.h"
QSK_SUBCONTROL( QskProgressIndicator, Groove )
QSK_SUBCONTROL( QskProgressIndicator, Fill )
namespace
{
class PositionAnimator : public QskAnimator
{
public:
PositionAnimator( QskProgressIndicator* indicator )
: m_indicator( indicator )
{
setAutoRepeat( true );
setDuration( 1300 );
setWindow( indicator->window() );
}
void advance( qreal value ) override
{
if ( m_indicator->setPositionHint( QskProgressIndicator::Fill, value ) )
m_indicator->update();
}
private:
QskProgressIndicator* m_indicator;
};
}
class QskProgressIndicator::PrivateData
{
public:
void updateIndeterminateAnimator( QskProgressIndicator* indicator )
{
if ( !isIndeterminate )
{
delete animator;
animator = nullptr;
return;
}
if ( indicator->window() && indicator->isVisible() )
{
if ( animator == nullptr )
animator = new PositionAnimator( indicator );
animator->start();
}
else
{
if ( animator )
animator->stop();
}
}
PositionAnimator* animator = nullptr;
qreal value = 0.0;
qreal origin = 0.0;
bool hasOrigin = false;
bool isIndeterminate = false;
};
QskProgressIndicator::QskProgressIndicator( qreal min, qreal max, QQuickItem* parent )
: QskBoundedControl( min, max, parent )
, m_data( new PrivateData )
{
m_data->value = minimum();
connect( this, &QskBoundedControl::boundariesChanged,
this, &QskProgressIndicator::adjustValue );
}
QskProgressIndicator::QskProgressIndicator( QQuickItem* parent )
: QskProgressIndicator( 0.0, 100.0, parent )
{
}
QskProgressIndicator::QskProgressIndicator( const QskIntervalF& boundaries, QQuickItem* parent )
: QskProgressIndicator( boundaries.lowerBound(), boundaries.upperBound(), parent )
{
}
QskProgressIndicator::~QskProgressIndicator()
{
delete m_data->animator;
}
bool QskProgressIndicator::isIndeterminate() const
{
return m_data->isIndeterminate;
}
void QskProgressIndicator::setIndeterminate( bool on )
{
if ( on == m_data->isIndeterminate )
return;
m_data->isIndeterminate = on;
m_data->updateIndeterminateAnimator( this );
update();
Q_EMIT indeterminateChanged( on );
}
void QskProgressIndicator::setFillGradient( const QskGradient& gradient )
{
setGradientHint( Fill, gradient );
}
void QskProgressIndicator::resetFillGradient()
{
resetColor( Fill );
}
QskGradient QskProgressIndicator::fillGradient() const
{
return gradientHint( Fill );
}
void QskProgressIndicator::setExtent( qreal extent )
{
if ( extent < 0.0 )
extent = 0.0;
if ( setMetric( Groove | QskAspect::Size, extent ) )
Q_EMIT extentChanged( extent );
}
void QskProgressIndicator::resetExtent()
{
if ( resetMetric( Groove | QskAspect::Size ) )
Q_EMIT extentChanged( extent() );
}
qreal QskProgressIndicator::extent() const
{
auto grooveSize = metric( Groove | QskAspect::Size );
auto fillSize = metric( Fill | QskAspect::Size );
return qMax( grooveSize, fillSize );
}
void QskProgressIndicator::setOrigin( qreal origin )
{
if ( isComponentComplete() )
origin = boundedValue( origin );
if( !m_data->hasOrigin || !qskFuzzyCompare( m_data->origin, origin ) )
{
m_data->hasOrigin = true;
m_data->origin = origin;
update();
Q_EMIT originChanged( origin );
}
}
void QskProgressIndicator::resetOrigin()
{
if ( m_data->hasOrigin )
{
m_data->hasOrigin = false;
update();
Q_EMIT originChanged( origin() );
}
}
qreal QskProgressIndicator::origin() const
{
if ( m_data->hasOrigin )
{
return boundedValue( m_data->origin );
}
return minimum();
}
void QskProgressIndicator::setValue( qreal value )
{
if ( isComponentComplete() )
value = boundedValue( value );
setValueInternal( value );
}
qreal QskProgressIndicator::value() const
{
return m_data->value;
}
void QskProgressIndicator::setValueAsRatio( qreal ratio )
{
ratio = qBound( 0.0, ratio, 1.0 );
setValue( minimum() + ratio * boundaryLength() );
}
qreal QskProgressIndicator::valueAsRatio() const
{
return valueAsRatio( m_data->value );
}
void QskProgressIndicator::componentComplete()
{
Inherited::componentComplete();
adjustValue();
}
void QskProgressIndicator::adjustValue()
{
if ( isComponentComplete() )
setValueInternal( boundedValue( m_data->value ) );
}
void QskProgressIndicator::setValueInternal( qreal value )
{
if ( !qskFuzzyCompare( value, m_data->value ) )
{
m_data->value = value;
Q_EMIT valueChanged( value );
update();
}
}
void QskProgressIndicator::itemChange( QQuickItem::ItemChange change,
const QQuickItem::ItemChangeData& value )
{
switch( static_cast< int >( change ) )
{
case QQuickItem::ItemVisibleHasChanged:
case QQuickItem::ItemSceneChange:
{
m_data->updateIndeterminateAnimator( this );
break;
}
}
Inherited::itemChange( change, value );
}
#include "moc_QskProgressIndicator.cpp"

View File

@ -0,0 +1,83 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_PROGRESS_INDICATOR_H
#define QSK_PROGRESS_INDICATOR_H
#include "QskBoundedControl.h"
class QskIntervalF;
class QSK_EXPORT QskProgressIndicator : public QskBoundedControl
{
Q_OBJECT
Q_PROPERTY( qreal extent READ extent
WRITE setExtent RESET resetExtent NOTIFY extentChanged )
Q_PROPERTY( bool indeterminate READ isIndeterminate
WRITE setIndeterminate NOTIFY indeterminateChanged )
Q_PROPERTY( qreal origin READ origin
WRITE setOrigin RESET resetOrigin NOTIFY originChanged )
Q_PROPERTY( qreal value READ value WRITE setValue NOTIFY valueChanged )
Q_PROPERTY( qreal valueAsRatio READ valueAsRatio
WRITE setValueAsRatio NOTIFY valueChanged )
using Inherited = QskBoundedControl;
public:
QSK_SUBCONTROLS( Groove, Fill )
QskProgressIndicator( QQuickItem* parent = nullptr );
QskProgressIndicator( qreal min, qreal max, QQuickItem* parent = nullptr );
QskProgressIndicator( const QskIntervalF&, QQuickItem* parent = nullptr );
~QskProgressIndicator() override;
bool isIndeterminate() const;
void setIndeterminate( bool on = true );
void setFillGradient( const QskGradient& );
void resetFillGradient();
QskGradient fillGradient() const;
void setExtent( qreal );
void resetExtent();
qreal extent() const;
void resetOrigin();
qreal origin() const;
qreal value() const;
qreal valueAsRatio() const; // [0.0, 1.0]
using QskBoundedControl::valueAsRatio;
public Q_SLOTS:
void setValue( qreal );
void setValueAsRatio( qreal );
void setOrigin( qreal );
Q_SIGNALS:
void extentChanged( qreal );
void indeterminateChanged( bool );
void valueChanged( qreal );
void originChanged( qreal );
protected:
void componentComplete() override;
void itemChange( ItemChange, const ItemChangeData& ) override;
private:
void setValueInternal( qreal value );
void adjustBoundaries( bool increasing );
void adjustValue();
class PrivateData;
std::unique_ptr< PrivateData > m_data;
};
#endif

View File

@ -0,0 +1,38 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskProgressIndicatorSkinlet.h"
#include "QskProgressIndicator.h"
QskProgressIndicatorSkinlet::QskProgressIndicatorSkinlet( QskSkin* skin )
: Inherited( skin )
{
setNodeRoles( { GrooveRole, FillRole } );
}
QskProgressIndicatorSkinlet::~QskProgressIndicatorSkinlet()
{
}
QSGNode* QskProgressIndicatorSkinlet::updateSubNode(
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
{
const auto indicator = static_cast< const QskProgressIndicator* >( skinnable );
switch( nodeRole )
{
case GrooveRole:
{
return updateGrooveNode( indicator, node );
}
case FillRole:
{
return updateFillNode( indicator, node );
}
}
return Inherited::updateSubNode( skinnable, nodeRole, node );
}

View File

@ -0,0 +1,38 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_PROGRESS_INDICATOR_SKINLET_H
#define QSK_PROGRESS_INDICATOR_SKINLET_H
#include "QskSkinlet.h"
class QskProgressIndicator;
class QSK_EXPORT QskProgressIndicatorSkinlet : public QskSkinlet
{
using Inherited = QskSkinlet;
public:
enum NodeRole
{
GrooveRole,
FillRole,
RoleCount
};
~QskProgressIndicatorSkinlet() override;
protected:
QskProgressIndicatorSkinlet( QskSkin* = nullptr );
QSGNode* updateSubNode( const QskSkinnable*,
quint8 nodeRole, QSGNode* ) const override;
virtual QSGNode* updateGrooveNode( const QskProgressIndicator*, QSGNode* ) const = 0;
virtual QSGNode* updateFillNode( const QskProgressIndicator*, QSGNode* ) const = 0;
};
#endif

View File

@ -0,0 +1,76 @@
/******************************************************************************
* QSkinny - Copyright (C) 2023 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskProgressRing.h"
#include "QskIntervalF.h"
QSK_SUBCONTROL( QskProgressRing, Groove )
QSK_SUBCONTROL( QskProgressRing, Fill )
class QskProgressRing::PrivateData
{
public:
int size : 2;
};
QskProgressRing::QskProgressRing( qreal min, qreal max, QQuickItem* parent )
: Inherited( min, max, parent )
, m_data( new PrivateData )
{
m_data->size = NormalSize;
setSubcontrolProxy( Inherited::Groove, Groove );
setSubcontrolProxy( Inherited::Fill, Fill );
}
QskProgressRing::QskProgressRing( QQuickItem* parent )
: QskProgressRing( 0.0, 100.0, parent )
{
}
QskProgressRing::QskProgressRing( const QskIntervalF& boundaries, QQuickItem* parent )
: QskProgressRing( boundaries.lowerBound(), boundaries.upperBound(), parent )
{
}
QskProgressRing::~QskProgressRing()
{
}
QskAspect::Variation QskProgressRing::effectiveVariation() const
{
switch( size() )
{
case SmallSize:
return QskAspect::Small;
case LargeSize:
return QskAspect::Large;
default:
return QskAspect::NoVariation;
}
}
void QskProgressRing::setSize( Size size )
{
if ( size != m_data->size )
{
m_data->size = size;
resetImplicitSize();
update();
Q_EMIT sizeChanged( size );
}
}
QskProgressRing::Size QskProgressRing::size() const
{
return static_cast< Size >( m_data->size );
}
#include "moc_QskProgressRing.cpp"

View File

@ -0,0 +1,50 @@
/******************************************************************************
* QSkinny - Copyright (C) 2023 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_PROGRESS_RING_H
#define QSK_PROGRESS_RING_H
#include "QskProgressIndicator.h"
class QSK_EXPORT QskProgressRing : public QskProgressIndicator
{
Q_OBJECT
Q_PROPERTY( Size size READ size
WRITE setSize NOTIFY sizeChanged )
using Inherited = QskProgressIndicator;
public:
QSK_SUBCONTROLS( Groove, Fill )
enum Size
{
SmallSize = -1,
NormalSize = 0,
LargeSize = 1
};
Q_ENUM( Size )
QskProgressRing( QQuickItem* parent = nullptr );
QskProgressRing( qreal min, qreal max, QQuickItem* parent = nullptr );
QskProgressRing( const QskIntervalF&, QQuickItem* parent = nullptr );
~QskProgressRing() override;
QskAspect::Variation effectiveVariation() const override;
void setSize( Size );
Size size() const;
Q_SIGNALS:
void sizeChanged( Size );
private:
class PrivateData;
std::unique_ptr< PrivateData > m_data;
};
#endif

View File

@ -0,0 +1,125 @@
/******************************************************************************
* QSkinny - Copyright (C) 2023 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskProgressRingSkinlet.h"
#include "QskArcMetrics.h"
#include "QskProgressRing.h"
#include "QskIntervalF.h"
using Q = QskProgressRing;
namespace
{
QskIntervalF qskFillInterval( const Q* ring )
{
qreal pos1, pos2;
if ( ring->isIndeterminate() )
{
const auto pos = ring->positionHint( QskProgressIndicator::Fill );
pos1 = pos2 = pos;
}
else
{
pos1 = ring->valueAsRatio( ring->origin() );
pos2 = ring->valueAsRatio( ring->value() );
}
if ( pos1 > pos2 )
std::swap( pos1, pos2 );
return QskIntervalF( pos1, pos2 );
}
}
QskProgressRingSkinlet::QskProgressRingSkinlet( QskSkin* skin )
: Inherited( skin )
{
}
QskProgressRingSkinlet::~QskProgressRingSkinlet()
{
}
QRectF QskProgressRingSkinlet::subControlRect(
const QskSkinnable* skinnable, const QRectF& contentsRect,
QskAspect::Subcontrol subControl ) const
{
const auto ring = static_cast< const Q* >( skinnable );
if( subControl == Q::Groove || subControl == Q::Fill )
{
auto rect = contentsRect;
const auto size = ring->strutSizeHint( Q::Fill );
if( ring->layoutMirroring() )
{
rect.setLeft( rect.right() - size.width() );
}
else
{
rect.setWidth( size.width() );
}
rect.setTop( rect.top() + 0.5 * ( rect.height() - size.height() ) );
rect.setHeight( size.height() );
return rect;
}
return Inherited::subControlRect( skinnable, contentsRect, subControl );
}
QSGNode* QskProgressRingSkinlet::updateGrooveNode(
const QskProgressIndicator* indicator, QSGNode* node ) const
{
return updateArcNode( indicator, node, Q::Groove );
}
QSGNode* QskProgressRingSkinlet::updateFillNode(
const QskProgressIndicator* indicator, QSGNode* node ) const
{
const auto ring = static_cast< const Q* >( indicator );
const auto subControl = Q::Fill;
const auto rect = ring->subControlRect( subControl );
if ( rect.isEmpty() )
return nullptr;
auto gradient = ring->gradientHint( subControl );
if ( !gradient.isVisible() )
return nullptr;
if ( ( gradient.type() == QskGradient::Stops ) && !gradient.isMonochrome() )
{
const auto center = rect.center();
const auto arcMetrics = ring->arcMetricsHint( Q::Fill );
gradient.setConicDirection( center.x(), center.y(), arcMetrics.startAngle(), arcMetrics.spanAngle() );
}
const auto interval = qskFillInterval( ring );
const auto arcMetrics = ring->arcMetricsHint( subControl );
const auto startAngle = arcMetrics.startAngle() + interval.lowerBound() * arcMetrics.spanAngle();
const auto spanAngle = interval.upperBound() * arcMetrics.spanAngle();
return updateArcNode( ring, node, rect, gradient, startAngle, spanAngle, subControl );
}
QSizeF QskProgressRingSkinlet::sizeHint( const QskSkinnable* skinnable,
Qt::SizeHint which, const QSizeF& ) const
{
if ( which != Qt::PreferredSize )
return QSizeF();
const auto ring = static_cast< const Q* >( skinnable );
const auto r = ring->strutSizeHint( Q::Fill );
return r;
}
#include "moc_QskProgressRingSkinlet.cpp"

View File

@ -0,0 +1,34 @@
/******************************************************************************
* QSkinny - Copyright (C) 2023 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_PROGRESS_RING_SKINLET_H
#define QSK_PROGRESS_RING_SKINLET_H
#include "QskProgressIndicatorSkinlet.h"
class QskProgressRing;
class QSK_EXPORT QskProgressRingSkinlet : public QskProgressIndicatorSkinlet
{
Q_GADGET
using Inherited = QskProgressIndicatorSkinlet;
public:
Q_INVOKABLE QskProgressRingSkinlet( QskSkin* = nullptr );
~QskProgressRingSkinlet() override;
QRectF subControlRect( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol ) const override;
QSizeF sizeHint( const QskSkinnable*,
Qt::SizeHint, const QSizeF& ) const override;
protected:
QSGNode* updateGrooveNode( const QskProgressIndicator*, QSGNode* ) const override;
QSGNode* updateFillNode( const QskProgressIndicator*, QSGNode* ) const override;
};
#endif

View File

@ -540,7 +540,6 @@ void qskUngrabMouse( QQuickItem* item )
if ( qskIsMouseGrabber( item ) )
item->ungrabMouse();
}
}

View File

@ -362,6 +362,25 @@ void QskScrollBox::geometryChangeEvent( QskGeometryChangeEvent* event )
Inherited::geometryChangeEvent( event );
}
void QskScrollBox::mousePressEvent( QMouseEvent* event )
{
auto& recognizer = m_data->panRecognizer;
if ( recognizer.hasProcessedBefore( event ) )
{
if ( m_data->panRecognizerTimeout != 0 )
{
recognizer.abort();
recognizer.setTimeout( -1 );
recognizer.processEvent( this, event, false );
}
return;
}
return Inherited::mousePressEvent( event );
}
void QskScrollBox::gestureEvent( QskGestureEvent* event )
{
if ( event->gesture()->type() == QskGesture::Pan )
@ -427,7 +446,7 @@ void QskScrollBox::wheelEvent( QWheelEvent* event )
#endif
bool QskScrollBox::gestureFilter( QQuickItem* item, QEvent* event )
bool QskScrollBox::gestureFilter( const QQuickItem* item, const QEvent* event )
{
if ( event->type() == QEvent::MouseButtonPress )
{
@ -458,38 +477,39 @@ bool QskScrollBox::gestureFilter( QQuickItem* item, QEvent* event )
return false;
}
/*
This code is a bit tricky as the filter is called in different situations:
a) The press was on a child of the view
b) The press was on the view
In case of b) things are simple and we can let the recognizer
decide without timeout if it is was a gesture or not.
In case of a) we give the recognizer some time to decide - usually
based on the distances of the following mouse events. If no decision
could be made the recognizer aborts and replays the mouse events, so
that the children can process them.
But if a child does not accept a mouse event it will be sent to
its parent. So we might finally receive the reposted events, but then
we can proceed as in b).
*/
auto& recognizer = m_data->panRecognizer;
recognizer.setTimeout( m_data->panRecognizerTimeout );
if ( event->type() == QEvent::MouseButtonPress )
{
if ( ( item != this ) && ( recognizer.timeout() < 0 ) )
/*
This code is a bit tricky as the filter is called in different situations:
a) The press was on a child of the view
b) The press was on the view
In case of b) things are simple and we can let the recognizer
decide without timeout if it is was a gesture or not.
In case of a) we give the recognizer some time to decide - usually
based on the distances of the following mouse events. If no decision
could be made the recognizer aborts and replays the mouse events, so
that the children can process them.
But if a child does not accept the mouse event it will be sent to
its parent, finally ending up here for a second time.
*/
auto mouseEvent = static_cast< const QMouseEvent* >( event );
if ( recognizer.hasProcessedBefore( mouseEvent ) )
{
const auto mouseEvent = static_cast< QMouseEvent* >( event );
if ( recognizer.hasProcessedBefore( mouseEvent ) )
return false;
/*
Note that the recognizer will be restarted without timout if the
event ends up in in mousePressEvent ( = nobody else was interested )
*/
return false;
}
recognizer.setTimeout( ( item == this ) ? -1 : m_data->panRecognizerTimeout );
}
return recognizer.processEvent( item, event );

View File

@ -64,6 +64,8 @@ class QSK_EXPORT QskScrollBox : public QskControl
protected:
void geometryChangeEvent( QskGeometryChangeEvent* ) override;
void windowChangeEvent( QskWindowChangeEvent* ) override;
void mousePressEvent( QMouseEvent* ) override;
void gestureEvent( QskGestureEvent* ) override;
#ifndef QT_NO_WHEELEVENT
@ -71,7 +73,7 @@ class QSK_EXPORT QskScrollBox : public QskControl
virtual QPointF scrollOffset( const QWheelEvent* ) const;
#endif
bool gestureFilter( QQuickItem*, QEvent* ) override;
bool gestureFilter( const QQuickItem*, const QEvent* ) override;
void setScrollableSize( const QSizeF& );
private:

View File

@ -53,6 +53,9 @@
#include "QskProgressBar.h"
#include "QskProgressBarSkinlet.h"
#include "QskProgressRing.h"
#include "QskProgressRingSkinlet.h"
#include "QskRadioBox.h"
#include "QskRadioBoxSkinlet.h"
@ -178,6 +181,7 @@ QskSkin::QskSkin( QObject* parent )
declareSkinlet< QskTextLabel, QskTextLabelSkinlet >();
declareSkinlet< QskTextInput, QskTextInputSkinlet >();
declareSkinlet< QskProgressBar, QskProgressBarSkinlet >();
declareSkinlet< QskProgressRing, QskProgressRingSkinlet >();
declareSkinlet< QskRadioBox, QskRadioBoxSkinlet >();
const QFont font = QGuiApplication::font();

View File

@ -15,7 +15,7 @@ class QskSkinStateChanger
QskSkinStateChanger( const QskSkinnable* );
~QskSkinStateChanger();
void setStates( QskAspect::States );
void setStates( QskAspect::States, int sampleIndex = -1 );
void resetStates();
private:
@ -34,16 +34,15 @@ inline QskSkinStateChanger::~QskSkinStateChanger()
resetStates();
}
inline void QskSkinStateChanger::setStates( QskAspect::States states )
inline void QskSkinStateChanger::setStates(
QskAspect::States states, int sampleIndex )
{
if ( states != m_skinnable->skinStates() )
m_skinnable->replaceSkinStates( states );
m_skinnable->replaceSkinStates( states, sampleIndex );
}
inline void QskSkinStateChanger::resetStates()
{
if ( m_oldStates != m_skinnable->skinStates() )
m_skinnable->replaceSkinStates( m_oldStates );
m_skinnable->replaceSkinStates( m_oldStates, -1 );
}
#endif

View File

@ -282,8 +282,6 @@ class QskSkinlet::PrivateData
QskSkin* skin;
QVector< quint8 > nodeRoles;
int animatorIndex = -1;
bool ownedBySkinnable : 1;
};
@ -311,21 +309,6 @@ bool QskSkinlet::isOwnedBySkinnable() const
return m_data->ownedBySkinnable;
}
void QskSkinlet::setAnimatorIndex( int index )
{
m_data->animatorIndex = index;
}
void QskSkinlet::resetAnimatorIndex()
{
m_data->animatorIndex = -1;
}
int QskSkinlet::animatorIndex() const
{
return m_data->animatorIndex;
}
void QskSkinlet::setNodeRoles( const QVector< quint8 >& nodeRoles )
{
m_data->nodeRoles = nodeRoles;
@ -796,26 +779,7 @@ QSGNode* QskSkinlet::updateSeriesNode( const QskSkinnable* skinnable,
const auto newStates = sampleStates( skinnable, subControl, i );
QskSkinStateChanger stateChanger( skinnable );
stateChanger.setStates( newStates );
class IndexChanger
{
public:
inline IndexChanger( const QskSkinlet* skinlet, int index )
: m_skinlet( const_cast< QskSkinlet* >( skinlet ) )
{
m_skinlet->setAnimatorIndex( index );
}
inline ~IndexChanger()
{
m_skinlet->resetAnimatorIndex();
}
private:
QskSkinlet* m_skinlet;
};
IndexChanger indexChanger( this, i );
stateChanger.setStates( newStates, i );
newNode = updateSampleNode( skinnable, subControl, i, node );
}

View File

@ -71,10 +71,6 @@ class QSK_EXPORT QskSkinlet
void setOwnedBySkinnable( bool on );
bool isOwnedBySkinnable() const;
void setAnimatorIndex( int );
void resetAnimatorIndex();
int animatorIndex() const;
// Helper functions for creating nodes
static QSGNode* updateBoxNode( const QskSkinnable*, QSGNode*,

View File

@ -122,6 +122,16 @@ static inline T qskColor( const QskSkinnable* skinnable,
aspect | QskAspect::Color, status ).value< T >();
}
static inline constexpr QskAspect qskAnimatorAspect( const QskAspect aspect )
{
/*
We do not need the extra bits that would slow down resolving
the effective aspect in animatedHint.
*/
return aspect.type() | aspect.subControl() | aspect.primitive();
}
static inline void qskTriggerUpdates( QskAspect aspect, QQuickItem* item )
{
/*
@ -238,6 +248,8 @@ class QskSkinnable::PrivateData
QskSkinHintTable hintTable;
QskHintAnimatorTable animators;
int sampleIndex = -1; // for the ugly QskSkinStateChanger hack
typedef std::map< QskAspect::Subcontrol, QskAspect::Subcontrol > ProxyMap;
ProxyMap* subcontrolProxies = nullptr;
@ -983,11 +995,11 @@ QVariant QskSkinnable::animatedHint(
if ( !m_data->animators.isEmpty() )
{
const int index = effectiveSkinlet()->animatorIndex();
const auto a = qskAnimatorAspect( aspect );
v = m_data->animators.currentValue( aspect, index );
if ( !v.isValid() && index >= 0 )
v = m_data->animators.currentValue( aspect, -1 );
v = m_data->animators.currentValue( a, m_data->sampleIndex );
if ( !v.isValid() && m_data->sampleIndex >= 0 )
v = m_data->animators.currentValue( a, -1 );
}
if ( status && v.isValid() )
@ -1296,18 +1308,10 @@ void QskSkinnable::startHintTransition( QskAspect aspect, int index,
v2.setValue( skin->graphicFilter( v2.toInt() ) );
}
/*
We do not need the extra bits that would slow down resolving
the effective aspect in animatedHint.
*/
aspect.clearStates();
aspect.setSection( QskAspect::Body );
aspect.setVariation( QskAspect::NoVariation );
aspect.setAnimator( false );
aspect = qskAnimatorAspect( aspect );
#if DEBUG_ANIMATOR
qDebug() << aspect << animationHint.duration;
qDebug() << aspect << index << animationHint.duration;
#endif
auto animator = m_data->animators.animator( aspect, index );
@ -1326,9 +1330,20 @@ void QskSkinnable::setSkinStateFlag( QskAspect::State stateFlag, bool on )
setSkinStates( newState );
}
void QskSkinnable::replaceSkinStates( QskAspect::States newStates )
void QskSkinnable::replaceSkinStates(
QskAspect::States newStates, int sampleIndex )
{
/*
Hack time: we might need different hints for a specific instance
of a subcontrol ( f.e the selected row in a list box ), what is not
supported by QskAspect.
As a workaround we use QskSkinStateChanger, that sets/restores this state/index
while retrieving the skin hints.
*/
m_data->skinStates = newStates;
m_data->sampleIndex = sampleIndex; // needed to find specific animators
}
void QskSkinnable::addSkinStates( QskAspect::States states )

View File

@ -39,6 +39,7 @@ class QskGraphic;
class QskSkin;
class QskSkinlet;
class QskSkinHintTable;
class QskSkinStateChanger;
class QSK_EXPORT QskSkinHintStatus
{
@ -149,8 +150,6 @@ class QSK_EXPORT QskSkinnable
void addSkinStates( QskAspect::States );
void clearSkinStates( QskAspect::States );
void replaceSkinStates( QskAspect::States );
bool hasSkinState( QskAspect::State ) const;
QskAspect::States skinStates() const;
@ -281,6 +280,9 @@ class QSK_EXPORT QskSkinnable
QVariant interpolatedHint( QskAspect, QskSkinHintStatus* ) const;
const QVariant& storedHint( QskAspect, QskSkinHintStatus* = nullptr ) const;
friend class QskSkinStateChanger;
void replaceSkinStates( QskAspect::States, int sampleIndex = -1 );
class PrivateData;
std::unique_ptr< PrivateData > m_data;
};

View File

@ -0,0 +1,168 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskSwipeView.h"
#include "QskEvent.h"
#include "QskGesture.h"
#include "QskPanGestureRecognizer.h"
#include "QskStackBoxAnimator.h"
#include "QskPlatform.h"
class QskSwipeView::PrivateData
{
public:
QskPanGestureRecognizer panRecognizer;
int duration = -1; // should be a skinHint
};
QSK_SUBCONTROL( QskSwipeView, Panel )
QskSwipeView::QskSwipeView( QQuickItem* parent )
: Inherited( parent )
, m_data( new PrivateData() )
{
setFiltersChildMouseEvents( true );
setAcceptedMouseButtons( Qt::LeftButton );
auto& recognizer = m_data->panRecognizer;
recognizer.setWatchedItem( this );
// should be skin hints, TODO
recognizer.setOrientations( Qt::Horizontal );
recognizer.setTimeout( 100 );
resetSwipeDistance();
resetDuration();
}
QskSwipeView::~QskSwipeView()
{
}
void QskSwipeView::setOrientation( Qt::Orientation orientation )
{
if ( orientation != this->orientation() )
{
m_data->panRecognizer.setOrientations( orientation );
Q_EMIT orientationChanged( orientation );
}
}
Qt::Orientation QskSwipeView::orientation() const
{
return ( m_data->panRecognizer.orientations() == Qt::Vertical )
? Qt::Vertical : Qt::Horizontal;
}
int QskSwipeView::swipeDistance() const
{
return m_data->panRecognizer.minDistance();
}
void QskSwipeView::setSwipeDistance( int distance )
{
const auto oldDistance = m_data->panRecognizer.minDistance();
m_data->panRecognizer.setMinDistance( distance );
if ( oldDistance != m_data->panRecognizer.minDistance() )
Q_EMIT swipeDistanceChanged( m_data->panRecognizer.minDistance() );
}
void QskSwipeView::resetSwipeDistance()
{
setSwipeDistance( qRound( qskDpToPixels( 40 ) ) );
}
int QskSwipeView::duration() const
{
return m_data->duration;
}
void QskSwipeView::setDuration( int duration )
{
if ( duration != m_data->duration )
{
m_data->duration = duration;
Q_EMIT durationChanged( duration );
}
}
void QskSwipeView::resetDuration()
{
setDuration( 500 );
}
bool QskSwipeView::gestureFilter( const QQuickItem* item, const QEvent* event )
{
// see QskScrollBox.cpp
auto& recognizer = m_data->panRecognizer;
if ( event->type() == QEvent::MouseButtonPress )
{
auto mouseEvent = static_cast< const QMouseEvent* >( event );
if ( recognizer.hasProcessedBefore( mouseEvent ) )
return false;
}
return recognizer.processEvent( item, event );
}
void QskSwipeView::gestureEvent( QskGestureEvent* event )
{
const auto gesture = static_cast< const QskPanGesture* >( event->gesture().get() );
if( gesture->type() == QskGesture::Pan && gesture->state() == QskGesture::Started )
{
if ( itemCount() <= 1 )
return;
bool forwards;
if ( orientation() == Qt::Horizontal )
forwards = gesture->angle() >= 90.0 && gesture->angle() <= 270.0;
else
forwards = gesture->angle() >= 180.0;
auto animator = qobject_cast< QskStackBoxAnimator1* >( this->animator() );
if ( animator == nullptr )
animator = new QskStackBoxAnimator1( this );
if ( orientation() == Qt::Horizontal )
animator->setDirection( forwards ? Qsk::LeftToRight : Qsk::RightToLeft );
else
animator->setDirection( forwards ? Qsk::TopToBottom : Qsk::BottomToTop );
animator->setDuration( m_data->duration );
QskStackBox::setAnimator( animator );
auto newIndex = forwards ? currentIndex() + 1 : currentIndex() - 1;
if( newIndex < 0 )
newIndex += itemCount();
newIndex %= itemCount();
setCurrentIndex( newIndex );
return;
}
Inherited::gestureEvent( event );
}
QskAspect::Subcontrol QskSwipeView::effectiveSubcontrol(
QskAspect::Subcontrol subControl ) const
{
if ( subControl == QskBox::Panel )
return QskSwipeView::Panel;
return Inherited::effectiveSubcontrol( subControl );
}
#include "moc_QskSwipeView.cpp"

View File

@ -0,0 +1,70 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_SWIPE_VIEW_H
#define QSK_SWIPE_VIEW_H
#include "QskStackBox.h"
class QSK_EXPORT QskSwipeView : public QskStackBox
{
Q_OBJECT
Q_PROPERTY( int duration READ duration
WRITE setDuration RESET resetDuration NOTIFY durationChanged )
Q_PROPERTY( int swipeDistance READ swipeDistance
WRITE setSwipeDistance RESET resetSwipeDistance NOTIFY swipeDistanceChanged )
Q_PROPERTY( Qt::Orientation orientation READ orientation
WRITE setOrientation NOTIFY orientationChanged )
using Inherited = QskStackBox;
public:
QSK_SUBCONTROLS( Panel )
QskSwipeView( QQuickItem* parent = nullptr );
~QskSwipeView() override;
void setOrientation( Qt::Orientation );
Qt::Orientation orientation() const;
// Duration is the time ( in ms ) used for changing between pages
int duration() const;
void setDuration( int );
void resetDuration();
/*
Even if called "swipe view" we use a pan - no swipe - gesture.
( = pages are moved before the gesture has been confirmed )
The swipe distance is the minimum distance in pixels of the pan gesture
*/
int swipeDistance() const;
void setSwipeDistance( int );
void resetSwipeDistance();
QskAspect::Subcontrol effectiveSubcontrol( QskAspect::Subcontrol ) const;
Q_SIGNALS:
void orientationChanged( Qt::Orientation );
void durationChanged( int );
void swipeDistanceChanged( int );
protected:
bool gestureFilter( const QQuickItem*, const QEvent* ) override;
void gestureEvent( QskGestureEvent* ) override;
private:
void setAnimator( QskStackBoxAnimator* ) = delete;
class PrivateData;
std::unique_ptr< PrivateData > m_data;
};
#endif

View File

@ -13,53 +13,6 @@ QSK_QT_PRIVATE_BEGIN
#include <private/qquickitem_p.h>
QSK_QT_PRIVATE_END
static Qsk::Direction qskDirection(
Qt::Orientation orientation, int from, int to, int itemCount )
{
Qsk::Direction direction;
if ( orientation == Qt::Horizontal )
{
direction = Qsk::RightToLeft;
if ( to > from )
{
const bool isWrapping = ( from == 0 ) && ( to == itemCount - 1 );
if ( !isWrapping )
direction = Qsk::LeftToRight;
}
else
{
const bool isWrapping = ( to == 0 ) && ( from == itemCount - 1 );
if ( isWrapping )
direction = Qsk::LeftToRight;
}
}
else
{
direction = Qsk::BottomToTop;
if ( to > from )
{
const bool isWrapping = ( from == 0 ) && ( to == itemCount - 1 );
if ( !isWrapping )
direction = Qsk::TopToBottom;
}
else
{
const bool isWrapping = ( to == 0 ) && ( from == itemCount - 1 );
if ( isWrapping )
direction = Qsk::TopToBottom;
}
}
return direction;
}
namespace
{
class RotationTransform : public QQuickTransform
@ -240,7 +193,7 @@ void QskStackBoxAnimator::advance( qreal progress )
QskStackBoxAnimator1::QskStackBoxAnimator1( QskStackBox* parent )
: QskStackBoxAnimator( parent )
, m_orientation( Qt::Horizontal )
, m_direction( Qsk::LeftToRight )
, m_isDirty( false )
, m_hasClip( false )
{
@ -251,27 +204,24 @@ QskStackBoxAnimator1::~QskStackBoxAnimator1()
{
}
void QskStackBoxAnimator1::setOrientation( Qt::Orientation orientation )
void QskStackBoxAnimator1::setDirection( Qsk::Direction direction )
{
if ( m_orientation != orientation )
if ( m_direction != direction )
{
stop();
m_orientation = orientation;
m_direction = direction;
}
}
Qt::Orientation QskStackBoxAnimator1::orientation() const
Qsk::Direction QskStackBoxAnimator1::direction() const
{
return m_orientation;
return m_direction;
}
void QskStackBoxAnimator1::setup()
{
auto stackBox = this->stackBox();
m_direction = qskDirection( m_orientation,
startIndex(), endIndex(), stackBox->itemCount() );
m_hasClip = stackBox->clip();
if ( !m_hasClip )
stackBox->setClip( true );
@ -283,7 +233,9 @@ void QskStackBoxAnimator1::setup()
void QskStackBoxAnimator1::advanceIndex( qreal value )
{
auto stackBox = this->stackBox();
const bool isHorizontal = m_orientation == Qt::Horizontal;
const bool isHorizontal = ( m_direction == Qsk::LeftToRight )
|| ( m_direction == Qsk::RightToLeft );
for ( int i = 0; i < 2; i++ )
{

View File

@ -49,14 +49,14 @@ class QSK_EXPORT QskStackBoxAnimator1 : public QskStackBoxAnimator
{
Q_OBJECT
Q_PROPERTY( Qt::Orientation orientation READ orientation WRITE setOrientation )
Q_PROPERTY( Qsk::Direction direction READ direction WRITE setDirection )
public:
QskStackBoxAnimator1( QskStackBox* );
~QskStackBoxAnimator1() override;
void setOrientation( Qt::Orientation );
Qt::Orientation orientation() const;
void setDirection( Qsk::Direction );
Qsk::Direction direction() const;
protected:
bool eventFilter( QObject*, QEvent* ) override;
@ -68,7 +68,6 @@ class QSK_EXPORT QskStackBoxAnimator1 : public QskStackBoxAnimator
private:
qreal m_itemOffset[ 2 ];
Qt::Orientation m_orientation : 2;
Qsk::Direction m_direction : 4;
bool m_isDirty : 1;
bool m_hasClip : 1;