Merge branch 'master' into features/menubutton

This commit is contained in:
Uwe Rathmann 2023-07-28 08:11:16 +02:00
commit f67ff13f93
78 changed files with 3460 additions and 2266 deletions

View File

@ -6,8 +6,6 @@
add_subdirectory(desktop)
add_subdirectory(gallery)
add_subdirectory(layouts)
add_subdirectory(listbox)
add_subdirectory(messagebox)
add_subdirectory(mycontrols)
add_subdirectory(qvgviewer)
add_subdirectory(thumbnails)
@ -19,5 +17,4 @@ if( BUILD_QML_EXPORT )
add_subdirectory(buttons)
add_subdirectory(frames)
add_subdirectory(glabels)
add_subdirectory(messageboxQml)
endif()

View File

@ -9,7 +9,6 @@ Qsk.Window
width: 600
height: 600
color: "Beige"
Component.onCompleted:
{
@ -30,9 +29,10 @@ Qsk.Window
{
orientation: Qt.Horizontal
dimension: 3
panel : true // to have a themed background
//margins: 10 // only possible with Qt <= 6.1
margins { left: 10; top: 10; right: 10; bottom: 10 }
// padding: 10 // only possible with Qt <= 6.1
padding { left: 10; top: 10; right: 10; bottom: 10 }
spacing: 10
TestButton

View File

@ -10,6 +10,7 @@ set(SOURCES
button/ButtonPage.h button/ButtonPage.cpp
selector/SelectorPage.h selector/SelectorPage.cpp
dialog/DialogPage.h dialog/DialogPage.cpp
listbox/ListBoxPage.h listbox/ListBoxPage.cpp
Page.h Page.cpp
main.cpp
)

View File

@ -15,80 +15,106 @@ namespace
{
class Button : public QskPushButton
{
Q_OBJECT
public:
enum ButtonType
Button( const QString& text, QQuickItem* parent = nullptr )
: QskPushButton( text, parent )
{
Message,
Information,
Warning,
Critical,
}
};
Question,
Selection,
TypeCount
};
Q_ENUM( ButtonType )
Button( ButtonType type, QQuickItem* parent = nullptr )
: QskPushButton( parent )
, m_type( type )
class ButtonBox : public QskLinearBox
{
public:
ButtonBox( QQuickItem* parent = nullptr )
: QskLinearBox( Qt::Horizontal, 2, parent )
{
setShape( 10 );
initSizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Fixed );
setObjectName( "ButtonBox" );
const int index = metaObject()->indexOfEnumerator( "ButtonType" );
setText( metaObject()->enumerator( index ).key( m_type ) );
setMargins( 10 );
setSpacing( 20 );
connect( this, &QskPushButton::clicked, this, &Button::showDialog );
auto messageButton = new Button( "Message", this );
connect( messageButton, &Button::clicked, this, &ButtonBox::execMessage );
auto informationButton = new Button( "Information", this );
connect( informationButton, &Button::clicked, this, &ButtonBox::execInformation );
auto questionButton = new Button( "Question", this );
connect( questionButton, &Button::clicked, this, &ButtonBox::execQuestion );
auto warningButton = new Button( "Warning", this );
connect( warningButton, &Button::clicked, this, &ButtonBox::execWarning );
auto criticalButton = new Button( "Critical", this );
connect( criticalButton, &Button::clicked, this, &ButtonBox::execCritical );
auto selectButton = new Button( "Selection", this );
connect( selectButton, &Button::clicked, this, &ButtonBox::execSelection );
setExtraSpacingAt( Qt::BottomEdge );
}
private:
void showDialog()
void execMessage()
{
switch( static_cast< int >( m_type ) )
{
case Message:
qskDialog->message( text(), text(), QskStandardSymbol::Ok );
break;
case Information:
qskDialog->information( text(), text() );
break;
case Warning:
qskDialog->warning( text(), text() );
break;
case Critical:
qskDialog->critical( text(), text() );
break;
case Question:
qskDialog->question( text(), text() );
break;
case Selection:
qskDialog->select( text(), text(), { "yes", "no", "maybe" } );
break;
}
qskDialog->message( "Message", "Request vector, over.",
QskStandardSymbol::NoSymbol, QskDialog::Close );
}
const ButtonType m_type;
void execInformation()
{
qskDialog->information( "Information",
"We have clearance, Clarence." );
}
void execQuestion()
{
qskDialog->question( "Question",
"Roger, Roger. Do we have a vector, Victor ?" );
}
void execWarning()
{
qskDialog->warning( "Warning", "We have clearance, Clarence." );
}
void execCritical()
{
qskDialog->critical( "Critical", "That's Clarence Oveur. Over." );
}
void execSelection()
{
// of course we all love "The Teens"
const QStringList entries =
{
"Give Me More",
"Gimme Gimme Your Love",
"1-2-3-4 Red Light",
"New York",
"If You Walk Away",
"Eloise",
"On The Radio",
"We Are The Teens",
"Never Gonna Tell No Lie To You",
"Walking On Sunshine ",
"Get Out Of My Mind",
"Cover Girl ",
"Here I Stand",
"Gypsy Caravan",
"It´s Good To Have A Friend",
"We´ll Have A Party Tonite ´nite",
"Automatic World",
"Gimme Gimme Gimme Gimme Gimme Your Love"
};
qskDialog->select( "Here we go ...", "Hot Hot Hot", entries, 7 );
}
};
}
DialogPage::DialogPage( QQuickItem* parent )
: Page( Qt::Horizontal, parent )
{
auto box = new QskLinearBox( Qt::Horizontal, 2, this );
box->setSpacing( 20 );
box->setExtraSpacingAt( Qt::BottomEdge );
for ( int i = 0; i < Button::TypeCount; i++ )
new Button( static_cast< Button::ButtonType >( i ), box );
( void ) new ButtonBox( this );
}
#include "DialogPage.moc"

View File

@ -0,0 +1,56 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "ListBoxPage.h"
#include <QskSimpleListBox.h>
#include <QskFunctions.h>
namespace
{
class ListBox : public QskSimpleListBox
{
public:
ListBox( QQuickItem* parent = nullptr )
: QskSimpleListBox( parent )
{
setMargins( QMarginsF( 15, 10, 10, 10 ) );
populate();
setSelectedRow( 5 );
}
private:
void populate()
{
const int count = 10000;
const QString format( "Row %1: The quick brown fox jumps over the lazy dog" );
QStringList entries;
entries.reserve( count );
for ( int i = 0; i < count; i++ )
{
entries += format.arg( i + 1 );
}
// we know, that the last entry is the longest one and
// can prevent the list box from having to find it out
// the expensive way.
const qreal maxWidth = qskHorizontalAdvance( effectiveFont( Cell ), entries.last() );
setColumnWidthHint( 0, maxWidth );
append( entries );
}
};
}
ListBoxPage::ListBoxPage( QQuickItem* parent )
: Page( Qt::Horizontal, parent )
{
setMargins( 5 );
(void) new ListBox( this );
}

View File

@ -0,0 +1,14 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include "Page.h"
class ListBoxPage : public Page
{
public:
ListBoxPage( QQuickItem* = nullptr );
};

View File

@ -10,6 +10,7 @@
#include "button/ButtonPage.h"
#include "selector/SelectorPage.h"
#include "dialog/DialogPage.h"
#include "listbox/ListBoxPage.h"
#include <SkinnyShortcut.h>
#include <SkinnyShapeProvider.h>
@ -100,6 +101,14 @@ namespace
auto scrollArea = new QskScrollArea();
scrollArea->setMargins( 5 );
#if 1
/*
We need a mode, where the focus policy gets adjusted
when a scroll bar becomes visible. TODO ...
*/
scrollArea->setFocusPolicy( Qt::NoFocus );
#endif
// hiding the viewport
scrollArea->setGradientHint( QskScrollView::Viewport, QskGradient() );
scrollArea->setBoxShapeHint( QskScrollView::Viewport, 0 );
@ -232,6 +241,7 @@ namespace
tabView->addPage( "Progress\nBars", new ProgressBarPage() );
tabView->addPage( "Selectors", new SelectorPage() );
tabView->addPage( "Dialogs", new DialogPage() );
tabView->addPage( "ListBox", new ListBoxPage() );
connect( header, &Header::enabledToggled,
tabView, &TabView::setPagesEnabled );
@ -251,8 +261,11 @@ int main( int argc, char* argv[] )
Qsk::addGraphicProvider( QString(), new GraphicProvider() );
Qsk::addGraphicProvider( "shapes", new SkinnyShapeProvider() );
// dialogs in faked windows -> QskSubWindow
QskDialog::instance()->setPolicy( QskDialog::EmbeddedBox );
if ( true ) // environment variable, TODO ...
{
// dialogs in faked windows -> QskSubWindow
QskDialog::instance()->setPolicy( QskDialog::EmbeddedBox );
}
QGuiApplication app( argc, argv );

View File

