menu separators added

This commit is contained in:
Uwe Rathmann 2022-01-06 18:36:15 +01:00
parent 8b5077ed2b
commit 36001a6fec
5 changed files with 149 additions and 77 deletions

View File

@ -88,10 +88,11 @@ class GraphicLabel : public QskGraphicLabel
QskMenu menu( this ); QskMenu menu( this );
menu.setPopupFlag( QskPopup::DeleteOnClose, false ); menu.setPopupFlag( QskPopup::DeleteOnClose, false );
menu.addItem( "image://shapes/Rectangle/White", "Print" ); menu.addOption( "image://shapes/Rectangle/White", "Print" );
menu.addItem( "image://shapes/Diamond/Yellow", "Save As" ); menu.addOption( "image://shapes/Diamond/Yellow", "Save As" );
menu.addItem( "image://shapes/Ellipse/Red", "Setup" ); menu.addOption( "image://shapes/Ellipse/Red", "Setup" );
menu.addItem( "image://shapes/Hexagon/PapayaWhip", "Help" ); menu.addSeparator();
menu.addOption( "image://shapes/Hexagon/PapayaWhip", "Help" );
menu.setOrigin( qskMousePosition( event ) ); menu.setOrigin( qskMousePosition( event ) );

View File

@ -317,9 +317,9 @@ void Editor::setupMenu()
#if 0 #if 0
setPadding( Q::Separator, QMarginsF( 10, 0, 10, 0 ) ); setPadding( Q::Separator, QMarginsF( 10, 0, 10, 0 ) );
setMetric( Q::Separator | QskAspect::Size, 3 );
setVGradient( Q::Separator, c2, c1 );
#endif #endif
setMetric( Q::Separator | A::Size, 2 );
setSeparator( Q::Separator | A::Horizontal );
setPadding( Q::Cell, QskMargins( 2, 10, 2, 10 ) ); setPadding( Q::Cell, QskMargins( 2, 10, 2, 10 ) );
setSpacing( Q::Cell, 5 ); setSpacing( Q::Cell, 5 );

View File

