code simplified

This commit is contained in:
Uwe Rathmann 2020-12-13 19:38:46 +01:00
parent f33f38bbbb
commit 80004ed8e8
16 changed files with 310 additions and 1152 deletions

View File

@ -1,221 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "DefaultSkin.h"
#include "ButtonBar.h"
#include "SkinFactory.h"
#include "SoundControl.h"
#include "Speedometer.h"
#include "SpeedometerSkinlet.h"
#include <QskBox.h>
#include <QskBoxBorderColors.h>
#include <QskBoxBorderMetrics.h>
#include <QskColorFilter.h>
#include <QskFunctions.h>
#include <QskMargins.h>
#include <QskPushButton.h>
#include <QskSeparator.h>
#include <QskSkinTransition.h>
#include <QskSlider.h>
#include <QskTextLabel.h>
#include <QDebug>
class Transition final : public QskSkinTransition
{
protected:
void updateSkin( QskSkin*, QskSkin* newSkin ) override
{
DefaultSkin* skin = static_cast< DefaultSkin* >( newSkin );
skin->resetHints();
}
};
class Palette
{
public:
Palette( DefaultSkin::Scheme scheme = DefaultSkin::Daylight )
{
if ( scheme == DefaultSkin::Daylight )
{
// colorful:
color1.setNamedColor( "#011627" ); // Maastricht blue
color2.setNamedColor( "#FF0022" ); // ruddy
color3.setNamedColor( "#41EAD4" ); // Turquoise
color4.setNamedColor( "#FDFFFC" ); // baby powder
color5.setNamedColor( "#B91372" ); // red violet
}
else
{
// greenish:
color4.setNamedColor( "#FAF3DD" ); // Beige
color2.setNamedColor( "#C8D5B9" ); // Pale Silver
color3.setNamedColor( "#8FC0A9" ); // Eton Blue
color1.setNamedColor( "#68B0AB" ); // Green Sheen
color5.setNamedColor( "#4A7C59" ); // Amazon
}
}
QColor color1;
QColor color2;
QColor color3;
QColor color4;
QColor color5;
};
namespace
{
static inline QFont qskFont( qreal pointSize )
{
QFont font( "Roboto" );
font.setPointSizeF( pointSize / qskDpiScaled( 1.0 ) );
return font;
}
} // namespace
DefaultSkin::DefaultSkin( const QString& name, QObject* parent )
: QskSkin( parent )
, m_name( name )
, m_palette( new Palette )
, m_scheme( Daylight )
{
setObjectName( "DefaultSkin" );
declareSkinlet< Speedometer, SpeedometerSkinlet >();
initHints();
}
DefaultSkin::~DefaultSkin()
{
delete m_palette;
}
void DefaultSkin::initHints()
{
using namespace QskAspect;
const int duration = 200; // for animators
setFont( QskSkin::DefaultFont, qskFont( 13 ) );
setFont( QskSkin::LargeFont, qskFont( 20 ) );
setColor( QskTextLabel::Text, m_palette->color4 );
// -- sound control
setGradient( SoundControl::Overlay, 0 );
setGradient( SoundControl::CrossHair, m_palette->color3 );
setGradient( SoundControl::Marker, m_palette->color5 );
setBoxBorderMetrics( SoundControl::Marker, 2 );
setBoxShape( SoundControl::Marker, 100, Qt::RelativeSize );
setGradient( QskSeparator::Panel, m_palette->color3 );
setMetric( QskSeparator::Panel | Size, 2 );
// -- push buttons
setMargins( QskPushButton::Panel | Padding, 10 );
setGradient( QskPushButton::Panel, m_palette->color1 );
setColor( QskPushButton::Text, m_palette->color3 );
setGradient( QskPushButton::Panel | QskPushButton::Pressed, m_palette->color2 );
setAnimation( QskPushButton::Panel | Color, duration );
setGradient( SoundControl::SliderControl, m_palette->color1 );
setGradient( SoundControl::SliderControl | QskPushButton::Pressed, m_palette->color2 );
setAnimation( SoundControl::SliderControl | Color, duration );
setMetric( QskPushButton::Text | Size, 20 );
setSkinHint( QskPushButton::Text | FontRole, int( QskSkin::LargeFont ) );
setSkinHint( QskPushButton::Text | Alignment, Qt::AlignCenter );
// -- a more advanced setup of the hints for the slider
const qreal dim = 30;
setMetric( QskSlider::Panel | Size, dim );
setGradient( QskSlider::Panel, QskGradient() );
setMetric( QskSlider::Groove | Size, 2 );
setGradient( QskSlider::Groove, m_palette->color4 );
setMetric( QskSlider::Fill | Size, 2 );
setGradient( QskSlider::Fill, m_palette->color4.darker( 200 ) );
setMetric( QskSlider::Handle | Size, 24 );
setBoxBorderMetrics( QskSlider::Handle, 0 );
setBoxShape( QskSlider::Handle, 100.0, Qt::RelativeSize );
setGradient( QskSlider::Handle, m_palette->color5 );
// -- speedometers
setBoxBorderMetrics( Speedometer::Panel, 2 );
setGradient( Speedometer::Panel, m_palette->color1 );
setBoxBorderColors( Speedometer::Panel, m_palette->color3 );
setBoxBorderMetrics( Speedometer::NeedleHead, 2 );
setMetric( Speedometer::NeedleHead | Size, 15 );
setGradient( Speedometer::NeedleHead,
QskGradient( QskGradient::Diagonal, m_palette->color2, m_palette->color1 ) );
// setBoxBorderColors( Speedometer::NeedleHead, m_palette->color4 );
setMetric( Speedometer::Needle | MinimumWidth, 2 );
setMetric( Speedometer::Needle | Margin, 10 );
setColor( Speedometer::Needle, m_palette->color2 );
// margins between numbers and ticks:
setMargins( Speedometer::Labels, QskMargins( 4, 4, 4, 4 ) );
setMetric( Speedometer::Labels | MinimumWidth, 2 );
setMetric( Speedometer::Labels | Size, 15 ); // ticks size
setColor( Speedometer::Labels, m_palette->color4 );
setFontRole( Speedometer::Labels, QskSkin::SmallFont );
// handle expanding, when being pressed
for ( auto state : { QskAspect::NoState, QskSlider::Pressed } )
{
const auto aspect = QskSlider::Handle | state;
// fullsize, only when being pressed
const qreal sz = ( state == NoState ) ? 0.7 * dim : dim;
setMetric( aspect | Size, sz );
// move the handle smoothly, when using keys
setAnimation( aspect | Metric | Position,
( state == NoState ) ? 2 * duration : 0 );
}
setAnimation( QskSlider::Handle | Metric, duration );
// animator for color scheme transitions
setAnimation( Color, QskAnimationHint( 1000, QEasingCurve::InQuad ) );
}
void DefaultSkin::toggleScheme()
{
if ( m_scheme == Daylight )
m_scheme = Nighttime;
else
m_scheme = Daylight;
Transition transition;
transition.setSourceSkin( this );
transition.setTargetSkin( this );
transition.setMask( QskSkinTransition::Color );
transition.setAnimation( animation( QskAspect::Color ) );
transition.process();
}
void DefaultSkin::resetHints()
{
delete m_palette;
m_palette = new Palette( m_scheme );
initHints();
}

