QskSubWindow titleBar improvements

This commit is contained in:
Uwe Rathmann 2018-10-29 20:11:48 +01:00
parent 85f816e42d
commit 5da92830df
8 changed files with 292 additions and 65 deletions

View File

@ -22,20 +22,25 @@
class SubWindow : public QskSubWindow class SubWindow : public QskSubWindow
{ {
public: public:
SubWindow( const QString& graphicSource, QQuickItem* parent = nullptr ) SubWindow( const QString& iconSource, QQuickItem* parent = nullptr )
: QskSubWindow( parent ) : QskSubWindow( parent )
{ {
setObjectName( graphicSource ); setObjectName( iconSource );
const QUrl url( iconSource );
setWindowTitle( url.fileName() );
setWindowIconSource( url );
auto label = new QskGraphicLabel( this ); auto label = new QskGraphicLabel( this );
label->setSource( graphicSource ); label->setSource( iconSource );
label->setAlignment( Qt::AlignCenter ); label->setAlignment( Qt::AlignCenter );
setSizePolicy( QskSizePolicy::MinimumExpanding, setSizePolicy( QskSizePolicy::MinimumExpanding,
QskSizePolicy::MinimumExpanding ); QskSizePolicy::MinimumExpanding );
QskShortcutMap::addShortcut( this, QKeySequence( Qt::Key_P ), true, QskShortcutMap::addShortcut( this, QKeySequence( Qt::Key_P ), true,
[ graphicSource ] { qDebug() << graphicSource; } ); [ iconSource ] { qDebug() << iconSource; } );
} }
}; };

View File

@ -655,8 +655,9 @@ void QskMaterialSkin::initSubWindowHints()
const ColorPalette& pal = m_data->palette; const ColorPalette& pal = m_data->palette;
// panel // Panel
setSkinHint( Q::Panel | Decoration, true );
setMargins( Q::Panel | Padding, 10 ); setMargins( Q::Panel | Padding, 10 );
setBoxShape( Q::Panel, 0 ); setBoxShape( Q::Panel, 0 );
setBoxBorderMetrics( Q::Panel, 2 ); setBoxBorderMetrics( Q::Panel, 2 );
@ -668,11 +669,19 @@ void QskMaterialSkin::initSubWindowHints()
setBoxBorderColors( Q::Panel, colors ); setBoxBorderColors( Q::Panel, colors );
// title bar // TitleBar
setGradient( Q::TitleBar, pal.darker200 ); setGradient( Q::TitleBar, pal.darker200 );
setGradient( Q::TitleBar | Q::Focused, pal.accentColor ); setGradient( Q::TitleBar | Q::Focused, pal.accentColor );
setFontRole( Q::TitleBar, QskSkin::TinyFont ); // TitleBarText
setFontRole( Q::TitleBarText, QskSkin::SmallFont );
setSkinHint( Q::TitleBarText | Alignment,
static_cast<int>( Qt::AlignLeft | Qt::AlignVCenter ) );
for ( auto subControl : { Q::Panel, Q::TitleBar, Q::TitleBarText } )
setAnimation( subControl | Color, qskDuration );
} }
#include "moc_QskMaterialSkin.cpp" #include "moc_QskMaterialSkin.cpp"

View File