@ -8,15 +8,15 @@ Qsk.Window
width: 600
height: 600
color: "Beige"
Qsk.LinearBox
{
orientation: Qt.Horizontal
panel: true
dimension: 3
//margins: 10
margins { left: 10; top: 10; right: 10; bottom: 10 }
//padding: 10
padding { left: 10; top: 10; right: 10; bottom: 10 }
spacing: 20
Repeater

View File

@ -20,6 +20,29 @@
#include <QGuiApplication>
namespace
{
class TabView : public QskTabView
{
public:
TabView( QQuickItem* parent = nullptr )
: QskTabView( parent )
{
setMargins( 10 );
setTabBarEdge( Qt::LeftEdge );
setAutoFitTabs( true );
addTab( "Grid Layout", new GridLayoutPage() );
addTab( "Flow Layout", new FlowLayoutPage() );
addTab( "Linear Layout", new LinearLayoutPage() );
addTab( "Dynamic\nConstraints", new DynamicConstraintsPage() );
addTab( "Stack Layout", new StackLayoutPage() );
setCurrentIndex( 0 );
}
};
}
int main( int argc, char* argv[] )
{
#ifdef ITEM_STATISTICS
@ -32,25 +55,16 @@ int main( int argc, char* argv[] )
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
auto tabView = new QskTabView();
auto box = new QskBox(); // to have a themed application background
box->setAutoLayoutChildren( true );
tabView->setMargins( 10 );
tabView->setTabBarEdge( Qt::LeftEdge );
tabView->setAutoFitTabs( true );
tabView->addTab( "Grid Layout", new GridLayoutPage() );
tabView->addTab( "Flow Layout", new FlowLayoutPage() );
tabView->addTab( "Linear Layout", new LinearLayoutPage() );
tabView->addTab( "Dynamic\nConstraints", new DynamicConstraintsPage() );
tabView->addTab( "Stack Layout", new StackLayoutPage() );
tabView->setCurrentIndex( 0 );
(void) new TabView( box );
QSize size( 800, 600 );
size = size.expandedTo( tabView->sizeHint().toSize() );
size = size.expandedTo( box->sizeHint().toSize() );
QskWindow window;
window.addItem( tabView );
window.addItem( box );
window.addItem( new QskFocusIndicator() );
window.resize( size );

View File

@ -1,6 +0,0 @@
############################################################################
# QSkinny - Copyright (C) 2016 Uwe Rathmann
# SPDX-License-Identifier: BSD-3-Clause
############################################################################
qsk_add_example(listbox main.cpp)

View File

@ -1,77 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include <SkinnyShortcut.h>
#include <QskAspect.h>
#include <QskObjectCounter.h>
#include <QskSimpleListBox.h>
#include <QskWindow.h>
#include <QskFunctions.h>
#include <QFontMetricsF>
#include <QGuiApplication>
class ListBox : public QskSimpleListBox
{
public:
ListBox()
{
setMargins( QMarginsF( 15, 10, 10, 10 ) );
setAlternatingRowColors( true );
// increasing the padding of each row: usually the job of the skin !
setPaddingHint( Cell, QMargins( 10, 20, 10, 20 ) );
populate();
setSelectedRow( 5 );
}
private:
void populate()
{
const int count = 10000;
const QString format( "Row %1: The quick brown fox jumps over the lazy dog" );
QStringList entries;
entries.reserve( count );
for ( int i = 0; i < count; i++ )
{
entries += format.arg( i + 1 );
}
// we know, that the last entry is the longest one and
// can prevent the list box from having to find it out
// the expensive way.
const qreal maxWidth = qskHorizontalAdvance( effectiveFont( Cell ), entries.last() );
setColumnWidthHint( 0, maxWidth );
append( entries );
}
};
int main( int argc, char* argv[] )
{
#ifdef ITEM_STATISTICS
QskObjectCounter counter( true );
#endif
QGuiApplication app( argc, argv );
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
QskWindow window;
window.setColor( "Silver" );
window.addItem( new ListBox() );
window.resize( 400, 600 );
window.show();
return app.exec();
}

View File

@ -1,6 +0,0 @@
############################################################################
# QSkinny - Copyright (C) 2016 Uwe Rathmann
# SPDX-License-Identifier: BSD-3-Clause
############################################################################
qsk_add_example(messagebox main.cpp)

View File

@ -1,155 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include <SkinnyShortcut.h>
#include <QFontDatabase>
#include <QGuiApplication>
#include <QskAspect.h>
#include <QskDialog.h>
#include <QskFocusIndicator.h>
#include <QskLinearBox.h>
#include <QskObjectCounter.h>
#include <QskPushButton.h>
#include <QskStandardSymbol.h>
#include <QskWindow.h>
class Button : public QskPushButton
{
public:
Button( const QString& text, QQuickItem* parent = nullptr )
: QskPushButton( text, parent )
{
setObjectName( text );
setSizePolicy( QskSizePolicy::MinimumExpanding,
QskSizePolicy::MinimumExpanding );
}
};
class ButtonBox : public QskLinearBox
{
public:
ButtonBox( QQuickItem* parent = nullptr )
: QskLinearBox( Qt::Horizontal, 2, parent )
{
setObjectName( "ButtonBox" );
setMargins( 10 );
setSpacing( 5 );
Button* messageButton = new Button( "Message", this );
connect( messageButton, &Button::clicked, this, &ButtonBox::execMessage );
Button* informationButton = new Button( "Information", this );
connect( informationButton, &Button::clicked, this, &ButtonBox::execInformation );
Button* questionButton = new Button( "Question", this );
connect( questionButton, &Button::clicked, this, &ButtonBox::execQuestion );
Button* warningButton = new Button( "Warning", this );
connect( warningButton, &Button::clicked, this, &ButtonBox::execWarning );
Button* criticalButton = new Button( "Critical", this );
connect( criticalButton, &Button::clicked, this, &ButtonBox::execCritical );
Button* selectButton = new Button( "Selection", this );
connect( selectButton, &Button::clicked, this, &ButtonBox::execSelection );
}
private:
void execMessage()
{
qDebug() << qskDialog->message( "Message", "Request vector, over.",
QskStandardSymbol::NoSymbol, QskDialog::Close );
}
void execInformation()
{
qDebug() << qskDialog->information( "Information",
"We have clearance, Clarence." );
}
void execQuestion()
{
qDebug() << qskDialog->question( "Question",
"Roger, Roger. Do we have a vector, Victor ?" );
}
void execWarning()
{
qDebug() << qskDialog->warning( "Warning", "We have clearance, Clarence." );
}
void execCritical()
{
qDebug() << qskDialog->critical( "Critical", "That's Clarence Oveur. Over." );
}
void execSelection()
{
// of course we all love "The Teens"
const QStringList entries =
{
"Give Me More",
"Gimme Gimme Your Love",
"1-2-3-4 Red Light",
"New York",
"If You Walk Away",
"Eloise",
"On The Radio",
"We Are The Teens",
"Never Gonna Tell No Lie To You",
"Walking On Sunshine ",
"Get Out Of My Mind",
"Cover Girl ",
"Here I Stand",
"Gypsy Caravan",
"It´s Good To Have A Friend",
"We´ll Have A Party Tonite ´nite",
"Automatic World",
"Gimme Gimme Gimme Gimme Gimme Your Love"
};
qDebug() << qskDialog->select( "Here we go ...", "Hot Hot Hot", entries, 7 );
}
};
int main( int argc, char* argv[] )
{
#ifdef ITEM_STATISTICS
QskObjectCounter counter( true );
#endif
QGuiApplication app( argc, argv );
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
qskDialog->setPolicy( QskDialog::EmbeddedBox );
auto box = new ButtonBox();
/*
To avoid losing the focus, when a message box is executed
we have to define the "main window" ( here a ButtonBox ) to
be a focusScope.
*/
box->setFlag( QQuickItem::ItemIsFocusScope, true );
box->setTabFence( true );
box->setFocusPolicy( Qt::TabFocus );
// setting the initial focus
box->itemAtIndex( 0 )->setFocus( true );
box->setFocus( true );
QskWindow window;
window.addItem( box );
window.addItem( new QskFocusIndicator() );
window.resize( 800, 800 );
window.show();
return app.exec();
}

View File

@ -1,9 +0,0 @@
############################################################################
# QSkinny - Copyright (C) 2016 Uwe Rathmann
# SPDX-License-Identifier: BSD-3-Clause
############################################################################
set(SOURCES main.cpp)
qt_add_resources(SOURCES messagebox.qrc)
qsk_add_example(messageboxQml ${SOURCES})

View File

@ -1,29 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include <SkinnyShortcut.h>
#include <QskQml.h>
#include <QskObjectCounter.h>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main( int argc, char* argv[] )
{
#ifdef ITEM_STATISTICS
QskObjectCounter counter( true );
#endif
QskQml::registerTypes();
QGuiApplication app( argc, argv );
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
QQmlApplicationEngine engine( QUrl( "qrc:/qml/messagebox.qml" ) );
return app.exec();
}

View File

@ -1,147 +0,0 @@
import QtQuick 2.0
import Skinny 1.0 as Qsk
import "qrc:/qml"
Qsk.Window
{
id: window
visible: true
width: 600
height: 400
// color: "Beige"
Qsk.LinearBox
{
orientation: Qt.Horizontal
dimension: 2
margins { left: 10; top: 10; right: 10; bottom: 10 }
//margins: 10
Qsk.PushButton
{
id: messageButton
text: "Message"
focus: true
sizePolicy.vertical: Qsk.SizePolicy.MinimumExpanding
onClicked:
{
var answer = Qsk.Dialog.message(
"Message", "Request vector, over.",
Qsk.StandardSymbol.NoSymbol, Qsk.Dialog.Close
);
}
}
Qsk.PushButton
{
id: informationButton
text: "Information"
sizePolicy.vertical: Qsk.SizePolicy.MinimumExpanding
onClicked:
{
var answer = Qsk.Dialog.information(
"Information", "We have clearance, Clarence."
);
}
}
Qsk.PushButton
{
id: questionButton
text: "Question"
sizePolicy.vertical: Qsk.SizePolicy.MinimumExpanding
onClicked:
{
var answer = Qsk.Dialog.question(
"Question", "Roger, Roger. Do we have a vector, Victor ?",
Qsk.Dialog.Yes | Qsk.Dialog.No
)
if ( answer == Qsk.Dialog.Yes )
console.log( "Yes" )
else
console.log( "No" )
}
}
Qsk.PushButton
{
id: warningButton
text: "Warning"
sizePolicy.vertical: Qsk.SizePolicy.MinimumExpanding
onClicked:
{
var answer = Qsk.Dialog.warning(
"Warning", "We have clearance, Clarence."
)
}
}
Qsk.PushButton
{
id: criticalButton
text: "Critical"
sizePolicy.vertical: Qsk.SizePolicy.MinimumExpanding
onClicked:
{
var answer = Qsk.Dialog.critical(
"Critical", "That's Clarence Oveur. Over."
);
}
}
Qsk.PushButton
{
id: selectionButton
text: "Selection"
sizePolicy.vertical: Qsk.SizePolicy.MinimumExpanding
onClicked:
{
var hotTracks = [
"Give Me More",
"Gimme Gimme Your Love",
"1-2-3-4 Red Light",
"New York",
"If You Walk Away",
"Eloise",
"On The Radio",
"We Are The Teens",
"Never Gonna Tell No Lie To You",
"Walking On Sunshine ",
"Get Out Of My Mind",
"Cover Girl ",
"Here I Stand",
"Gypsy Caravan",
"It´s Good To Have A Friend",
"We´ll Have A Party Tonite ´nite",
"Automatic World",
"Gimme Gimme Gimme Gimme Gimme Your Love"
]
var hottestTrackEver = Qsk.Dialog.select(
"Here we go ...", "Hot Hot Hot", hotTracks, 7 )
console.log( hottestTrackEver )
}
}
}
Qsk.FocusIndicator
{
}
}

View File

@ -1,5 +0,0 @@
<RCC>
<qresource prefix="/qml">
<file>messagebox.qml</file>
</qresource>
</RCC>

View File

@ -28,7 +28,7 @@ class GraphicLabel : public QskGraphicLabel
public:
enum Role
{
Normal,
Normal = 1000,
Inverted
};
@ -94,7 +94,8 @@ MainWindow::MainWindow()
invertButton->setLayoutAlignmentHint( Qt::AlignRight );
auto box = new QskLinearBox( Qt::Vertical );
box->setMargins( 5 );
box->setPanel( true );
box->setPadding( 5 );
box->addItem( invertButton );
box->addItem( m_tabView );

View File

@ -20,7 +20,8 @@ int main( int argc, char* argv[] )
QGuiApplication app( argc, argv );
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
SkinnyShortcut::enable( SkinnyShortcut::DebugBackground |
SkinnyShortcut::DebugStatistics | SkinnyShortcut::Quit );
auto focusIndicator = new QskFocusIndicator();
focusIndicator->setObjectName( "FocusIndicator" );

View File

@ -160,8 +160,9 @@ int main( int argc, char* argv[] )
auto layoutBox = new QskLinearBox( Qt::Vertical );
layoutBox->setDefaultAlignment( Qt::AlignLeft );
layoutBox->setMargins( 20 );
layoutBox->setPadding( 20 );
layoutBox->setSpacing( 10 );
layoutBox->setPanel( true );
layoutBox->addItem( buttonBox );
layoutBox->addItem( tabView );

View File

@ -77,8 +77,6 @@ class Thumbnail : public QskPushButton
setBoxShapeHint( QskPushButton::Panel, QskBoxShapeMetrics( 20, Qt::RelativeSize ) );
setStrutSizeHint( QskPushButton::Icon, -1, -1 );
setSection( QskAspect::Header ); // to make them flat
}
private:
@ -191,7 +189,8 @@ class ScrollArea : public QskScrollArea
{
// settings usually done in the skins
setBoxBorderMetricsHint( Viewport, 2 );
setBoxShapeHint( Viewport, 20 );
setBoxBorderColorsHint( Viewport, Qt::gray ); // works with most color schemes
setBoxShapeHint( Viewport, 40 ); // a radius to see that clipping works
for ( auto subControl : { HorizontalScrollBar, VerticalScrollBar } )
setMetric( subControl | QskAspect::Size, 20 );
@ -257,7 +256,8 @@ int main( int argc, char* argv[] )
*/
auto box = new QskLinearBox( Qt::Vertical );
box->setMargins( 20 );
box->setPanel( true );
box->setPadding( 20 );
auto buttonBox = new QskLinearBox( Qt::Horizontal, box );
buttonBox->setSizePolicy( Qt::Vertical, QskSizePolicy::Fixed );
@ -280,7 +280,6 @@ int main( int argc, char* argv[] )
QskWindow window;
window.resize( 600, 600 );
window.setColor( "SteelBlue" );
window.addItem( box );
window.addItem( focusIndicator );

View File

@ -14,7 +14,8 @@ Window::Window( Qt::Orientation orientation )
{
m_layoutBox = new QskLinearBox( invertedOrientation() );
m_layoutBox->setObjectName( "MainBox" );
m_layoutBox->setMargins( 10 );
m_layoutBox->setPanel( true );
m_layoutBox->setPadding( 10 );
m_layoutBox->setExtraSpacingAt( Qt::BottomEdge | Qt::RightEdge );
addBox( QskDialog::Ok );

View File

@ -329,7 +329,8 @@ class Window : public QskWindow
{
auto box = new QskLinearBox( Qt::Horizontal );
box->setSpacing( 10 );
box->setMargins( 20 );
box->setPadding( 10 );
box->setPanel( true );
auto listView = new LocaleListView( box );
auto inputBox = new InputBox( box );
@ -367,14 +368,14 @@ int main( int argc, char* argv[] )
Window window1;
window1.setObjectName( "Window 1" );
window1.setColor( "PapayaWhip" );
window1.setTitle( "Window 1" );
window1.resize( 600, 600 );
window1.show();
#if 1
Window window2;
window2.setObjectName( "Window 2" );
window2.setColor( "Pink" );
window2.setTitle( "Window 2" );
window2.setX( window1.x() + 100 );
window2.resize( 600, 600 );
window2.show();

View File

@ -65,7 +65,8 @@ class GridBox : public QskGridBox
GridBox( QQuickItem* parent = nullptr )
: QskGridBox( parent )
{
setMargins( 5 );
setPanel( true );
setPadding( 5 );
setColumnStretchFactor( 1, 1 );
auto sliderX = new Slider( -50, 50, 1, 10 );

View File

@ -4,7 +4,9 @@
############################################################################
set(SOURCES
QskFluent2Global.h QskFluent2Skin.h QskFluent2Skin.cpp
QskFluent2Global.h
QskFluent2Theme.h QskFluent2Theme.cpp
QskFluent2Skin.h QskFluent2Skin.cpp
QskFluent2SkinFactory.h QskFluent2SkinFactory.cpp
)
qt_add_resources(SOURCES icons.qrc)

View File

@ -6,7 +6,7 @@
#ifndef QSK_FLUENT2_GLOBAL_H
#define QSK_FLUENT2_GLOBAL_H
#include "QskGlobal.h"
#include <QskGlobal.h>
#ifdef QSK_DLL

File diff suppressed because it is too large Load Diff

View File

@ -7,327 +7,9 @@
#define QSK_FLUENT2_SKIN_H
#include "QskFluent2Global.h"
#include <QskBoxShapeMetrics.h>
#include <QskGradient.h>
#include <QskShadowMetrics.h>
#include <QskSkin.h>
#include <array>
class QSK_FLUENT2_EXPORT QskFluent2Theme
{
public:
enum Theme
{
Light,
Dark
};
enum AccentColors
{
AccentLight3,
AccentLight2,
AccentLight1,
AccentBase,
AccentDark1,
AccentDark2,
AccentDark3,
NumAccentColors
};
QskFluent2Theme( Theme );
QskFluent2Theme( Theme, std::array< QRgb, NumAccentColors > );
typedef std::array< QRgb, 2 > BorderGradient;
struct FillColor
{
struct Text
{
QRgb primary;
QRgb secondary;
QRgb tertiary;
QRgb disabled;
};
struct AccentText
{
QRgb primary;
QRgb secondary;
QRgb tertiary;
QRgb disabled;
};
struct TextOnAccent
{
QRgb primary;
QRgb secondary;
QRgb tertiary;
QRgb disabled;
QRgb selectedText;
};
struct Control
{
QRgb transparent;
QRgb defaultColor;
QRgb secondary;
QRgb tertiary;
QRgb inputActive;
QRgb disabled;
};
struct ControlStrong
{
QRgb defaultColor;
QRgb disabled;
};
struct Subtle
{
QRgb transparent;
QRgb secondary;
QRgb tertiary;
QRgb disabled;
};
struct ControlSolid
{
QRgb defaultColor;
};
struct ControlAlt
{
QRgb transparent;
QRgb secondary;
QRgb tertiary;
QRgb quaternary;
QRgb disabled;
};
struct Accent
{
QRgb defaultColor;
QRgb secondary;
QRgb tertiary;
QRgb disabled;
QRgb selectedTextBackground;
};
struct System
{
QRgb critical;
QRgb success;
QRgb attention;
QRgb caution;
QRgb attentionBackground;
QRgb successBackground;
QRgb cautionBackground;
QRgb criticalBackground;
QRgb neutral;
QRgb neutralBackground;
QRgb solidNeutral;
QRgb solidAttentionBackground;
QRgb solidNeutralBackground;
};
struct ControlOnImage
{
QRgb defaultColor;
QRgb secondary;
QRgb tertiary;
QRgb disabled;
};
Text text;
AccentText accentText;
TextOnAccent textOnAccent;
Control control;
ControlStrong controlStrong;
Subtle subtle;
ControlSolid controlSolid;
ControlAlt controlAlt;
Accent accent;
System system;
ControlOnImage controlOnImage;
};
struct Elevation
{
struct Control
{
BorderGradient border;
};
struct Circle
{
BorderGradient border;
};
struct TextControl
{
BorderGradient border;
BorderGradient borderFocused;
};
struct AccentControl
{
BorderGradient border;
};
Control control;
Circle circle;
TextControl textControl;
AccentControl accentControl;
};
struct StrokeColor
{
struct ControlStroke
{
QRgb defaultColor;
QRgb secondary;
QRgb onAccentDefault;
QRgb onAccentSecondary;
QRgb onAccentTertiary;
QRgb onAccentDisabled;
QRgb forStrongFillWhenOnImage;
};
struct ControlStrongStroke
{
QRgb defaultColor;
QRgb disabled;
};
struct CardStroke
{
QRgb defaultColor;
QRgb defaultSolid;
};
struct DividerStroke
{
QRgb defaultColor;
};
struct SurfaceStroke
{
QRgb defaultColor;
QRgb flyout;
};
struct FocusStroke
{
QRgb outer;
QRgb inner;
};
ControlStroke controlStroke;
ControlStrongStroke controlStrongStroke;
CardStroke cardStroke;
DividerStroke dividerStroke;
SurfaceStroke surfaceStroke;
FocusStroke focusStroke;
};
struct Background
{
struct FillColor
{
struct CardBackground
{
QRgb defaultColor;
QRgb secondary;
QRgb tertiary;
};
struct Smoke
{
QRgb defaultColor;
};
struct Layer
{
QRgb defaultColor;
QRgb alt;
};
struct LayerOnAcrylic
{
QRgb defaultColor;
};
struct LayerOnAccentAcrylic
{
QRgb defaultColor;
};
struct AcrylicBackground
{
QRgb defaultColor;
QRgb base;
};
struct AccentAcrylicBackground
{
QRgb base;
QRgb defaultColor;
};
struct MicaBackground
{
QRgb base;
};
struct SolidBackground
{
QRgb base;
QRgb secondary;
QRgb tertiary;
QRgb quaternary;
};
CardBackground cardBackground;
Smoke smoke;
Layer layer;
LayerOnAcrylic layerOnAcrylic;
LayerOnAccentAcrylic layerOnAccentAcrylic;
AcrylicBackground acrylicBackground;
AccentAcrylicBackground accentAcrylicBackground;
MicaBackground micaBackground;
SolidBackground solidBackground;
};
FillColor fillColor;
};
struct Palette
{
FillColor fillColor;
Elevation elevation;
StrokeColor strokeColor;
Background background;
};
Palette palette;
typedef QPair< QskShadowMetrics, QRgb > ShadowSettings;
struct Shadow
{
ShadowSettings cardRest;
ShadowSettings cardHover;
ShadowSettings tooltip;
ShadowSettings flyout;
ShadowSettings dialog;
};
Shadow shadow;
};
class QskFluent2Theme;
class QSK_FLUENT2_EXPORT QskFluent2Skin : public QskSkin
{
@ -336,8 +18,11 @@ class QSK_FLUENT2_EXPORT QskFluent2Skin : public QskSkin
using Inherited = QskSkin;
public:
QskFluent2Skin( const QskFluent2Theme&, QObject* parent = nullptr );
~QskFluent2Skin() override;
QskFluent2Skin( QObject* parent = nullptr );
~QskFluent2Skin() override;
void addTheme( QskAspect::Section, const QskFluent2Theme& );
void setup();
enum GraphicRole
{
@ -366,7 +51,7 @@ class QSK_FLUENT2_EXPORT QskFluent2Skin : public QskSkin
private:
void setupFonts();
void setupGraphicFilters( const QskFluent2Theme& palette );
void setupGraphicFilters( const QskFluent2Theme& );
void setGraphicColor( GraphicRole, QRgb );
};

View File

@ -5,9 +5,18 @@
#include "QskFluent2SkinFactory.h"
#include "QskFluent2Skin.h"
#include "QskFluent2Theme.h"
static const QString fluent2LightSkinName = QStringLiteral( "Fluent2 Light" );
static const QString fluent2DarkSkinName = QStringLiteral( "Fluent2 Dark" );
static const QString nameLight = QStringLiteral( "Fluent2 Light" );
static const QString nameDark = QStringLiteral( "Fluent2 Dark" );
namespace
{
inline constexpr QRgb rgbGray( int value )
{
return qRgba( value, value, value, 255 );
}
}
QskFluent2SkinFactory::QskFluent2SkinFactory( QObject* parent )
: QskSkinFactory( parent )
@ -20,23 +29,71 @@ QskFluent2SkinFactory::~QskFluent2SkinFactory()
QStringList QskFluent2SkinFactory::skinNames() const
{
return { fluent2LightSkinName, fluent2DarkSkinName };
return { nameLight, nameDark };
}
QskSkin* QskFluent2SkinFactory::createSkin( const QString& skinName )
{
if ( QString::compare( skinName, fluent2LightSkinName, Qt::CaseInsensitive ) == 0 )
QskSkin::ColorScheme colorScheme;
if ( QString::compare( skinName, nameLight, Qt::CaseInsensitive ) == 0 )
{
QskFluent2Theme theme( QskFluent2Theme::Light );
return new QskFluent2Skin( theme );
colorScheme = QskSkin::LightScheme;
}
else if ( QString::compare( skinName, fluent2DarkSkinName, Qt::CaseInsensitive ) == 0 )
else if ( QString::compare( skinName, nameDark, Qt::CaseInsensitive ) == 0 )
{
QskFluent2Theme theme( QskFluent2Theme::Dark );
return new QskFluent2Skin( theme );
colorScheme = QskSkin::DarkScheme;
}
else
{
return nullptr;
}
return nullptr;
struct
{
QskSkin::ColorScheme scheme;
QskFluent2Theme::BaseColors baseColors;
QskFluent2Theme::AccentColors accentColors;
QskFluent2Theme theme() const { return { scheme, baseColors, accentColors }; }
} colors[2];
switch( colorScheme )
{
case QskSkin::LightScheme:
{
colors[0].scheme = colorScheme;
colors[0].baseColors = { rgbGray( 243 ), rgbGray( 249 ), rgbGray( 238 ) };
colors[0].accentColors = { 0xff0078d4, 0xff005eb7, 0xff003d92, 0xff001968 };
colors[1].scheme = colorScheme;
colors[1].baseColors = { rgbGray( 249 ), rgbGray( 249 ), rgbGray( 238 ) };
colors[1].accentColors = colors[0].accentColors;
break;
}
case QskSkin::DarkScheme:
{
colors[0].scheme = colorScheme;
colors[0].baseColors = { rgbGray( 32 ), rgbGray( 40 ), rgbGray( 28 ) };
colors[0].accentColors = { 0xff0078d4, 0xff0093f9, 0xff60ccfe, 0xff98ecfe };
colors[1].scheme = colorScheme;
colors[1].baseColors = { rgbGray( 40 ), rgbGray( 44 ), rgbGray( 28 ) };
colors[1].accentColors = colors[0].accentColors;
break;
}
default:;
}
auto skin = new QskFluent2Skin();
skin->addTheme( QskAspect::Body, colors[0].theme() );
skin->addTheme( QskAspect::Header, colors[1].theme() );
skin->addTheme( QskAspect::Footer, colors[1].theme() );
return skin;
}
#include "moc_QskFluent2SkinFactory.cpp"

View File

@ -19,7 +19,7 @@ class QSK_FLUENT2_EXPORT QskFluent2SkinFactory : public QskSkinFactory
public:
QskFluent2SkinFactory( QObject* parent = nullptr );
~QskFluent2SkinFactory() override;
~QskFluent2SkinFactory() override;
QStringList skinNames() const override;
QskSkin* createSkin( const QString& skinName ) override;

View File

@ -0,0 +1,278 @@
/******************************************************************************
* QSkinny - Copyright (C) 2023 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskFluent2Theme.h"
#include <QskRgbValue.h>
namespace
{
inline constexpr QRgb rgbGray( int value, qreal opacity = 1.0 )
{
return qRgba( value, value, value, qRound( opacity * 255 ) );
}
}
QskFluent2Theme::QskFluent2Theme( QskSkin::ColorScheme colorScheme,
const BaseColors& baseColors, const AccentColors& accentColors )
{
using namespace QskRgb;
{
auto& colors = palette.background;
colors.solid.base = baseColors.primary;
colors.solid.secondary = baseColors.secondary;
colors.solid.tertiary = baseColors.tertiary;
}
if( colorScheme != QskSkin::DarkScheme )
{
{
palette.background.solid.quaternary = rgbGray( 255 );
}
{
auto& colors = palette.fillColor;
colors.text.primary = rgbGray( 0, 0.8956 );
colors.text.secondary = rgbGray( 0, 0.6063 );
colors.text.tertiary = rgbGray( 0, 0.4458 );
colors.text.disabled = rgbGray( 0, 0.3614 );
colors.accentText.primary = accentColors.tertiary;
colors.accentText.secondary = accentColors.quaternary;
colors.accentText.tertiary = accentColors.secondary;
colors.accentText.disabled = rgbGray( 0, 0.3614 );
colors.textOnAccent.primary = rgbGray( 255 );
colors.textOnAccent.secondary = rgbGray( 255, 0.70 );
colors.textOnAccent.disabled = rgbGray( 255 );
colors.textOnAccent.selectedText = rgbGray( 255 );
colors.control.defaultColor = rgbGray( 255, 0.70 );
colors.control.secondary = rgbGray( 249, 0.50 );
colors.control.tertiary = rgbGray( 249, 0.30 );
colors.control.inputActive = rgbGray( 255 );
colors.control.disabled = rgbGray( 249, 0.30 );
colors.controlStrong.defaultColor = rgbGray( 0, 0.4458 );
colors.controlStrong.disabled = rgbGray( 0, 0.3173 );
colors.subtle.secondary = rgbGray( 0, 0.0373 );
colors.subtle.tertiary = rgbGray( 0, 0.0241 );
colors.subtle.disabled = Qt::transparent;
colors.controlSolid.defaultColor = rgbGray( 255 );
colors.controlAlt.secondary = rgbGray( 0, 0.0241 );
colors.controlAlt.tertiary = rgbGray( 0, 0.0578 );
colors.controlAlt.quaternary = rgbGray( 0, 0.0924 );
colors.controlAlt.disabled = Qt::transparent;
colors.accent.defaultColor = accentColors.secondary;
colors.accent.secondary = toTransparentF( accentColors.secondary, 0.90 );
colors.accent.tertiary = toTransparentF( accentColors.secondary, 0.80 );
colors.accent.disabled = rgbGray( 0, 0.2169 );
colors.accent.selectedTextBackground = accentColors.primary;
colors.acrylic.background = rgbGray( 252, 0.85 );
}
#if 0
{
// system colors
critical = 0xffc42b1c;
success = 0xff0f7b0f;
attention = 0xff005fb7;
caution = 0xff9d5d00;
attentionBackground = rgbGray( 246, 0.50 );
successBackground = 0xffdff6dd;
cautionBackground = 0xfffff4ce;
criticalBackground = 0xfffde7e9;
neutral = rgbGray( 0, 0.4458 );
neutralBackground = rgbGray( 0, 0.0241 );
solidNeutral = rgbGray( 138 );
solidAttentionBackground = rgbGray( 247 );
solidNeutralBackground = rgbGray( 243 );
}
#endif
{
auto& colors = palette.elevation;
colors.control.border = { rgbGray( 0, 0.0578 ), rgbGray( 0, 0.1622 ) };
colors.circle.border = { rgbGray( 0, 0.0578 ), rgbGray( 0, 0.1622 ) };
colors.textControl.border = { rgbGray( 0, 0.0578 ), palette.fillColor.text.secondary };
colors.textControl.borderFocused = { rgbGray( 0, 0.0578 ), rgbGray( 0, 0.0578 ) };
colors.accentControl.border = { rgbGray( 255, 0.08 ), rgbGray( 0, 0.40 ) };
}
{
auto& colors = palette.strokeColor;
colors.control.defaultColor = rgbGray( 0, 0.0578 );
colors.control.secondary = rgbGray( 0, 0.1622 );
colors.control.onAccentDefault = rgbGray( 255.08 );
colors.control.onAccentSecondary = rgbGray( 0, 0.40 );
colors.control.onAccentTertiary = rgbGray( 0, 0.2169 );
colors.control.onAccentDisabled = rgbGray( 0, 0.0578 );
colors.controlStrong.defaultColor = rgbGray( 0, 0.4458 );
colors.controlStrong.disabled = rgbGray( 0, 0.2169 );
colors.card.defaultColor = rgbGray( 0, 0.0578 );
colors.card.defaultSolid = rgbGray( 235 );
colors.divider.defaultColor = rgbGray( 0, 0.0803 );
colors.surface.defaultColor = rgbGray( 117, 0.40 );
colors.surface.flyout = rgbGray( 0, 0.0578 );
colors.focus.outer = rgbGray( 0, 0.8956 );
colors.focus.inner = rgbGray( 255 );
}
{
auto& colors = palette.background;
colors.overlay.defaultColor = rgbGray( 0, 0.30 );
colors.layer.alt = rgbGray( 255 );
colors.flyout.defaultColor = rgbGray( 252, 0.85 );
}
// Shadow:
shadow.flyout = { QskShadowMetrics( 0, 16, QPointF( 0, 8 ) ), rgbGray( 0, 0.14 ) };
// ### should actually be drawn twice with different values:
shadow.dialog = { QskShadowMetrics( 0, 21, QPointF( 0, 2 ) ), rgbGray( 0, 0.1474 ) };
}
else
{
{
palette.background.solid.quaternary = rgbGray( 44 );
}
{
auto& colors = palette.fillColor;
colors.text.primary = rgbGray( 255 );
colors.text.secondary = rgbGray( 255, 0.786 );
colors.text.tertiary = rgbGray( 255, 0.5442 );
colors.text.disabled = rgbGray( 255, 0.3628 );
colors.accentText.primary = accentColors.quaternary;
colors.accentText.secondary = accentColors.quaternary;
colors.accentText.tertiary = accentColors.tertiary;
colors.accentText.disabled = rgbGray( 255, 0.3628 );
colors.textOnAccent.primary = rgbGray( 0 );
colors.textOnAccent.secondary = rgbGray( 0, 0.50 );
colors.textOnAccent.disabled = rgbGray( 255, 0.5302 );
colors.textOnAccent.selectedText = rgbGray( 255 );
colors.control.defaultColor = rgbGray( 255, 0.0605 );
colors.control.secondary = rgbGray( 255, 0.0837 );
colors.control.tertiary = rgbGray( 255, 0.0326 );
colors.control.inputActive = rgbGray( 30, 0.70 );
colors.control.disabled = rgbGray( 255, 0.0419 );
colors.controlStrong.defaultColor = rgbGray( 255, 0.5442 );
colors.controlStrong.disabled = rgbGray( 255, 0.2465 );
colors.subtle.secondary = rgbGray( 255, 0.0605 );
colors.subtle.tertiary = rgbGray( 255, 0.0419 );
colors.subtle.disabled = Qt::transparent;
colors.controlSolid.defaultColor = rgbGray( 69 );
colors.controlAlt.secondary = rgbGray( 0, 0.10 );
colors.controlAlt.tertiary = rgbGray( 255, 0.0419 );
colors.controlAlt.quaternary = rgbGray( 255, 0.0698 );
colors.controlAlt.disabled = Qt::transparent;
colors.accent.defaultColor = accentColors.tertiary;
colors.accent.secondary = toTransparentF( accentColors.tertiary, 0.90 );
colors.accent.tertiary = toTransparentF( accentColors.tertiary, 0.80 );
colors.accent.disabled = rgbGray( 255, 0.1581 );
colors.accent.selectedTextBackground = accentColors.primary;
colors.acrylic.background = rgbGray( 44, 0.96 );
}
#if 0
{
// system colors
critical = 0xffff99a4;
success = 0xff6ccb5f;
attention = 0xff60cdff;
caution = 0xfffce100;
attentionBackground = rgbGray( 255, 0.0326 );
successBackground = 0xff393d1b;
cautionBackground = 0xff433519;
criticalBackground = 0xff442726;
neutral = rgbGray( 255, 0.5442 );
neutralBackground = rgbGray( 255, 0.0326 );
solidNeutral = rgbGray( 157 );
solidAttentionBackground = rgbGray( 46 );
solidNeutralBackground = rgbGray( 46 );
}
#endif
{
auto& colors = palette.elevation;
colors.control.border = { rgbGray( 255, 0.093 ), rgbGray( 255, 0.0698 ) };
colors.circle.border = { rgbGray( 255, 0.093 ), rgbGray( 255, 0.0698 ) };
colors.textControl.border = { rgbGray( 255, 0.08 ), palette.fillColor.text.secondary };
colors.textControl.borderFocused = { rgbGray( 255, 0.08 ), rgbGray( 255, 0.08 ) };
colors.accentControl.border = { rgbGray( 255, 0.08 ), rgbGray( 0, 0.14 ) };
}
{
auto& colors = palette.strokeColor;
colors.control.defaultColor = rgbGray( 255, 0.0698 );
colors.control.secondary = rgbGray( 255, 0.093 );
colors.control.onAccentDefault = rgbGray( 255, 0.08 );
colors.control.onAccentSecondary = rgbGray( 0, 0.14 );
colors.control.onAccentTertiary = rgbGray( 0, 0.2169 );
colors.control.onAccentDisabled = rgbGray( 0, 0.20 );
colors.controlStrong.defaultColor = rgbGray( 255, 0.5442 );
colors.controlStrong.disabled = rgbGray( 255, 0.1581 );
colors.card.defaultColor = rgbGray( 255, 0.0578 );
colors.card.defaultSolid = rgbGray( 235 );
colors.divider.defaultColor = rgbGray( 255, 0.0837 );
colors.surface.defaultColor = rgbGray( 117, 0.40 );
colors.surface.flyout = rgbGray( 0, 0.20 );
colors.focus.outer = rgbGray( 255 );
colors.focus.inner = rgbGray( 0, 0.70 );
}
{
auto& colors = palette.background;
colors.overlay.defaultColor = rgbGray( 0, 0.30 );
colors.layer.alt = rgbGray( 255, 0.0538 );
colors.flyout.defaultColor = rgbGray( 44, 0.96 );
}
// Shadow:
shadow.flyout = { QskShadowMetrics( 0, 16, QPointF( 0, 8 ) ), rgbGray( 0, 0.26 ) };
// ### should actually be drawn twice with different values:
shadow.dialog = { QskShadowMetrics( 0, 21, QPointF( 0, 2 ) ), rgbGray( 0, 0.37 ) };
}
}

View File

@ -0,0 +1,230 @@
/******************************************************************************
* QSkinny - Copyright (C) 2023 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_FLUENT2_THEME_H
#define QSK_FLUENT2_THEME_H
#include "QskFluent2Global.h"
#include <QskSkin.h>
#include <QskShadowMetrics.h>
#include <qcolor.h>
#include <array>
class QSK_FLUENT2_EXPORT QskFluent2Theme
{
public:
struct BaseColors
{
QRgb primary;
QRgb secondary;
QRgb tertiary;
};
struct AccentColors
{
QRgb primary;
QRgb secondary;
QRgb tertiary;
QRgb quaternary;
};
QskFluent2Theme( QskSkin::ColorScheme, const BaseColors& baseColors,
const AccentColors& accentColors );
typedef std::array< QRgb, 2 > BorderGradient;
struct FillColor
{
struct
{
QRgb primary;
QRgb secondary;
QRgb tertiary;
QRgb disabled;
} text;
struct
{
QRgb primary;
QRgb secondary;
QRgb tertiary;
QRgb disabled;
} accentText;
struct
{
QRgb primary;
QRgb secondary;
QRgb tertiary;
QRgb disabled;
QRgb selectedText;
} textOnAccent;
struct
{
QRgb defaultColor;
QRgb secondary;
QRgb tertiary;
QRgb inputActive;
QRgb disabled;
} control;
struct
{
QRgb defaultColor;
QRgb disabled;
} controlStrong;
struct
{
QRgb secondary;
QRgb tertiary;
QRgb disabled;
} subtle;
struct
{
QRgb defaultColor;
} controlSolid;
struct
{
QRgb secondary;
QRgb tertiary;
QRgb quaternary;
QRgb disabled;
} controlAlt;
struct
{
QRgb defaultColor;
QRgb secondary;
QRgb tertiary;
QRgb disabled;
QRgb selectedTextBackground;
} accent;
struct
{
QRgb background;
} acrylic;
};
struct Elevation
{
struct
{
BorderGradient border;
} control;
struct
{
BorderGradient border;
} circle;
struct
{
BorderGradient border;
BorderGradient borderFocused;
} textControl;
struct
{
BorderGradient border;
} accentControl;
};
struct StrokeColor
{
struct
{
QRgb defaultColor;
QRgb secondary;
QRgb onAccentDefault;
QRgb onAccentSecondary;
QRgb onAccentTertiary;
QRgb onAccentDisabled;
} control;
struct
{
QRgb defaultColor;
QRgb disabled;
} controlStrong;
struct
{
QRgb defaultColor;
QRgb defaultSolid;
} card;
struct
{
QRgb defaultColor;
} divider;
struct
{
QRgb defaultColor;
QRgb flyout;
} surface;
struct
{
QRgb outer;
QRgb inner;
} focus;
};
struct Background
{
struct
{
QRgb defaultColor;
} overlay;
struct
{
QRgb alt;
} layer;
struct
{
QRgb defaultColor;
} flyout;
struct
{
QRgb base;
QRgb secondary;
QRgb tertiary;
QRgb quaternary;
} solid;
};
struct
{
FillColor fillColor;
Elevation elevation;
StrokeColor strokeColor;
Background background;
} palette;
struct ShadowSettings
{
QskShadowMetrics metrics;
QRgb color;
};
struct
{
ShadowSettings flyout;
ShadowSettings dialog;
} shadow;
};
#endif

View File

@ -1,4 +1,5 @@
{
"FactoryId": "Fluent2Factory",
"Skins": [ "Fluent2 Light", "Fluent2 Dark" ]
"Skins": [ { "Name": "Fluent2 Light", "Scheme": "Light" },
{ "Name": "Fluent2 Dark", "Scheme": "Dark" } ]
}

View File

@ -278,6 +278,10 @@ void Editor::setupComboBox()
m_pal.surfaceVariant, m_pal.focusOpacity );
setGradient( Q::Panel | Q::Focused, focusColor );
const auto pressedColor = flattenedColor( m_pal.onSurfaceVariant,
m_pal.surfaceVariant, m_pal.pressedOpacity );
setGradient( Q::Panel | Q::Pressed, pressedColor );
const auto activeColor = flattenedColor( m_pal.onSurfaceVariant,
m_pal.surfaceVariant, m_pal.pressedOpacity );
setGradient( Q::Panel | Q::PopupOpen, activeColor );
@ -340,8 +344,8 @@ void Editor::setupMenu()
// The color here is primary with an opacity of 8% - we blend that
// with the background, because we don't want the menu to have transparency:
const auto panel = flattenedColor( m_pal.primary, m_pal.background, 0.08 );
setGradient( Q::Panel, panel );
const auto panelColor = flattenedColor( m_pal.primary, m_pal.background, 0.08 );
setGradient( Q::Panel, panelColor );
setShadowMetrics( Q::Panel, m_pal.elevation2 );
setShadowColor( Q::Panel, m_pal.shadow );
@ -355,7 +359,14 @@ void Editor::setupMenu()
setSpacing( Q::Segment, 5_dp );
setGradient( Q::Segment, Qt::transparent );
setGradient( Q::Cursor, m_pal.primary12 );
const auto hoverColor = flattenedColor( m_pal.onSurface, panelColor, m_pal.hoverOpacity );
setGradient( Q::Segment | Q::Hovered, hoverColor );
setGradient( Q::Segment | Q::Selected, m_pal.primary12 );
const auto hoverSelectedColor = flattenedColor( m_pal.onSurface, m_pal.primary12, m_pal.hoverOpacity );
setGradient( Q::Segment | Q::Selected | Q::Hovered, hoverSelectedColor );
const auto pressedSelectedColor = flattenedColor( m_pal.onSurface, m_pal.primary12, m_pal.pressedOpacity );
setGradient( Q::Segment | Q::Pressed | Q::Selected, pressedSelectedColor );
setPadding( Q::Icon, 7_dp );
setStrutSize( Q::Icon, 24_dp, 24_dp );
@ -489,7 +500,6 @@ void Editor::setupFocusIndicator()
void Editor::setupSegmentedBar()
{
// copied from Squiek: we need something similar to a tab bar here. TODO ...
using A = QskAspect;
using Q = QskSegmentedBar;
@ -507,18 +517,33 @@ void Editor::setupSegmentedBar()
setBoxBorderMetrics( Q::Panel, 1_dp );
setBoxBorderColors( Q::Panel, m_pal.outline );
setBoxBorderColors( Q::Panel | Q::Disabled, m_pal.onSurface12 );
setStrutSize( Q::Panel | A::Horizontal, panelStrutSize );
setStrutSize( Q::Panel | A::Vertical, panelStrutSize.transposed() );
setFlag( Q::Panel | A::Option, true ); // adjust segments to the panel radius
}
{
// Segment
// Segment / Splash
setStrutSize( Q::Segment | A::Horizontal, segmentStrutSize );
setStrutSize( Q::Segment | A::Vertical, segmentStrutSize.transposed() );
setGradient( Q::Segment, Qt::transparent );
setGradient( Q::Segment | Q::Hovered, m_pal.onSurface8 );
setGradient( Q::Segment | Q::Focused, m_pal.onSurface12 );
setGradient( Q::Segment | Q::Selected, m_pal.secondaryContainer );
setGradient( Q::Segment | Q::Selected | Q::Hovered,
flattenedColor( m_pal.onSurface, m_pal.secondaryContainer, m_pal.hoverOpacity ) );
setGradient( Q::Segment | Q::Selected | Q::Focused,
flattenedColor( m_pal.onSurface, m_pal.secondaryContainer, m_pal.focusOpacity ) );
setGradient( Q::Segment | Q::Selected | Q::Disabled, m_pal.onSurface12 );
setPadding( Q::Segment | A::Horizontal, 12_dp, 0, 12_dp, 0 );
setPadding( Q::Segment | A::Vertical, 0, 12_dp, 0, 12_dp );
}
@ -534,30 +559,10 @@ void Editor::setupSegmentedBar()
}
{
// Cursor
setBoxShape( Q::Cursor, 0 );
// Splash
setBoxShape( Q::Cursor | Q::Minimum | A::Horizontal,
{ 100, 0, 100, 0, Qt::RelativeSize },
{ QskStateCombination::CombinationNoState, Q::Disabled } );
setBoxShape( Q::Cursor | Q::Maximum | A::Horizontal,
{ 0, 100, 0, 100, Qt::RelativeSize },
{ QskStateCombination::CombinationNoState, Q::Disabled } );
setBoxShape( Q::Cursor | Q::Minimum | A::Vertical,
{ 100, 100, 0, 0, Qt::RelativeSize },
{ QskStateCombination::CombinationNoState, Q::Disabled } );
setBoxShape( Q::Cursor | Q::Maximum | A::Vertical,
{ 0, 0, 100, 100, Qt::RelativeSize },
{ QskStateCombination::CombinationNoState, Q::Disabled } );
setGradient( Q::Cursor, m_pal.secondaryContainer );
setGradient( Q::Cursor | Q::Disabled, m_pal.onSurface12 );
setBoxBorderMetrics( Q::Cursor, 1_dp );
setBoxBorderColors( Q::Cursor, Qt::transparent );
setGradient( Q::Splash, stateLayerColor( m_pal.onSecondaryContainer, m_pal.pressedOpacity ) );
setAnimation( Q::Splash | A::Color, qskDuration );
}
{
@ -634,6 +639,7 @@ void Editor::setupPushButton()
setSpacing( Q::Panel, 8_dp );
setPadding( Q::Panel, { 24_dp, 0, 24_dp, 0 } );
setBoxShape( Q::Panel, 100, Qt::RelativeSize );
setShadowColor( Q::Panel, m_pal.shadow );
setStrutSize( Q::Icon, 18_dp, 18_dp );
setPadding( Q::Icon, { 0, 0, 8_dp, 0 } );
@ -642,8 +648,7 @@ void Editor::setupPushButton()
setFontRole( Q::Text, QskMaterial3Skin::M3LabelLarge );
setPadding( Q::Text, 0 );
setShadowColor( Q::Panel, m_pal.shadow );
setBoxShape( Q::Splash, 40_dp );
setAnimation( Q::Splash | QskAspect::Color, qskDuration );
@ -985,6 +990,11 @@ void Editor::setupTabButton()
using Q = QskTabButton;
setStrutSize( Q::Panel, 48_dp, 64_dp );
#if 1
// couldn't find a value in the specs
setPadding( Q::Panel, 8, 0, 8, 0 );
#endif
setGradient( Q::Panel, m_pal.surface );
setColor( Q::Text, m_pal.onSurfaceVariant );
@ -1114,12 +1124,11 @@ void Editor::setupScrollView()
using Q = QskScrollView;
setGradient( Q::Panel, m_pal.background );
setGradient( Q::Viewport, m_pal.secondaryContainer );
for ( auto subControl : { Q::HorizontalScrollBar, Q::VerticalScrollBar } )
{
setMetric( subControl | A::Size, 10_dp );
setMetric( subControl | A::Size, 6_dp );
setPadding( subControl, 0 );
}
@ -1129,9 +1138,9 @@ void Editor::setupScrollView()
for ( auto subControl : { Q::HorizontalScrollHandle, Q::VerticalScrollHandle } )
{
setBoxShape( subControl, 3_dp );
setBoxShape( subControl, { 100, Qt::RelativeSize } );
setBoxBorderMetrics( subControl, 0 );
setGradient( subControl, m_pal.primary );
setGradient( subControl, m_pal.secondary );
setAnimation( subControl | A::Color, qskDuration );
}
@ -1143,13 +1152,14 @@ void Editor::setupListView()
{
using Q = QskListView;
setStrutSize( Q::Cell, { -1, 56 } );
setPadding( Q::Cell, { 16_dp, 12_dp, 16_dp, 12_dp } );
setBoxBorderMetrics( Q::Cell, { 0, 0, 0, 1_dp } );
setBoxBorderColors( Q::Cell, m_pal.outline );
setColor( Q::Cell, m_pal.surface );
setColor( Q::Cell | Q::Selected, m_pal.primary12 );
setColor( Q::Text, m_pal.onSurfaceVariant );
setBoxBorderColors( Q::Cell, m_pal.outline );
setGradient( Q::Cell, m_pal.surface );
setGradient( Q::Cell | Q::Selected, m_pal.primary12 );
setColor( Q::Text, m_pal.onSurface );
}
void Editor::setupSubWindow()
@ -1187,8 +1197,8 @@ void Editor::setupSubWindow()
}
QskMaterial3Theme::QskMaterial3Theme( Lightness lightness )
: QskMaterial3Theme( lightness,
QskMaterial3Theme::QskMaterial3Theme( QskSkin::ColorScheme colorScheme )
: QskMaterial3Theme( colorScheme,
{ // default Material colors:
0xff6750A4,
0xff625B71,
@ -1200,11 +1210,11 @@ QskMaterial3Theme::QskMaterial3Theme( Lightness lightness )
{
}
QskMaterial3Theme::QskMaterial3Theme( Lightness lightness,
QskMaterial3Theme::QskMaterial3Theme( QskSkin::ColorScheme colorScheme,
std::array< QskHctColor, NumPaletteTypes > palettes )
: m_palettes( palettes )
{
if ( lightness == Light )
if ( colorScheme == QskSkin::LightScheme )
{
primary = m_palettes[ Primary ].toned( 40 ).rgb();
onPrimary = m_palettes[ Primary ].toned( 100 ).rgb();
@ -1238,7 +1248,7 @@ QskMaterial3Theme::QskMaterial3Theme( Lightness lightness,
shadow = m_palettes[ Neutral ].toned( 0 ).rgb();
}
else if ( lightness == Dark )
else if ( colorScheme == QskSkin::DarkScheme )
{
primary = m_palettes[ Primary ].toned( 80 ).rgb();
onPrimary = m_palettes[ Primary ].toned( 20 ).rgb();

View File

@ -18,12 +18,6 @@
class QSK_MATERIAL3_EXPORT QskMaterial3Theme
{
public:
enum Lightness
{
Light,
Dark
};
enum PaletteType
{
Primary,
@ -36,8 +30,8 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Theme
NumPaletteTypes
};
QskMaterial3Theme( Lightness );
QskMaterial3Theme( Lightness, std::array< QskHctColor, NumPaletteTypes > );
QskMaterial3Theme( QskSkin::ColorScheme );
QskMaterial3Theme( QskSkin::ColorScheme, std::array< QskHctColor, NumPaletteTypes > );
QRgb primary;
QRgb primary8; // ### rename to primaryHovered or so?

View File

@ -27,12 +27,12 @@ QskSkin* QskMaterial3SkinFactory::createSkin( const QString& skinName )
{
if ( QString::compare( skinName, materialLightSkinName, Qt::CaseInsensitive ) == 0 )
{
QskMaterial3Theme theme( QskMaterial3Theme::Light );
QskMaterial3Theme theme( QskSkin::LightScheme );
return new QskMaterial3Skin( theme );
}
else if ( QString::compare( skinName, materialDarkSkinName, Qt::CaseInsensitive ) == 0 )
{
QskMaterial3Theme theme( QskMaterial3Theme::Dark );
QskMaterial3Theme theme( QskSkin::DarkScheme );
return new QskMaterial3Skin( theme );
}

View File

@ -1,4 +1,5 @@
{
"FactoryId": "Material3Factory",
"Skins": [ "Material3 Light", "Material3 Dark" ]
"Skins": [ { "Name": "Material3 Light", "Scheme": "Light" },
{ "Name": "Material3 Dark", "Scheme": "Dark" } ]
}

View File

@ -521,13 +521,15 @@ void Editor::setupProgressBar()
using A = QskAspect;
using Q = QskProgressBar;
setMetric( Q::Groove | A::Size, 8 );
setPadding( Q::Groove, 0 );
setGradient( Q::Groove, m_pal.darker200 );
setBoxShape( Q::Groove, 4 );
for ( auto subControl : { Q::Groove, Q::Bar } )
{
setMetric( subControl | A::Size, 6 );
setPadding( subControl, 0 );
setBoxShape( subControl, 4 );
}
setGradient( Q::Groove, m_pal.darker200 );
setGradient( Q::Bar, m_pal.highlighted );
setBoxShape( Q::Bar, 4 );
}
void Editor::setupFocusIndicator()
@ -778,7 +780,7 @@ void Editor::setupTabButton()
{
const auto aspect = Q::Panel | variation;
QskMargins margins0, margins1, padding;
QskMargins margins0, margins1;
QskBoxBorderMetrics border( 1 );
QskBoxShapeMetrics shape( 4 );
@ -830,7 +832,7 @@ void Editor::setupTabButton()
for ( const auto state : { Q::Checked | A::NoState, Q::Checked | Q::Pressed } )
setMargin( aspect | state, margins1 );
setPadding( aspect, padding );
setPadding( aspect, { 6, 12, 6, 12 } );
setBoxBorderMetrics( aspect, border );
setBoxShape( aspect, shape );
@ -1010,9 +1012,13 @@ void Editor::setupScrollView()
// scroll bars
for ( auto subControl : { Q::HorizontalScrollBar, Q::VerticalScrollBar } )
{
setMetric( subControl | A::Size, 12_dp );
setPadding( subControl, 0 );
setMetric( subControl | A::Size, 14 );
setPadding( subControl, 2 );
setMargin( subControl, 0 );
setPanel( subControl, Sunken );
setBoxShape( subControl, 100, Qt::RelativeSize );
setBoxBorderMetrics( subControl, 1 );
}
// scrollbar handles
@ -1021,19 +1027,16 @@ void Editor::setupScrollView()
const qreal bw = 1.0;
setButton( subControl, Raised, bw );
setButton( subControl | Q::Pressed, Sunken, bw );
setBoxShape( subControl, 100, Qt::RelativeSize );
setBoxShape( subControl | Q::Pressed, 100, Qt::RelativeSize );
const auto extent = 40_dp;
if ( subControl == Q::HorizontalScrollHandle )
{
setStrutSize( subControl, extent, 0.0 );
setButton( subControl | Q::HorizontalHandlePressed, Sunken, bw );
}
else
{
setStrutSize( subControl, 0.0, extent );
setButton( subControl | Q::VerticalHandlePressed, Sunken, bw );
}
setAnimation( subControl | A::Color, qskDuration );
}
@ -1044,15 +1047,21 @@ void Editor::setupScrollView()
void Editor::setupListView()
{
using A = QskAspect;
using Q = QskListView;
// padding for each cell
setPadding( Q::Cell, QskMargins( 4, 8 ) );
setColor( Q::Text, m_pal.themeForeground );
setColor( Q::Cell, m_pal.contrasted );
setColor( Q::Cell | Q::Selected, m_pal.highlighted );
// alternating row colors
setColor( Q::Cell | A::Lower, Qt::white );
setColor( Q::Cell | Q::Selected | A::Lower, m_pal.highlighted );
setColor( Q::Cell | A::Upper, m_pal.contrasted );
setColor( Q::Cell | Q::Selected | A::Upper, m_pal.highlighted );
setColor( Q::Text | Q::Selected, m_pal.highlightedText );
}

View File

@ -1,4 +1,4 @@
{
"FactoryId": "SquiekFactory",
"Skins": [ "Squiek" ]
"Skins": [ { "Name": "Squiek", "Scheme": "Unknown" } ]
}

View File

@ -35,6 +35,8 @@ class QSK_EXPORT QskAspect
Header,
Footer,
Card,
Floating
};
Q_ENUM( Section )
@ -109,7 +111,7 @@ class QSK_EXPORT QskAspect
NoState = 0,
FirstSystemState = 1 << 0,
FirstUserState = 1 << 4,
FirstUserState = 1 << 5,
LastUserState = 1 << 11,
LastSystemState = 1 << 15,

View File

@ -230,7 +230,7 @@ inline const QskGradientStops& QskGradient::stops() const noexcept
#if 1
/*
Returning a const& so that it is possible to write:
for ( const auto& stop : qAsConst( gradient.stops() ) )
for ( const auto& stop : gradient.stops() )
Once we have changed QskGradientStop from QColor to QRgb
we should check if there is a better solution possible

View File

@ -12,6 +12,7 @@
QSK_QT_PRIVATE_BEGIN
#include <private/qhooks_p.h>
#include <private/qquickitem_p.h>
QSK_QT_PRIVATE_END
#define QSK_OBJECT_INFO 0
@ -20,19 +21,8 @@ QSK_QT_PRIVATE_END
#include <qset.h>
#endif
#if QT_VERSION < QT_VERSION_CHECK( 6, 4, 0 )
QSK_QT_PRIVATE_BEGIN
#include <private/qquickitem_p.h>
QSK_QT_PRIVATE_END
#endif
static inline bool qskIsItem( const QObject* object )
{
#if QT_VERSION >= QT_VERSION_CHECK( 6, 4, 0 )
return object->isQuickItemType();
#else
/*
The addObject hook is called from the constructor of QObject,
where we don't have the derived class constructed yet.
@ -42,7 +32,6 @@ static inline bool qskIsItem( const QObject* object )
auto o_p = QObjectPrivate::get( const_cast< QObject* >( object ) );
return dynamic_cast< QQuickItemPrivate* >( o_p ) != nullptr;
#endif
}
namespace
@ -173,7 +162,7 @@ void CounterHook::addObject( QObject* object )
{
const bool isItem = qskIsItem( object );
for ( auto counterData : qAsConst( m_counterDataSet ) )
for ( auto counterData : std::as_const( m_counterDataSet ) )
{
counterData->counter[ QskObjectCounter::Objects ].increment();
@ -193,7 +182,7 @@ void CounterHook::removeObject( QObject* object )
{
const bool isItem = qskIsItem( object );
for ( auto counterData : qAsConst( m_counterDataSet ) )
for ( auto counterData : std::as_const( m_counterDataSet ) )
{
counterData->counter[ QskObjectCounter::Objects ].decrement();

View File

@ -18,7 +18,8 @@ QSK_SUBCONTROL( QskComboBox, Icon )
QSK_SUBCONTROL( QskComboBox, Text )
QSK_SUBCONTROL( QskComboBox, StatusIndicator )
QSK_SYSTEM_STATE( QskComboBox, PopupOpen, QskAspect::FirstSystemState << 1 )
QSK_SYSTEM_STATE( QskComboBox, Pressed, QskAspect::FirstSystemState << 1 )
QSK_SYSTEM_STATE( QskComboBox, PopupOpen, QskAspect::FirstSystemState << 2 )
static inline void qskTraverseOptions( QskComboBox* comboBox, int steps )
{
@ -89,6 +90,25 @@ QskComboBox::~QskComboBox()
{
}
bool QskComboBox::isPressed() const
{
return hasSkinState( Pressed );
}
void QskComboBox::setPressed( bool on )
{
if ( on == isPressed() )
return;
setSkinStateFlag( Pressed, on );
Q_EMIT pressedChanged( on );
if ( on )
Q_EMIT pressed();
else
Q_EMIT released();
}
void QskComboBox::setPopupOpen( bool on )
{
if ( on == isPopupOpen() )
@ -246,11 +266,13 @@ void QskComboBox::closePopup()
void QskComboBox::mousePressEvent( QMouseEvent* )
{
setPressed( true );
setPopupOpen( true );
}
void QskComboBox::mouseReleaseEvent( QMouseEvent* )
{
setPressed( false );
}
void QskComboBox::keyPressEvent( QKeyEvent* event )
@ -259,6 +281,7 @@ void QskComboBox::keyPressEvent( QKeyEvent* event )
{
if ( !event->isAutoRepeat() )
{
setPressed( true );
setPopupOpen( true );
return;
}
@ -270,6 +293,7 @@ void QskComboBox::keyPressEvent( QKeyEvent* event )
case Qt::Key_F4:
{
// QComboBox does this ???
setPressed( true );
setPopupOpen( true );
return;
}

View File

@ -34,16 +34,22 @@ class QSK_EXPORT QskComboBox : public QskControl
Q_PROPERTY( int indexInPopup READ indexInPopup
NOTIFY indexInPopupChanged )
Q_PROPERTY( bool pressed READ isPressed
WRITE setPressed NOTIFY pressedChanged FINAL )
using Inherited = QskControl;
public:
QSK_SUBCONTROLS( Panel, Icon, Text, StatusIndicator )
QSK_STATES( PopupOpen )
QSK_STATES( Pressed, PopupOpen )
QskComboBox( QQuickItem* parent = nullptr );
~QskComboBox() override;
void setPressed( bool on );
bool isPressed() const;
void setPopupOpen( bool );
bool isPopupOpen() const;
@ -78,6 +84,10 @@ class QSK_EXPORT QskComboBox : public QskControl
void setCurrentIndex( int );
Q_SIGNALS:
void pressed();
void released();
void pressedChanged( bool );
void currentIndexChanged( int );
void indexInPopupChanged( int );

View File

@ -44,12 +44,20 @@ static inline QRectF qskFocusIndicatorClipRect( const QQuickItem* item )
return rect;
}
static inline QskAspect::Section qskItemSection( const QQuickItem* item )
{
if ( auto control = qskControlCast( item ) )
return control->section();
return QskAspect::Body;
}
class QskFocusIndicator::PrivateData
{
public:
void resetConnections()
{
for ( const auto& connection : qAsConst( connections ) )
for ( const auto& connection : std::as_const( connections ) )
QObject::disconnect( connection );
connections.clear();
@ -122,6 +130,8 @@ void QskFocusIndicator::onFocusItemChanged()
if ( focusItem && ( focusItem != window()->contentItem() ) )
{
setSection( qskItemSection( focusItem ) );
auto item = focusItem;
m_data->connections += connectItem( item );

View File

@ -132,7 +132,7 @@ namespace
{
Timer* timer = nullptr;
for ( auto t : qAsConst( m_table ) )
for ( auto t : std::as_const( m_table ) )
{
if ( t->recognizer() == nullptr ||
t->recognizer() == recognizer )
@ -153,7 +153,7 @@ namespace
void stopTimer( const QskGestureRecognizer* recognizer )
{
for ( auto timer : qAsConst( m_table ) )
for ( auto timer : std::as_const( m_table ) )
{
if ( timer->recognizer() == recognizer )
{

View File

@ -7,6 +7,7 @@
#include "QskAspect.h"
#include "QskColorFilter.h"
#include "QskEvent.h"
#include "QskSkinlet.h"
#include <qguiapplication.h>
#include <qstylehints.h>
@ -15,31 +16,55 @@
QSK_SUBCONTROL( QskListView, Cell )
QSK_SUBCONTROL( QskListView, Text )
QSK_SUBCONTROL( QskListView, Graphic )
QSK_STATE( QskListView, Selected, QskAspect::FirstUserState )
#define FOCUS_ON_CURRENT 1
static inline int qskRowAt( const QskListView* listView, const QPointF& pos )
{
const auto rect = listView->viewContentsRect();
if ( rect.contains( pos ) )
{
const auto y = pos.y() - rect.top() + listView->scrollPos().y();
const int row = y / listView->rowHeight();
if ( row >= 0 && row < listView->rowCount() )
return row;
}
return -1;
}
class QskListView::PrivateData
{
public:
PrivateData()
: preferredWidthFromColumns( false )
, alternatingRowColors( false )
, selectionMode( QskListView::SingleSelection )
, selectedRow( -1 )
{
}
/*
Currently we only support single selection. We can't navigate
the current item ( = focus ) without changing the selection.
So for the moment the selected row is always the currentRow.
*/
bool preferredWidthFromColumns : 1;
bool alternatingRowColors : 1;
SelectionMode selectionMode : 4;
int selectedRow;
int selectedRow = -1;
};
QskListView::QskListView( QQuickItem* parent )
: QskScrollView( parent )
, m_data( new PrivateData() )
{
#if FOCUS_ON_CURRENT
connect( this, &QskScrollView::scrollPosChanged, &QskControl::focusIndicatorRectChanged );
#endif
}
QskListView::~QskListView()
@ -62,22 +87,6 @@ bool QskListView::preferredWidthFromColumns() const
return m_data->preferredWidthFromColumns;
}
void QskListView::setAlternatingRowColors( bool on )
{
if ( on != m_data->alternatingRowColors )
{
m_data->alternatingRowColors = on;
update();
Q_EMIT alternatingRowColorsChanged();
}
}
bool QskListView::alternatingRowColors() const
{
return m_data->alternatingRowColors;
}
void QskListView::setTextOptions( const QskTextOptions& textOptions )
{
if ( setTextOptionsHint( Text, textOptions ) )
@ -92,6 +101,15 @@ QskTextOptions QskListView::textOptions() const
return textOptionsHint( Text );
}
void QskListView::resetTextOptions()
{
if ( resetTextOptionsHint( Text ) )
{
updateScrollableSize();
Q_EMIT textOptionsChanged();
}
}
void QskListView::setSelectedRow( int row )
{
if ( row < 0 )
@ -115,6 +133,7 @@ void QskListView::setSelectedRow( int row )
{
m_data->selectedRow = row;
Q_EMIT selectedRowChanged( row );
Q_EMIT focusIndicatorRectChanged();
update();
}
@ -143,12 +162,21 @@ QskListView::SelectionMode QskListView::selectionMode() const
return m_data->selectionMode;
}
QskColorFilter QskListView::graphicFilterAt( int row, int col ) const
QRectF QskListView::focusIndicatorRect() const
{
Q_UNUSED( row )
Q_UNUSED( col )
#if FOCUS_ON_CURRENT
if( m_data->selectedRow >= 0 )
{
auto rect = effectiveSkinlet()->sampleRect(
this, contentsRect(), Cell, m_data->selectedRow );
return QskColorFilter();
rect = rect.translated( -scrollPos() );
if ( rect.intersects( viewContentsRect() ) )
return rect;
}
#endif
return Inherited::focusIndicatorRect();
}
void QskListView::keyPressEvent( QKeyEvent* event )
@ -249,13 +277,10 @@ void QskListView::mousePressEvent( QMouseEvent* event )
{
if ( m_data->selectionMode != NoSelection )
{
const QRectF vr = viewContentsRect();
if ( vr.contains( event->pos() ) )
const int row = qskRowAt( this, qskMousePosition( event ) );
if ( row >= 0 )
{
const int row = ( event->pos().y() - vr.top() + scrollPos().y() ) / rowHeight();
if ( row >= 0 && row < rowCount() )
setSelectedRow( row );
setSelectedRow( row );
return;
}
}
@ -268,6 +293,14 @@ void QskListView::mouseReleaseEvent( QMouseEvent* event )
Inherited::mouseReleaseEvent( event );
}
void QskListView::changeEvent( QEvent* event )
{
if ( event->type() == QEvent::StyleChange )
updateScrollableSize();
Inherited::changeEvent( event );
}
#ifndef QT_NO_WHEELEVENT
static qreal qskAlignedToRows( const qreal y0, qreal dy,

View File

@ -13,9 +13,6 @@ class QSK_EXPORT QskListView : public QskScrollView
{
Q_OBJECT
Q_PROPERTY( bool alternatingRowColors READ alternatingRowColors
WRITE setAlternatingRowColors NOTIFY alternatingRowColorsChanged FINAL )
Q_PROPERTY( SelectionMode selectionMode READ selectionMode
WRITE setSelectionMode NOTIFY selectionModeChanged FINAL )
@ -23,7 +20,8 @@ class QSK_EXPORT QskListView : public QskScrollView
WRITE setSelectedRow NOTIFY selectedRowChanged FINAL )
Q_PROPERTY( QskTextOptions textOptions READ textOptions
WRITE setTextOptions NOTIFY textOptionsChanged FINAL )
WRITE setTextOptions RESET resetTextOptions
NOTIFY textOptionsChanged FINAL )
Q_PROPERTY( bool preferredWidthFromColumns READ preferredWidthFromColumns
WRITE setPreferredWidthFromColumns NOTIFY preferredWidthFromColumnsChanged() )
@ -31,7 +29,7 @@ class QSK_EXPORT QskListView : public QskScrollView
using Inherited = QskScrollView;
public:
QSK_SUBCONTROLS( Cell, Text )
QSK_SUBCONTROLS( Cell, Text, Graphic )
QSK_STATES( Selected )
enum SelectionMode
@ -48,13 +46,11 @@ class QSK_EXPORT QskListView : public QskScrollView
void setPreferredWidthFromColumns( bool );
bool preferredWidthFromColumns() const;
void setAlternatingRowColors( bool );
bool alternatingRowColors() const;
void setSelectionMode( SelectionMode );
SelectionMode selectionMode() const;
void setTextOptions( const QskTextOptions& textOptions );
void resetTextOptions();
QskTextOptions textOptions() const;
Q_INVOKABLE int selectedRow() const;
@ -67,9 +63,7 @@ class QSK_EXPORT QskListView : public QskScrollView
Q_INVOKABLE virtual QVariant valueAt( int row, int col ) const = 0;
#if 1
virtual QskColorFilter graphicFilterAt( int row, int col ) const;
#endif
QRectF focusIndicatorRect() const override;
public Q_SLOTS:
void setSelectedRow( int row );
@ -78,11 +72,12 @@ class QSK_EXPORT QskListView : public QskScrollView
void selectedRowChanged( int row );
void selectionModeChanged();
void alternatingRowColorsChanged();
void preferredWidthFromColumnsChanged();
void textOptionsChanged();
protected:
void changeEvent( QEvent* ) override;
void keyPressEvent( QKeyEvent* ) override;
void keyReleaseEvent( QKeyEvent* ) override;

View File

@ -8,81 +8,168 @@
#include "QskColorFilter.h"
#include "QskGraphic.h"
#include "QskBoxHints.h"
#include "QskSGNode.h"
#include "QskSkinStateChanger.h"
#include "QskQuick.h"
#include <qmath.h>
#include <qsgnode.h>
#include <qsgsimplerectnode.h>
#include <qtransform.h>
class QskListViewNode final : public QSGTransformNode
namespace
{
public:
inline QskListViewNode( int columnCount )
: m_columnCount( columnCount )
class ForegroundNode : public QSGNode
{
m_backgroundNode.setFlag( QSGNode::OwnedByParent, false );
appendChildNode( &m_backgroundNode );
public:
void invalidate()
{
removeAllChildNodes();
m_columnCount = m_oldRowMin = m_oldRowMax = -1;
}
m_foregroundNode.setFlag( QSGNode::OwnedByParent, false );
appendChildNode( &m_foregroundNode );
void rearrangeNodes( int rowMin, int rowMax, int columnCount )
{
const bool doReorder = ( columnCount == m_columnCount )
&& ( rowMin <= m_oldRowMax ) && ( rowMax >= m_oldRowMin );
if ( doReorder )
{
/*
We have nodes that will be at a different position in the
list of child nodes - however their content might be unchanged.
This is a common situation, when resizing or scrolling the list.
To avoid that the text/graphic nodes have to be updated we
try to rearrange the nodes, so that they are in increasing
row order for further processing.
To avoid delete/new calls we append the leading and prepend
the trailing nodes, so that they might be used later.
*/
if ( rowMin >= m_oldRowMin )
{
for ( int row = m_oldRowMin; row < rowMin; row++ )
{
for ( int col = 0; col < columnCount; col++ )
{
auto childNode = firstChild();
removeChildNode( childNode );
appendChildNode( childNode );
}
}
}
else
{
for ( int row = rowMin; row < m_oldRowMin; row++ )
{
for ( int col = 0; col < columnCount; col++ )
{
auto childNode = lastChild();
removeChildNode( childNode );
prependChildNode( childNode );
}
}
}
}
m_oldRowMin = rowMin;
m_oldRowMax = rowMax;
m_columnCount = columnCount;
}
private:
/*
When scrolling the majority of the child nodes are simply translated
while only few rows appear/disappear. To implement this in an efficient
way we store how the nodes were related to the rows in the previous update,
*/
int m_oldRowMin = -1;
int m_oldRowMax = -1;
int m_columnCount = -1;
};
class ListViewNode final : public QSGTransformNode
{
public:
inline ListViewNode()
{
m_backgroundNode.setFlag( QSGNode::OwnedByParent, false );
appendChildNode( &m_backgroundNode );
m_foregroundNode.setFlag( QSGNode::OwnedByParent, false );
appendChildNode( &m_foregroundNode );
}
void initialize( const QskListView* listView )
{
const auto scrollPos = listView->scrollPos();
setMatrix( QTransform::fromTranslate( -scrollPos.x(), -scrollPos.y() ) );
m_clipRect = listView->viewContentsRect();
m_rowHeight = listView->rowHeight();
m_rowMin = qFloor( scrollPos.y() / m_rowHeight );
const auto rowMax = ( scrollPos.y() + m_clipRect.height() ) / m_rowHeight;
m_rowMax = qFloor( rowMax - 10e-6 );
if ( m_rowMax >= listView->rowCount() )
m_rowMax = listView->rowCount() - 1;
}
QRectF clipRect() const { return m_clipRect; }
int rowMin() const { return m_rowMin; }
int rowMax() const { return m_rowMax; }
int rowCount() const { return m_rowMax - m_rowMin + 1; }
int rowHeight() const { return m_rowHeight; }
QSGNode* backgroundNode() { return &m_backgroundNode; }
ForegroundNode* foregroundNode() { return &m_foregroundNode; }
private:
// caching some calculations to speed things up
QRectF m_clipRect;
qreal m_rowHeight;
int m_rowMin, m_rowMax;
QSGNode m_backgroundNode;
ForegroundNode m_foregroundNode;
};
}
static inline ListViewNode* qskListViewNode( const QskListView* listView )
{
if ( auto node = const_cast< QSGNode* >( qskPaintNode( listView ) ) )
{
using namespace QskSGNode;
node = findChildNode( node, QskScrollViewSkinlet::ContentsRootRole );
if ( node )
{
node = node->firstChild();
if ( node )
{
Q_ASSERT( node->type() == QSGNode::TransformNodeType );
return static_cast< ListViewNode* >( node );
}
}
}
QSGNode* backgroundNode()
{
return &m_backgroundNode;
}
return nullptr;
}
QSGNode* foregroundNode()
{
return &m_foregroundNode;
}
inline void resetRows( int rowMin, int rowMax )
{
m_rowMin = rowMin;
m_rowMax = rowMax;
}
inline int rowMin() const
{
return m_rowMin;
}
inline int rowMax() const
{
return m_rowMax;
}
inline bool intersects( int rowMin, int rowMax ) const
{
return ( rowMin <= m_rowMax ) && ( rowMax >= m_rowMin );
}
inline int nodeCount() const
{
return ( m_rowMin >= 0 ) ? ( m_rowMax - m_rowMin + 1 ) * m_columnCount : 0;
}
inline int columnCount() const
{
return m_columnCount;
}
inline void invalidate()
{
m_rowMin = m_rowMax = -1;
}
private:
int m_columnCount;
int m_rowMin = -1;
int m_rowMax = -1;
QSGNode m_backgroundNode;
QSGNode m_foregroundNode;
};
static inline ListViewNode* qskListViewNode( const QskSkinnable* skinnable )
{
return qskListViewNode( static_cast< const QskListView* >( skinnable ) );
}
QskListViewSkinlet::QskListViewSkinlet( QskSkin* skin )
: Inherited( skin )
@ -96,119 +183,67 @@ QSGNode* QskListViewSkinlet::updateContentsNode(
{
const auto listView = static_cast< const QskListView* >( scrollView );
auto listViewNode = static_cast< QskListViewNode* >( node );
if ( listViewNode == nullptr )
listViewNode = new QskListViewNode( listView->columnCount() );
auto listViewNode = QskSGNode::ensureNode< ListViewNode >( node );
listViewNode->initialize( listView );
QTransform transform;
transform.translate( -listView->scrollPos().x(), -listView->scrollPos().y() );
listViewNode->setMatrix( transform );
updateBackgroundNodes( listView, listViewNode );
updateForegroundNodes( listView, listViewNode );
updateBackgroundNodes( listView, listViewNode->backgroundNode() );
updateForegroundNodes( listView, listViewNode->foregroundNode() );
return listViewNode;
}
void QskListViewSkinlet::updateBackgroundNodes(
const QskListView* listView, QskListViewNode* listViewNode ) const
const QskListView* listView, QSGNode* backgroundNode ) const
{
QSGNode* backgroundNode = listViewNode->backgroundNode();
using Q = QskListView;
using A = QskAspect;
const qreal cellHeight = listView->rowHeight();
const QRectF viewRect = listView->viewContentsRect();
auto listViewNode = static_cast< const ListViewNode* >( backgroundNode->parent() );
const QPointF scrolledPos = listView->scrollPos();
const int rowMin = qFloor( scrolledPos.y() / cellHeight );
auto rowNode = backgroundNode->firstChild();
int rowMax = qCeil( ( scrolledPos.y() + viewRect.height() ) / cellHeight );
if ( rowMax >= listView->rowCount() )
rowMax = listView->rowCount() - 1;
const int rowSelected = listView->selectedRow();
const double x0 = viewRect.left() + scrolledPos.x();
const double y0 = viewRect.top();
auto* rowNode = static_cast< QSGSimpleRectNode* >( backgroundNode->firstChild() );
if ( listView->alternatingRowColors() )
{
#if 1
/*
Cell might be better for regular cells, while ( Cell | AlternateColor )
could be used for the alternate color TODO ...
*/
#endif
const auto color = listView->color( QskListView::Cell );
for ( int row = rowMin; row <= rowMax; row++ )
{
if ( row % 2 )
{
if ( rowNode == nullptr )
{
rowNode = new QSGSimpleRectNode();
backgroundNode->appendChildNode( rowNode );
}
rowNode->setRect( x0, y0 + row * cellHeight, viewRect.width(), cellHeight );
rowNode->setColor( color );
rowNode = static_cast< QSGSimpleRectNode* >( rowNode->nextSibling() );
}
}
}
if ( rowSelected >= rowMin && rowSelected <= rowMax )
for ( int row = listViewNode->rowMin(); row <= listViewNode->rowMax(); row++ )
{
QskSkinStateChanger stateChanger( listView );
stateChanger.setStates( listView->skinStates() | QskListView::Selected );
stateChanger.setStates( sampleStates( listView, Q::Cell, row ) );
const QColor color = listView->color( QskListView::Cell );
const auto rect = sampleRect( listView, listView->contentsRect(), Q::Cell, row );
if ( rowNode == nullptr )
const QskAspect aspect = Q::Cell | ( ( row % 2 ) ? A::Upper : A::Lower );
const auto boxHints = listView->boxHints( aspect );
auto newNode = updateBoxNode( listView, rowNode, rect, boxHints );
if ( newNode )
{
rowNode = new QSGSimpleRectNode();
backgroundNode->appendChildNode( rowNode );
if ( newNode->parent() != backgroundNode )
backgroundNode->appendChildNode( newNode );
else
rowNode = newNode->nextSibling();
}
rowNode->setRect( x0, y0 + rowSelected * cellHeight, viewRect.width(), cellHeight );
rowNode->setColor( color );
rowNode = static_cast< QSGSimpleRectNode* >( rowNode->nextSibling() );
}
QSGNode* nextNode = rowNode;
while ( nextNode != nullptr )
{
QSGNode* tmpNode = nextNode;
nextNode = nextNode->nextSibling();
delete tmpNode;
}
QskSGNode::removeAllChildNodesFrom( backgroundNode, rowNode );
}
void QskListViewSkinlet::updateForegroundNodes(
const QskListView* listView, QskListViewNode* listViewNode ) const
const QskListView* listView, QSGNode* parentNode ) const
{
auto parentNode = listViewNode->foregroundNode();
auto foregroundNode = static_cast< ForegroundNode* >( parentNode );
if ( listView->rowCount() <= 0 || listView->columnCount() <= 0 )
{
parentNode->removeAllChildNodes();
listViewNode->invalidate();
foregroundNode->invalidate();
return;
}
const auto margins = listView->paddingHint( QskListView::Cell );
auto listViewNode = static_cast< const ListViewNode* >( parentNode->parent() );
const auto cr = listView->viewContentsRect();
const auto scrolledPos = listView->scrollPos();
const auto clipRect = listViewNode->clipRect();
const int rowMin = qFloor( scrolledPos.y() / listView->rowHeight() );
const int rowMin = listViewNode->rowMin();
const int rowMax = listViewNode->rowMax();
int rowMax = rowMin + qCeil( cr.height() / listView->rowHeight() );
if ( rowMax >= listView->rowCount() )
rowMax = listView->rowCount() - 1;
foregroundNode->rearrangeNodes( rowMin, rowMax, listView->columnCount() );
#if 1
// should be optimized for visible columns only
@ -216,67 +251,28 @@ void QskListViewSkinlet::updateForegroundNodes(
const int colMax = listView->columnCount() - 1;
#endif
bool forwards = true;
const auto margins = listView->paddingHint( QskListView::Cell );
if ( listViewNode->intersects( rowMin, rowMax ) )
{
/*
We try to avoid reallcations when scrolling, by reusing
the nodes of the cells leaving the viewport for those becoming visible.
*/
forwards = ( rowMin >= listViewNode->rowMin() );
if ( forwards )
{
// usually scrolling down
for ( int row = listViewNode->rowMin(); row < rowMin; row++ )
{
for ( int col = 0; col < listView->columnCount(); col++ )
{
QSGNode* childNode = parentNode->firstChild();
parentNode->removeChildNode( childNode );
parentNode->appendChildNode( childNode );
}
}
}
else
{
// usually scrolling up
for ( int row = rowMax; row < listViewNode->rowMax(); row++ )
{
for ( int col = 0; col < listView->columnCount(); col++ )
{
QSGNode* childNode = parentNode->lastChild();
parentNode->removeChildNode( childNode );
parentNode->prependChildNode( childNode );
}
}
}
}
updateVisibleForegroundNodes( listView, listViewNode,
rowMin, rowMax, colMin, colMax, margins, forwards );
updateVisibleForegroundNodes(
listView, foregroundNode, rowMin, rowMax, margins );
// finally putting the nodes into their position
auto node = parentNode->firstChild();
auto node = foregroundNode->firstChild();
const qreal rowHeight = listView->rowHeight();
qreal y = cr.top() + rowMin * rowHeight;
const auto rowHeight = listView->rowHeight();
auto y = clipRect.top() + rowMin * rowHeight;
for ( int row = rowMin; row <= rowMax; row++ )
{
qreal x = cr.left();
qreal x = clipRect.left();
for ( int col = colMin; col <= colMax; col++ )
{
Q_ASSERT( node->type() == QSGNode::TransformNodeType );
auto transformNode = static_cast< QSGTransformNode* >( node );
QTransform transform;
transform.translate( x + margins.left(), y + margins.top() );
transformNode->setMatrix( transform );
transformNode->setMatrix(
QTransform::fromTranslate( x + margins.left(), y + margins.top() ) );
node = node->nextSibling();
x += listView->columnWidth( col );
@ -284,72 +280,36 @@ void QskListViewSkinlet::updateForegroundNodes(
y += rowHeight;
}
listViewNode->resetRows( rowMin, rowMax );
}
void QskListViewSkinlet::updateVisibleForegroundNodes(
const QskListView* listView, QskListViewNode* listViewNode,
int rowMin, int rowMax, int colMin, int colMax, const QMarginsF& margins,
bool forward ) const
const QskListView* listView, QSGNode* parentNode,
int rowMin, int rowMax, const QMarginsF& margins ) const
{
auto parentNode = listViewNode->foregroundNode();
auto node = parentNode->firstChild();
const int rowCount = rowMax - rowMin + 1;
const int colCount = colMax - colMin + 1;
const int obsoleteNodesCount = listViewNode->nodeCount() - rowCount * colCount;
if ( forward )
for ( int row = rowMin; row <= rowMax; row++ )
{
for ( int i = 0; i < obsoleteNodesCount; i++ )
delete parentNode->lastChild();
const auto h = listView->rowHeight() - ( margins.top() + margins.bottom() );
auto node = parentNode->firstChild();
for ( int row = rowMin; row <= rowMax; row++ )
for ( int col = 0; col < listView->columnCount(); col++ )
{
const qreal h = listView->rowHeight() - ( margins.top() + margins.bottom() );
const auto w = listView->columnWidth( col ) - ( margins.left() + margins.right() );
for ( int col = 0; col < listView->columnCount(); col++ )
{
const qreal w = listView->columnWidth( col ) - ( margins.left() + margins.right() );
node = updateForegroundNode( listView,
parentNode, static_cast< QSGTransformNode* >( node ),
row, col, QSizeF( w, h ) );
node = updateForegroundNode( listView,
parentNode, static_cast< QSGTransformNode* >( node ),
row, col, QSizeF( w, h ), forward );
node = node->nextSibling();
}
node = node->nextSibling();
}
}
else
{
for ( int i = 0; i < obsoleteNodesCount; i++ )
delete parentNode->firstChild();
auto* node = parentNode->lastChild();
for ( int row = rowMax; row >= rowMin; row-- )
{
const qreal h = listView->rowHeight() - ( margins.top() + margins.bottom() );
for ( int col = listView->columnCount() - 1; col >= 0; col-- )
{
const qreal w = listView->columnWidth( col ) - ( margins.left() + margins.right() );
node = updateForegroundNode( listView,
parentNode, static_cast< QSGTransformNode* >( node ),
row, col, QSizeF( w, h ), forward );
node = node->previousSibling();
}
}
}
QskSGNode::removeAllChildNodesFrom( parentNode, node );
}
QSGTransformNode* QskListViewSkinlet::updateForegroundNode(
const QskListView* listView, QSGNode* parentNode, QSGTransformNode* cellNode,
int row, int col, const QSizeF& size, bool forward ) const
int row, int col, const QSizeF& size ) const
{
const QRectF cellRect( 0.0, 0.0, size.width(), size.height() );
@ -421,10 +381,7 @@ QSGTransformNode* QskListViewSkinlet::updateForegroundNode(
}
else
{
if ( forward )
parentNode->appendChildNode( newCellNode );
else
parentNode->prependChildNode( newCellNode );
parentNode->appendChildNode( newCellNode );
}
}
@ -434,14 +391,11 @@ QSGTransformNode* QskListViewSkinlet::updateForegroundNode(
QSGNode* QskListViewSkinlet::updateCellNode( const QskListView* listView,
QSGNode* contentNode, const QRectF& rect, int row, int col ) const
{
using Q = QskListView;
using namespace QskSGNode;
auto rowStates = listView->skinStates();
if ( row == listView->selectedRow() )
rowStates |= QskListView::Selected;
QskSkinStateChanger stateChanger( listView );
stateChanger.setStates( rowStates );
stateChanger.setStates( sampleStates( listView, Q::Cell, row ) );
QSGNode* newNode = nullptr;
@ -453,7 +407,7 @@ QSGNode* QskListViewSkinlet::updateCellNode( const QskListView* listView,
*/
#endif
const auto alignment = listView->alignmentHint(
QskListView::Cell, Qt::AlignVCenter | Qt::AlignLeft );
Q::Cell, Qt::AlignVCenter | Qt::AlignLeft );
const auto value = listView->valueAt( row, col );
@ -462,7 +416,7 @@ QSGNode* QskListViewSkinlet::updateCellNode( const QskListView* listView,
if ( nodeRole( contentNode ) == GraphicRole )
newNode = contentNode;
const auto colorFilter = listView->graphicFilterAt( row, col );
const auto colorFilter = listView->effectiveGraphicFilter( Q::Graphic );
newNode = updateGraphicNode( listView, newNode,
value.value< QskGraphic >(), colorFilter, rect, alignment );
@ -476,7 +430,7 @@ QSGNode* QskListViewSkinlet::updateCellNode( const QskListView* listView,
newNode = contentNode;
newNode = updateTextNode( listView, newNode, rect, alignment,
value.toString(), QskListView::Text );
value.toString(), Q::Text );
if ( newNode )
setNodeRole( newNode, TextRole );
@ -508,4 +462,46 @@ QSizeF QskListViewSkinlet::sizeHint( const QskSkinnable* skinnable,
return QSizeF( w, -1.0 );
}
QskAspect::States QskListViewSkinlet::sampleStates( const QskSkinnable* skinnable,
QskAspect::Subcontrol subControl, int index ) const
{
using Q = QskListView;
if ( subControl == Q::Cell || subControl == Q::Text || subControl == Q::Graphic )
{
const auto listView = static_cast< const QskListView* >( skinnable );
auto states = listView->skinStates();
if ( index == listView->selectedRow() )
states |= Q::Selected;
return states;
}
return Inherited::sampleStates( skinnable, subControl, index );
}
QRectF QskListViewSkinlet::sampleRect( const QskSkinnable* skinnable,
const QRectF& contentsRect, QskAspect::Subcontrol subControl, int index ) const
{
using Q = QskListView;
const auto listView = static_cast< const QskListView* >( skinnable );
if ( subControl == Q::Cell )
{
auto node = qskListViewNode( listView );
const auto clipRect = node ? node->clipRect() : listView->viewContentsRect();
const auto w = clipRect.width();
const auto h = listView->rowHeight();
const auto x = clipRect.left() + listView->scrollPos().x();
const auto y = clipRect.top() + index * h;
return QRectF( x, y, w, h );
}
return Inherited::sampleRect( skinnable, contentsRect, subControl, index );
}
#include "moc_QskListViewSkinlet.cpp"

View File

@ -9,7 +9,6 @@
#include "QskScrollViewSkinlet.h"
class QskListView;
class QskListViewNode;
class QMarginsF;
class QSizeF;
@ -37,25 +36,30 @@ class QSK_EXPORT QskListViewSkinlet : public QskScrollViewSkinlet
QSizeF sizeHint( const QskSkinnable*,
Qt::SizeHint, const QSizeF& ) const override;
QRectF sampleRect( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol, int index ) const override;
QskAspect::States sampleStates( const QskSkinnable*,
QskAspect::Subcontrol, int index ) const override;
protected:
QSGNode* updateContentsNode(
const QskScrollView*, QSGNode* ) const override;
virtual QSGNode* updateCellNode( const QskListView*,
QSGNode*, const QRectF&, int row, int col ) const;
private:
void updateForegroundNodes( const QskListView*, QskListViewNode* ) const;
void updateBackgroundNodes( const QskListView*, QskListViewNode* ) const;
void updateForegroundNodes( const QskListView*, QSGNode* ) const;
void updateBackgroundNodes( const QskListView*, QSGNode* ) const;
void updateVisibleForegroundNodes(
const QskListView*, QskListViewNode*,
int rowMin, int rowMax, int colMin, int colMax,
const QMarginsF& margin, bool forward ) const;
const QskListView*, QSGNode*,
int rowMin, int rowMax, const QMarginsF& margin ) const;
QSGTransformNode* updateForegroundNode( const QskListView*,
QSGNode* parentNode, QSGTransformNode* cellNode,
int row, int col, const QSizeF&, bool forward ) const;
int row, int col, const QSizeF& ) const;
QSGNode* updateCellNode( const QskListView*,
QSGNode*, const QRectF&, int row, int col ) const;
};
#endif

View File

@ -27,6 +27,7 @@ QskMainView::QskMainView( QQuickItem* parent )
setPanel( true );
setFlag( QQuickItem::ItemIsFocusScope, true );
setTabFence( true );
setFocusPolicy( Qt::StrongFocus );
}

View File

@ -27,6 +27,7 @@ QSK_SUBCONTROL( QskMenu, Icon )
QSK_SUBCONTROL( QskMenu, Separator )
QSK_SYSTEM_STATE( QskMenu, Selected, QskAspect::FirstSystemState << 2 )
QSK_SYSTEM_STATE( QskMenu, Pressed, QskAspect::FirstSystemState << 3 )
static inline int qskActionIndex( const QVector< int >& actions, int index )
{
@ -72,6 +73,8 @@ QskMenu::QskMenu( QQuickItem* parent )
connect( this, &QskMenu::opened, this,
[this]() { m_data->triggeredIndex = -1; } );
setAcceptHoverEvents( true );
}
QskMenu::~QskMenu()
@ -307,7 +310,7 @@ void QskMenu::keyPressEvent( QKeyEvent* event )
void QskMenu::keyReleaseEvent( QKeyEvent* )
{
if( m_data->isPressed )
if( isPressed() )
{
m_data->isPressed = false;
@ -319,6 +322,30 @@ void QskMenu::keyReleaseEvent( QKeyEvent* )
}
}
void QskMenu::hoverEnterEvent( QHoverEvent* event )
{
using A = QskAspect;
setSkinHint( Segment | Hovered | A::Metric | A::Position, qskHoverPosition( event ) );
update();
}
void QskMenu::hoverMoveEvent( QHoverEvent* event )
{
using A = QskAspect;
setSkinHint( Segment | Hovered | A::Metric | A::Position, qskHoverPosition( event ) );
update();
}
void QskMenu::hoverLeaveEvent( QHoverEvent* )
{
using A = QskAspect;
setSkinHint( Segment | Hovered | A::Metric | A::Position, QPointF() );
update();
}
#ifndef QT_NO_WHEELEVENT
void QskMenu::wheelEvent( QWheelEvent* event )
@ -390,7 +417,7 @@ void QskMenu::mouseReleaseEvent( QMouseEvent* event )
{
if ( event->button() == Qt::LeftButton )
{
if( m_data->isPressed )
if( isPressed() )
{
m_data->isPressed = false;
@ -455,6 +482,11 @@ int QskMenu::indexAtPosition( const QPointF& pos ) const
return m_data->actions.value( index, -1 );
}
bool QskMenu::isPressed() const
{
return m_data->isPressed;
}
void QskMenu::trigger( int index )
{
if ( index >= 0 && index < m_data->options.count() )

View File

@ -38,7 +38,7 @@ class QSK_EXPORT QskMenu : public QskPopup
public:
QSK_SUBCONTROLS( Overlay, Panel, Segment, Cursor, Text, Icon, Separator )
QSK_STATES( Selected )
QSK_STATES( Selected, Pressed )
QskMenu( QQuickItem* parentItem = nullptr );
~QskMenu() override;
@ -68,6 +68,7 @@ class QSK_EXPORT QskMenu : public QskPopup
QVector< int > actions() const;
int currentIndex() const;
QString currentText() const;
int triggeredIndex() const;
@ -78,6 +79,8 @@ class QSK_EXPORT QskMenu : public QskPopup
QRectF cellRect( int index ) const;
int indexAtPosition( const QPointF& ) const;
bool isPressed() const;
Q_INVOKABLE int exec();
Q_SIGNALS:
@ -97,6 +100,10 @@ class QSK_EXPORT QskMenu : public QskPopup
void keyPressEvent( QKeyEvent* ) override;
void keyReleaseEvent( QKeyEvent* ) override;
void hoverEnterEvent( QHoverEvent* ) override;
void hoverMoveEvent( QHoverEvent* ) override;
void hoverLeaveEvent( QHoverEvent* ) override;
#ifndef QT_NO_WHEELEVENT
void wheelEvent( QWheelEvent* ) override;
#endif

View File

@ -385,6 +385,7 @@ QskAspect::States QskMenuSkinlet::sampleStates(
const QskSkinnable* skinnable, QskAspect::Subcontrol subControl, int index ) const
{
using Q = QskMenu;
using A = QskAspect;
auto states = Inherited::sampleStates( skinnable, subControl, index );
@ -393,7 +394,29 @@ QskAspect::States QskMenuSkinlet::sampleStates(
const auto menu = static_cast< const QskMenu* >( skinnable );
if ( menu->currentIndex() == menu->actions()[ index ] )
states |= QskMenu::Selected;
{
states |= Q::Selected;
if( menu->isPressed() )
{
states |= Q::Pressed;
}
else
{
states &= ~Q::Pressed;
}
}
const auto cursorPos = menu->effectiveSkinHint( Q::Segment | Q::Hovered | A::Metric | A::Position ).toPointF();
if( !cursorPos.isNull() && menu->indexAtPosition( cursorPos ) == index )
{
states |= Q::Hovered;
}
else
{
states &= ~Q::Hovered;
}
}
return states;

View File

@ -306,6 +306,7 @@ void QskPushButton::mousePressEvent( QMouseEvent* event )
using A = QskAspect;
const auto hint = animationHint( Splash | A::Color );
if( hint.isValid() )
{
setPositionHint( Splash, qskMousePosition( event ).x() );

View File

@ -463,7 +463,7 @@ void qskItemUpdateRecursive( QQuickItem* item )
static const QQuickPointerTouchEvent* qskPointerPressEvent( const QQuickWindowPrivate* wd )
{
for ( const auto event : qAsConst( wd->pointerEventInstances ) )
for ( const auto event : std::as_const( wd->pointerEventInstances ) )
{
if ( auto touchEvent = event->asPointerTouchEvent() )
{

View File

@ -15,30 +15,134 @@ QSK_SUBCONTROL( QskScrollView, HorizontalScrollHandle )
QSK_SUBCONTROL( QskScrollView, VerticalScrollBar )
QSK_SUBCONTROL( QskScrollView, VerticalScrollHandle )
QSK_SYSTEM_STATE( QskScrollView, VerticalHandlePressed, QskAspect::FirstSystemState << 1 )
QSK_SYSTEM_STATE( QskScrollView, HorizontalHandlePressed, QskAspect::FirstSystemState << 2 )
QSK_SYSTEM_STATE( QskScrollView, Pressed, QskAspect::FirstSystemState << 1 )
static inline QskAspect::Subcontrol qskSubControlAt(
const QskScrollView* scrollView, const QPointF& pos )
{
using Q = QskScrollView;
const auto rect = scrollView->contentsRect();
// order is important as the handles are inside the bars !
for ( auto subControl : { Q::VerticalScrollHandle, Q::VerticalScrollBar,
Q::HorizontalScrollHandle, Q::HorizontalScrollBar } )
{
if ( scrollView->subControlRect( rect, subControl ).contains( pos ) )
return subControl;
}
return QskAspect::NoSubcontrol;
}
class QskScrollView::PrivateData
{
public:
PrivateData()
: horizontalScrollBarPolicy( Qt::ScrollBarAsNeeded )
, verticalScrollBarPolicy( Qt::ScrollBarAsNeeded )
, isScrolling( 0 )
inline void resetScrolling( QskScrollView* scrollView )
{
setScrolling( scrollView, QskAspect::NoSubcontrol, 0.0 );
}
Qt::ScrollBarPolicy horizontalScrollBarPolicy;
Qt::ScrollBarPolicy verticalScrollBarPolicy;
inline void setScrolling( QskScrollView* scrollView,
QskAspect::Subcontrol subControl, qreal pos )
{
if ( subControl == pressedSubControl )
return;
qreal scrollPressPos;
int isScrolling;
QskAspect::Subcontrol subControls[2];
if ( subControl == VerticalScrollHandle || pressedSubControl == VerticalScrollHandle )
{
subControls[0] = VerticalScrollHandle;
subControls[1] = VerticalScrollBar;
}
else
{
subControls[0] = HorizontalScrollHandle;;
subControls[1] = HorizontalScrollBar;
}
pressedSubControl = subControl;
scrollPressPos = pos;
scrollView->update();
auto oldStates = scrollView->skinStates() | scrollView->scrollBarStates( subControl );
auto newStates = oldStates | QskScrollView::Pressed;
if ( pressedSubControl == QskAspect::NoSubcontrol )
qSwap( oldStates, newStates );
scrollView->startHintTransitions( { subControls[0] }, oldStates, newStates );
scrollView->startHintTransitions( { subControls[1] }, oldStates, newStates );
}
void setHovered( QskScrollView* scrollView, QskAspect::Subcontrol subControl )
{
if ( subControl == this->hoveredSubControl )
return;
QskAspect::Subcontrol subControls[2];
if ( subControl == VerticalScrollHandle
|| hoveredSubControl == VerticalScrollHandle
|| subControl == VerticalScrollBar
|| hoveredSubControl == VerticalScrollBar )
{
subControls[0] = VerticalScrollHandle;
subControls[1] = VerticalScrollBar;
}
else
{
subControls[0] = HorizontalScrollHandle;;
subControls[1] = HorizontalScrollBar;
}
hoveredSubControl = subControl;
auto oldStates = scrollView->skinStates();
auto newStates = oldStates | QskScrollView::Hovered;
if ( hoveredSubControl == QskAspect::NoSubcontrol )
qSwap( oldStates, newStates );
scrollView->startHintTransitions( { subControls[0] }, oldStates, newStates );
scrollView->startHintTransitions( { subControls[1] }, oldStates, newStates );
}
bool hasState( QskAspect::Subcontrol subControl, QskAspect::State state ) const
{
if ( subControl == QskAspect::NoSubcontrol )
return false;
const auto stateSubcontrol =
( state == QskControl::Hovered ) ? hoveredSubControl : pressedSubControl;
if ( subControl == stateSubcontrol )
return true;
if ( subControl == VerticalScrollBar )
return stateSubcontrol == VerticalScrollHandle;
if ( subControl == HorizontalScrollBar )
return stateSubcontrol == HorizontalScrollHandle;
return false;
}
Qt::ScrollBarPolicy horizontalScrollBarPolicy = Qt::ScrollBarAsNeeded;
Qt::ScrollBarPolicy verticalScrollBarPolicy = Qt::ScrollBarAsNeeded;
qreal scrollPressPos = 0.0;
QskAspect::Subcontrol pressedSubControl = QskAspect::NoSubcontrol;
QskAspect::Subcontrol hoveredSubControl = QskAspect::NoSubcontrol;
};
QskScrollView::QskScrollView( QQuickItem* parent )
: Inherited( parent )
, m_data( new PrivateData() )
{
setAcceptHoverEvents( true );
}
QskScrollView::~QskScrollView()
@ -85,16 +189,32 @@ Qt::ScrollBarPolicy QskScrollView::horizontalScrollBarPolicy() const
bool QskScrollView::isScrolling( Qt::Orientation orientation ) const
{
return m_data->isScrolling == orientation;
if ( orientation == Qt::Vertical )
return m_data->pressedSubControl == VerticalScrollHandle;
else
return m_data->pressedSubControl == HorizontalScrollHandle;
}
QskAspect::States QskScrollView::scrollBarStates(
QskAspect::Subcontrol subControl ) const
{
auto states = skinStates();
if ( m_data->hasState( subControl, Pressed ) )
states |= Pressed;
if ( m_data->hasState( subControl, Hovered ) )
states |= Hovered;
return states;
}
QRectF QskScrollView::viewContentsRect() const
{
// This code should be done in the skinlet. TODO ...
const qreal bw = boxBorderMetricsHint( Viewport ).widthAt( Qt::TopEdge );
const auto borderMetrics = boxBorderMetricsHint( Viewport );
const QRectF r = subControlRect( Viewport );
return r.adjusted( bw, bw, -bw, -bw );
return r.marginsRemoved( borderMetrics.widths() );
}
void QskScrollView::mousePressEvent( QMouseEvent* event )
@ -103,14 +223,11 @@ void QskScrollView::mousePressEvent( QMouseEvent* event )
if ( subControlRect( VerticalScrollBar ).contains( mousePos ) )
{
const QRectF handleRect = subControlRect( VerticalScrollHandle );
const auto handleRect = subControlRect( VerticalScrollHandle );
if ( handleRect.contains( mousePos ) )
{
m_data->isScrolling = Qt::Vertical;
m_data->scrollPressPos = mousePos.y();
setSkinStateFlag( VerticalHandlePressed, true );
m_data->setScrolling( this, VerticalScrollHandle, mousePos.y() );
}
else
{
@ -135,10 +252,7 @@ void QskScrollView::mousePressEvent( QMouseEvent* event )
if ( handleRect.contains( mousePos ) )
{
m_data->isScrolling = Qt::Horizontal;
m_data->scrollPressPos = mousePos.x();
setSkinStateFlag( HorizontalHandlePressed, true );
m_data->setScrolling( this, HorizontalScrollHandle, mousePos.x() );
}
else
{
@ -162,7 +276,7 @@ void QskScrollView::mousePressEvent( QMouseEvent* event )
void QskScrollView::mouseMoveEvent( QMouseEvent* event )
{
if ( !m_data->isScrolling )
if ( m_data->pressedSubControl == QskAspect::NoSubcontrol )
{
Inherited::mouseMoveEvent( event );
return;
@ -171,7 +285,7 @@ void QskScrollView::mouseMoveEvent( QMouseEvent* event )
const auto mousePos = qskMousePosition( event );
QPointF pos = scrollPos();
if ( m_data->isScrolling == Qt::Horizontal )
if ( m_data->pressedSubControl == HorizontalScrollHandle )
{
const qreal dx = mousePos.x() - m_data->scrollPressPos;
const qreal w = subControlRect( HorizontalScrollBar ).width();
@ -179,7 +293,7 @@ void QskScrollView::mouseMoveEvent( QMouseEvent* event )
pos.rx() += dx / w * scrollableSize().width();
m_data->scrollPressPos = mousePos.x();
}
else if ( m_data->isScrolling == Qt::Vertical )
else
{
const qreal dy = mousePos.y() - m_data->scrollPressPos;
const qreal h = subControlRect( VerticalScrollBar ).height();
@ -194,17 +308,35 @@ void QskScrollView::mouseMoveEvent( QMouseEvent* event )
void QskScrollView::mouseReleaseEvent( QMouseEvent* event )
{
if ( !m_data->isScrolling )
if ( m_data->pressedSubControl == QskAspect::NoSubcontrol )
{
Inherited::mouseReleaseEvent( event );
return;
}
m_data->isScrolling = 0;
m_data->scrollPressPos = 0;
m_data->resetScrolling( this );
}
setSkinStateFlag( HorizontalHandlePressed, false );
setSkinStateFlag( VerticalHandlePressed, false );
void QskScrollView::mouseUngrabEvent()
{
m_data->resetScrolling( this );
}
void QskScrollView::hoverEnterEvent( QHoverEvent* event )
{
const auto subControl = qskSubControlAt( this, qskHoverPosition( event ) );
m_data->setHovered( this, subControl );
}
void QskScrollView::hoverMoveEvent( QHoverEvent* event )
{
const auto subControl = qskSubControlAt( this, qskHoverPosition( event ) );
m_data->setHovered( this, subControl );
}
void QskScrollView::hoverLeaveEvent( QHoverEvent* )
{
m_data->setHovered( this, QskAspect::NoSubcontrol );
}
#ifndef QT_NO_WHEELEVENT

View File

@ -25,7 +25,7 @@ class QSK_EXPORT QskScrollView : public QskScrollBox
HorizontalScrollBar, HorizontalScrollHandle,
VerticalScrollBar, VerticalScrollHandle )
QSK_STATES( VerticalHandlePressed, HorizontalHandlePressed )
QSK_STATES( Pressed )
QskScrollView( QQuickItem* parent = nullptr );
~QskScrollView() override;
@ -39,6 +39,7 @@ class QSK_EXPORT QskScrollView : public QskScrollBox
Qt::Orientations scrollableOrientations() const;
bool isScrolling( Qt::Orientation ) const;
QskAspect::States scrollBarStates( QskAspect::Subcontrol ) const;
QRectF viewContentsRect() const override;
QskAnimationHint flickHint() const override;
@ -51,6 +52,11 @@ class QSK_EXPORT QskScrollView : public QskScrollBox
void mouseMoveEvent( QMouseEvent* ) override;
void mousePressEvent( QMouseEvent* ) override;
void mouseReleaseEvent( QMouseEvent* ) override;
void mouseUngrabEvent() override;
void hoverEnterEvent( QHoverEvent* ) override;
void hoverMoveEvent( QHoverEvent* ) override;
void hoverLeaveEvent( QHoverEvent* ) override;
#ifndef QT_NO_WHEELEVENT
QPointF scrollOffset( const QWheelEvent* ) const override;

View File

@ -9,6 +9,7 @@
#include "QskAspect.h"
#include "QskQuick.h"
#include "QskSGNode.h"
#include "QskSkinStateChanger.h"
#include <qsgnode.h>
@ -16,7 +17,9 @@ static void qskAlignedHandle( qreal start, qreal end,
qreal scrollBarLength, qreal minHandleLength,
qreal& handleStart, qreal& handleEnd )
{
minHandleLength = qBound( 4.0, minHandleLength, scrollBarLength );
// no qBound: scrollBarLength might be < 4.0
minHandleLength = qMax( 4.0, minHandleLength );
minHandleLength = qMin( minHandleLength, scrollBarLength );
handleStart = start * scrollBarLength;
handleEnd = end * scrollBarLength;
@ -38,6 +41,18 @@ static void qskAlignedHandle( qreal start, qreal end,
}
}
static qreal qskScrollBarExtent(
const QskScrollView* scrollView, Qt::Orientation orientation )
{
const auto subControl = ( orientation == Qt::Horizontal )
? QskScrollView::HorizontalScrollBar : QskScrollView::VerticalScrollBar;
QskSkinStateChanger stateChanger( scrollView );
stateChanger.setStates( scrollView->scrollBarStates( subControl ) );
return scrollView->metric( subControl | QskAspect::Size );
}
QskScrollViewSkinlet::QskScrollViewSkinlet( QskSkin* skin )
: Inherited( skin )
{
@ -51,37 +66,27 @@ QskScrollViewSkinlet::~QskScrollViewSkinlet() = default;
QRectF QskScrollViewSkinlet::subControlRect( const QskSkinnable* skinnable,
const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
{
using Q = QskScrollView;
const auto scrollView = static_cast< const QskScrollView* >( skinnable );
if ( subControl == QskScrollView::Panel )
{
if ( subControl == Q::Panel )
return contentsRect;
}
if ( subControl == QskScrollView::Viewport )
{
if ( subControl == Q::Viewport )
return viewportRect( scrollView, contentsRect );
}
if ( subControl == QskScrollView::HorizontalScrollBar )
{
if ( subControl == Q::HorizontalScrollBar )
return scrollBarRect( scrollView, contentsRect, Qt::Horizontal );
}
if ( subControl == QskScrollView::HorizontalScrollHandle )
{
if ( subControl == Q::HorizontalScrollHandle )
return scrollHandleRect( scrollView, contentsRect, Qt::Horizontal );
}
if ( subControl == QskScrollView::VerticalScrollBar )
{
if ( subControl == Q::VerticalScrollBar )
return scrollBarRect( scrollView, contentsRect, Qt::Vertical );
}
if ( subControl == QskScrollView::VerticalScrollHandle )
{
if ( subControl == Q::VerticalScrollHandle )
return scrollHandleRect( scrollView, contentsRect, Qt::Vertical );
}
return Inherited::subControlRect( skinnable, contentsRect, subControl );
}
@ -89,44 +94,50 @@ QRectF QskScrollViewSkinlet::subControlRect( const QskSkinnable* skinnable,
QSGNode* QskScrollViewSkinlet::updateSubNode(
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
{
using Q = QskScrollView;
const auto scrollView = static_cast< const QskScrollView* >( skinnable );
switch ( nodeRole )
{
case PanelRole:
{
return updateBoxNode( skinnable, node, QskScrollView::Panel );
}
return updateBoxNode( skinnable, node, Q::Panel );
case ViewportRole:
{
return updateBoxNode( skinnable, node, QskScrollView::Viewport );
}
return updateBoxNode( skinnable, node, Q::Viewport );
case HorizontalScrollHandleRole:
{
return updateBoxNode( skinnable, node, QskScrollView::HorizontalScrollHandle );
}
return updateScrollBarNode( scrollView, Q::HorizontalScrollHandle, node );
case VerticalScrollHandleRole:
{
return updateBoxNode( skinnable, node, QskScrollView::VerticalScrollHandle );
}
case ContentsRootRole:
{
return updateContentsRootNode( scrollView, node );
}
return updateScrollBarNode( scrollView, Q::VerticalScrollHandle, node );
case HorizontalScrollBarRole:
return updateScrollBarNode( scrollView, Q::HorizontalScrollBar, node );
case VerticalScrollBarRole:
{
return nullptr;
}
return updateScrollBarNode( scrollView, Q::VerticalScrollBar, node );
case ContentsRootRole:
return updateContentsRootNode( scrollView, node );
}
return Inherited::updateSubNode( skinnable, nodeRole, node );
}
QSGNode* QskScrollViewSkinlet::updateScrollBarNode( const QskScrollView* scrollView,
QskAspect::Subcontrol subControl, QSGNode* node ) const
{
const auto rect = subControlRect( scrollView,
scrollView->contentsRect(), subControl );
QskSkinStateChanger stateChanger( scrollView );
stateChanger.setStates( scrollView->scrollBarStates( subControl ) );
return updateBoxNode( scrollView, node, rect, subControl );
}
QSGNode* QskScrollViewSkinlet::updateContentsRootNode(
const QskScrollView* scrollView, QSGNode* node ) const
{
@ -169,22 +180,6 @@ QSGNode* QskScrollViewSkinlet::updateContentsNode(
return nullptr;
}
QSGNode* QskScrollViewSkinlet::contentsNode( const QskScrollView* scrollView )
{
if ( auto node = const_cast< QSGNode* >( qskPaintNode( scrollView ) ) )
{
node = QskSGNode::findChildNode( node, ContentsRootRole );
if ( node )
{
node = node->firstChild();
if ( node )
return node->firstChild();
}
}
return nullptr;
}
QRectF QskScrollViewSkinlet::viewportRect(
const QskScrollView* scrollView, const QRectF& contentsRect ) const
{
@ -236,22 +231,23 @@ QRectF QskScrollViewSkinlet::scrollHandleRect( const QskScrollView* scrollView,
const auto vRect = subControlRect(
scrollView, contentsRect, QskScrollView::Viewport );
const auto scrollableSize = scrollView->scrollableSize();
QRectF handleRect;
if ( orientation == Qt::Vertical )
{
const auto subControlBar = Q::VerticalScrollBar;
const auto sbRect = subControlRect( scrollView, contentsRect, Q::VerticalScrollBar );
const auto sbRect = subControlRect( scrollView, contentsRect, subControlBar );
const auto padding = scrollView->paddingHint( subControlBar );
const qreal h = scrollView->scrollableSize().height();
const qreal y1 = pos.y() / h;
const qreal y2 = ( pos.y() + vRect.height() ) / h;
QskSkinStateChanger stateChanger( scrollView );
stateChanger.setStates( scrollView->scrollBarStates( Q::VerticalScrollBar ) );
const auto padding = scrollView->paddingHint( Q::VerticalScrollBar );
const auto strut = scrollView->strutSizeHint( Q::VerticalScrollHandle );
const qreal y1 = pos.y() / scrollableSize.height();
const qreal y2 = ( pos.y() + vRect.height() ) / scrollableSize.height();
qreal top, bottom;
qskAlignedHandle( y1, y2, sbRect.height(), strut.height(), top, bottom );
@ -262,15 +258,15 @@ QRectF QskScrollViewSkinlet::scrollHandleRect( const QskScrollView* scrollView,
}
else
{
const auto subControlBar = Q::HorizontalScrollBar;
const auto sbRect = subControlRect( scrollView, contentsRect, Q::HorizontalScrollBar );
const auto sbRect = subControlRect( scrollView, contentsRect, subControlBar );
const auto padding = scrollView->paddingHint( subControlBar );
QskSkinStateChanger stateChanger( scrollView );
stateChanger.setStates( scrollView->scrollBarStates( Q::HorizontalScrollBar ) );
const qreal w = scrollView->scrollableSize().width();
const auto padding = scrollView->paddingHint( Q::HorizontalScrollBar );
const qreal x1 = pos.x() / w;
const qreal x2 = ( pos.x() + vRect.width() ) / w;
const qreal x1 = pos.x() / scrollableSize.width();
const qreal x2 = ( pos.x() + vRect.width() ) / scrollableSize.width();
const auto strut = scrollView->strutSizeHint( Q::HorizontalScrollHandle );
@ -289,7 +285,6 @@ QRectF QskScrollViewSkinlet::scrollHandleRect( const QskScrollView* scrollView,
QRectF QskScrollViewSkinlet::scrollBarRect( const QskScrollView* scrollView,
const QRectF& contentsRect, Qt::Orientation orientation ) const
{
using A = QskAspect;
using Q = QskScrollView;
const auto scrollOrientations = scrollView->scrollableOrientations();
@ -300,23 +295,23 @@ QRectF QskScrollViewSkinlet::scrollBarRect( const QskScrollView* scrollView,
if ( orientation == Qt::Horizontal )
{
const qreal h = scrollView->metric( Q::HorizontalScrollBar | A::Size );
const qreal h = qskScrollBarExtent( scrollView, Qt::Horizontal );
r.setTop( r.bottom() - h );
if ( scrollOrientations & Qt::Vertical )
{
const qreal w = scrollView->metric( Q::VerticalScrollBar | A::Size );
const qreal w = qskScrollBarExtent( scrollView, Qt::Vertical );
r.setRight( r.right() - w );
}
}
else
{
const qreal w = scrollView->metric( Q::VerticalScrollBar | A::Size );
const qreal w = qskScrollBarExtent( scrollView, Qt::Vertical );
r.setLeft( r.right() - w );
if ( scrollOrientations & Qt::Horizontal )
{
const qreal h = scrollView->metric( Q::HorizontalScrollBar | A::Size );
const qreal h = qskScrollBarExtent( scrollView, Qt::Horizontal );
r.setBottom( r.bottom() - h );
}
}

View File

@ -43,10 +43,11 @@ class QSK_EXPORT QskScrollViewSkinlet : public QskSkinlet
quint8 nodeRole, QSGNode* ) const override;
virtual QSGNode* updateContentsNode( const QskScrollView*, QSGNode* ) const;
QSGNode* contentsNode( const QskScrollView* );
private:
QSGNode* updateContentsRootNode( const QskScrollView*, QSGNode* ) const;
QSGNode* updateScrollBarNode(
const QskScrollView*, QskAspect::Subcontrol, QSGNode* ) const;
QRectF viewportRect( const QskScrollView*, const QRectF& ) const;
QRectF scrollBarRect( const QskScrollView*, const QRectF&, Qt::Orientation ) const;

View File

@ -10,12 +10,14 @@
#include "QskEvent.h"
#include "QskSkinlet.h"
#include "QskAspect.h"
#include "QskAnimationHint.h"
#include <qguiapplication.h>
#include <qstylehints.h>
#include <qfontmetrics.h>
QSK_SUBCONTROL( QskSegmentedBar, Panel )
QSK_SUBCONTROL( QskSegmentedBar, Splash )
QSK_SUBCONTROL( QskSegmentedBar, Segment )
QSK_SUBCONTROL( QskSegmentedBar, Separator )
QSK_SUBCONTROL( QskSegmentedBar, Cursor )
@ -23,8 +25,7 @@ QSK_SUBCONTROL( QskSegmentedBar, Text )
QSK_SUBCONTROL( QskSegmentedBar, Icon )
QSK_SYSTEM_STATE( QskSegmentedBar, Selected, QskAspect::FirstSystemState << 1 )
QSK_SYSTEM_STATE( QskSegmentedBar, Minimum, QskAspect::FirstSystemState << 2 )
QSK_SYSTEM_STATE( QskSegmentedBar, Maximum, QskAspect::FirstSystemState << 3 )
QSK_SYSTEM_STATE( QskSegmentedBar, Pressed, QskAspect::FirstSystemState << 2 )
class QskSegmentedBar::PrivateData
{
@ -53,6 +54,8 @@ QskSegmentedBar::QskSegmentedBar( Qt::Orientation orientation, QQuickItem* paren
: Inherited( parent )
, m_data( new PrivateData( orientation ) )
{
setAcceptHoverEvents( true );
if( orientation == Qt::Horizontal )
initSizePolicy( QskSizePolicy::MinimumExpanding, QskSizePolicy::Fixed );
else
@ -148,6 +151,8 @@ QskAspect::Variation QskSegmentedBar::effectiveVariation() const
void QskSegmentedBar::mousePressEvent( QMouseEvent* event )
{
using A = QskAspect;
const int index = indexAtPosition( qskMousePosition( event ) );
if( isSegmentEnabled( index ) )
@ -163,6 +168,14 @@ void QskSegmentedBar::mousePressEvent( QMouseEvent* event )
}
}
}
const auto hint = animationHint( Splash | A::Color );
if( hint.isValid() )
{
setSkinHint( Splash | A::Metric | A::Position, qskMousePosition( event ) );
startTransition( Splash | A::Metric | A::Size, hint, 0.0, 1.0 );
}
}
void QskSegmentedBar::mouseUngrabEvent()
@ -260,6 +273,30 @@ void QskSegmentedBar::keyReleaseEvent( QKeyEvent* event )
Inherited::keyReleaseEvent( event );
}
void QskSegmentedBar::hoverEnterEvent( QHoverEvent* event )
{
using A = QskAspect;
setSkinHint( Segment | Hovered | A::Metric | A::Position, qskHoverPosition( event ) );
update();
}
void QskSegmentedBar::hoverMoveEvent( QHoverEvent* event )
{
using A = QskAspect;
setSkinHint( Segment | Hovered | A::Metric | A::Position, qskHoverPosition( event ) );
update();
}
void QskSegmentedBar::hoverLeaveEvent( QHoverEvent* )
{
using A = QskAspect;
setSkinHint( Segment | Hovered | A::Metric | A::Position, QPointF() );
update();
}
void QskSegmentedBar::focusInEvent( QFocusEvent* event )
{
int index = m_data->currentIndex;
@ -291,6 +328,12 @@ void QskSegmentedBar::focusInEvent( QFocusEvent* event )
Inherited::focusInEvent( event );
}
void QskSegmentedBar::focusOutEvent( QFocusEvent* event )
{
setCurrentIndex( -1 );
Inherited::focusOutEvent( event );
}
void QskSegmentedBar::clear()
{
if( count() == 0 )
@ -322,6 +365,8 @@ void QskSegmentedBar::setCurrentIndex( int index )
if( index != m_data->currentIndex )
{
m_data->currentIndex = index;
setPositionHint( Segment | Focused, index );
Q_EMIT currentIndexChanged( index );
}
}
@ -354,9 +399,6 @@ void QskSegmentedBar::setSelectedIndex( int index )
Q_EMIT selectedIndexChanged( index );
setSkinStateFlag( Minimum, ( m_data->selectedIndex == 0 ) );
setSkinStateFlag( Maximum, ( m_data->selectedIndex == count() - 1 ) );
const auto states = skinStates();
if ( oldIndex >= 0 )

View File

@ -36,8 +36,8 @@ class QSK_EXPORT QskSegmentedBar : public QskControl
using Inherited = QskControl;
public:
QSK_SUBCONTROLS( Panel, Segment, Separator, Cursor, Text, Icon )
QSK_STATES( Selected, Minimum, Maximum )
QSK_SUBCONTROLS( Panel, Splash, Segment, Separator, Cursor, Text, Icon )
QSK_STATES( Selected, Pressed )
QskSegmentedBar( QQuickItem* parent = nullptr );
QskSegmentedBar( Qt::Orientation, QQuickItem* parent = nullptr );
@ -94,7 +94,12 @@ class QSK_EXPORT QskSegmentedBar : public QskControl
void keyPressEvent( QKeyEvent* ) override;
void keyReleaseEvent( QKeyEvent* ) override;
void hoverEnterEvent( QHoverEvent* ) override;
void hoverMoveEvent( QHoverEvent* ) override;
void hoverLeaveEvent( QHoverEvent* ) override;
void focusInEvent( QFocusEvent* ) override;
void focusOutEvent( QFocusEvent* ) override;
private:
int nextIndex( int index, bool forward ) const;

View File

@ -10,22 +10,85 @@
#include "QskGraphic.h"
#include "QskColorFilter.h"
#include "QskFunctions.h"
#include "QskSGNode.h"
#include "QskSkin.h"
#include "QskStandardSymbol.h"
#include "QskSkinStateChanger.h"
#include "QskSubcontrolLayoutEngine.h"
#include "QskBoxHints.h"
#include <qfontmetrics.h>
#include <qmath.h>
namespace
{
QskBoxHints effectiveBoxHints( QskAspect::Subcontrol subControl,
const QskSegmentedBar* bar, int index )
{
using Q = QskSegmentedBar;
auto boxHints = bar->boxHints( subControl );
const bool leading = ( index == 0 );
const bool trailing = ( index == bar->count() - 1 );
if ( !( leading || trailing ) )
return boxHints;
// something more expressive than just a boolean. TODO ...
if ( !bar->flagHint< bool >( Q::Panel | QskAspect::Option, false ) )
return boxHints;
const auto panelShape = bar->boxShapeHint( Q::Panel );
auto& shape = boxHints.shape;
// when there is only 1 segment we have to fit both ends
if ( leading )
{
Qt::Corner corners[2];
corners[0] = Qt::TopLeftCorner;
if ( bar->orientation() == Qt::Vertical )
corners[1] = Qt::TopRightCorner;
else
corners[1] = Qt::BottomLeftCorner;
shape.setSizeMode( panelShape.sizeMode() );
shape.setRadius( corners[0], panelShape.radius( corners[0] ) );
shape.setRadius( corners[1], panelShape.radius( corners[1] ) );
}
if ( trailing )
{
Qt::Corner corners[2];
corners[0] = Qt::BottomRightCorner;
if ( bar->orientation() == Qt::Vertical )
corners[1] = Qt::BottomLeftCorner;
else
corners[1] = Qt::TopRightCorner;
shape.setSizeMode( panelShape.sizeMode() );
shape.setRadius( corners[0], panelShape.radius( corners[0] ) );
shape.setRadius( corners[1], panelShape.radius( corners[1] ) );
}
boxHints.borderMetrics = bar->boxBorderMetricsHint( Q::Panel );
boxHints.borderColors = QColor();
return boxHints;
}
QskGraphic iconAt( const QskSegmentedBar* bar, const int index )
{
using Q = QskSegmentedBar;
if ( bar->selectedIndex() == index )
{
/*
/*
Material 3 replaces the icon of the selected element by a checkmark,
when icon and text are set. So this code is actually not correct
as it also replaces the icon when there is no text
@ -66,8 +129,8 @@ namespace
QskSegmentedBarSkinlet::QskSegmentedBarSkinlet( QskSkin* skin )
: Inherited( skin )
{
setNodeRoles( { PanelRole, SegmentRole,
SeparatorRole, CursorRole, TextRole, IconRole } );
setNodeRoles( { PanelRole, SegmentRole, SeparatorRole,
CursorRole, SplashRole, TextRole, IconRole } );
}
QskSegmentedBarSkinlet::~QskSegmentedBarSkinlet() = default;
@ -86,6 +149,9 @@ QRectF QskSegmentedBarSkinlet::subControlRect(
if( subControl == Q::Cursor )
return cursorRect( bar, contentsRect );
if( subControl == Q::Splash )
return splashRect( bar, contentsRect );
return Inherited::subControlRect( skinnable, contentsRect, subControl );
}
@ -120,6 +186,48 @@ QRectF QskSegmentedBarSkinlet::cursorRect(
return cursorRect;
}
QRectF QskSegmentedBarSkinlet::splashRect(
const QskSegmentedBar* bar, const QRectF& contentsRect ) const
{
using Q = QskSegmentedBar;
QRectF rect;
const auto ratio = bar->metric( Q::Splash | QskAspect::Size );
if ( ratio > 0.0 )
{
const auto pos = bar->effectiveSkinHint(
Q::Splash | QskAspect::Metric | QskAspect::Position ).toPointF();
const int index = bar->indexAtPosition( pos );
if( index >= 0 && index < bar->count() )
{
const auto sr = segmentRect( bar, contentsRect, index );
rect = sr;
qreal w, h;
if( bar->orientation() == Qt::Horizontal )
{
w = 2.0 * rect.width() * ratio;
h = 2.0 * rect.height();
}
else
{
w = 2.0 * rect.width();
h = 2.0 * rect.height() * ratio;
}
rect.setSize( { w, h } );
rect.moveCenter( pos );
rect = rect.intersected( sr );
}
}
return rect;
}
QRectF QskSegmentedBarSkinlet::segmentRect(
const QskSegmentedBar* bar, const QRectF& contentsRect, int index ) const
{
@ -163,7 +271,7 @@ QRectF QskSegmentedBarSkinlet::separatorRect(
if( bar->orientation() == Qt::Horizontal )
{
rect.setLeft( rect.right() ); // ### *0.5 or so?
rect.setLeft( rect.right() );
rect.setSize( { strutSize.width(), sh.height() } );
}
else
@ -183,11 +291,16 @@ QSGNode* QskSegmentedBarSkinlet::updateSubNode(
{
using Q = QskSegmentedBar;
const auto bar = static_cast< const QskSegmentedBar* >( skinnable );
switch( nodeRole )
{
case CursorRole:
return updateBoxNode( skinnable, node, Q::Cursor );
case SplashRole:
return updateSplashNode( bar, node );
case PanelRole:
return updateBoxNode( skinnable, node, Q::Panel );
@ -317,13 +430,52 @@ QskAspect::States QskSegmentedBarSkinlet::sampleStates(
const QskSkinnable* skinnable, QskAspect::Subcontrol subControl, int index ) const
{
using Q = QskSegmentedBar;
using A = QskAspect;
auto states = Inherited::sampleStates( skinnable, subControl, index );
if ( subControl == Q::Segment || subControl == Q::Icon || subControl == Q::Text )
{
const auto bar = static_cast< const QskSegmentedBar* >( skinnable );
const auto* bar = static_cast< const QskSegmentedBar* >( skinnable );
if ( subControl == Q::Segment )
{
if ( bar->isSegmentEnabled( index ) )
{
if ( bar->selectedIndex() == index )
states |= Q::Selected;
}
else
{
states |= Q::Disabled;
}
const auto cursorPos = bar->effectiveSkinHint(
Q::Segment | Q::Hovered | A::Metric | A::Position ).toPointF();
if( !cursorPos.isNull() && bar->indexAtPosition( cursorPos ) == index )
{
states |= Q::Hovered;
}
else
{
states &= ~Q::Hovered;
}
const auto focusIndex = bar->positionHint( Q::Segment | Q::Focused );
if( focusIndex >= 0 && focusIndex < bar->count() )
{
if( focusIndex == index )
{
states |= Q::Focused;
}
else
{
states &= ~Q::Focused;
}
}
}
else if( subControl == Q::Icon || subControl == Q::Text )
{
if ( bar->isSegmentEnabled( index ) )
{
if ( bar->selectedIndex() == index )
@ -347,11 +499,17 @@ QSGNode* QskSegmentedBarSkinlet::updateSampleNode( const QskSkinnable* skinnable
const auto rect = sampleRect( bar, bar->contentsRect(), subControl, index );
if ( subControl == Q::Segment || subControl == Q::Separator )
if ( subControl == Q::Separator )
{
return updateBoxNode( skinnable, node, rect, subControl );
}
if ( subControl == Q::Segment )
{
const auto boxHints = effectiveBoxHints( subControl, bar, index );
return updateBoxNode( bar, node, rect, boxHints );
}
const auto alignment = bar->alignmentHint( subControl, Qt::AlignCenter );
if ( subControl == Q::Text )
@ -387,4 +545,26 @@ QSGNode* QskSegmentedBarSkinlet::updateSampleNode( const QskSkinnable* skinnable
return Inherited::updateSampleNode( skinnable, subControl, index, node );
}
QSGNode* QskSegmentedBarSkinlet::updateSplashNode(
const QskSegmentedBar* bar, QSGNode* node ) const
{
using Q = QskSegmentedBar;
const auto splashRect = bar->subControlRect( Q::Splash );
if ( splashRect.isEmpty() )
return nullptr;
auto clipNode = updateBoxClipNode(
bar, node, bar->subControlRect( Q::Panel ), Q::Panel );
if ( clipNode )
{
auto boxNode = updateBoxNode( bar, clipNode->firstChild(), splashRect, Q::Splash );
if ( boxNode->parent() == nullptr )
clipNode->appendChildNode( boxNode );
}
return clipNode;
}
#include "moc_QskSegmentedBarSkinlet.cpp"

View File

@ -23,6 +23,7 @@ class QSK_EXPORT QskSegmentedBarSkinlet : public QskSkinlet
SegmentRole,
SeparatorRole,
CursorRole,
SplashRole,
TextRole,
IconRole,
@ -60,6 +61,9 @@ class QSK_EXPORT QskSegmentedBarSkinlet : public QskSkinlet
QRectF segmentRect( const QskSegmentedBar*, const QRectF&, int index ) const;
QRectF separatorRect( const QskSegmentedBar*, const QRectF&, int index ) const;
QRectF cursorRect( const QskSegmentedBar*, const QRectF& ) const;
QRectF splashRect( const QskSegmentedBar*, const QRectF& ) const;
QSGNode* updateSplashNode( const QskSegmentedBar*, QSGNode* ) const;
};
#endif

View File

@ -173,7 +173,7 @@ void QskShortcutHandler::remove( int id )
Finally let's check if we can disconnect
from the destroyed signals
*/
for ( const auto& entry : qAsConst( m_invokeDataMap ) )
for ( const auto& entry : std::as_const( m_invokeDataMap ) )
{
if ( item == nullptr && receiver == nullptr )
break;
@ -276,7 +276,7 @@ bool QskShortcutHandler::invoke( QQuickItem* item, const QKeySequence& sequence
{
bool found = false;
for ( const auto& entry : qAsConst( m_invokeDataMap ) )
for ( const auto& entry : std::as_const( m_invokeDataMap ) )
{
auto& data = entry.second;

View File

@ -46,6 +46,18 @@ class QSK_EXPORT QskSkin : public QObject
Q_ENUM( SkinFontRole )
#if 1
// Use Qt::ColorScheme once minimum version is Qt 6.5
enum ColorScheme
{
UnknownScheme,
LightScheme,
DarkScheme
};
Q_ENUM( ColorScheme )
#endif
QskSkin( QObject* parent = nullptr );
~QskSkin() override;

View File

@ -15,6 +15,11 @@
#include <qpointer.h>
#include <qset.h>
#if QT_VERSION >= QT_VERSION_CHECK( 6, 5, 0 )
#include <qguiapplication.h>
#include <qstylehints.h>
#endif
static inline QStringList qskSplitPath( const QString& s )
{
const auto separator = QDir::listSeparator();
@ -74,6 +79,8 @@ namespace
const QLatin1String TokenData( "MetaData" );
const QLatin1String TokenFactoryId( "FactoryId" );
const QLatin1String TokenSkins( "Skins" );
const QLatin1String TokenName( "Name" );
const QLatin1String TokenScheme( "Scheme" );
const QLatin1String InterfaceId( QskSkinFactoryIID );
@ -83,10 +90,6 @@ namespace
const auto factoryData = pluginData.value( TokenData ).toObject();
m_factoryId = factoryData.value( TokenFactoryId ).toString().toLower();
#if 1
if ( m_factoryId == "fluent2factory" )
return false; // we need to solve a couple of problems first
#endif
if ( m_factoryId.isEmpty() )
{
// Creating a dummy factory id
@ -94,10 +97,45 @@ namespace
m_factoryId = QStringLiteral( "skin_factory_" ) + QString::number( i++ );
}
const auto skinNames = factoryData.value( TokenSkins ).toArray();
const auto skins = factoryData.value( TokenSkins ).toArray();
for ( const auto& name : skinNames )
m_skinNames += name.toString();
for ( const auto& skin : skins )
{
const auto& skinObject = skin.toObject();
const auto& name = skinObject.value( TokenName ).toString();
#if QT_VERSION >= QT_VERSION_CHECK( 6, 5, 0 )
const auto& schemeString = skinObject.value( TokenScheme ).toString();
Qt::ColorScheme scheme;
if( schemeString == QStringLiteral( "Light" ) )
{
scheme = Qt::ColorScheme::Light;
}
else if( schemeString == QStringLiteral( "Dark" ) )
{
scheme = Qt::ColorScheme::Dark;
}
else
{
scheme = Qt::ColorScheme::Unknown;
}
const auto systemScheme = qGuiApp->styleHints()->colorScheme();
if( scheme == systemScheme )
{
m_skinNames.prepend( name );
}
else
{
m_skinNames.append( name );
}
#else
Q_UNUSED( TokenScheme )
m_skinNames += name;
#endif
}
}
return !m_skinNames.isEmpty();
@ -327,7 +365,7 @@ class QskSkinManager::PrivateData
{
if ( !pluginsRegistered )
{
for ( const auto& path : qAsConst( pluginPaths ) )
for ( const auto& path : std::as_const( pluginPaths ) )
registerPlugins( path + QStringLiteral( "/skins" ) );
pluginsRegistered = true;

View File

@ -16,6 +16,7 @@ class QskSkinStateChanger
~QskSkinStateChanger();
void setStates( QskAspect::States );
void resetStates();
private:
QskSkinnable* m_skinnable;
@ -30,8 +31,7 @@ inline QskSkinStateChanger::QskSkinStateChanger( const QskSkinnable* skinnable )
inline QskSkinStateChanger::~QskSkinStateChanger()
{
if ( m_oldStates != m_skinnable->skinStates() )
m_skinnable->replaceSkinStates( m_oldStates );
resetStates();
}
inline void QskSkinStateChanger::setStates( QskAspect::States states )
@ -40,4 +40,10 @@ inline void QskSkinStateChanger::setStates( QskAspect::States states )
m_skinnable->replaceSkinStates( states );
}
inline void QskSkinStateChanger::resetStates()
{
if ( m_oldStates != m_skinnable->skinStates() )
m_skinnable->replaceSkinStates( m_oldStates );
}
#endif

View File

@ -368,7 +368,7 @@ void QskSkinlet::updateNode( QskSkinnable* skinnable, QSGNode* parentNode ) cons
replaceChildNode( DebugRole, parentNode, oldNode, newNode );
}
for ( const auto nodeRole : qAsConst( m_data->nodeRoles ) )
for ( const auto nodeRole : std::as_const( m_data->nodeRoles ) )
{
Q_ASSERT( nodeRole < FirstReservedRole );

View File

@ -1382,7 +1382,19 @@ void QskSkinnable::setSkinStates( QskAspect::States newStates )
bool QskSkinnable::startHintTransitions(
QskAspect::States oldStates, QskAspect::States newStates, int index )
{
if ( !isTransitionAccepted( QskAspect() ) )
QVector< QskAspect::Subcontrol > subControls;
if ( const auto control = qskControlCast( owningItem() ) )
subControls = control->subControls();
return startHintTransitions( subControls, oldStates, newStates, index );
}
bool QskSkinnable::startHintTransitions(
const QVector< QskAspect::Subcontrol >& subControls,
QskAspect::States oldStates, QskAspect::States newStates, int index )
{
if ( !isTransitionAccepted( QskAspect() ) || subControls.isEmpty() )
{
// the control does not like any animated transition at the moment
return false;
@ -1401,7 +1413,6 @@ bool QskSkinnable::startHintTransitions(
const auto primitiveCount = QskAspect::primitiveCount();
const auto subControls = control->subControls();
for ( const auto subControl : subControls )
{
aspect.setSubcontrol( subControl );

View File

@ -260,6 +260,8 @@ class QSK_EXPORT QskSkinnable
const QskSkinHintTable& hintTable() const;
bool startHintTransitions( QskAspect::States, QskAspect::States, int index = -1 );
bool startHintTransitions( const QVector< QskAspect::Subcontrol >&,
QskAspect::States, QskAspect::States, int index = -1 );
protected:
virtual void updateNode( QSGNode* );

View File

@ -118,7 +118,7 @@ QskDialogButtonBox::~QskDialogButtonBox()
{
for ( int i = 0; i < QskDialog::NActionRoles; i++ )
{
for ( auto button : qAsConst( m_data->buttons[ i ] ) )
for ( auto button : std::as_const( m_data->buttons[ i ] ) )
{
/*
The destructor of QQuickItem sets the parentItem of

View File

@ -42,7 +42,8 @@ QskDialogWindow::QskDialogWindow( QWindow* parent )
// doing the layout manually instead ???
setAutoLayoutChildren( true );
m_data->layoutBox = new QskLinearBox( Qt::Vertical, contentItem() );
m_data->layoutBox->setMargins( 5 );
m_data->layoutBox->setPadding( 5 );
m_data->layoutBox->setPanel( true ); // for a themed background
}
QskDialogWindow::~QskDialogWindow()

View File

@ -568,7 +568,7 @@ QRectF QskGraphic::scaledBoundingRect( qreal sx, qreal sy ) const
QRectF rect = transform.mapRect( m_data->pointRect );
for ( const auto& info : qAsConst( m_data->pathInfos ) )
for ( const auto& info : std::as_const( m_data->pathInfos ) )
rect |= info.scaledBoundingRect( sx, sy, scalePens );
return rect;
@ -681,7 +681,7 @@ void QskGraphic::render( QPainter* painter, const QRectF& rect,
const bool scalePens = !( m_data->renderHints & RenderPensUnscaled );
for ( const auto& info : qAsConst( m_data->pathInfos ) )
for ( const auto& info : std::as_const( m_data->pathInfos ) )
{
const qreal ssx = info.scaleFactorX( m_data->pointRect,
rect, m_data->boundingRect, scalePens );

View File

@ -524,6 +524,8 @@ bool QskGridLayoutEngine::clear()
m_data->rowSettings.clear();
m_data->columnSettings.clear();
m_data->rowCount = m_data->columnCount = 0;
invalidate();
return true;
}

View File

@ -318,7 +318,7 @@ void QskStackBox::autoRemoveItem( QQuickItem* item )
void QskStackBox::clear( bool autoDelete )
{
for ( const auto item : qAsConst( m_data->items ) )
for ( const auto item : std::as_const( m_data->items ) )
{
if( autoDelete && ( item->parent() == this ) )
delete item;
@ -380,7 +380,7 @@ QSizeF QskStackBox::layoutSizeHint(
qreal w = -1.0;
qreal h = -1.0;
for ( const auto item : qAsConst( m_data->items ) )
for ( const auto item : std::as_const( m_data->items ) )
{
/*
We ignore the retainSizeWhenVisible flag and include all

View File

@ -39,7 +39,25 @@ void QskBoxClipNode::setBox( const QRectF& rect,
m_rect = rect;
m_hash = hash;
bool isRectangular = false;
#if 0
/*
Depending on isRectangular the "renderer can use scissoring instead of stencil,
which is significantly faster."
However the batch renderer ( qsgbatchrenderer.cpp ) is rounding the clip rectangle
to integers and the clip might become too small/large.
So we always have to use stencil clipping - even if it might have a negative
impact on the performance. TODO ...
*/
if ( shape.isRectangle() )
isRectangular = true;
#endif
if ( isRectangular )
{
if ( m_geometry.vertexCount() > 0 )
m_geometry.allocate( 0 );

View File

@ -23,6 +23,7 @@ class QskColorFilter;
class QSGNode;
class QVariant;
class QRectF;
class QSizeF;
class QSK_EXPORT QskScaleRenderer
{