View File

@ -1,36 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#ifndef DEFAULTSKIN_H
#define DEFAULTSKIN_H
#include <QskSkin.h>
class Palette;
class DefaultSkin : public QskSkin
{
public:
DefaultSkin( const QString& name, QObject* parent = nullptr );
~DefaultSkin() override;
void toggleScheme();
void resetHints();
enum Scheme
{
Daylight,
Nighttime
};
private:
void initHints();
QString m_name;
Palette* m_palette;
Scheme m_scheme;
};
#endif // DEFAULTSKIN_H

View File

@ -6,7 +6,6 @@
#include "MainWindow.h"
#include "ButtonBar.h"
#include "SkinFactory.h"
#include "SoundControl.h"
#include "SpeedometerDisplay.h"
#include <QskGraphic.h>
@ -18,70 +17,63 @@
#include <QDate>
#include <QImage>
#define SPEEDO 1
namespace
{
class Header : public ButtonBar
{
public:
Header()
{
addIndicator( "bluetooth" );
addIndicator( "location" );
addIndicator( "phone" );
( void ) new QskTextLabel( QDate::currentDate().toString(), this );
addIndicator( "user" );
addIndicator( "bookmark" );
addIndicator( "menu" );
}
};
class Footer : public ButtonBar
{
public:
Footer()
{
addIndicator( "cloud" );
addIndicator( "man" );
addIndicator( "bus" );
addIndicator( "plane" );
addIndicator( "train" );
addStretch( 10 );
}
};
}
MainWindow::MainWindow()
{
setAutoLayoutChildren( true );
const QImage image( QStringLiteral( ":/images/background.jpg" ) );
auto backgroundImage = new QskGraphicLabel( contentItem() );
backgroundImage->setGraphic( QskGraphic::fromImage( image ) );
backgroundImage->setFillMode( QskGraphicLabel::Stretch );
auto header = headerBar();
auto content = mainContent();
auto footer = footerBar();
auto header = new Header();
auto speedoDisplay = new SpeedometerDisplay();
auto footer = new Footer();
auto layout = new QskLinearBox( Qt::Vertical, contentItem() );
layout->addItem( header );
layout->setStretchFactor( header, 1 );
layout->addItem( content );
layout->setStretchFactor( content, 8 );
layout->addItem( speedoDisplay );
layout->setStretchFactor( speedoDisplay, 8 );
layout->addItem( footer );
layout->setStretchFactor( footer, 1 );
setAutoLayoutChildren( true );
}
QQuickItem* MainWindow::headerBar() const
{
auto* header = new ButtonBar();
header->addIndicator( "bluetooth" );
header->addIndicator( "location" );
header->addIndicator( "phone" );
( void ) new QskTextLabel( QDate::currentDate().toString(), header );
header->addIndicator( "user" );
header->addIndicator( "bookmark" );
header->addIndicator( "menu" );
return header;
}
QQuickItem* MainWindow::mainContent() const
{
#if SPEEDO
return new SpeedometerDisplay();
#else
return new SoundControl();
#endif
}
QQuickItem* MainWindow::footerBar() const
{
auto* footer = new ButtonBar();
footer->addIndicator( "cloud" );
footer->addIndicator( "man" );
footer->addIndicator( "bus" );
footer->addIndicator( "plane" );
footer->addIndicator( "train" );
footer->addStretch( 10 );
return footer;
}

View File

@ -14,11 +14,6 @@ class MainWindow : public QskWindow
{
public:
MainWindow();
private:
QQuickItem* headerBar() const;
QQuickItem* mainContent() const;
QQuickItem* footerBar() const;
};
#endif

View File