@ -739,11 +739,14 @@ void QskSquiekSkin::initSubWindowHints()
const ColorPalette& pal = m_data->palette; const ColorPalette& pal = m_data->palette;
const qreal radius = 5.0;
// Panel // Panel
setSkinHint( Q::Panel | Decoration, true );
setMargins( Q::Panel | Padding, 10 ); setMargins( Q::Panel | Padding, 10 );
setBoxBorderMetrics( Q::Panel, 2 ); setBoxBorderMetrics( Q::Panel, 2 );
setBoxShape( Q::Panel, 0 ); setBoxShape( Q::Panel, radius, radius, 0, 0, Qt::AbsoluteSize );
QskBoxBorderColors borderColors; QskBoxBorderColors borderColors;
borderColors.setColorsAt( Qt::TopEdge | Qt::LeftEdge, pal.lighter125 ); borderColors.setColorsAt( Qt::TopEdge | Qt::LeftEdge, pal.lighter125 );
@ -754,9 +757,22 @@ void QskSquiekSkin::initSubWindowHints()
// TitleBar // TitleBar
setFontRole( Q::TitleBar, QskSkin::TinyFont );
setGradient( Q::TitleBar | Q::Focused, pal.highlighted ); setGradient( Q::TitleBar | Q::Focused, pal.highlighted );
setGradient( Q::TitleBar, pal.contrasted ); setGradient( Q::TitleBar, pal.contrasted );
setMetric( Q::TitleBar | Spacing, 5 );
setMetric( Q::TitleBar | MinimumHeight, 20 );
setBoxShape( Q::TitleBar, radius, radius, 0, 0, Qt::AbsoluteSize );
// TitleBarText
setFontRole( Q::TitleBarText, QskSkin::SmallFont );
setColor( Q::TitleBarText | Q::Focused, pal.highlightedText );
setColor( Q::TitleBarText, pal.themeForeground );
setSkinHint( Q::TitleBarText | Alignment,
static_cast<int>( Qt::AlignLeft | Qt::AlignVCenter ) );
for ( auto subControl : { Q::Panel, Q::TitleBar, Q::TitleBarText } )
setAnimation( subControl | Color, qskDuration );
} }
#include "moc_QskSquiekSkin.cpp" #include "moc_QskSquiekSkin.cpp"

View File

