diff --git a/playground/CMakeLists.txt b/playground/CMakeLists.txt index 7fc3449a..3b997bf1 100644 --- a/playground/CMakeLists.txt +++ b/playground/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(invoker) add_subdirectory(shadows) add_subdirectory(shapes) add_subdirectory(charts) +add_subdirectory(levelingsensor) if (BUILD_INPUTCONTEXT) add_subdirectory(inputpanel) diff --git a/playground/levelingsensor/CMakeLists.txt b/playground/levelingsensor/CMakeLists.txt new file mode 100644 index 00000000..b397f548 --- /dev/null +++ b/playground/levelingsensor/CMakeLists.txt @@ -0,0 +1,11 @@ +############################################################################ +# QSkinny - Copyright (C) 2016 Uwe Rathmann +# SPDX-License-Identifier: BSD-3-Clause +############################################################################ + +set(SOURCES + SkinFactory.h SkinFactory.cpp + main.cpp +) + +qsk_add_example(levelingsensor ${SOURCES}) diff --git a/playground/levelingsensor/Dashboard.cpp b/playground/levelingsensor/Dashboard.cpp new file mode 100644 index 00000000..5d960dff --- /dev/null +++ b/playground/levelingsensor/Dashboard.cpp @@ -0,0 +1,125 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include + +#include + +namespace +{ + class DashboardDial : public Dial + { + public: + DashboardDial( const QString& title, QQuickItem* parent = nullptr ) + : Dial( 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 DashboardDial + { + public: + RevCounter( QQuickItem* parent = nullptr ) + : DashboardDial( "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 ); + + setTickLabels( labels ); + } + }; + + class SpeedoMeter : public DashboardDial + { + public: + SpeedoMeter( QQuickItem* parent = nullptr ) + : DashboardDial( "km/h", parent ) + { + setMinimum( -215 ); + setMaximum( 35 ); + setValue( -90 ); + + constexpr int labelsCount = 17; + + QVector< QString > labels; + labels.reserve( labelsCount ); + + for ( int i = 0; i < labelsCount; i++ ) + labels.append( QString::number( i * 10 ) ); + + setTickLabels( labels ); + } + + void updateValue() + { + setValue( value() + std::rand() % 3 - 0.95 ); + } + }; + + class FuelGauge : public DashboardDial + { + public: + FuelGauge( QQuickItem* parent = nullptr ) + : DashboardDial( "fuel", parent ) + { + setMinimum( 195 ); + setMaximum( 345 ); + setValue( 330 ); + + setTickLabels( { "0", "", "1/2", "", "1/1" } ); + } + + void updateValue() + { + setValue( 0.99997 * value() ); + } + }; +} + +Dashboard::Dashboard( QQuickItem* parent ) + : QskLinearBox( Qt::Horizontal, parent ) +{ + (void ) new RevCounter( this ); + auto speedometer = new SpeedoMeter( this ); + auto fuelGauge = new FuelGauge( this ); + + setMargins( 10 ); + setSpacing( 10 ); + + auto timer = new QTimer( this ); + + connect( timer, &QTimer::timeout, speedometer, &SpeedoMeter::updateValue ); + connect( timer, &QTimer::timeout, fuelGauge, &FuelGauge::updateValue ); + + timer->setInterval( 16 ); + timer->start(); +} diff --git a/playground/levelingsensor/MainWindow.h b/playground/levelingsensor/MainWindow.h new file mode 100644 index 00000000..f45b6733 --- /dev/null +++ b/playground/levelingsensor/MainWindow.h @@ -0,0 +1,16 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#pragma once + +#include + +class QQuickItem; + +class MainWindow : public QskWindow +{ + public: + MainWindow(); +}; diff --git a/playground/levelingsensor/SkinFactory.cpp b/playground/levelingsensor/SkinFactory.cpp new file mode 100644 index 00000000..894574f6 --- /dev/null +++ b/playground/levelingsensor/SkinFactory.cpp @@ -0,0 +1,168 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "SkinFactory.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +namespace +{ + class Skin : public QskSkin + { + template< typename T > + void style( QskSkinHintTableEditor& editor ); + + template< typename Skinnable, typename Skinlet > + void declareSkinlet( ) + { + QskSkin::declareSkinlet< Skinnable, Skinlet >(); + } + + template< typename Skinnable, typename Skinlet > + void declareSkinlet( QskSkinHintTableEditor& editor ) + { + QskSkin::declareSkinlet< Skinnable, Skinlet >(); + style< Skinnable >( editor ); + } + + template<> + void style< QskSlider >( QskSkinHintTableEditor& editor ) + { + using A = QskAspect; + using Q = QskSlider; + + const qreal extent = 40; + + // Panel + + for ( auto variation : { A::Horizontal, A::Vertical } ) + { + const auto aspect = Q::Panel | variation; + + editor.setMetric( aspect | A::Size, extent ); + editor.setBoxBorderMetrics( aspect, 0 ); + editor.setBoxShape( aspect, 0 ); + editor.setGradient( aspect, QskGradient() ); + } + + // Groove, Fill + + for ( auto variation : { A::Horizontal, A::Vertical } ) + { + for ( auto subControl : { Q::Groove, Q::Fill } ) + { + const auto aspect = subControl | variation; + + editor.setMetric( aspect | A::Size, 0.3 * extent ); + + editor.setBoxBorderMetrics( aspect, 0 ); + editor.setBoxShape( aspect, 0.1 * extent ); + } + + editor.setGradient( Q::Groove | variation, Qt::lightGray ); + editor.setGradient( Q::Fill | variation, Qt::darkGray ); + } + + // Handle + + for ( auto variation : { A::Horizontal, A::Vertical } ) + { + const auto aspect = Q::Handle | variation; + editor.setColor( aspect, Qt::black ); + + editor.setBoxShape( aspect, 20.0, Qt::RelativeSize ); + + const qreal sz = 0.75 * extent; + editor.setStrutSize( aspect, sz, sz ); + } + } + + template<> + void style< QskLevelingSensor >( QskSkinHintTableEditor& ed ) + { + using Q = QskLevelingSensor; + + static constexpr auto r1 = 0.9; + static constexpr auto r2 = 1.0; + + QskGradient gradient{ { + { 0.5, Qt::lightGray }, + { 0.5, Qt::lightGray }, + { 0.5, Qt::darkGray }, + { 1.0, Qt::darkGray }, + } }; + gradient.setLinearDirection( Qt::Vertical ); + + ed.setColor( Q::Background, "dimgray" ); + + ed.setStrutSize( Q::OuterDisk, { r2, r2 } ); + ed.setColor( Q::OuterDisk, Qt::white ); + + ed.setGradient( Q::Horizon, gradient ); + ed.setStrutSize( Q::Horizon, { r1, r1 } ); + + ed.setColor( Q::TickmarksX, Qt::black ); + ed.setStrutSize( Q::TickmarksX, { r1, 0.2 } ); // w %, h % + ed.setHint( Q::TickmarksX, QVector3D{ 0.50, 0.75, 1.0 } ); // % + + ed.setStrutSize( Q::TickmarksXLabels, { r1, 0.15 } ); // w %, h % + ed.setAlignment( Q::TickmarksXLabels, Qt::AlignTop | Qt::AlignHCenter ); + + ed.setColor( Q::TickmarksY, Qt::black ); + ed.setStrutSize( Q::TickmarksY, { 0.1, r1 } ); // w %, h % + ed.setHint( Q::TickmarksY, QVector3D{ 0.50, 0.75, 1.00 } ); // % + + ed.setStrutSize( Q::TickmarksYLabels, { 0.15, r1 } ); // w %, h % + ed.setAlignment( Q::TickmarksYLabels, Qt::AlignCenter ); + + ed.setColor( Q::TickmarksZ, "silver" ); + ed.setStrutSize( Q::TickmarksZ, { 0.90, 0.95 } ); + ed.setHint( Q::TickmarksZ, QVector3D{ 0.50, 0.75, 1.00 } ); // % + + ed.setStrutSize( Q::TickmarksZLabels, { 0.9, 0.0 } ); // r1 %, r2 % + ed.setAlignment( Q::TickmarksZLabels, Qt::AlignCenter ); + } + + public: + Skin() + { + QskSkinHintTableEditor editor( &hintTable() ); + declareSkinlet< QskSlider, QskSliderSkinlet >( editor ); + declareSkinlet< QskTextLabel, QskTextLabelSkinlet >(); + declareSkinlet< QskLevelingSensor, QskLevelingSensorSkinlet >( editor ); + } + }; +} + +QStringList SkinFactory::skinNames() const +{ + return { "Skin" }; +} + +QskSkin* SkinFactory::createSkin( const QString& skinName ) +{ + if ( skinName == "Skin" ) + return new Skin(); + + return nullptr; +} + +#include "moc_SkinFactory.cpp" diff --git a/playground/levelingsensor/SkinFactory.h b/playground/levelingsensor/SkinFactory.h new file mode 100644 index 00000000..6bb0f2fa --- /dev/null +++ b/playground/levelingsensor/SkinFactory.h @@ -0,0 +1,17 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#pragma once + +#include + +class SkinFactory : public QskSkinFactory +{ + Q_OBJECT + + public: + QStringList skinNames() const override; + QskSkin* createSkin( const QString& ) override; +}; diff --git a/playground/levelingsensor/main.cpp b/playground/levelingsensor/main.cpp new file mode 100644 index 00000000..694b1c40 --- /dev/null +++ b/playground/levelingsensor/main.cpp @@ -0,0 +1,159 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "SkinFactory.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace +{ + void updateTickmarks( const Qt::Axis axis, const QskIntervalF& intervalA, + const QskIntervalF& intervalB, QskLevelingSensor* const sensor ) + { + QskScaleTickmarks tickmarks; + QVector< qreal > major; + QVector< qreal > medium; + QVector< qreal > minor; + + for ( const auto& interval : { intervalA, intervalB } ) + { + for ( int deg = ( int ) interval.lowerBound(); deg < ( int ) interval.upperBound(); + ++deg ) + { + if ( deg % 45 == 0 ) + { + major << deg; + } + if ( deg % 45 != 0 && deg % 5 == 0 ) + { + medium << deg; + } + if ( deg % 45 != 0 && deg % 5 != 0 ) + { + minor << deg; + } + } + } + + tickmarks.setMajorTicks( major ); + tickmarks.setMediumTicks( medium ); + tickmarks.setMinorTicks( minor ); + sensor->setTickmarks( axis, tickmarks ); + } + + void updateTickmarksLabels( const Qt::Axis axis, const QskIntervalF& intervalA, + const QskIntervalF& intervalB, int step, QskLevelingSensor* const sensor ) + { + QskLevelingSensor::TickmarksLabels labels; + for ( const auto& interval : { intervalA, intervalB } ) + { + for ( int deg = ( ( int ) interval.lowerBound() / step ) * step; + deg < ( int ) interval.upperBound(); deg += step ) + { + labels << QskLevelingSensor::TickmarksLabels::value_type{ ( float ) deg, + QString( deg > 0 ? "+" : "" ) + QString::number( deg ) }; + } + } + sensor->setTickmarksLabels( axis, labels ); + } + + Q_REQUIRED_RESULT QskSlider* makeTickmarksSlider( const Qt::Axis axis, QskLevelingSensor* const sensor, int min, int max, std::function intervalA, std::function intervalB, QQuickItem* const parent = nullptr ) + { + auto* const slider = new QskSlider( Qt::Horizontal, parent ); + slider->setMinimum( min ); + slider->setMaximum( max ); + + QObject::connect(slider, &QskSlider::valueChanged, sensor, [ = ]( const qreal degree ) { + updateTickmarks( axis, intervalA(degree), intervalB(degree), sensor ); + updateTickmarksLabels( axis, intervalA( degree ), intervalB( degree ), 10, sensor ); + } ); + + return slider; + } + + Q_REQUIRED_RESULT QskSlider* makeRotationSlider( + const Qt::Axis axis, QskLevelingSensor* const sensor, QQuickItem* const parent = nullptr ) + { + auto* const slider = new QskSlider( Qt::Horizontal, parent ); + slider->setMinimum( -360 ); + slider->setMaximum( +360 ); + + QObject::connect( sensor, &QskLevelingSensor::rotationChanged, slider, + [ slider, axis ]( const QVector3D& degree ) { slider->setValue( degree[ axis ] ); } ); + + QObject::connect( slider, &QskSlider::valueChanged, sensor, + [ sensor, axis ]( const qreal degree ) { sensor->setRotation( axis, degree ); } ); + + return slider; + } + + class Window : public QskWindow + { + public: + Window() + { + auto* const root = new QskLinearBox( Qt::Horizontal, contentItem() ); + auto* const left = new QskLinearBox( Qt::Vertical, root ); + auto* const right = new QskLinearBox( Qt::Vertical, root ); + auto* const sensor = new QskLevelingSensor( left ); + + auto linearIntervalA = [](const qreal degree)->QskIntervalF{ return {-degree, +degree};}; + auto linearIntervalB = [](const qreal degree)->QskIntervalF{ return {}; }; + + auto radialIntervalA = [](const qreal degree)->QskIntervalF{ return {-degree, +degree};}; + auto radialIntervalB = [](const qreal degree)->QskIntervalF{ return {180-degree, 180+degree};}; + + ( void ) new QskTextLabel( "Tickmarks X", right ); + auto* const sliderTickmarksX = makeTickmarksSlider( Qt::XAxis, sensor, 0, 90, linearIntervalA, linearIntervalB, right ); + ( void ) new QskTextLabel( "Tickmarks Y", right ); + auto* const sliderTickmarksY = makeTickmarksSlider( Qt::YAxis, sensor, 0, 90, linearIntervalA, linearIntervalB, right ); + ( void ) new QskTextLabel( "Tickmarks Z", right ); + auto* const sliderTickmarksZ = makeTickmarksSlider( Qt::ZAxis, sensor, 0, 90, radialIntervalA, radialIntervalB, right ); + + ( void ) new QskTextLabel( "Rotation X", right ); + ( void ) makeRotationSlider( Qt::XAxis, sensor, right ); + ( void ) new QskTextLabel( "Rotation Y", right ); + ( void ) makeRotationSlider( Qt::YAxis, sensor, right ); + ( void ) new QskTextLabel( "Rotation Z", right ); + ( void ) makeRotationSlider( Qt::ZAxis, sensor, right ); + + sliderTickmarksX->setValue(15); + sliderTickmarksY->setValue(15); + sliderTickmarksZ->setValue(30); + } + }; +} + +int main( int argc, char** argv ) +{ +#ifdef ITEM_STATISTICS + QskObjectCounter counter( true ); +#endif + + qskSkinManager->setPluginPaths( QStringList() ); // no skin plugins + qskSkinManager->registerFactory( QStringLiteral( "sample" ), new SkinFactory() ); + + QGuiApplication app( argc, argv ); + + SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); + + Window window; + window.showMaximized(); + + return app.exec(); +}