@ -1,190 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "OtherSkin.h"
#include "SkinFactory.h"
#include "ButtonBar.h"
#include "SoundControl.h"
#include "Speedometer.h"
#include "SpeedometerSkinlet.h"
#include <QskBox.h>
#include <QskBoxBorderColors.h>
#include <QskBoxBorderMetrics.h>
#include <QskColorFilter.h>
#include <QskFunctions.h>
#include <QskMargins.h>
#include <QskPushButton.h>
#include <QskSeparator.h>
#include <QskSkinTransition.h>
#include <QskSlider.h>
#include <QskTextLabel.h>
#include <QDebug>
class Palette
{
public:
Palette()
{
// grey-blue-yellow:
color1.setNamedColor( "#363636" ); // Jet
color2.setNamedColor( "#242F40" ); // Yankees blue
color3.setNamedColor( "#CCA43B" ); // Satin sheet gold
color4.setNamedColor( "#E5E5E5" ); // Platinum
color5.setNamedColor( "#FFFFFF" ); // white
}
QColor color1;
QColor color2;
QColor color3;
QColor color4;
QColor color5;
};
namespace
{
static inline QFont qskFont( qreal pointSize )
{
QFont font( "Roboto" );
font.setPointSizeF( pointSize / qskDpiScaled( 1.0 ) );
return font;
}
}
OtherSkin::OtherSkin( const QString& name, QObject* parent )
: QskSkin( parent )
, m_name( name )
, m_palette( new Palette )
{
setObjectName( "OtherSkin" );
declareSkinlet< Speedometer, SpeedometerSkinlet >();
initHints();
initGraphicFilters();
}
OtherSkin::~OtherSkin()
{
delete m_palette;
}
void OtherSkin::initHints()
{
using namespace QskAspect;
const int duration = 200; // for animators
setFont( QskSkin::DefaultFont, qskFont( 13 ) );
setFont( QskSkin::LargeFont, qskFont( 20 ) );
setColor( QskTextLabel::Text, m_palette->color3 );
// -- sound control
setGradient( SoundControl::CrossHair, QColor( "OliveDrab" ).lighter( 120 ) );
setGradient( SoundControl::Marker, QColor( "OliveDrab" ) );
setBoxBorderMetrics( SoundControl::Marker, 2 );
setBoxShape( SoundControl::Marker, 100, Qt::RelativeSize );
setSkinHint( ButtonBar::Indicator | GraphicRole, SkinFactory::Indicator );
setSkinHint( SoundControl::Vehicle | GraphicRole, SkinFactory::Vehicle );
setSkinHint( SoundControl::MarkerControl | GraphicRole, SkinFactory::Vehicle );
setBoxBorderMetrics( QskSeparator::Panel, 0 );
setGradient( QskSeparator::Panel, m_palette->color3 );
setMetric( QskSeparator::Panel | Size, 1 );
// -- push buttons
setMargins( QskPushButton::Panel | Padding, 8 );
setBoxBorderMetrics( QskPushButton::Panel, 0 );
setBoxShape( QskPushButton::Panel, 4 );
setGradient( QskPushButton::Panel, m_palette->color1 );
setGradient( QskPushButton::Panel | QskPushButton::Pressed, m_palette->color2 );
setColor( QskPushButton::Text, m_palette->color3 );
setAnimation( QskPushButton::Panel | Color, duration );
// -- overlay
QColor overlayColor( "#011627" );
overlayColor.setAlpha( 200 );
setGradient( SoundControl::Overlay, overlayColor );
// -- slider control buttons
setBoxBorderMetrics( SoundControl::SliderControl, 0 );
setBoxShape( SoundControl::SliderControl, 4 );
setGradient( SoundControl::SliderControl, m_palette->color1 );
setGradient( SoundControl::SliderControl | QskPushButton::Pressed, m_palette->color2 );
setAnimation( SoundControl::SliderControl | Color, duration );
setMetric( QskPushButton::Text | Size, 20 );
setSkinHint( QskPushButton::Text | FontRole, int( QskSkin::LargeFont ) );
setSkinHint( QskPushButton::Text | Alignment, Qt::AlignCenter );
// -- a more advanced setup of the hints for the slider
setMetric( QskSlider::Panel | Size, 30 );
setGradient( QskSlider::Panel, QskGradient() );
setMetric( QskSlider::Groove | Size, 5 );
setGradient( QskSlider::Groove, m_palette->color4.darker( 200 ) );
setMetric( QskSlider::Fill | Size, 5 );
setGradient( QskSlider::Fill, m_palette->color3.lighter( 150 ) );
setMetric( QskSlider::Handle | Size, 22 );
setBoxBorderMetrics( QskSlider::Handle, 0 );
setBoxShape( QskSlider::Handle, 6 );
setGradient( QskSlider::Handle, m_palette->color3 );
// -- speedometers
setBoxBorderMetrics( Speedometer::Panel, 5 );
setGradient( Speedometer::Panel,
QskGradient( QskGradient::Vertical, m_palette->color2, m_palette->color4 ) );
setBoxBorderColors( Speedometer::Panel, m_palette->color3 );
setBoxBorderMetrics( Speedometer::NeedleHead, 5 );
setMetric( Speedometer::NeedleHead | Size, 10 );
setGradient( Speedometer::NeedleHead, m_palette->color2 );
setBoxBorderColors( Speedometer::NeedleHead, m_palette->color4 );
setMetric( Speedometer::Needle | MinimumWidth, 4 );
setMetric( Speedometer::Needle | Margin, 15 );
setColor( Speedometer::Needle, m_palette->color4 );
// margins between numbers and ticks:
setMargins( Speedometer::Labels, QskMargins( 3, 3, 3, 3 ) );
setMetric( Speedometer::Labels | MinimumWidth, 3 );
setMetric( Speedometer::Labels | Size, 25 ); // ticks size
setColor( Speedometer::Labels, m_palette->color4 );
setFontRole( Speedometer::Labels, QskSkin::SmallFont );
}
void OtherSkin::initGraphicFilters()
{
{
// all SVGs on the header/footer are plain white
QskColorFilter filter;
filter.addColorSubstitution( Qt::white, m_palette->color3.rgb() );
setGraphicFilter( SkinFactory::Indicator, filter );
}
{
// we need to modify the SVG to have more colors for substutions !!
QskColorFilter filter;
filter.addColorSubstitution( Qt::white, m_palette->color3.rgb() );
setGraphicFilter( SkinFactory::Vehicle, filter );
}
}

View File

@ -1,27 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#ifndef OTHERSKIN_H
#define OTHERSKIN_H
#include <QskSkin.h>
class Palette;
class OtherSkin : public QskSkin
{
public:
OtherSkin( const QString& name, QObject* parent = nullptr );
~OtherSkin() override;
private:
void initHints();
void initGraphicFilters();
QString m_name;
Palette* m_palette;
};
#endif