@ -6,24 +6,41 @@
#include "QskSubWindow.h" #include "QskSubWindow.h"
#include "QskAspect.h" #include "QskAspect.h"
#include "QskFunctions.h" #include "QskFunctions.h"
#include "QskGraphic.h"
#include "QskGraphicProvider.h"
#include "QskTextOptions.h"
#include "QskQuick.h" #include "QskQuick.h"
#include <qurl.h>
QSK_SUBCONTROL( QskSubWindow, Panel ) QSK_SUBCONTROL( QskSubWindow, Panel )
QSK_SUBCONTROL( QskSubWindow, TitleBar ) QSK_SUBCONTROL( QskSubWindow, TitleBar )
QSK_SUBCONTROL( QskSubWindow, TitleBarSymbol )
QSK_SUBCONTROL( QskSubWindow, TitleBarText )
class QskSubWindow::PrivateData class QskSubWindow::PrivateData
{ {
public: public:
PrivateData() PrivateData()
: isWindowIconSourceDirty( false )
{ {
// should be available from the platform somehow. TODO ... // should be available from the platform somehow. TODO ...
windowButtons = QskSubWindow::WindowButtons( QskSubWindow::MinimizeButton | windowButtons = QskSubWindow::WindowButtons( QskSubWindow::MinimizeButton |
QskSubWindow::MaximizeButton | QskSubWindow::CloseButton ); QskSubWindow::MaximizeButton | QskSubWindow::CloseButton );
windowTitleTextOptions.setElideMode( Qt::ElideRight );
} }
QskSubWindow::WindowButtons windowButtons; QskSubWindow::WindowButtons windowButtons;
QString title;
QString windowTitle;
QskTextOptions windowTitleTextOptions;
QUrl windowIconSource;
QskGraphic windowIcon;
bool isWindowIconSourceDirty : 1;
}; };
QskSubWindow::QskSubWindow( QQuickItem* parent ) QskSubWindow::QskSubWindow( QQuickItem* parent )
@ -45,7 +62,7 @@ void QskSubWindow::setDecorated( bool on )
if ( on == isDecorated() ) if ( on == isDecorated() )
return; return;
const auto subControl = effectiveSubcontrol( QskSubWindow::TitleBar ); const auto subControl = effectiveSubcontrol( QskSubWindow::Panel );
setFlagHint( subControl | QskAspect::Decoration, on ); setFlagHint( subControl | QskAspect::Decoration, on );
resetImplicitSize(); // in case some parent wants to layout resetImplicitSize(); // in case some parent wants to layout
@ -58,23 +75,93 @@ void QskSubWindow::setDecorated( bool on )
bool QskSubWindow::isDecorated() const bool QskSubWindow::isDecorated() const
{ {
return flagHint< bool >( TitleBar | QskAspect::Decoration, true ); return flagHint< bool >( Panel | QskAspect::Decoration, true );
} }
void QskSubWindow::setTitle( const QString& title ) void QskSubWindow::setWindowTitle( const QString& title )
{ {
if ( m_data->title != title ) if ( m_data->windowTitle != title )
{ {
m_data->title = title; m_data->windowTitle = title;
Q_EMIT titleChanged(); Q_EMIT windowTitleChanged();
} }
} }
QString QskSubWindow::title() const QString QskSubWindow::windowTitle() const
{ {
return m_data->title; return m_data->windowTitle;
} }
void QskSubWindow::setWindowTitleTextOptions( const QskTextOptions& options )
{
if ( options != m_data->windowTitleTextOptions )
{
m_data->windowTitleTextOptions = options;
update();
Q_EMIT windowTitleTextOptionsChanged();
}
}
QskTextOptions QskSubWindow::windowTitleTextOptions() const
{
return m_data->windowTitleTextOptions;
}
void QskSubWindow::setWindowIconSource( const QUrl& url )
{
if ( m_data->windowIconSource == url )
return;
m_data->windowIconSource = url;
m_data->windowIcon.reset();
m_data->isWindowIconSourceDirty = true;
polish();
update();
Q_EMIT windowIconSourceChanged();
}
QUrl QskSubWindow::windowIconSource() const
{
return m_data->windowIconSource;
}
void QskSubWindow::setWindowIcon( const QskGraphic& graphic )
{
if ( graphic != m_data->windowIcon )
{
m_data->windowIcon = graphic;
if ( !m_data->windowIconSource.isEmpty() )
{
m_data->windowIconSource = QString();
m_data->isWindowIconSourceDirty = false;
Q_EMIT windowIconSourceChanged();
}
polish();
update();
Q_EMIT windowIconChanged();
}
}
QskGraphic QskSubWindow::windowIcon() const
{
return m_data->windowIcon;
}
bool QskSubWindow::hasWindowIcon() const
{
return !( windowIcon().isEmpty() && windowIconSource().isEmpty() );
}
void QskSubWindow::setWindowButtons( WindowButtons buttons ) void QskSubWindow::setWindowButtons( WindowButtons buttons )
{ {
if ( buttons != m_data->windowButtons ) if ( buttons != m_data->windowButtons )
@ -122,6 +209,22 @@ bool QskSubWindow::event( QEvent* event )
return Inherited::event( event ); return Inherited::event( event );
} }
void QskSubWindow::updateLayout()
{
if ( m_data->isWindowIconSourceDirty )
{
if ( !m_data->windowIconSource.isEmpty() )
{
m_data->windowIcon = Qsk::loadGraphic( m_data->windowIconSource );
Q_EMIT windowIconChanged();
}
m_data->isWindowIconSourceDirty = false;
}
Inherited::updateLayout();
}
QRectF QskSubWindow::layoutRect() const QRectF QskSubWindow::layoutRect() const
{ {
QRectF rect = contentsRect(); QRectF rect = contentsRect();
@ -135,36 +238,20 @@ QRectF QskSubWindow::layoutRect() const
QSizeF QskSubWindow::contentsSizeHint() const QSizeF QskSubWindow::contentsSizeHint() const
{ {
qreal w = -1; // the size we get from the children
qreal h = -1; auto hint = Inherited::contentsSizeHint();
const auto children = childItems();
for ( auto child : children )
{
if ( qskIsTransparentForPositioner( child ) )
continue;
const QskControl* control = qobject_cast< QskControl* >( child );
if ( control )
{
const QSizeF sz = control->sizeHint();
w = qMax( w, sz.width() );
h = qMax( h, sz.height() );
}
}
#if 1 #if 1
// should be Minimum Width/Height from the hints // should be Minimum Width/Height from the hints
if ( w < 0 ) if ( hint.width() < 0 )
w = qskDpiScaled( 100 ); hint.setWidth( qskDpiScaled( 100 ) );
if ( h < 0 ) if ( hint.height() < 0 )
h = qskDpiScaled( 80 ); hint.setHeight( qskDpiScaled( 80 ) );
#endif #endif
QSizeF hint = outerBoxSize( Panel, QSizeF( w, h ) ); hint = outerBoxSize( Panel, hint );
hint.setHeight( hint.height() + titleBarRect().height() ); hint.setHeight( hint.height() + subControlRect( TitleBar ).height() );
return hint; return hint;
} }

View File

@ -8,6 +8,10 @@
#include "QskPopup.h" #include "QskPopup.h"
class QskGraphic;
class QskTextOptions;
class QUrl;
class QSK_EXPORT QskSubWindow : public QskPopup class QSK_EXPORT QskSubWindow : public QskPopup
{ {
Q_OBJECT Q_OBJECT
@ -15,8 +19,17 @@ class QSK_EXPORT QskSubWindow : public QskPopup
Q_PROPERTY( bool decorated READ isDecorated Q_PROPERTY( bool decorated READ isDecorated
WRITE setDecorated NOTIFY decoratedChanged ) WRITE setDecorated NOTIFY decoratedChanged )
Q_PROPERTY( QString title READ title Q_PROPERTY( QString windowTitle READ windowTitle
WRITE setTitle NOTIFY titleChanged ) WRITE setWindowTitle NOTIFY windowTitleChanged )
Q_PROPERTY( QskTextOptions windowTitleTextOptions READ windowTitleTextOptions
WRITE setWindowTitleTextOptions NOTIFY windowTitleTextOptionsChanged )
Q_PROPERTY( QUrl windowIconSource READ windowIconSource
WRITE setWindowIconSource NOTIFY windowIconSourceChanged )
Q_PROPERTY( QskGraphic windowIcon READ windowIcon
WRITE setWindowIcon NOTIFY windowIconChanged FINAL )
Q_PROPERTY( WindowButtons windowButtons READ windowButtons Q_PROPERTY( WindowButtons windowButtons READ windowButtons
WRITE setWindowButtons NOTIFY windowButtonsChanged ) WRITE setWindowButtons NOTIFY windowButtonsChanged )
@ -34,22 +47,33 @@ class QSK_EXPORT QskSubWindow : public QskPopup
Q_ENUM( WindowButton ) Q_ENUM( WindowButton )
Q_DECLARE_FLAGS( WindowButtons, WindowButton ) Q_DECLARE_FLAGS( WindowButtons, WindowButton )
QSK_SUBCONTROLS( Panel, TitleBar ) QSK_SUBCONTROLS( Panel, TitleBar, TitleBarSymbol, TitleBarText )
QskSubWindow( QQuickItem* parent = nullptr ); QskSubWindow( QQuickItem* parent = nullptr );
~QskSubWindow() override; ~QskSubWindow() override;
Q_INVOKABLE void setTitle( const QString& ); void setDecorated( bool );
Q_INVOKABLE QString title() const; bool isDecorated() const;
Q_INVOKABLE void setDecorated( bool ); void setWindowTitleTextOptions( const QskTextOptions& );
Q_INVOKABLE bool isDecorated() const; QskTextOptions windowTitleTextOptions() const;
Q_INVOKABLE void setWindowButtons( WindowButtons ); void setWindowTitle( const QString& );
Q_INVOKABLE WindowButtons windowButtons() const; QString windowTitle() const;
Q_INVOKABLE void setWindowButton( WindowButton, bool on = true ); void setWindowIconSource( const QUrl& );
Q_INVOKABLE bool testWindowButton( WindowButton ) const; QUrl windowIconSource() const;
void setWindowIcon( const QskGraphic& );
QskGraphic windowIcon() const;
bool hasWindowIcon() const;
void setWindowButtons( WindowButtons );
WindowButtons windowButtons() const;
void setWindowButton( WindowButton, bool on = true );
bool testWindowButton( WindowButton ) const;
QRectF titleBarRect() const; QRectF titleBarRect() const;
@ -57,13 +81,18 @@ class QSK_EXPORT QskSubWindow : public QskPopup
QRectF layoutRect() const override; QRectF layoutRect() const override;
Q_SIGNALS: Q_SIGNALS:
void titleChanged();
void decoratedChanged(); void decoratedChanged();
void windowTitleChanged();
void windowTitleTextOptionsChanged();
void windowIconChanged();
void windowIconSourceChanged();
void windowButtonsChanged(); void windowButtonsChanged();
protected: protected:
bool event( QEvent* ) override; bool event( QEvent* ) override;
void updateLayout() override;
void itemChange( QQuickItem::ItemChange, void itemChange( QQuickItem::ItemChange,
const QQuickItem::ItemChangeData& ) override; const QQuickItem::ItemChangeData& ) override;

View File

@ -8,13 +8,15 @@
#include "QskAspect.h" #include "QskAspect.h"
#include "QskBoxBorderMetrics.h" #include "QskBoxBorderMetrics.h"
#include "QskGraphic.h"
#include "QskTextOptions.h"
#include <qfontmetrics.h> #include <qfontmetrics.h>
QskSubWindowSkinlet::QskSubWindowSkinlet( QskSkin* skin ) QskSubWindowSkinlet::QskSubWindowSkinlet( QskSkin* skin )
: Inherited( skin ) : Inherited( skin )
{ {
appendNodeRoles( { PanelRole, TitleBarRole } ); appendNodeRoles( { PanelRole, TitleBarRole, SymbolRole, TitleRole } );
} }
QskSubWindowSkinlet::~QskSubWindowSkinlet() = default; QskSubWindowSkinlet::~QskSubWindowSkinlet() = default;
@ -24,15 +26,22 @@ QRectF QskSubWindowSkinlet::subControlRect(
{ {
const auto subWindow = static_cast< const QskSubWindow* >( skinnable ); const auto subWindow = static_cast< const QskSubWindow* >( skinnable );
if ( subControl == QskSubWindow::TitleBar )
{
return titleBarRect( subWindow );
}
if ( subControl == QskSubWindow::Panel ) if ( subControl == QskSubWindow::Panel )
{ {
return subWindow->contentsRect(); return subWindow->contentsRect();
} }
else if ( subControl == QskSubWindow::TitleBar )
{
return titleBarRect( subWindow );
}
else if ( subControl == QskSubWindow::TitleBarSymbol )
{
return symbolRect( subWindow );
}
else if ( subControl == QskSubWindow::TitleBarText )
{
return titleRect( subWindow );
}
return Inherited::subControlRect( skinnable, subControl ); return Inherited::subControlRect( skinnable, subControl );
} }
@ -45,10 +54,36 @@ QSGNode* QskSubWindowSkinlet::updateSubNode(
switch ( nodeRole ) switch ( nodeRole )
{ {
case PanelRole: case PanelRole:
{
return updateBoxNode( subWindow, node, QskSubWindow::Panel ); return updateBoxNode( subWindow, node, QskSubWindow::Panel );
}
case TitleBarRole: case TitleBarRole:
return updateBoxNode( subWindow, node, QskSubWindow::TitleBar ); {
if ( subWindow->isDecorated() )
return updateBoxNode( subWindow, node, QskSubWindow::TitleBar );
return nullptr;
}
case SymbolRole:
{
if ( subWindow->isDecorated() )
{
return updateGraphicNode( subWindow, node,
subWindow->windowIcon(), QskSubWindow::TitleBarSymbol );
}
return nullptr;
}
case TitleRole:
{
if ( subWindow->isDecorated() )
{
return updateTextNode( subWindow, node, subWindow->windowTitle(),
subWindow->windowTitleTextOptions(), QskSubWindow::TitleBarText );
}
return nullptr;
}
} }
return Inherited::updateSubNode( skinnable, nodeRole, node ); return Inherited::updateSubNode( skinnable, nodeRole, node );
@ -71,8 +106,8 @@ qreal QskSubWindowSkinlet::titleBarHeight( const QskSubWindow* subWindow ) const
if ( !subWindow->isDecorated() ) if ( !subWindow->isDecorated() )
return 0; return 0;
const QFontMetricsF fm( subWindow->effectiveFont( QskSubWindow::TitleBar ) );
const QMarginsF margins = subWindow->marginsHint( QskSubWindow::TitleBar | Padding ); const QMarginsF margins = subWindow->marginsHint( QskSubWindow::TitleBar | Padding );
const QFontMetricsF fm( subWindow->effectiveFont( QskSubWindow::TitleBarText ) );
const qreal height = fm.height() + margins.top() + margins.bottom(); const qreal height = fm.height() + margins.top() + margins.bottom();
const qreal minHeight = subWindow->metric( QskSubWindow::TitleBar | MinimumHeight ); const qreal minHeight = subWindow->metric( QskSubWindow::TitleBar | MinimumHeight );
@ -80,4 +115,45 @@ qreal QskSubWindowSkinlet::titleBarHeight( const QskSubWindow* subWindow ) const
return qMax( height, minHeight ); return qMax( height, minHeight );
} }
QRectF QskSubWindowSkinlet::symbolRect( const QskSubWindow* subWindow ) const
{
auto rect = subControlRect( subWindow, QskSubWindow::TitleBar );
rect = subWindow->innerBox( QskSubWindow::TitleBar, rect );
int w = 0;
if ( !rect.isEmpty() )
{
const auto symbol = subWindow->windowIcon();
if ( !symbol.isNull() )
w = symbol.widthForHeight( rect.height() );
rect.setWidth( w );
}
return rect;
}
QRectF QskSubWindowSkinlet::titleRect( const QskSubWindow* subWindow ) const
{
auto rect = subControlRect( subWindow, QskSubWindow::TitleBar );
rect = subWindow->innerBox( QskSubWindow::TitleBar, rect );
if ( !rect.isEmpty() )
{
const auto spacing = subWindow->metric(
QskSubWindow::TitleBar | QskAspect::Spacing );
const auto symbolRect = subControlRect( subWindow, QskSubWindow::TitleBarSymbol );
rect.setX( rect.x() + symbolRect.right() + spacing );
#if 0
const QFontMetricsF fm( subWindow->effectiveFont( QskSubWindow::TitleBarText ) );
rect.setHeight( fm.height() ); // TitleBarText | Alignment
#endif
}
return rect;
}
#include "moc_QskSubWindowSkinlet.cpp" #include "moc_QskSubWindowSkinlet.cpp"

View File

@ -20,7 +20,9 @@ class QSK_EXPORT QskSubWindowSkinlet : public QskPopupSkinlet
enum NodeRole enum NodeRole
{ {
PanelRole = QskPopupSkinlet::OverlayRole + 1, PanelRole = QskPopupSkinlet::OverlayRole + 1,
TitleBarRole TitleBarRole,
SymbolRole,
TitleRole
}; };
Q_INVOKABLE QskSubWindowSkinlet( QskSkin* = nullptr ); Q_INVOKABLE QskSubWindowSkinlet( QskSkin* = nullptr );
@ -35,7 +37,10 @@ class QSK_EXPORT QskSubWindowSkinlet : public QskPopupSkinlet
private: private:
qreal titleBarHeight( const QskSubWindow* ) const; qreal titleBarHeight( const QskSubWindow* ) const;
QRectF titleBarRect( const QskSubWindow* ) const; QRectF titleBarRect( const QskSubWindow* ) const;
QRectF symbolRect( const QskSubWindow* ) const;
QRectF titleRect( const QskSubWindow* ) const;
}; };
#endif #endif

View File

@ -53,7 +53,7 @@ static void qskSetupSubWindow(
QskDialog::StandardButton defaultButton, QskInputSubWindow* subWindow ) QskDialog::StandardButton defaultButton, QskInputSubWindow* subWindow )
{ {
subWindow->setModal( true ); subWindow->setModal( true );
subWindow->setTitle( title ); subWindow->setWindowTitle( title );
subWindow->setStandardButtons( buttons ); subWindow->setStandardButtons( buttons );
if ( defaultButton == QskDialog::NoButton ) if ( defaultButton == QskDialog::NoButton )