internal layoutBox replaced by a plain layout. A bit more lightweight
and we do not end up with focus changes when rearranging the buttons
This commit is contained in:
parent
ff8a5fbe31
commit
4938156ada
|
@ -8,6 +8,8 @@
|
||||||
#include "QskLinearBox.h"
|
#include "QskLinearBox.h"
|
||||||
#include "QskSkin.h"
|
#include "QskSkin.h"
|
||||||
|
|
||||||
|
#include "QskLinearLayoutEngine.h"
|
||||||
|
|
||||||
#include <qevent.h>
|
#include <qevent.h>
|
||||||
#include <qpointer.h>
|
#include <qpointer.h>
|
||||||
#include <qvector.h>
|
#include <qvector.h>
|
||||||
|
@ -19,6 +21,8 @@ QSK_QT_PRIVATE_BEGIN
|
||||||
#include <private/qguiapplication_p.h>
|
#include <private/qguiapplication_p.h>
|
||||||
QSK_QT_PRIVATE_END
|
QSK_QT_PRIVATE_END
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
QSK_SUBCONTROL( QskDialogButtonBox, Panel )
|
QSK_SUBCONTROL( QskDialogButtonBox, Panel )
|
||||||
|
|
||||||
static void qskSendEventTo( QObject* object, QEvent::Type type )
|
static void qskSendEventTo( QObject* object, QEvent::Type type )
|
||||||
|
@ -35,38 +39,53 @@ static inline QskDialog::ActionRole qskActionRole( QskDialog::Action action )
|
||||||
return static_cast< QskDialog::ActionRole >( role );
|
return static_cast< QskDialog::ActionRole >( role );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qskAddToLayout( const QVector< QskPushButton* >& buttons,
|
namespace
|
||||||
bool reverse, QskLinearBox* layoutBox )
|
|
||||||
{
|
{
|
||||||
if ( reverse )
|
class LayoutEngine : public QskLinearLayoutEngine
|
||||||
{
|
{
|
||||||
for ( int i = buttons.count() - 1; i >= 0; i-- )
|
public:
|
||||||
layoutBox->addItem( buttons[ i ] );
|
LayoutEngine( Qt::Orientation orientation )
|
||||||
}
|
: QskLinearLayoutEngine( orientation, std::numeric_limits< uint >::max() )
|
||||||
else
|
{
|
||||||
{
|
}
|
||||||
for ( int i = 0; i < buttons.count(); i++ )
|
|
||||||
layoutBox->addItem( buttons[ i ] );
|
void addStretch()
|
||||||
}
|
{
|
||||||
|
const auto index = insertSpacerAt( count(), 0 );
|
||||||
|
setStretchFactorAt( index, 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void addButtons( const QVector< QskPushButton* >& buttons, bool reverse )
|
||||||
|
{
|
||||||
|
if ( reverse )
|
||||||
|
{
|
||||||
|
for ( int i = buttons.count() - 1; i >= 0; i-- )
|
||||||
|
addItem( buttons[ i ] );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < buttons.count(); i++ )
|
||||||
|
addItem( buttons[ i ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class QskDialogButtonBox::PrivateData
|
class QskDialogButtonBox::PrivateData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PrivateData()
|
PrivateData( Qt::Orientation orientation )
|
||||||
: centeredButtons( false )
|
: layoutEngine( orientation )
|
||||||
, dirtyLayout( false )
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QskLinearBox* layoutBox = nullptr;
|
LayoutEngine layoutEngine;
|
||||||
|
|
||||||
QVector< QskPushButton* > buttons[ QskDialog::NActionRoles ];
|
QVector< QskPushButton* > buttons[ QskDialog::NActionRoles ];
|
||||||
QPointer< QskPushButton > defaultButton;
|
QPointer< QskPushButton > defaultButton;
|
||||||
|
|
||||||
QskDialog::Action clickedAction = QskDialog::NoAction;
|
QskDialog::Action clickedAction = QskDialog::NoAction;
|
||||||
|
bool centeredButtons = false;
|
||||||
bool centeredButtons : 1;
|
|
||||||
bool dirtyLayout : 1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QskDialogButtonBox::QskDialogButtonBox( QQuickItem* parent )
|
QskDialogButtonBox::QskDialogButtonBox( QQuickItem* parent )
|
||||||
|
@ -76,10 +95,14 @@ QskDialogButtonBox::QskDialogButtonBox( QQuickItem* parent )
|
||||||
|
|
||||||
QskDialogButtonBox::QskDialogButtonBox( Qt::Orientation orientation, QQuickItem* parent )
|
QskDialogButtonBox::QskDialogButtonBox( Qt::Orientation orientation, QQuickItem* parent )
|
||||||
: Inherited( parent )
|
: Inherited( parent )
|
||||||
, m_data( new PrivateData() )
|
, m_data( new PrivateData( orientation ) )
|
||||||
{
|
{
|
||||||
setPolishOnResize( true );
|
setPolishOnResize( true );
|
||||||
setOrientation( orientation );
|
|
||||||
|
if ( orientation == Qt::Horizontal )
|
||||||
|
initSizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Fixed );
|
||||||
|
else
|
||||||
|
initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Preferred );
|
||||||
}
|
}
|
||||||
|
|
||||||
QskDialogButtonBox::~QskDialogButtonBox()
|
QskDialogButtonBox::~QskDialogButtonBox()
|
||||||
|
@ -88,13 +111,10 @@ QskDialogButtonBox::~QskDialogButtonBox()
|
||||||
|
|
||||||
void QskDialogButtonBox::setOrientation( Qt::Orientation orientation )
|
void QskDialogButtonBox::setOrientation( Qt::Orientation orientation )
|
||||||
{
|
{
|
||||||
if ( m_data->layoutBox && m_data->layoutBox->orientation() == orientation )
|
if ( m_data->layoutEngine.orientation() == orientation )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
delete m_data->layoutBox;
|
m_data->layoutEngine.setOrientation( orientation );
|
||||||
|
|
||||||
m_data->layoutBox = new QskLinearBox( orientation, this );
|
|
||||||
m_data->layoutBox->setObjectName( QStringLiteral( "DialogButtonBoxLayout" ) );
|
|
||||||
|
|
||||||
if ( orientation == Qt::Horizontal )
|
if ( orientation == Qt::Horizontal )
|
||||||
setSizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Fixed );
|
setSizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Fixed );
|
||||||
|
@ -108,7 +128,7 @@ void QskDialogButtonBox::setOrientation( Qt::Orientation orientation )
|
||||||
|
|
||||||
Qt::Orientation QskDialogButtonBox::orientation() const
|
Qt::Orientation QskDialogButtonBox::orientation() const
|
||||||
{
|
{
|
||||||
return m_data->layoutBox->orientation();
|
return m_data->layoutEngine.orientation();
|
||||||
}
|
}
|
||||||
|
|
||||||
QskAspect::Subcontrol QskDialogButtonBox::substitutedSubcontrol(
|
QskAspect::Subcontrol QskDialogButtonBox::substitutedSubcontrol(
|
||||||
|
@ -123,35 +143,38 @@ QskAspect::Subcontrol QskDialogButtonBox::substitutedSubcontrol(
|
||||||
QSizeF QskDialogButtonBox::layoutSizeHint(
|
QSizeF QskDialogButtonBox::layoutSizeHint(
|
||||||
Qt::SizeHint which, const QSizeF& constraint ) const
|
Qt::SizeHint which, const QSizeF& constraint ) const
|
||||||
{
|
{
|
||||||
if ( m_data->dirtyLayout )
|
if ( which == Qt::MaximumSize )
|
||||||
|
return QSizeF(); // unlimited
|
||||||
|
|
||||||
|
if ( ( m_data->layoutEngine.count() == 0 ) && hasChildItems() )
|
||||||
{
|
{
|
||||||
const_cast< QskDialogButtonBox* >( this )->rearrangeButtons();
|
const_cast< QskDialogButtonBox* >( this )->rearrangeButtons();
|
||||||
m_data->dirtyLayout = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_data->layoutBox->effectiveSizeHint( which, constraint );
|
return m_data->layoutEngine.sizeHint( which, constraint );
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskDialogButtonBox::invalidateLayout()
|
void QskDialogButtonBox::invalidateLayout()
|
||||||
{
|
{
|
||||||
m_data->dirtyLayout = true;
|
m_data->layoutEngine.clear();
|
||||||
|
|
||||||
resetImplicitSize();
|
resetImplicitSize();
|
||||||
polish();
|
polish();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskDialogButtonBox::updateLayout()
|
void QskDialogButtonBox::updateLayout()
|
||||||
{
|
{
|
||||||
if ( m_data->dirtyLayout )
|
auto& layoutEngine = m_data->layoutEngine;
|
||||||
|
|
||||||
|
if ( ( layoutEngine.count() == 0 ) && hasChildItems() )
|
||||||
{
|
{
|
||||||
rearrangeButtons();
|
rearrangeButtons();
|
||||||
m_data->dirtyLayout = false;
|
|
||||||
|
|
||||||
if ( parentItem() )
|
if ( parentItem() && ( layoutEngine.count() > 0 ) )
|
||||||
qskSendEventTo( parentItem(), QEvent::LayoutRequest );
|
qskSendEventTo( parentItem(), QEvent::LayoutRequest );
|
||||||
}
|
}
|
||||||
|
|
||||||
m_data->layoutBox->setGeometry( layoutRect() );
|
if ( !maybeUnresized() )
|
||||||
|
layoutEngine.setGeometries( layoutRect() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskDialogButtonBox::rearrangeButtons()
|
void QskDialogButtonBox::rearrangeButtons()
|
||||||
|
@ -159,14 +182,13 @@ void QskDialogButtonBox::rearrangeButtons()
|
||||||
// Result differs from QDialogButtonBox. Needs more
|
// Result differs from QDialogButtonBox. Needs more
|
||||||
// investigation - TODO ...
|
// investigation - TODO ...
|
||||||
|
|
||||||
auto layoutBox = m_data->layoutBox;
|
auto& layoutEngine = m_data->layoutEngine;
|
||||||
|
layoutEngine.clear();
|
||||||
layoutBox->clear();
|
|
||||||
|
|
||||||
const int* currentLayout = effectiveSkin()->dialogButtonLayout( orientation() );
|
const int* currentLayout = effectiveSkin()->dialogButtonLayout( orientation() );
|
||||||
|
|
||||||
if ( m_data->centeredButtons )
|
if ( m_data->centeredButtons )
|
||||||
layoutBox->addStretch( 1 );
|
layoutEngine.addStretch();
|
||||||
|
|
||||||
while ( *currentLayout != QPlatformDialogHelper::EOL )
|
while ( *currentLayout != QPlatformDialogHelper::EOL )
|
||||||
{
|
{
|
||||||
|
@ -178,7 +200,7 @@ void QskDialogButtonBox::rearrangeButtons()
|
||||||
case QPlatformDialogHelper::Stretch:
|
case QPlatformDialogHelper::Stretch:
|
||||||
{
|
{
|
||||||
if ( !m_data->centeredButtons )
|
if ( !m_data->centeredButtons )
|
||||||
layoutBox->addStretch( 1 );
|
layoutEngine.addStretch();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -187,7 +209,7 @@ void QskDialogButtonBox::rearrangeButtons()
|
||||||
const auto& buttons = m_data->buttons[ role ];
|
const auto& buttons = m_data->buttons[ role ];
|
||||||
|
|
||||||
if ( !buttons.isEmpty() )
|
if ( !buttons.isEmpty() )
|
||||||
layoutBox->addItem( buttons.first() );
|
layoutEngine.addItem( buttons.first() );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -196,7 +218,7 @@ void QskDialogButtonBox::rearrangeButtons()
|
||||||
const auto& buttons = m_data->buttons[ QskDialog::AcceptRole ];
|
const auto& buttons = m_data->buttons[ QskDialog::AcceptRole ];
|
||||||
|
|
||||||
if ( buttons.size() > 1 )
|
if ( buttons.size() > 1 )
|
||||||
qskAddToLayout( buttons.mid( 1 ), reverse, layoutBox );
|
layoutEngine.addButtons( buttons.mid( 1 ), reverse );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -212,7 +234,7 @@ void QskDialogButtonBox::rearrangeButtons()
|
||||||
const auto& buttons = m_data->buttons[ role ];
|
const auto& buttons = m_data->buttons[ role ];
|
||||||
|
|
||||||
if ( !buttons.isEmpty() )
|
if ( !buttons.isEmpty() )
|
||||||
qskAddToLayout( buttons, reverse, layoutBox );
|
layoutEngine.addButtons( buttons, reverse );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -222,9 +244,29 @@ void QskDialogButtonBox::rearrangeButtons()
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( m_data->centeredButtons )
|
if ( m_data->centeredButtons )
|
||||||
layoutBox->addStretch( 1 );
|
layoutEngine.addStretch();
|
||||||
|
|
||||||
// reorganizing the tab chain ???
|
updateTabFocusChain();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskDialogButtonBox::updateTabFocusChain()
|
||||||
|
{
|
||||||
|
if ( childItems().count() <= 1 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
QQuickItem* lastItem = nullptr;
|
||||||
|
|
||||||
|
const auto& layoutEngine = m_data->layoutEngine;
|
||||||
|
for ( int i = 0; i < layoutEngine.count(); i++ )
|
||||||
|
{
|
||||||
|
if ( auto item = layoutEngine.itemAt( i ) )
|
||||||
|
{
|
||||||
|
if ( lastItem )
|
||||||
|
item->stackAfter( lastItem );
|
||||||
|
|
||||||
|
lastItem = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskDialogButtonBox::setCenteredButtons( bool centered )
|
void QskDialogButtonBox::setCenteredButtons( bool centered )
|
||||||
|
@ -255,14 +297,18 @@ void QskDialogButtonBox::addButton(
|
||||||
button->setParent( this );
|
button->setParent( this );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
To have a proper ownership. Inserting the buttons
|
Order of the children according to the layout rules
|
||||||
according to the layout rules will be done later
|
will be done later in updateTabOrder
|
||||||
*/
|
*/
|
||||||
button->setParentItem( m_data->layoutBox );
|
button->setParentItem( this );
|
||||||
|
|
||||||
connect( button, &QskPushButton::clicked, this,
|
connect( button, &QskPushButton::clicked,
|
||||||
&QskDialogButtonBox::onButtonClicked );
|
this, &QskDialogButtonBox::onButtonClicked );
|
||||||
|
|
||||||
|
connect( button, &QskPushButton::visibleChanged,
|
||||||
|
this, &QskDialogButtonBox::invalidateLayout );
|
||||||
|
|
||||||
|
m_data->buttons[ role ].removeOne( button );
|
||||||
m_data->buttons[ role ] += button;
|
m_data->buttons[ role ] += button;
|
||||||
invalidateLayout();
|
invalidateLayout();
|
||||||
}
|
}
|
||||||
|
@ -277,20 +323,21 @@ void QskDialogButtonBox::addAction( QskDialog::Action action )
|
||||||
|
|
||||||
void QskDialogButtonBox::removeButton( QskPushButton* button )
|
void QskDialogButtonBox::removeButton( QskPushButton* button )
|
||||||
{
|
{
|
||||||
// ChildRemove Events !!!
|
|
||||||
|
|
||||||
if ( button == nullptr )
|
if ( button == nullptr )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for ( int i = 0; i < QskDialog::NActionRoles; i++ )
|
for ( int i = 0; i < QskDialog::NActionRoles; i++ )
|
||||||
{
|
{
|
||||||
auto& buttons = m_data->buttons[ i ];
|
if ( m_data->buttons[ i ].removeOne( button ) )
|
||||||
if ( buttons.removeOne( button ) )
|
|
||||||
{
|
{
|
||||||
disconnect( button, &QskPushButton::clicked,
|
disconnect( button, &QskPushButton::clicked,
|
||||||
this, &QskDialogButtonBox::onButtonClicked );
|
this, &QskDialogButtonBox::onButtonClicked );
|
||||||
|
|
||||||
|
disconnect( button, &QskPushButton::visibleChanged,
|
||||||
|
this, &QskDialogButtonBox::invalidateLayout );
|
||||||
|
|
||||||
invalidateLayout();
|
invalidateLayout();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -467,15 +514,43 @@ QskDialog::Action QskDialogButtonBox::clickedAction() const
|
||||||
|
|
||||||
bool QskDialogButtonBox::event( QEvent* event )
|
bool QskDialogButtonBox::event( QEvent* event )
|
||||||
{
|
{
|
||||||
if ( event->type() == QEvent::LayoutRequest )
|
switch ( static_cast< int >( event->type() ) )
|
||||||
{
|
{
|
||||||
if ( !m_data->dirtyLayout )
|
case QEvent::LayoutRequest:
|
||||||
resetImplicitSize();
|
{
|
||||||
|
invalidateLayout();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case QEvent::LayoutDirectionChange:
|
||||||
|
{
|
||||||
|
m_data->layoutEngine.setVisualDirection(
|
||||||
|
layoutMirroring() ? Qt::RightToLeft : Qt::LeftToRight );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::ContentsRectChange:
|
||||||
|
{
|
||||||
|
polish();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Inherited::event( event );
|
return Inherited::event( event );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QskDialogButtonBox::itemChange(
|
||||||
|
QQuickItem::ItemChange change, const QQuickItem::ItemChangeData& value )
|
||||||
|
{
|
||||||
|
Inherited::itemChange( change, value );
|
||||||
|
|
||||||
|
if ( change == ItemChildRemovedChange )
|
||||||
|
{
|
||||||
|
if ( auto button = qobject_cast< QskPushButton* >( value.item ) )
|
||||||
|
removeButton( button );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool QskDialogButtonBox::isDefaultButtonKeyEvent( const QKeyEvent* event )
|
bool QskDialogButtonBox::isDefaultButtonKeyEvent( const QKeyEvent* event )
|
||||||
{
|
{
|
||||||
if ( event->modifiers() & Qt::KeypadModifier && event->key() == Qt::Key_Enter )
|
if ( event->modifiers() & Qt::KeypadModifier && event->key() == Qt::Key_Enter )
|
||||||
|
|
|
@ -72,7 +72,8 @@ class QSK_EXPORT QskDialogButtonBox : public QskBox
|
||||||
void orientationChanged();
|
void orientationChanged();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool event( QEvent* event ) override;
|
bool event( QEvent* ) override;
|
||||||
|
void itemChange( ItemChange, const ItemChangeData& ) override;
|
||||||
|
|
||||||
void updateLayout() override;
|
void updateLayout() override;
|
||||||
QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override;
|
QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override;
|
||||||
|
@ -86,6 +87,7 @@ class QSK_EXPORT QskDialogButtonBox : public QskBox
|
||||||
private:
|
private:
|
||||||
void onButtonClicked();
|
void onButtonClicked();
|
||||||
void rearrangeButtons();
|
void rearrangeButtons();
|
||||||
|
void updateTabFocusChain();
|
||||||
|
|
||||||
class PrivateData;
|
class PrivateData;
|
||||||
std::unique_ptr< PrivateData > m_data;
|
std::unique_ptr< PrivateData > m_data;
|
||||||
|
|
Loading…
Reference in New Issue