@ -16,23 +16,35 @@ QSK_SUBCONTROL( QskMenu, Cell )
QSK_SUBCONTROL( QskMenu, Cursor ) QSK_SUBCONTROL( QskMenu, Cursor )
QSK_SUBCONTROL( QskMenu, Text ) QSK_SUBCONTROL( QskMenu, Text )
QSK_SUBCONTROL( QskMenu, Graphic ) QSK_SUBCONTROL( QskMenu, Graphic )
QSK_SUBCONTROL( QskMenu, Separator )
QSK_SYSTEM_STATE( QskMenu, Selected, QskAspect::FirstSystemState << 2 ) QSK_SYSTEM_STATE( QskMenu, Selected, QskAspect::FirstSystemState << 2 )
namespace namespace
{ {
struct Entry class Option
{ {
QUrl graphicSource; public:
Option( const QUrl& graphicSource, const QString& text )
: graphicSource( graphicSource )
, text( text )
{
if( !graphicSource.isEmpty() )
graphic = Qsk::loadGraphic( graphicSource );
}
const QUrl graphicSource;
const QString text;
QskGraphic graphic; QskGraphic graphic;
QString text;
}; };
} }
class QskMenu::PrivateData class QskMenu::PrivateData
{ {
public: public:
QVector< Entry > entries; QVector< Option > options;
QVector< int > separators;
QskTextOptions textOptions; QskTextOptions textOptions;
QPointF origin; QPointF origin;
@ -94,13 +106,9 @@ QPointF QskMenu::origin() const
return m_data->origin; return m_data->origin;
} }
void QskMenu::addItem( const QUrl& graphicSource, const QString& text ) void QskMenu::addOption( const QUrl& graphicSource, const QString& text )
{ {
QskGraphic graphic; m_data->options += Option( graphicSource, text );
if( !graphicSource.isEmpty() )
graphic = Qsk::loadGraphic( graphicSource );
m_data->entries += { graphicSource, graphic, text };
resetImplicitSize(); resetImplicitSize();
update(); update();
@ -109,38 +117,52 @@ void QskMenu::addItem( const QUrl& graphicSource, const QString& text )
countChanged( count() ); countChanged( count() );
} }
void QskMenu::addItem( const QString& graphicSource, const QString& text ) void QskMenu::addOption( const QString& graphicSource, const QString& text )
{ {
addItem( QUrl( graphicSource ), text ); addOption( QUrl( graphicSource ), text );
}
void QskMenu::addSeparator()
{
// TODO ...
}
void QskMenu::clear()
{
m_data->entries.clear();
} }
int QskMenu::count() const int QskMenu::count() const
{ {
return m_data->entries.count(); return m_data->options.count();
} }
QVariant QskMenu::itemAt( int index ) const void QskMenu::addSeparator()
{ {
const auto& entries = m_data->entries; m_data->separators += m_data->options.count();
if( index < 0 || index >= entries.count() ) resetImplicitSize();
return QVariant(); update();
}
const auto& entry = m_data->entries[ index ]; int QskMenu::separatorPosition( int index ) const
{
return m_data->separators.value( index, -1 );
}
int QskMenu::separatorCount() const
{
return m_data->separators.count();
}
void QskMenu::clear()
{
m_data->options.clear();
m_data->separators.clear();
}
QVariantList QskMenu::optionAt( int index ) const
{
const auto& options = m_data->options;
if( index < 0 || index >= options.count() )
return QVariantList();
const auto& option = options[ index ];
QVariantList list; QVariantList list;
list += QVariant::fromValue( entry.graphic ); list += QVariant::fromValue( option.graphic );
list += QVariant::fromValue( entry.text ); list += QVariant::fromValue( option.text );
return list; return list;
} }
@ -270,12 +292,6 @@ void QskMenu::traverse( int steps )
setCurrentIndex( newIndex ); setCurrentIndex( newIndex );
} }
QskColorFilter QskMenu::graphicFilterAt( int index ) const
{
Q_UNUSED( index )
return QskColorFilter();
}
void QskMenu::mousePressEvent( QMouseEvent* event ) void QskMenu::mousePressEvent( QMouseEvent* event )
{ {
// QGuiApplication::styleHints()->setFocusOnTouchRelease ?? // QGuiApplication::styleHints()->setFocusOnTouchRelease ??

View File

@ -32,7 +32,7 @@ class QSK_EXPORT QskMenu : public QskPopup
using Inherited = QskPopup; using Inherited = QskPopup;
public: public:
QSK_SUBCONTROLS( Panel, Cell, Cursor, Text, Graphic ) QSK_SUBCONTROLS( Panel, Cell, Cursor, Text, Graphic, Separator )
QSK_STATES( Selected ) QSK_STATES( Selected )
QskMenu( QQuickItem* parentItem = nullptr ); QskMenu( QQuickItem* parentItem = nullptr );
@ -45,22 +45,25 @@ class QSK_EXPORT QskMenu : public QskPopup
void setOrigin( const QPointF& ); void setOrigin( const QPointF& );
QPointF origin() const; QPointF origin() const;
// insert, remove, functors, actions, QskGraphic ...
void addItem( const QUrl& graphicSource, const QString& text );
void addItem( const QString& graphicSource, const QString& text );
void addSeparator();
virtual QVariant itemAt( int ) const;
virtual int count() const;
virtual void clear();
void setTextOptions( const QskTextOptions& textOptions ); void setTextOptions( const QskTextOptions& textOptions );
QskTextOptions textOptions() const; QskTextOptions textOptions() const;
// insert, remove, functors, actions, QskGraphic ...
void addOption( const QUrl& graphicSource, const QString& text );
void addOption( const QString& graphicSource, const QString& text );
QVariantList optionAt( int ) const;
int count() const;
void addSeparator();
int separatorPosition( int ) const;
int separatorCount() const;
void clear();
int currentIndex() const; int currentIndex() const;
virtual QskColorFilter graphicFilterAt( int index ) const;
QRectF focusIndicatorRect() const override; QRectF focusIndicatorRect() const override;
QRectF cellRect( int index ) const; QRectF cellRect( int index ) const;

View File

@ -19,19 +19,11 @@
template< class T > template< class T >
static inline QVariant qskSampleAt( const QskMenu* menu, int index ) static inline QVariant qskSampleAt( const QskMenu* menu, int index )
{ {
const auto item = menu->itemAt( index ); const auto list = menu->optionAt( index );
for ( const auto& value : list )
if ( item.canConvert< T >() )
return item;
if ( item.canConvert< QVariantList >() )
{ {
const auto list = item.value< QVariantList >(); if ( value.canConvert< T >() )
for ( const auto& value : list ) return value;
{
if ( value.canConvert< T >() )
return value;
}
} }
return QVariant(); return QVariant();
@ -70,6 +62,18 @@ class QskMenuSkinlet::PrivateData
m_cellHeight = m_cellWidth = m_graphicWidth = m_textWidth = -1.0; m_cellHeight = m_cellWidth = m_graphicWidth = m_textWidth = -1.0;
} }
inline int separatorsBefore( const QskMenu* menu, int index ) const
{
int i = 0;
for ( ; i < menu->separatorCount(); i++ )
{
if ( menu->separatorPosition( i ) > index )
break;
}
return i;
}
inline qreal graphicWidth( const QskMenu* menu ) const inline qreal graphicWidth( const QskMenu* menu ) const
{ {
if ( m_isCaching ) if ( m_isCaching )
@ -291,7 +295,16 @@ QRectF QskMenuSkinlet::sampleRect(
if ( subControl == Q::Cell ) if ( subControl == Q::Cell )
{ {
const auto r = menu->subControlContentsRect( Q::Panel ); const auto r = menu->subControlContentsRect( Q::Panel );
const auto h = m_data->cellHeight( menu );
auto h = m_data->cellHeight( menu );
if ( int n = m_data->separatorsBefore( menu, index ) )
{
// spacing ???
const qreal separatorH = menu->metric( Q::Separator | QskAspect::Size );
h += n * separatorH;
}
return QRectF( r.x(), r.y() + index * h, r.width(), h ); return QRectF( r.x(), r.y() + index * h, r.width(), h );
} }
@ -322,6 +335,26 @@ QRectF QskMenuSkinlet::sampleRect(
} }
} }
if ( subControl == QskMenu::Separator )
{
const int pos = menu->separatorPosition( index );
if ( pos < 0 )
return QRectF();
QRectF r = menu->subControlContentsRect( Q::Panel );
if ( pos < menu->count() )
{
const auto cellRect = sampleRect( skinnable, contentsRect, Q::Cell, pos );
r.setBottom( cellRect.top() ); // spacing ???
}
const qreal h = menu->metric( Q::Separator | QskAspect::Size );
r.setTop( r.bottom() - h );
return r;
}
return Inherited::sampleRect( return Inherited::sampleRect(
skinnable, contentsRect, subControl, index ); skinnable, contentsRect, subControl, index );
} }
@ -345,6 +378,12 @@ int QskMenuSkinlet::sampleCount(
return menu->count(); return menu->count();
} }
if ( subControl == Q::Separator )
{
const auto menu = static_cast< const QskMenu* >( skinnable );
return menu->separatorCount();
}
return Inherited::sampleCount( skinnable, subControl ); return Inherited::sampleCount( skinnable, subControl );
} }
@ -391,8 +430,8 @@ QSGNode* QskMenuSkinlet::updateContentsNode(
QSGNode* QskMenuSkinlet::updateMenuNode( QSGNode* QskMenuSkinlet::updateMenuNode(
const QskSkinnable* skinnable, QSGNode* contentsNode ) const const QskSkinnable* skinnable, QSGNode* contentsNode ) const
{ {
enum { Panel, Background, Cursor, Graphic, Text }; enum { Panel, Cell, Cursor, Graphic, Text, Separator };
static QVector< quint8 > roles = { Panel, Background, Cursor, Graphic, Text }; static QVector< quint8 > roles = { Panel, Separator, Cell, Cursor, Graphic, Text };
if ( contentsNode == nullptr ) if ( contentsNode == nullptr )
contentsNode = new QSGNode(); contentsNode = new QSGNode();
@ -410,7 +449,7 @@ QSGNode* QskMenuSkinlet::updateMenuNode(
newNode = updateBoxNode( skinnable, oldNode, QskMenu::Panel ); newNode = updateBoxNode( skinnable, oldNode, QskMenu::Panel );
break; break;
} }
case Background: case Cell:
{ {
newNode = updateSeriesNode( skinnable, QskMenu::Cell, oldNode ); newNode = updateSeriesNode( skinnable, QskMenu::Cell, oldNode );
break; break;
@ -430,6 +469,11 @@ QSGNode* QskMenuSkinlet::updateMenuNode(
newNode = updateSeriesNode( skinnable, QskMenu::Text, oldNode ); newNode = updateSeriesNode( skinnable, QskMenu::Text, oldNode );
break; break;
} }
case Separator:
{
newNode = updateSeriesNode( skinnable, QskMenu::Separator, oldNode );
break;
}
} }
QskSGNode::replaceChildNode( roles, role, contentsNode, oldNode, newNode ); QskSGNode::replaceChildNode( roles, role, contentsNode, oldNode, newNode );
@ -475,34 +519,42 @@ QSGNode* QskMenuSkinlet::updateSampleNode( const QskSkinnable* skinnable,
subControl, Qt::AlignVCenter | Qt::AlignLeft ); subControl, Qt::AlignVCenter | Qt::AlignLeft );
return QskSkinlet::updateTextNode( menu, node, rect, alignment, return QskSkinlet::updateTextNode( menu, node, rect, alignment,
text, menu->textOptions(), QskMenu::Text ); text, QskTextOptions(), Q::Text );
}
if ( subControl == Q::Separator )
{
return updateBoxNode( menu, node, rect, subControl );
} }
return nullptr; return nullptr;
} }
QSizeF QskMenuSkinlet::sizeHint( const QskSkinnable* skinnable, QSizeF QskMenuSkinlet::sizeHint( const QskSkinnable* skinnable,
Qt::SizeHint which, const QSizeF& ) const Qt::SizeHint which, const QSizeF& ) const
{ {
if ( which != Qt::PreferredSize ) if ( which != Qt::PreferredSize )
return QSizeF(); return QSizeF();
const PrivateData::CacheGuard guard( m_data.get() ); using Q = QskMenu;
const auto menu = static_cast< const QskMenu* >( skinnable );
const auto count = sampleCount( skinnable, QskMenu::Cell ); const PrivateData::CacheGuard guard( m_data.get() );
qreal w = 0.0; qreal w = 0.0;
qreal h = 0.0; qreal h = 0.0;
if ( count > 0 ) if ( const auto count = sampleCount( skinnable, Q::Cell ) )
{ {
const auto menu = static_cast< const QskMenu* >( skinnable );
w = m_data->cellWidth( menu ); w = m_data->cellWidth( menu );
h = count * m_data->cellHeight( menu ); h = count * m_data->cellHeight( menu );
} }
if ( const auto count = sampleCount( skinnable, Q::Separator ) )
{
h += count * menu->metric( Q::Separator | QskAspect::Size );
}
auto hint = skinnable->outerBoxSize( QskMenu::Panel, QSizeF( w, h ) ); auto hint = skinnable->outerBoxSize( QskMenu::Panel, QSizeF( w, h ) );
hint = hint.expandedTo( skinnable->strutSizeHint( QskMenu::Panel ) ); hint = hint.expandedTo( skinnable->strutSizeHint( QskMenu::Panel ) );