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 );
menu.setPopupFlag( QskPopup::DeleteOnClose, false );
menu.addItem( "image://shapes/Rectangle/White", "Print" );
menu.addItem( "image://shapes/Diamond/Yellow", "Save As" );
menu.addItem( "image://shapes/Ellipse/Red", "Setup" );
menu.addItem( "image://shapes/Hexagon/PapayaWhip", "Help" );
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", "Help" );
menu.setOrigin( qskMousePosition( event ) );

View File

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

View File

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

View File

@ -32,7 +32,7 @@ class QSK_EXPORT QskMenu : public QskPopup
using Inherited = QskPopup;
public:
QSK_SUBCONTROLS( Panel, Cell, Cursor, Text, Graphic )
QSK_SUBCONTROLS( Panel, Cell, Cursor, Text, Graphic, Separator )
QSK_STATES( Selected )
QskMenu( QQuickItem* parentItem = nullptr );
@ -45,22 +45,25 @@ class QSK_EXPORT QskMenu : public QskPopup
void setOrigin( const QPointF& );
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 );
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;
virtual QskColorFilter graphicFilterAt( int index ) const;
QRectF focusIndicatorRect() const override;
QRectF cellRect( int index ) const;

View File

@ -19,19 +19,11 @@
template< class T >
static inline QVariant qskSampleAt( const QskMenu* menu, int index )
{
const auto item = menu->itemAt( index );
if ( item.canConvert< T >() )
return item;
if ( item.canConvert< QVariantList >() )
const auto list = menu->optionAt( index );
for ( const auto& value : list )
{
const auto list = item.value< QVariantList >();
for ( const auto& value : list )
{
if ( value.canConvert< T >() )
return value;
}
if ( value.canConvert< T >() )
return value;
}
return QVariant();
@ -70,6 +62,18 @@ class QskMenuSkinlet::PrivateData
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
{
if ( m_isCaching )
@ -291,7 +295,16 @@ QRectF QskMenuSkinlet::sampleRect(
if ( subControl == Q::Cell )
{
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 );
}
@ -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(
skinnable, contentsRect, subControl, index );
}
@ -345,6 +378,12 @@ int QskMenuSkinlet::sampleCount(
return menu->count();
}
if ( subControl == Q::Separator )
{
const auto menu = static_cast< const QskMenu* >( skinnable );
return menu->separatorCount();
}
return Inherited::sampleCount( skinnable, subControl );
}
@ -391,8 +430,8 @@ QSGNode* QskMenuSkinlet::updateContentsNode(
QSGNode* QskMenuSkinlet::updateMenuNode(
const QskSkinnable* skinnable, QSGNode* contentsNode ) const
{
enum { Panel, Background, Cursor, Graphic, Text };
static QVector< quint8 > roles = { Panel, Background, Cursor, Graphic, Text };
enum { Panel, Cell, Cursor, Graphic, Text, Separator };
static QVector< quint8 > roles = { Panel, Separator, Cell, Cursor, Graphic, Text };
if ( contentsNode == nullptr )
contentsNode = new QSGNode();
@ -410,7 +449,7 @@ QSGNode* QskMenuSkinlet::updateMenuNode(
newNode = updateBoxNode( skinnable, oldNode, QskMenu::Panel );
break;
}
case Background:
case Cell:
{
newNode = updateSeriesNode( skinnable, QskMenu::Cell, oldNode );
break;
@ -430,6 +469,11 @@ QSGNode* QskMenuSkinlet::updateMenuNode(
newNode = updateSeriesNode( skinnable, QskMenu::Text, oldNode );
break;
}
case Separator:
{
newNode = updateSeriesNode( skinnable, QskMenu::Separator, oldNode );
break;
}
}
QskSGNode::replaceChildNode( roles, role, contentsNode, oldNode, newNode );
@ -475,34 +519,42 @@ QSGNode* QskMenuSkinlet::updateSampleNode( const QskSkinnable* skinnable,
subControl, Qt::AlignVCenter | Qt::AlignLeft );
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;
}
QSizeF QskMenuSkinlet::sizeHint( const QskSkinnable* skinnable,
Qt::SizeHint which, const QSizeF& ) const
{
if ( which != Qt::PreferredSize )
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 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 );
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 ) );
hint = hint.expandedTo( skinnable->strutSizeHint( QskMenu::Panel ) );