View File

@ -4,37 +4,163 @@
*****************************************************************************/
#include "SkinFactory.h"
#include "DefaultSkin.h"
#include "OtherSkin.h"
#include "ButtonBar.h"
#include "Speedometer.h"
#include "SpeedometerSkinlet.h"
#include <QskBoxBorderColors.h>
#include <QskBoxBorderMetrics.h>
#include <QskColorFilter.h>
#include <QskFunctions.h>
#include <QskMargins.h>
#include <QskTextLabel.h>
#include <QskAnimationHint.h>
#include <QskSetup.h>
#include <QskSkinTransition.h>
#include <QskSkin.h>
#include <QEasingCurve>
namespace
{
inline QFont qskFont( qreal pointSize )
{
QFont font( "Roboto" );
font.setPointSizeF( pointSize / qskDpiScaled( 1.0 ) );
return font;
}
class Skin : public QskSkin
{
public:
Skin()
{
using namespace QskAspect;
declareSkinlet< Speedometer, SpeedometerSkinlet >();
setFont( QskSkin::DefaultFont, qskFont( 13 ) );
setFont( QskSkin::LargeFont, qskFont( 20 ) );
setSkinHint( ButtonBar::Indicator | GraphicRole, SkinFactory::Indicator );
}
};
class Skin1 : public Skin
{
public:
Skin1()
{
using namespace QskAspect;
const QColor color1( "#363636" ); // Jet
const QColor color2( "#242F40" ); // Yankees blue
const QColor color3( "#CCA43B" ); // Satin sheet gold
const QColor color4( "#E5E5E5" ); // Platinum
const QColor color5( "#FFFFFF" ); // white
setColor( QskTextLabel::Text, color3 );
{
using Q = Speedometer;
setBoxBorderMetrics( Q::Panel, 5 );
setGradient( Q::Panel,
QskGradient( QskGradient::Vertical, color2, color4 ) );
setBoxBorderColors( Q::Panel, color3 );
setBoxBorderMetrics( Q::NeedleHead, 5 );
setMetric( Q::NeedleHead | Size, 10 );
setGradient( Q::NeedleHead, color2 );
setBoxBorderColors( Q::NeedleHead, color4 );
setMetric( Q::Needle | MinimumWidth, 4 );
setMetric( Q::Needle | Margin, 15 );
setColor( Q::Needle, color4 );
// margins between numbers and ticks:
setMargins( Q::Labels, QskMargins( 3, 3, 3, 3 ) );
setMetric( Q::Labels | MinimumWidth, 3 );
setMetric( Q::Labels | Size, 25 ); // ticks size
setColor( Q::Labels, color4 );
setFontRole( Q::Labels, QskSkin::SmallFont );
}
{
// all SVGs on the header/footer are plain white
QskColorFilter filter;
filter.addColorSubstitution( Qt::white, color3.rgb() );
setGraphicFilter( SkinFactory::Indicator, filter );
}
}
};
class Skin2 : public Skin
{
public:
Skin2()
{
using namespace QskAspect;
const QColor color1( "#011627" ); // Maastricht blue
const QColor color2( "#FF0022" ); // ruddy
const QColor color3( "#41EAD4" ); // Turquoise
const QColor color4( "#FDFFFC" ); // baby powder
const QColor color5( "#B91372" ); // red violet
setColor( QskTextLabel::Text, color4 );
{
using Q = Speedometer;
setBoxBorderMetrics( Q::Panel, 2 );
setGradient( Q::Panel, color1 );
setBoxBorderColors( Q::Panel, color3 );
setBoxBorderMetrics( Q::NeedleHead, 2 );
setMetric( Q::NeedleHead | Size, 15 );
setGradient( Q::NeedleHead,
QskGradient( QskGradient::Diagonal, color2, color1 ) );
// setBoxBorderColors( Q::NeedleHead, color4 );
setMetric( Q::Needle | MinimumWidth, 2 );
setMetric( Q::Needle | Margin, 10 );
setColor( Q::Needle, color2 );
// margins between numbers and ticks:
setMargins( Q::Labels, QskMargins( 4, 4, 4, 4 ) );
setMetric( Q::Labels | MinimumWidth, 2 );
setMetric( Q::Labels | Size, 15 ); // ticks size
setColor( Q::Labels, color4 );
setFontRole( Q::Labels, QskSkin::SmallFont );
}
}
};
}
QStringList SkinFactory::skinNames() const
{
return { "DefaultSkin", "OtherSkin" };
return { "Skin1", "Skin2" };
}
QskSkin* SkinFactory::createSkin( const QString& skinName )
{
if ( skinName == "DefaultSkin" )
return new DefaultSkin( skinName );
if ( skinName == "Skin1" )
return new Skin1();
if ( skinName == "OtherSkin" )
return new OtherSkin( skinName );
if ( skinName == "Skin2" )
return new Skin2();
return nullptr;
}
void SkinFactory::toggleScheme()
{
if ( qskSetup->skinName() == "DefaultSkin" )
static_cast< DefaultSkin* >( qskSetup->skin() )->toggleScheme();
}
void SkinFactory::rotateSkin()
{
const QStringList names = skinNames();
const auto names = skinNames();
int index = names.indexOf( qskSetup->skinName() );
index = ( index + 1 ) % names.size();

View File

@ -15,22 +15,15 @@ class SkinFactory : public QskSkinFactory
public:
enum GraphicRoles
{
// to be visible on a button
Button,
// to be visible on header/footer
Indicator,
// in contrast to the background pixmap
Vehicle
};
QStringList skinNames() const override;
QskSkin* createSkin( const QString& skinName ) override;
QskSkin* createSkin( const QString& ) override;
public Q_SLOTS:
void rotateSkin();
void toggleScheme();
};
#endif

