QskMenuButton introduced

This commit is contained in:
Uwe Rathmann 2023-05-15 16:58:46 +02:00
parent 99151186fb
commit dbe1fad7ec
7 changed files with 274 additions and 75 deletions

View File

@ -24,7 +24,7 @@
#include <QskSwitchButton.h> #include <QskSwitchButton.h>
#include <QskPushButton.h> #include <QskPushButton.h>
#include <QskScrollArea.h> #include <QskScrollArea.h>
#include <QskMenu.h> #include <QskMenuButton.h>
#include <QskWindow.h> #include <QskWindow.h>
#include <QskDialog.h> #include <QskDialog.h>
#include <QskSkinManager.h> #include <QskSkinManager.h>
@ -36,6 +36,7 @@
#include <QskGraphicProvider.h> #include <QskGraphicProvider.h>
#include <QskGraphicIO.h> #include <QskGraphicIO.h>
#include <QskGraphic.h> #include <QskGraphic.h>
#include <QskLabelData.h>
#include <QskSetup.h> #include <QskSetup.h>
#include <QGuiApplication> #include <QGuiApplication>
@ -111,100 +112,64 @@ namespace
} }
}; };
class MenuButton : public QskPushButton class SkinButton final : public QskMenuButton
{
public:
MenuButton( const QString& text, QQuickItem* parent = nullptr )
: QskPushButton( text, parent )
{
connect( this, &QskPushButton::pressed, this, &MenuButton::openMenu );
}
private:
void openMenu()
{
auto menu = new QskMenu( window()->contentItem() );
populateMenu( menu );
menu->setOrigin( geometry().bottomLeft() );
menu->open();
}
virtual void populateMenu( QskMenu* ) = 0;
};
class SkinButton final : public MenuButton
{ {
public: public:
SkinButton( const QString& text, QQuickItem* parent = nullptr ) SkinButton( const QString& text, QQuickItem* parent = nullptr )
: MenuButton( text, parent ) : QskMenuButton( text, parent )
{
}
private:
void populateMenu( QskMenu* menu ) override
{ {
const auto names = qskSkinManager->skinNames(); const auto names = qskSkinManager->skinNames();
for ( const auto& name : names ) setOptions( names );
menu->addOption( QUrl(), name );
if ( const auto index = names.indexOf( qskSetup->skinName() ) ) if ( const auto index = names.indexOf( qskSetup->skinName() ) )
menu->setCurrentIndex( index ); setStartIndex( index );
connect( menu, &QskMenu::triggered, this, &SkinButton::changeSkin ); connect( this, &QskMenuButton::triggered,
this, &SkinButton::changeSkin );
}
void openMenu() override
{
const auto names = qskSkinManager->skinNames();
setStartIndex( names.indexOf( qskSetup->skinName() ) );
QskMenuButton::openMenu();
} }
void changeSkin( int index ) void changeSkin( int index )
{ {
const auto names = qskSkinManager->skinNames(); const auto names = qskSkinManager->skinNames();
if ( index < 0 || index >= names.size() )
return;
if ( index == names.indexOf( qskSetup->skinName() ) ) if ( ( index >= 0 ) && ( index < names.size() )
return; && ( index != names.indexOf( qskSetup->skinName() ) ) )
auto oldSkin = qskSetup->skin();
if ( oldSkin->parent() == qskSetup )
oldSkin->setParent( nullptr ); // otherwise setSkin deletes it
if ( auto newSkin = qskSetup->setSkin( names[ index ] ) )
{ {
QskSkinTransition transition; Skinny::setSkin( index, 500 );
transition.setSourceSkin( oldSkin );
transition.setTargetSkin( newSkin );
transition.setAnimation( 500 );
transition.process();
if ( oldSkin->parent() == nullptr )
delete oldSkin;
} }
} }
}; };
class FileButton final : public MenuButton class FileButton final : public QskMenuButton
{ {
public: public:
FileButton( const QString& text, QQuickItem* parent = nullptr ) FileButton( const QString& text, QQuickItem* parent = nullptr )
: MenuButton( text, parent ) : QskMenuButton( text, parent )
{ {
} addOption( "image://shapes/Rectangle/White", "Print" );
addOption( "image://shapes/Diamond/Yellow", "Save As" );
private: addOption( "image://shapes/Ellipse/Red", "Setup" );
void populateMenu( QskMenu* menu ) override addSeparator();
{ addOption( "image://shapes/Hexagon/PapayaWhip", "Quit" );
menu->addOption( "image://shapes/Rectangle/White", "Print" );
menu->addOption( "image://shapes/Diamond/Yellow", "Save As" );
menu->addOption( "image://shapes/Ellipse/Red", "Setup" );
menu->addSeparator();
menu->addOption( "image://shapes/Hexagon/PapayaWhip", "Quit" );
// see https://github.com/uwerat/qskinny/issues/192 // see https://github.com/uwerat/qskinny/issues/192
connect( menu, &QskMenu::triggered, connect( this, &QskMenuButton::triggered,
[]( int index ) { if ( index == 3 ) qApp->quit(); } ); this, &FileButton::activate );
}
private:
void activate( int index )
{
if ( optionAt( index ).text() == "Quit" )
qApp->quit();
} }
}; };
@ -241,7 +206,7 @@ namespace
drawer->setEdge( Qt::RightEdge ); drawer->setEdge( Qt::RightEdge );
auto burger = new QskPushButton( "", this ); auto burger = new QskPushButton( "", this );
burger->setEmphasis( QskPushButton::LowEmphasis ); burger->setEmphasis( QskPushButton::LowEmphasis );
connect( burger, &QskPushButton::clicked, connect( burger, &QskPushButton::clicked,
drawer, &QskPopup::open ); drawer, &QskPopup::open );

