added leveling sensor playground

This commit is contained in:
Vogel, Rick 2023-07-17 12:50:36 +02:00
parent 0f452813ff
commit 87b304e0c5
7 changed files with 497 additions and 0 deletions

View File

@ -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)

View File

@ -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})

View File

@ -0,0 +1,125 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include <QskTextLabel.h>
#include <QTimer>
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();
}

View File

@ -0,0 +1,16 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskWindow.h>
class QQuickItem;
class MainWindow : public QskWindow
{
public:
MainWindow();
};

View File

@ -0,0 +1,168 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "SkinFactory.h"
#include <QskBoxBorderColors.h>
#include <QskGradient.h>
#include <QskGradientStop.h>
#include <QskPlatform.h>
#include <QskRgbValue.h>
#include <QskSkin.h>
#include <QskSkinHintTableEditor.h>
#include <QskTextLabel.h>
#include <LevelingSensor/QskLevelingSensor.h>
#include <LevelingSensor/QskLevelingSensorSkinlet.h>
#include <QskSlider.h>
#include <QskSliderSkinlet.h>
#include <QskTextLabel.h>
#include <QskTextLabelSkinlet.h>
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"

View File

@ -0,0 +1,17 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskSkinFactory.h>
class SkinFactory : public QskSkinFactory
{
Q_OBJECT
public:
QStringList skinNames() const override;
QskSkin* createSkin( const QString& ) override;
};

View File

@ -0,0 +1,159 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "SkinFactory.h"
#include <SkinnyShortcut.h>
#include <QskObjectCounter.h>
#include <QskSkinManager.h>
#include <QskWindow.h>
#include <LevelingSensor/QskLevelingSensor.h>
#include <QskIntervalF.h>
#include <QskLinearBox.h>
#include <QskSlider.h>
#include <QskTextLabel.h>
#include <QGuiApplication>
#include <QQuickWindow>
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<QskIntervalF(qreal)> intervalA, std::function<QskIntervalF(qreal)> 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();
}