View File

@ -1,424 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "SoundControl.h"
#include "SkinFactory.h"
#include <QskBox.h>
#include <QskGraphic.h>
#include <QskGraphicIO.h>
#include <QskGraphicLabel.h>
#include <QskGridBox.h>
#include <QskLinearBox.h>
#include <QskNamespace.h>
#include <QskPushButton.h>
#include <QskSeparator.h>
#include <QskSlider.h>
#include <QskTextLabel.h>
QSK_SUBCONTROL( SoundControl, Overlay )
QSK_SUBCONTROL( SoundControl, CrossHair )
QSK_SUBCONTROL( SoundControl, Marker )
QSK_SUBCONTROL( SoundControl, MarkerControl )
QSK_SUBCONTROL( SoundControl, Vehicle )
QSK_SUBCONTROL( SoundControl, SliderControl )
class VehicleLabel final : public QskGraphicLabel
{
public:
VehicleLabel( QQuickItem* parentItem = nullptr )
: QskGraphicLabel( parentItem )
{
setGraphic( QskGraphicIO::read( QString( ":/qvg/car.qvg" ) ) );
}
QskAspect::Subcontrol effectiveSubcontrol(
QskAspect::Subcontrol subControl ) const override
{
// so that we can set specific colors in the skin
if ( subControl == QskGraphicLabel::Graphic )
return SoundControl::Vehicle;
return subControl;
}
};
class CrossHairLine final : public QskBox
{
public:
CrossHairLine( QQuickItem* parent )
: QskBox( parent )
{
}
QskAspect::Subcontrol effectiveSubcontrol(
QskAspect::Subcontrol subControl ) const override
{
if ( subControl == QskBox::Panel )
return SoundControl::CrossHair;
return subControl;
}
};
class BalanceFadeMarker final : public QskBox
{
public:
BalanceFadeMarker( QQuickItem* parent )
: QskBox( parent )
{
}
QskAspect::Subcontrol effectiveSubcontrol(
QskAspect::Subcontrol subControl ) const override
{
if ( subControl == QskBox::Panel )
return SoundControl::Marker;
return subControl;
}
};
class MarkerControlButton final : public QskPushButton
{
public:
MarkerControlButton( Qsk::Direction direction, QQuickItem* parentItem = nullptr )
: QskPushButton( parentItem )
, m_direction( direction )
{
const char* svgList[] = { "right", "left", "down", "up" };
const QString fileName = QString( ":/qvg/%1.qvg" ).arg( svgList[ direction ] );
setGraphic( QskGraphicIO::read( fileName ) );
setAutoRepeat( true );
setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
}
QPointF offset() const
{
const qreal off = 5.0;
switch ( m_direction )
{
case Qsk::LeftToRight:
return QPointF( off, 0.0 );
case Qsk::RightToLeft:
return QPointF( -off, 0.0 );
case Qsk::TopToBottom:
return QPointF( 0.0, off );
case Qsk::BottomToTop:
return QPointF( 0.0, -off );
}
return QPointF();
}
QskAspect::Subcontrol effectiveSubcontrol(
QskAspect::Subcontrol subControl ) const override
{
// so that we can set specific colors in the skin
if ( subControl == QskPushButton::Graphic )
return SoundControl::MarkerControl;
return subControl;
}
protected:
QSizeF contentsSizeHint( Qt::SizeHint which, const QSizeF& ) const override
{
if ( which != Qt::PreferredSize )
return QSizeF();
const qreal dim = 100;
if ( m_direction == Qsk::LeftToRight || m_direction == Qsk::RightToLeft )
return QSizeF( 0.5 * dim, dim );
else
return QSizeF( dim, 0.5 * dim );
}
private:
const Qsk::Direction m_direction;
};
class ControlButton final : public QskPushButton
{
public:
ControlButton( const char symbol, QQuickItem* parentItem = nullptr )
: QskPushButton( parentItem )
{
setText( QChar( symbol ) );
setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
setAutoRepeat( true );
}
QskAspect::Subcontrol effectiveSubcontrol(
QskAspect::Subcontrol subControl ) const override
{
if ( subControl == QskPushButton::Panel )
return SoundControl::SliderControl;
return QskPushButton::effectiveSubcontrol( subControl );
}
QSizeF contentsSizeHint( Qt::SizeHint which, const QSizeF& ) const override
{
if ( which == Qt::PreferredSize )
{
qreal h = QskPushButton::contentsSizeHint( which, QSizeF() ).height();
return QSizeF( h, h );
}
return QSizeF();
}
};
class StackedControl final : public QskControl
{
public:
StackedControl( QQuickItem* parent = nullptr )
: QskControl( parent )
, m_offset( 0.0, 0.0 )
{
setPolishOnResize( true ); // we have t re-layout the crosshair
setSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Expanding );
auto horizontalCarRectangle = new CrossHairLine( this );
horizontalCarRectangle->setObjectName( "horizontalBar" );
auto verticalCarRectangle = new CrossHairLine( this );
verticalCarRectangle->setObjectName( "verticalBar" );
( void ) new VehicleLabel( this );
auto marker = new BalanceFadeMarker( this );
marker->setObjectName( "marker" );
}
QPointF offset() const
{
return m_offset;
}
void setOffset( const QPointF& offset )
{
m_offset = offset;
polish();
}
protected:
void updateLayout() override
{
const QRectF cr = contentsRect();
const qreal crossHairSize = 3;
for ( int a = 0; a < children().count(); a++ )
{
auto control = static_cast< QskControl* >( children().at( a ) );
if ( control->objectName() == "verticalBar" )
{
control->setGeometry( cr.center().x(), cr.top(), crossHairSize, cr.height() );
control->setZ( 1 );
}
else if ( control->objectName() == "horizontalBar" )
{
control->setGeometry( cr.left(), cr.center().y(), cr.width(), crossHairSize );
control->setZ( 1 );
}
else if ( control->objectName() == "marker" )
{
qreal size = 31;
control->setPosition(
cr.center() - 0.5 * QPointF( size, size ) + m_offset + QPointF( 1, 1 ) );
control->setSize( QSizeF( size, size ) );
control->setZ( 1 );
}
else
{
control->setGeometry( cr );
}
}
}
private:
QPointF m_offset;
};
class SectionTitleBar final : public QskLinearBox
{
public:
SectionTitleBar( const char* title, QQuickItem* parentItem = nullptr )
: QskLinearBox( Qt::Horizontal, parentItem )
{
setSpacing( 10 );
auto label = new QskTextLabel( title );
label->setSizePolicy( Qt::Horizontal, QskSizePolicy::Fixed );
addItem( new QskSeparator() );
addItem( label );
addItem( new QskSeparator() );
setStretchFactor( 0, 1 );
setStretchFactor( 2, 5 );
setSizePolicy( Qt::Vertical, QskSizePolicy::Fixed );
}
};
class SliderBox final : public QskLinearBox
{
public:
SliderBox( const char* title, qreal min, qreal max, QQuickItem* parentItem = nullptr )
: QskLinearBox( Qt::Vertical, parentItem )
{
auto label = new QskTextLabel( title );
m_numberLabel = new QskTextLabel();
// don't stretch the labels, so that the layout centers them
label->setSizePolicy( Qt::Horizontal, QskSizePolicy::Fixed );
m_numberLabel->setSizePolicy( Qt::Horizontal, QskSizePolicy::Fixed );
auto plusButton = new ControlButton( '+' );
auto minusButton = new ControlButton( '-' );
m_slider = new QskSlider( Qt::Vertical );
m_slider->setMinimum( min );
m_slider->setMaximum( max );
m_slider->setStepSize( 10 );
// layout
addItem( label );
addItem( m_numberLabel );
addItem( plusButton );
addSpacer( 10 );
addItem( m_slider );
addSpacer( 10 );
addItem( minusButton );
setDefaultAlignment( Qt::AlignCenter );
// finally connect buttons/slider/labels
connect( plusButton, &QskPushButton::pressed,
this, [ this ]() { increment( 1 ); } );
connect( minusButton, &QskPushButton::pressed,
this, [ this ]() { increment( -1 ); } );
connect( m_slider, &QskSlider::valueChanged,
this, &SliderBox::setValue );
}
public Q_SLOTS:
void setValue( qreal value )
{
m_slider->setValue( value );
QString txt;
txt.setNum( m_slider->value(), 'f', 1 );
m_numberLabel->setText( txt );
}
private:
void increment( qreal offset )
{
setValue( m_slider->value() + offset );
}
QskTextLabel* m_numberLabel;
QskSlider* m_slider;
};
class ToneControlBox final : public QskLinearBox
{
public:
ToneControlBox( QQuickItem* parentItem = nullptr )
: QskLinearBox( Qt::Horizontal, parentItem )
{
auto bassControl = new SliderBox( "Bass", 0.0, 40.0, this );
auto treebleControl = new SliderBox( "Treeble", 0.0, 40.0, this );
auto subControl = new SliderBox( "Sub", 0.0, 40.0, this );
bassControl->setValue( 30 );
treebleControl->setValue( 11 );
subControl->setValue( 18 );
}
};
class BalanceFadeControlBox final : public QskGridBox
{
public:
BalanceFadeControlBox( QQuickItem* parentItem = nullptr )
: QskGridBox( parentItem )
{
MarkerControlButton* buttons[ 4 ];
for ( int i = 0; i < 4; i++ )
{
auto button = new MarkerControlButton( static_cast< Qsk::Direction >( i ) );
button->setLayoutAlignmentHint( Qt::AlignCenter );
connect( button, &QskPushButton::pressed,
this, [ this, button ]() { shift( button->offset() ); } );
buttons[ i ] = button;
}
m_carControl = new StackedControl();
addItem( buttons[ Qsk::RightToLeft ], 1, 0 );
addItem( buttons[ Qsk::BottomToTop ], 0, 1 );
addItem( buttons[ Qsk::LeftToRight ], 1, 2 );
addItem( buttons[ Qsk::TopToBottom ], 2, 1 );
addItem( m_carControl, 1, 1 );
}
void shift( const QPointF& offset )
{
m_carControl->setOffset( m_carControl->offset() + offset );
}
StackedControl* m_carControl;
};
SoundControl::SoundControl( QQuickItem* parent )
: QskBox( parent )
{
setAutoLayoutChildren( true );
auto layout = new QskGridBox( this );
layout->setMargins( QMarginsF( 40, 20, 40, 20 ) );
layout->setSpacing( Qt::Vertical, 10 );
layout->setSpacing( Qt::Horizontal, 60 );
layout->setColumnStretchFactor( 0, 1 );
layout->setColumnStretchFactor( 1, 3 );
layout->addItem( new SectionTitleBar( "Tone" ), 0, 0 );
layout->addItem( new ToneControlBox(), 1, 0 );
layout->addItem( new SectionTitleBar( "Balance / Fade" ), 0, 1 );
layout->addItem( new BalanceFadeControlBox(), 1, 1 );
}
QskAspect::Subcontrol SoundControl::effectiveSubcontrol(
QskAspect::Subcontrol subControl ) const
{
if ( subControl == QskBox::Panel )
return SoundControl::Overlay;
return subControl;
}