View File

@ -184,6 +184,7 @@ list(APPEND HEADERS
controls/QskListViewSkinlet.h controls/QskListViewSkinlet.h
controls/QskMenu.h controls/QskMenu.h
controls/QskMenuSkinlet.h controls/QskMenuSkinlet.h
controls/QskMenuButton.h
controls/QskObjectTree.h controls/QskObjectTree.h
controls/QskPageIndicator.h controls/QskPageIndicator.h
controls/QskPageIndicatorSkinlet.h controls/QskPageIndicatorSkinlet.h
@ -280,8 +281,9 @@ list(APPEND SOURCES
controls/QskInputGrabber.cpp controls/QskInputGrabber.cpp
controls/QskListView.cpp controls/QskListView.cpp
controls/QskListViewSkinlet.cpp controls/QskListViewSkinlet.cpp
controls/QskMenuSkinlet.cpp
controls/QskMenu.cpp controls/QskMenu.cpp
controls/QskMenuSkinlet.cpp
controls/QskMenuButton.cpp
controls/QskObjectTree.cpp controls/QskObjectTree.cpp
controls/QskPageIndicator.cpp controls/QskPageIndicator.cpp
controls/QskPageIndicatorSkinlet.cpp controls/QskPageIndicatorSkinlet.cpp

View File

@ -71,8 +71,6 @@ class QSK_EXPORT QskMenu : public QskPopup
QVector< int > separators() const; QVector< int > separators() const;
QVector< int > actions() const; QVector< int > actions() const;
void clear();
int currentIndex() const; int currentIndex() const;
QString currentText() const; QString currentText() const;
@ -97,6 +95,7 @@ class QSK_EXPORT QskMenu : public QskPopup
public Q_SLOTS: public Q_SLOTS:
void setCurrentIndex( int ); void setCurrentIndex( int );
void clear();
protected: protected:
void keyPressEvent( QKeyEvent* ) override; void keyPressEvent( QKeyEvent* ) override;

View File

@ -0,0 +1,153 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskMenuButton.h"
#include "QskMenu.h"
#include "QskLabelData.h"
#include <qpointer.h>
#include <qquickwindow.h>
class QskMenuButton::PrivateData
{
public:
int triggeredIndex = -1;
int startIndex = -1;
QPointer< QskMenu > menu;
QVector< QskLabelData > options;
};
QskMenuButton::QskMenuButton( QQuickItem* parent )
: QskMenuButton( QString(), parent )
{
}
QskMenuButton::QskMenuButton( const QString& text, QQuickItem* parent )
: QskPushButton( text, parent )
, m_data( new PrivateData )
{
connect( this, &QskPushButton::pressed,
this, &QskMenuButton::openMenu );
}
QskMenuButton::~QskMenuButton()
{
}
int QskMenuButton::addOption( const QString& graphicSource, const QString& text )
{
return addOption( QskLabelData( text, graphicSource ) );
}
int QskMenuButton::addOption( const QUrl& graphicSource, const QString& text )
{
return addOption( QskLabelData( text, graphicSource ) );
}
int QskMenuButton::addOption( const QskLabelData& option )
{
const int index = m_data->options.count();
m_data->options += option;
if ( m_data->menu )
m_data->menu->setOptions( m_data->options );
return index;
}
void QskMenuButton::addSeparator()
{
addOption( QskLabelData() );
}
void QskMenuButton::setOptions( const QStringList& options )
{
setOptions( qskCreateLabelData( options ) );
}
void QskMenuButton::setOptions( const QVector< QskLabelData >& options )
{
m_data->options = options;
if ( m_data->menu )
m_data->menu->setOptions( m_data->options );
}
void QskMenuButton::clear()
{
m_data->options.clear();
if ( m_data->menu )
m_data->menu->clear();
}
QVector< QskLabelData > QskMenuButton::options() const
{
return m_data->options;
}
QskLabelData QskMenuButton::optionAt( int index ) const
{
return m_data->options.value( index );
}
int QskMenuButton::optionsCount() const
{
return m_data->options.count();
}
void QskMenuButton::setStartIndex( int index )
{
m_data->startIndex = index;
}
int QskMenuButton::triggeredIndex() const
{
return m_data->triggeredIndex;
}
QString QskMenuButton::triggeredText() const
{
return optionAt( m_data->triggeredIndex ).text();
}
const QskMenu* QskMenuButton::menu() const
{
return m_data->menu;
}
void QskMenuButton::openMenu()
{
if ( m_data->menu || window() == nullptr || m_data->options.isEmpty() )
return;
m_data->triggeredIndex = -1;
auto menu = new QskMenu( window()->contentItem() );
m_data->menu = menu;
menu->setOptions( m_data->options );
if ( m_data->startIndex >= 0 )
menu->setCurrentIndex( m_data->startIndex );
menu->setOrigin( geometry().bottomLeft() );
connect( menu, &QskMenu::triggered,
this, &QskMenuButton::updateTriggeredIndex );
menu->open();
}
void QskMenuButton::updateTriggeredIndex( int index )
{
if ( m_data->triggeredIndex != index )
{
m_data->triggeredIndex = index;
Q_EMIT triggered( index );
}
}
#include "moc_QskMenuButton.cpp"

View File

@ -0,0 +1,67 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_MENU_BUTTON_H
#define QSK_MENU_BUTTON_H
#include "QskPushButton.h"
class QskMenu;
class QskLabelData;
class QSK_EXPORT QskMenuButton : public QskPushButton
{
Q_OBJECT
Q_PROPERTY( QVector< QskLabelData > options READ options
WRITE setOptions NOTIFY optionsChanged )
Q_PROPERTY( int optionsCount READ optionsCount )
Q_PROPERTY( int triggeredIndex READ triggeredIndex NOTIFY triggered )
Q_PROPERTY( QString triggeredText READ triggeredText NOTIFY triggered )
public:
QskMenuButton( QQuickItem* parent = nullptr );
QskMenuButton( const QString& text, QQuickItem* parent = nullptr );
~QskMenuButton() override;
int addOption( const QString&, const QString& );
int addOption( const QUrl&, const QString& );
int addOption( const QskLabelData& );
void addSeparator();
void setOptions( const QVector< QskLabelData >& );
void setOptions( const QStringList& );
QVector< QskLabelData > options() const;
QskLabelData optionAt( int ) const;
int optionsCount() const;
const QskMenu* menu() const;
int triggeredIndex() const;
QString triggeredText() const;
public Q_SLOTS:
void setStartIndex( int );
void clear();
Q_SIGNALS:
void triggered( int index );
void optionsChanged();
protected:
virtual void openMenu();
private:
void updateTriggeredIndex( int );
class PrivateData;
std::unique_ptr< PrivateData > m_data;
};
#endif

View File

@ -135,13 +135,25 @@ static bool pluginPath = initPluginPath();
Q_COREAPP_STARTUP_FUNCTION( initFonts ) Q_COREAPP_STARTUP_FUNCTION( initFonts )
void Skinny::changeSkin( QskAnimationHint hint ) void Skinny::changeSkin( QskAnimationHint hint )
{
const auto names = qskSkinManager->skinNames();
if ( names.size() > 1 )
{
auto index = names.indexOf( qskSetup->skinName() );
index = ( index + 1 ) % names.size();
setSkin( index, hint );
}
}
void Skinny::setSkin( int index, QskAnimationHint hint )
{ {
const auto names = qskSkinManager->skinNames(); const auto names = qskSkinManager->skinNames();
if ( names.size() <= 1 ) if ( names.size() <= 1 )
return; return;
int index = names.indexOf( qskSetup->skinName() ); if ( index == names.indexOf( qskSetup->skinName() ) )
index = ( index + 1 ) % names.size(); return;
auto oldSkin = qskSetup->skin(); auto oldSkin = qskSetup->skin();
if ( oldSkin->parent() == qskSetup ) if ( oldSkin->parent() == qskSetup )

View File

@ -11,6 +11,7 @@
namespace Skinny namespace Skinny
{ {
SKINNY_EXPORT void changeSkin( QskAnimationHint hint = 500 ); SKINNY_EXPORT void changeSkin( QskAnimationHint hint = 500 );
SKINNY_EXPORT void setSkin( int index, QskAnimationHint hint = 500 );
SKINNY_EXPORT void changeFonts( int increment ); SKINNY_EXPORT void changeFonts( int increment );
SKINNY_EXPORT void init(); SKINNY_EXPORT void init();
} }