diff --git a/examples/gallery/icons.qrc b/examples/gallery/icons.qrc
index f6580c6a..001e16e2 100644
--- a/examples/gallery/icons.qrc
+++ b/examples/gallery/icons.qrc
@@ -1,5 +1,9 @@
+ icons/qvg/airport_shuttle.qvg
+ icons/qvg/flight.qvg
+ icons/qvg/local_pizza.qvg
icons/qvg/plus.qvg
+ icons/qvg/sports_soccer.qvg
diff --git a/examples/gallery/icons/airport_shuttle.svg b/examples/gallery/icons/airport_shuttle.svg
new file mode 100644
index 00000000..429b665d
--- /dev/null
+++ b/examples/gallery/icons/airport_shuttle.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/examples/gallery/icons/flight.svg b/examples/gallery/icons/flight.svg
new file mode 100644
index 00000000..fac609e6
--- /dev/null
+++ b/examples/gallery/icons/flight.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/examples/gallery/icons/local_pizza.svg b/examples/gallery/icons/local_pizza.svg
new file mode 100644
index 00000000..37f91bb0
--- /dev/null
+++ b/examples/gallery/icons/local_pizza.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/examples/gallery/icons/qvg/airport_shuttle.qvg b/examples/gallery/icons/qvg/airport_shuttle.qvg
new file mode 100644
index 00000000..d6e0d203
Binary files /dev/null and b/examples/gallery/icons/qvg/airport_shuttle.qvg differ
diff --git a/examples/gallery/icons/qvg/flight.qvg b/examples/gallery/icons/qvg/flight.qvg
new file mode 100644
index 00000000..fc10d775
Binary files /dev/null and b/examples/gallery/icons/qvg/flight.qvg differ
diff --git a/examples/gallery/icons/qvg/local_pizza.qvg b/examples/gallery/icons/qvg/local_pizza.qvg
new file mode 100644
index 00000000..45232c20
Binary files /dev/null and b/examples/gallery/icons/qvg/local_pizza.qvg differ
diff --git a/examples/gallery/icons/qvg/sports_soccer.qvg b/examples/gallery/icons/qvg/sports_soccer.qvg
new file mode 100644
index 00000000..ff92937b
Binary files /dev/null and b/examples/gallery/icons/qvg/sports_soccer.qvg differ
diff --git a/examples/gallery/icons/sports_soccer.svg b/examples/gallery/icons/sports_soccer.svg
new file mode 100644
index 00000000..0ee97398
--- /dev/null
+++ b/examples/gallery/icons/sports_soccer.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/examples/gallery/selector/SelectorPage.cpp b/examples/gallery/selector/SelectorPage.cpp
index 483949a8..054577d4 100644
--- a/examples/gallery/selector/SelectorPage.cpp
+++ b/examples/gallery/selector/SelectorPage.cpp
@@ -19,31 +19,33 @@ namespace
orientation = ( orientation == Qt::Horizontal )
? Qt::Vertical : Qt::Horizontal;
+ const char* texts[] =
+ {
+ "airport",
+ "flight",
+ "pizza",
+ "soccer"
+ };
+
{
auto bar = new QskSegmentedBar( orientation, this );
- bar->addText( "Option 1" );
- bar->addText( "Option 2" );
- bar->addText( "Option 3" );
- bar->addText( "Option 4" );
+ for ( const auto text: texts )
+ bar->addText( text );
}
{
- const auto prefix = QStringLiteral( "image://shapes/" );
-
const char* icons[] =
{
- "rectangle/crimson",
- "triangleright/thistle",
- "ellipse/khaki",
- "ring/sandybrown",
- "star/darkviolet",
- "hexagon/darkslategray"
+ "airport_shuttle",
+ "flight",
+ "local_pizza",
+ "sports_soccer"
};
auto bar = new QskSegmentedBar( orientation, this );
- for ( const auto icon : icons )
- bar->addGraphic( prefix + icon );
+ for ( uint i = 0; i < sizeof( icons ) / sizeof( icons[ 0 ] ); ++i )
+ bar->addGraphicAndText( QUrl( QString( icons[ i ] ) ), texts[ i ] );
}
setExtraSpacingAt( Qt::LeftEdge | Qt::BottomEdge );
diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp
index 9dd14c73..be4eeff0 100644
--- a/skins/material3/QskMaterial3Skin.cpp
+++ b/skins/material3/QskMaterial3Skin.cpp
@@ -433,13 +433,15 @@ void Editor::setupSegmentedBar()
using A = QskAspect;
using Q = QskSegmentedBar;
- const QSize strutSize( -1, 40_dp );
+ const QSize panelStrutSize( -1, 48_dp );
+ const QSize segmentStrutSize( 48_dp, 40_dp );
{
- // Panel
+ // Container
+ setGradient( Q::Panel, Qt::transparent ); // ### background
setPadding( Q::Panel, 0 );
- setSpacing( Q::Panel, 0 );
+ setSpacing( Q::Panel, 8_dp ); // ### messes up the cursor
setBoxShape( Q::Panel, 100, Qt::RelativeSize );
@@ -447,22 +449,24 @@ void Editor::setupSegmentedBar()
setBoxBorderColors( Q::Panel, m_pal.outline );
setBoxBorderColors( Q::Panel | Q::Disabled, m_pal.onSurface12 );
- setStrutSize( Q::Panel | A::Horizontal, strutSize );
- setStrutSize( Q::Panel | A::Vertical, strutSize.transposed() );
+ setStrutSize( Q::Panel | A::Horizontal, panelStrutSize );
+ setStrutSize( Q::Panel | A::Vertical, panelStrutSize.transposed() );
}
{
// Segment
- setGradient( Q::Segment, Qt::transparent );
+ setStrutSize( Q::Segment | A::Horizontal, segmentStrutSize );
+ setStrutSize( Q::Segment | A::Vertical, segmentStrutSize.transposed() );
+ setGradient( Q::Segment, Qt::transparent ); // ### background
setPadding( Q::Segment, 0 );
}
{
// Separator
- setStrutSize( Q::Separator | A::Horizontal, 1_dp, strutSize.height() );
- setStrutSize( Q::Separator | A::Vertical, strutSize.height(), 1_dp );
+ setStrutSize( Q::Separator | A::Horizontal, 1_dp, segmentStrutSize.height() );
+ setStrutSize( Q::Separator | A::Vertical, segmentStrutSize.height(), 1_dp );
setPadding( Q::Separator, 0 );
setGradient( Q::Separator, m_pal.outline );
setColor( Q::Separator | Q::Disabled, m_pal.onSurface38 );
@@ -470,7 +474,6 @@ void Editor::setupSegmentedBar()
{
// Cursor
- setMargin( Q::Cursor, 1_dp );
setBoxShape( Q::Cursor, 0 );
setBoxShape( Q::Cursor | Q::Minimum | A::Horizontal,
@@ -489,7 +492,6 @@ void Editor::setupSegmentedBar()
setGradient( Q::Cursor, m_pal.secondaryContainer );
setGradient( Q::Cursor | Q::Disabled, m_pal.onSurface12 );
-
setAnimation( Q::Cursor | A::Metric | A::Position, 100 );
}
@@ -509,8 +511,8 @@ void Editor::setupSegmentedBar()
{
// Graphic
- setPadding( Q::Graphic, 10_dp );
- setMargin( Q::Graphic, 10_dp );
+ setPadding( Q::Graphic, 0_dp );
+ setStrutSize( Q::Graphic, { 18_dp, 18_dp } );
}
}
diff --git a/src/controls/QskSegmentedBar.cpp b/src/controls/QskSegmentedBar.cpp
index 14275b92..a01314a9 100644
--- a/src/controls/QskSegmentedBar.cpp
+++ b/src/controls/QskSegmentedBar.cpp
@@ -149,6 +149,22 @@ int QskSegmentedBar::addGraphic( const QUrl& graphicSource )
return count() - 1;
}
+int QskSegmentedBar::addGraphicAndText( const QUrl& graphicSource, const QString& text )
+{
+ m_data->addOption( this, Option( graphicSource, text ) );
+ return count() - 1;
+}
+
+QString QskSegmentedBar::textAt( int index ) const
+{
+ return m_data->options.at( index ).text;
+}
+
+QskGraphic QskSegmentedBar::graphicAt( int index ) const
+{
+ return m_data->options.at( index ).graphic;
+}
+
QVariant QskSegmentedBar::optionAt( int index ) const
{
const auto& options = m_data->options;
diff --git a/src/controls/QskSegmentedBar.h b/src/controls/QskSegmentedBar.h
index e2afa911..d7fb6b23 100644
--- a/src/controls/QskSegmentedBar.h
+++ b/src/controls/QskSegmentedBar.h
@@ -48,6 +48,10 @@ class QSK_EXPORT QskSegmentedBar : public QskControl
int addText( const QString& );
int addGraphic( const QUrl& );
+ int addGraphicAndText( const QUrl&, const QString& );
+
+ QString textAt( int ) const;
+ QskGraphic graphicAt( int ) const;
void clear();
diff --git a/src/controls/QskSegmentedBarSkinlet.cpp b/src/controls/QskSegmentedBarSkinlet.cpp
index 54f40dd8..45258bdc 100644
--- a/src/controls/QskSegmentedBarSkinlet.cpp
+++ b/src/controls/QskSegmentedBarSkinlet.cpp
@@ -8,18 +8,50 @@
#include "QskGraphic.h"
#include "QskColorFilter.h"
-#include "QskTextOptions.h"
-#include "QskSGNode.h"
#include "QskFunctions.h"
+#include "QskSubcontrolLayoutEngine.h"
#include
#include
+static inline Qt::Orientation qskOrientation( const QskSegmentedBar* bar )
+{
+ // For the moment we only handle the orientation TODO ...
+
+ const auto direction = bar->flagHint(
+ QskSegmentedBar::Panel | QskAspect::Direction, Qsk::LeftToRight );
+
+ if ( direction == Qsk::LeftToRight || direction == Qsk::RightToLeft )
+ return Qt::Horizontal;
+ else
+ return Qt::Vertical;
+}
+
+namespace
+{
+ class LayoutEngine : public QskSubcontrolLayoutEngine
+ {
+ public:
+ LayoutEngine( const QskSegmentedBar* bar, int index )
+ : QskSubcontrolLayoutEngine( qskOrientation( bar ) )
+ {
+ setSpacing( bar->spacingHint( QskSegmentedBar::Panel ) );
+
+ setGraphicTextElements( bar,
+ QskSegmentedBar::Text, bar->textAt( index ),
+ QskSegmentedBar::Graphic, bar->graphicAt( index ).defaultSize() );
+
+ const auto alignment = bar->alignmentHint( QskSegmentedBar::Panel, Qt::AlignCenter );
+ setFixedContent( QskSegmentedBar::Text, Qt::Horizontal, alignment );
+ }
+ };
+}
+
QskSegmentedBarSkinlet::QskSegmentedBarSkinlet( QskSkin* skin )
: Inherited( skin )
{
- setNodeRoles( { PanelRole, SegmentRole, SeparatorRole,
- CursorRole, TextRole, GraphicRole } );
+ setNodeRoles( { CursorRole, PanelRole, SegmentRole,
+ SeparatorRole, TextRole, GraphicRole } );
}
QskSegmentedBarSkinlet::~QskSegmentedBarSkinlet() = default;
@@ -115,7 +147,7 @@ QRectF QskSegmentedBarSkinlet::separatorRect(
if( bar->orientation() == Qt::Horizontal )
{
- rect.setLeft( rect.right() );
+ rect.setLeft( rect.right() ); // ### *0.5 or so?
rect.setSize( { strutSize.width(), sh.height() } );
}
else
@@ -137,12 +169,12 @@ QSGNode* QskSegmentedBarSkinlet::updateSubNode(
switch( nodeRole )
{
- case PanelRole:
- return updateBoxNode( skinnable, node, Q::Panel );
-
case CursorRole:
return updateBoxNode( skinnable, node, Q::Cursor );
+ case PanelRole:
+ return updateBoxNode( skinnable, node, Q::Panel );
+
case SegmentRole:
return updateSeriesNode( skinnable, Q::Segment, node );
@@ -159,56 +191,29 @@ QSGNode* QskSegmentedBarSkinlet::updateSubNode(
return nullptr;
}
-QSizeF QskSegmentedBarSkinlet::segmentSizeHint( const QskSegmentedBar* bar ) const
+QSizeF QskSegmentedBarSkinlet::segmentSizeHint( const QskSegmentedBar* bar, Qt::SizeHint which ) const
{
- qreal widthMax = 0;
- qreal graphicRatioMax = 0;
+ using Q = QskSegmentedBar;
- const QFontMetricsF fm( bar->effectiveFont( QskSegmentedBar::Text ) );
+ QSizeF sizeMax;
for ( int i = 0; i < bar->count(); i++ )
{
- const auto value = bar->optionAt( i );
+ LayoutEngine layoutEngine( bar, i );
- if ( value.canConvert< QskGraphic >() )
+ const auto size = layoutEngine.sizeHint( which, QSizeF() );
+
+ if( size.width() > sizeMax.width() )
{
- const auto graphic = value.value< QskGraphic >();
-
- if ( !graphic.isNull() )
- {
- const auto sz = graphic.defaultSize();
-
- if( sz.isValid() )
- {
- const qreal ratio = sz.width() / sz.height();
-
- if( graphicRatioMax < ratio )
- graphicRatioMax = ratio;
- }
- }
- }
- else if ( value.canConvert< QString >() )
- {
- const auto text = value.value< QString >();
- if ( !text.isEmpty() )
- {
- const auto sz = fm.size( Qt::TextShowMnemonic, text );
-
- if( sz.width() > widthMax )
- widthMax = sz.width();
- }
+ sizeMax = size;
}
}
- if( graphicRatioMax > 0 )
- {
- const qreal w = fm.height() * graphicRatioMax;
+ sizeMax = bar->outerBoxSize( Q::Segment, sizeMax );
+ sizeMax = sizeMax.expandedTo( bar->strutSizeHint( Q::Segment ) );
+ sizeMax = sizeMax.grownBy( bar->marginHint( Q::Segment ) );
- if( w > widthMax )
- widthMax = w;
- }
-
- return bar->outerBoxSize( QskSegmentedBar::Segment, QSizeF( widthMax, fm.height() ) );
+ return sizeMax;
}
QSizeF QskSegmentedBarSkinlet::sizeHint( const QskSkinnable* skinnable,
@@ -231,7 +236,7 @@ QSizeF QskSegmentedBarSkinlet::sizeHint( const QskSkinnable* skinnable,
const qreal spacing = skinnable->spacingHint( Q::Panel );
const auto bar = static_cast< const QskSegmentedBar* >( skinnable );
- const auto segmentSize = segmentSizeHint( bar );
+ const auto segmentSize = segmentSizeHint( bar, which );
if( bar->orientation() == Qt::Horizontal )
{
@@ -275,7 +280,10 @@ QRectF QskSegmentedBarSkinlet::sampleRect( const QskSkinnable* skinnable,
if ( subControl == Q::Text || subControl == Q::Graphic )
{
const auto rect = sampleRect( skinnable, contentsRect, Q::Segment, index );
- return rect;
+
+ LayoutEngine layoutEngine( bar, index );
+ layoutEngine.setGeometries( rect );
+ return layoutEngine.subControlRect( subControl );
}
return Inherited::sampleRect( skinnable, contentsRect, subControl, index );
@@ -324,11 +332,10 @@ QSGNode* QskSegmentedBarSkinlet::updateSampleNode( const QskSkinnable* skinnable
if ( subControl == Q::Text )
{
- const auto value = bar->optionAt( index );
- if ( value.canConvert< QString >() )
- {
- const auto text = value.value< QString >();
+ const auto text = bar->textAt( index );
+ if( !text.isEmpty() )
+ {
return QskSkinlet::updateTextNode( bar, node,
rect, alignment, text, Q::Text );
}
@@ -338,10 +345,10 @@ QSGNode* QskSegmentedBarSkinlet::updateSampleNode( const QskSkinnable* skinnable
if ( subControl == Q::Graphic )
{
- const auto value = bar->optionAt( index );
- if ( value.canConvert< QskGraphic >() )
+ const auto graphic = bar->graphicAt( index );
+
+ if( !graphic.isEmpty() )
{
- const auto graphic = value.value< QskGraphic >();
const auto filter = bar->effectiveGraphicFilter( subControl );
const auto padding = bar->paddingHint( Q::Graphic );
const auto graphicRect = rect.marginsRemoved( padding );
diff --git a/src/controls/QskSegmentedBarSkinlet.h b/src/controls/QskSegmentedBarSkinlet.h
index 8bb8faa8..a61a2318 100644
--- a/src/controls/QskSegmentedBarSkinlet.h
+++ b/src/controls/QskSegmentedBarSkinlet.h
@@ -55,7 +55,7 @@ class QSK_EXPORT QskSegmentedBarSkinlet : public QskSkinlet
QskAspect::Subcontrol, int index, QSGNode* ) const override;
private:
- QSizeF segmentSizeHint( const QskSegmentedBar* ) const;
+ QSizeF segmentSizeHint(const QskSegmentedBar*, Qt::SizeHint ) const;
QRectF segmentRect( const QskSegmentedBar*, const QRectF&, int index ) const;
QRectF separatorRect( const QskSegmentedBar*, const QRectF&, int index ) const;
diff --git a/src/layouts/QskSubcontrolLayoutEngine.cpp b/src/layouts/QskSubcontrolLayoutEngine.cpp
index 3c594f1e..4c42b011 100644
--- a/src/layouts/QskSubcontrolLayoutEngine.cpp
+++ b/src/layouts/QskSubcontrolLayoutEngine.cpp
@@ -11,6 +11,7 @@
#include "QskMargins.h"
#include "QskTextOptions.h"
+#include
#include
#include
#include