View File

@ -1,22 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#ifndef SOUNDCONTROL_H
#define SOUNDCONTROL_H
#include <QskBox.h>
class SoundControl : public QskBox
{
public:
QSK_SUBCONTROLS( Overlay, CrossHair, Marker, Vehicle, SliderControl, MarkerControl )
SoundControl( QQuickItem* parent = nullptr );
QskAspect::Subcontrol effectiveSubcontrol(
QskAspect::Subcontrol subControl ) const override final;
};
#endif

View File

@ -18,7 +18,7 @@ class Speedometer : public QskBoundedValueInput
Speedometer( QQuickItem* parent = nullptr );
QVector< QString > labels() const;
void setLabels( const QVector< QString >& labels );
void setLabels( const QVector< QString >& );
private:
QVector< QString > m_labels;

View File

@ -4,118 +4,130 @@
*****************************************************************************/
#include "SpeedometerDisplay.h"
#include "Speedometer.h"
#include <QskEvent.h>
#include <QskLinearBox.h>
#include <QskTextLabel.h>
#include <QTime>
#include <QTimer>
#include <QtGlobal>
#include <cstdlib>
namespace
{
class Dial : public Speedometer
{
public:
Dial( const QString& title, QQuickItem* parent = nullptr )
: Speedometer( parent )
{
setPolishOnResize( true );
m_label = new QskTextLabel( title, this );
}
protected:
void updateLayout() override
{
const auto r = layoutRect();
const auto hint = m_label->sizeConstraint();
const qreal y = r.y() + 0.6 * r.height() - 0.5 * hint.height();
const qreal x = r.center().x() - 0.5 * hint.width();
m_label->setGeometry( x, y, hint.width(), hint.height() );
}
private:
QskTextLabel* m_label;
};
class RevCounter : public Dial
{
public:
RevCounter( QQuickItem* parent = nullptr )
: Dial( "x 1000 min^-1", parent )
{
setMinimum( 145 );
setMaximum( 305 );
setValue( 200 );
constexpr int labelsCount = 8;
QVector< QString > labels;
labels.reserve( labelsCount );
for ( int i = 0; i < labelsCount; i++ )
labels += QString::number( i );
setLabels( labels );
}
};
class Speedo : public Dial
{
public:
Speedo( QQuickItem* parent = nullptr )
: Dial( "km/h", parent )
{
setMinimum( -215 );
setMaximum( 35 );
setValue( -90 );
constexpr int labelsCount = 23;
QVector< QString > labels;
labels.reserve( labelsCount );
for ( int i = 0; i < labelsCount; i++ )
labels.append( QString::number( i * 10 ) );
setLabels( labels );
}
void updateValue()
{
setValue( value() + std::rand() % 3 - 0.95 );
}
};
class FuelGauge : public Dial
{
public:
FuelGauge( QQuickItem* parent = nullptr )
: Dial( "fuel", parent )
{
setMinimum( 195 );
setMaximum( 345 );
setValue( 330 );
setLabels( { "0", "", "1/2", "", "1/1" } );
}
void updateValue()
{
setValue( 0.99997 * value() );
}
};
}
SpeedometerDisplay::SpeedometerDisplay( QQuickItem* parent )
: QskControl( parent )
, m_box( new QskLinearBox( Qt::Horizontal, this ) )
, m_revCounter( new Speedometer( m_box ) )
, m_revCounterText( new QskTextLabel( QStringLiteral( "x 1000 min^-1" ), m_revCounter ) )
, m_speedometer( new Speedometer( m_box ) )
, m_speedometerText( new QskTextLabel( QStringLiteral( "km/h" ), m_speedometer ) )
, m_fuelGauge( new Speedometer( m_box ) )
, m_fuelGaugeText( new QskTextLabel( QStringLiteral( "fuel" ), m_fuelGauge ) )
: QskLinearBox( Qt::Horizontal, parent )
{
std::srand( static_cast< uint >( QTime::currentTime().msec() ) );
setPolishOnResize( true );
m_box->setAutoAddChildren( true );
m_box->setAutoLayoutChildren( true );
m_box->setSpacing( 20 );
m_revCounter->setObjectName( QStringLiteral( "RevCounter" ) );
m_revCounter->setMinimum( 145 );
m_revCounter->setMaximum( 305 );
m_revCounter->setValue( 200 );
QVector< QString > revCounterLabels;
int numberLabels = 8;
revCounterLabels.reserve( numberLabels );
for ( int i = 0; i < numberLabels; ++i )
{
revCounterLabels.append( QString::number( i ) );
}
m_revCounter->setLabels( revCounterLabels );
m_speedometer->setObjectName( QStringLiteral( "Speedometer" ) );
m_speedometer->setMinimum( -215 );
m_speedometer->setMaximum( 35 );
m_speedometer->setValue( -90 );
QVector< QString > speedometerLabels;
numberLabels = 23;
speedometerLabels.reserve( numberLabels );
for ( int i = 0; i < numberLabels; ++i )
{
speedometerLabels.append( QString::number( i * 10 ) );
}
m_speedometer->setLabels( speedometerLabels );
(void ) new RevCounter( this );
auto speedometer = new Speedo( this );
auto fuelGauge = new FuelGauge( this );
setMargins( 10 );
setSpacing( 10 );
auto timer = new QTimer( this );
connect( timer, &QTimer::timeout, this, [ this ]()
{
auto speedometerValue = m_speedometer->value() + std::rand() % 3 - 0.95;
m_speedometer->setValue( speedometerValue );
auto fuelGaugeValue = 0.99997 * m_fuelGauge->value();
m_fuelGauge->setValue( fuelGaugeValue );
});
connect( timer, &QTimer::timeout, speedometer, &Speedo::updateValue );
connect( timer, &QTimer::timeout, fuelGauge, &FuelGauge::updateValue );
timer->setInterval( 16 );
timer->start();
m_fuelGauge->setObjectName( QStringLiteral( "Fuel Gauge" ) );
m_fuelGauge->setMinimum( 195 );
m_fuelGauge->setMaximum( 345 );
m_fuelGauge->setValue( 330 );
QVector< QString > fuelGaugeLabels;
fuelGaugeLabels.append( { "0", "", "1/2", "", "1/1" } );
m_fuelGauge->setLabels( fuelGaugeLabels );
m_revCounterText->setMargins( 50 );
m_speedometerText->setMargins( 50 );
m_fuelGaugeText->setMargins( 50 );
}
void SpeedometerDisplay::updateLayout()
{
auto radius = qMin( 0.33 * size().width(), size().height() );
auto x = ( width() - radius * 2.7 - 2 * m_box->spacing() ) / 2;
auto y = ( height() - radius ) / 2;
m_box->setPosition( { x, y } );
m_revCounter->setFixedSize( radius, radius );
QSizeF hint = m_revCounterText->sizeHint();
x = ( radius - hint.width() ) / 2;
y = ( ( radius - hint.height() ) / 2 ) + m_revCounterText->margins().top();
m_revCounterText->setGeometry( x, y, hint.width(), hint.height() );
m_speedometer->setFixedSize( radius, radius );
hint = m_speedometerText->sizeHint();
x = ( radius - hint.width() ) / 2;
y = ( ( radius - hint.height() ) / 2 ) + m_speedometerText->margins().top();
m_speedometerText->setGeometry( x, y, hint.width(), hint.height() );
m_fuelGauge->setFixedSize( 0.7 * radius, 0.7 * radius );
hint = m_fuelGaugeText->sizeHint();
x = ( 0.7 * radius - hint.width() ) / 2;
y = ( ( 0.7 * radius - hint.height() ) / 2 ) + m_fuelGaugeText->margins().top();
m_fuelGaugeText->setGeometry( x, y, hint.width(), hint.height() );
}

View File

@ -6,28 +6,12 @@
#ifndef SPEEDOMETERDISPLAY_H
#define SPEEDOMETERDISPLAY_H
#include <QskControl.h>
#include <QskLinearBox.h>
class QskLinearBox;
class QskTextLabel;
class Speedometer;
class SpeedometerDisplay : public QskControl
class SpeedometerDisplay : public QskLinearBox
{
public:
SpeedometerDisplay( QQuickItem* parent = nullptr );
protected:
void updateLayout() override;
private:
QskLinearBox* m_box;
Speedometer* m_revCounter;
QskTextLabel* m_revCounterText;
Speedometer* m_speedometer;
QskTextLabel* m_speedometerText;
Speedometer* m_fuelGauge;
QskTextLabel* m_fuelGaugeText;
};
#endif

View File

@ -60,7 +60,12 @@ SpeedometerSkinlet::~SpeedometerSkinlet() = default;
QRectF SpeedometerSkinlet::subControlRect( const QskSkinnable*,
const QRectF& contentsRect, QskAspect::Subcontrol ) const
{
return contentsRect;
const auto extent = qMin( contentsRect.width(), contentsRect.height() );
QRectF r( 0.0, 0.0, extent, extent );
r.moveCenter( contentsRect.center() );
return r;
}
QSGNode* SpeedometerSkinlet::updateSubNode(

View File

@ -2,10 +2,7 @@ CONFIG += qskexample qskqvg
HEADERS += \
ButtonBar.h \
SoundControl.h \
SkinFactory.h \
DefaultSkin.h \
OtherSkin.h \
MainWindow.h \
Speedometer.h \
SpeedometerSkinlet.h \
@ -13,15 +10,12 @@ HEADERS += \
SOURCES += \
ButtonBar.cpp \
SoundControl.cpp \
SkinFactory.cpp \
DefaultSkin.cpp \
OtherSkin.cpp \
MainWindow.cpp \
main.cpp \
Speedometer.cpp \
SpeedometerSkinlet.cpp \
SpeedometerDisplay.cpp
SpeedometerDisplay.cpp \
main.cpp \
RESOURCES += \
images.qrc \

View File

@ -6,56 +6,33 @@
#include "MainWindow.h"
#include "SkinFactory.h"
#include <SkinnyShortcut.h>
#include <SkinnyFont.h>
#include <QskSetup.h>
#include <QskShortcutMap.h>
#include <QskSkinManager.h>
#include <SkinnyShortcut.h>
#include <QGuiApplication>
#include <iostream>
using namespace std;
int main( int argc, char** argv )
{
auto skinFactory = new SkinFactory();
qskSkinManager->setPluginPaths( QStringList() ); // no plugins
qskSkinManager->registerFactory(
QStringLiteral( "SampleSkinFactory" ), skinFactory );
qskSkinManager->setPluginPaths( QStringList() ); // no skin plugins
qskSkinManager->registerFactory( QStringLiteral( "sample" ), new SkinFactory() );
QGuiApplication app( argc, argv );
/*
When going over QPainter for the SVGs we prefer the raster paint
engine, simply showing better results. Interestingly the OpenGL paint
engine was even slower for the use case of non-complex SVGs.
Looks like its tesselation is not much faster than "pixeling"
those images directly.
engine, simply showing better results.
*/
qskSetup->setControlFlag( QskSetup::PreferRasterForTextures, true );
// Starting with a simple skin made for this example
// CTRL-S allow to rotate through the registered skins and CTRL-T
// changes the colors, when the DefaultSkin is active.
SkinnyFont::init( &app );
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
qskSetup->setSkin( QStringLiteral( "DefaultSkin" ) );
cout << "CTRL-S to change the skin." << endl;
cout << "CTRL-T to change the color scheme, when the \"Default\" skin is active." << endl;
QskShortcutMap::addShortcut( QKeySequence( Qt::CTRL | Qt::Key_T ),
false, skinFactory, &SkinFactory::toggleScheme );
QskShortcutMap::addShortcut( QKeySequence( Qt::CTRL | Qt::Key_S ),
false, skinFactory, &SkinFactory::rotateSkin );
// With CTRL-B you can rotate a couple of visual debug modes
SkinnyShortcut::enable( SkinnyShortcut::DebugBackground |
SkinnyShortcut::DebugStatistics | SkinnyShortcut::Quit );
MainWindow mainWindow;
mainWindow.show();
MainWindow window;
window.show();
return app.exec();
}