From 8f6b83be8e43859627eae6b69e27d5969d1f1c40 Mon Sep 17 00:00:00 2001 From: "Vogel, Rick" Date: Tue, 8 Aug 2023 15:06:09 +0200 Subject: [PATCH 1/3] radial tickmarks node initial commit --- playground/CMakeLists.txt | 1 + playground/nodes/CMakeLists.txt | 12 ++ playground/nodes/RadialNodes.cpp | 17 ++ playground/nodes/RadialNodes.h | 10 + playground/nodes/RadialNodesSkinlet.cpp | 244 ++++++++++++++++++++++++ playground/nodes/RadialNodesSkinlet.h | 22 +++ playground/nodes/main.cpp | 83 ++++++++ 7 files changed, 389 insertions(+) create mode 100644 playground/nodes/CMakeLists.txt create mode 100644 playground/nodes/RadialNodes.cpp create mode 100644 playground/nodes/RadialNodes.h create mode 100644 playground/nodes/RadialNodesSkinlet.cpp create mode 100644 playground/nodes/RadialNodesSkinlet.h create mode 100644 playground/nodes/main.cpp diff --git a/playground/CMakeLists.txt b/playground/CMakeLists.txt index 7fc3449a..19ac9d4e 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(nodes) if (BUILD_INPUTCONTEXT) add_subdirectory(inputpanel) diff --git a/playground/nodes/CMakeLists.txt b/playground/nodes/CMakeLists.txt new file mode 100644 index 00000000..9583d592 --- /dev/null +++ b/playground/nodes/CMakeLists.txt @@ -0,0 +1,12 @@ +############################################################################ +# QSkinny - Copyright (C) 2016 Uwe Rathmann +# SPDX-License-Identifier: BSD-3-Clause +############################################################################ + +qsk_add_example(nodes + main.cpp + RadialNodes.h + RadialNodes.cpp + RadialNodesSkinlet.h + RadialNodesSkinlet.cpp +) diff --git a/playground/nodes/RadialNodes.cpp b/playground/nodes/RadialNodes.cpp new file mode 100644 index 00000000..bc711741 --- /dev/null +++ b/playground/nodes/RadialNodes.cpp @@ -0,0 +1,17 @@ +#include "RadialNodes.h" + +QSK_SUBCONTROL(RadialNodes, Foreground) +QSK_SUBCONTROL(RadialNodes, Text) +QSK_SUBCONTROL(RadialNodes, Lines) + +RadialNodes::RadialNodes( QQuickItem* const parent ) : QskControl( parent ) +{ + // TODO move into your skin + setColor(Background, Qt::lightGray); + setColor(Foreground, Qt::black); + setColor(Text, Qt::white); + setColor(Lines, Qt::red); + setStrutSizeHint( Lines, 2, 10 ); +} + +#include "moc_RadialNodes.cpp" \ No newline at end of file diff --git a/playground/nodes/RadialNodes.h b/playground/nodes/RadialNodes.h new file mode 100644 index 00000000..11741a35 --- /dev/null +++ b/playground/nodes/RadialNodes.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +class RadialNodes : public QskControl +{ +public: + QSK_SUBCONTROLS(Foreground, Text, Lines) + explicit RadialNodes( QQuickItem* parent = nullptr ); +}; \ No newline at end of file diff --git a/playground/nodes/RadialNodesSkinlet.cpp b/playground/nodes/RadialNodesSkinlet.cpp new file mode 100644 index 00000000..c84e261b --- /dev/null +++ b/playground/nodes/RadialNodesSkinlet.cpp @@ -0,0 +1,244 @@ +#include "RadialNodesSkinlet.h" +#include "RadialNodes.h" + +#include +#include +#include + +#include +#include +#include + +namespace +{ + template< typename T > + Q_REQUIRED_RESULT inline bool compareExchange( T& dst, const T& src ) + { + if ( dst != src ) + { + dst = src; + return true; + } + return false; + } + + template<> + Q_REQUIRED_RESULT inline bool compareExchange< float >( float& dst, const float& src ) + { + if ( !qskFuzzyCompare( dst, src ) ) + { + dst = src; + return true; + } + return false; + } + + template<> + Q_REQUIRED_RESULT inline bool compareExchange< qreal >( qreal& dst, const qreal& src ) + { + if ( !qskFuzzyCompare( dst, src ) ) + { + dst = src; + return true; + } + return false; + } + + class QskRadialTickmarksNode final : public QSGGeometryNode + { + public: + QskRadialTickmarksNode() + : m_geometry( QSGGeometry::defaultAttributes_Point2D(), 0 ) + { + m_geometry.setDrawingMode( QSGGeometry::DrawLines ); + m_geometry.setVertexDataPattern( QSGGeometry::StaticPattern ); + + setGeometry( &m_geometry ); + setMaterial( &m_material ); + } + + void setMaterialProperties( const QColor& color ) + { + if ( m_material.color() != color ) + { + m_material.setColor( color ); + markDirty( QSGNode::DirtyMaterial ); + } + } + + void setGeometryProperties( const QskScaleTickmarks& tickmarks, + const QVector2D& r1 = { 1.0f, 1.0f }, const QVector3D& height = { 1.0f, 1.0f, 1.0f }, + const QVector2D& center = {}, Qt::Alignment alignment = Qt::AlignVCenter, + float lineWidth = 1.0 ) + { + auto dirty = false; + + if ( dirty |= ( m_geometry.lineWidth() != lineWidth ) ) + { + m_geometry.setLineWidth( lineWidth ); + } + + dirty |= compareExchange( m_radius, r1 ); + dirty |= compareExchange( m_height, height ); + dirty |= compareExchange( m_center, center ); + dirty |= compareExchange( m_alignment, alignment ); + dirty |= compareExchange( m_tickmarksHash, tickmarks.hash() ); + + if ( dirty ) + { + update( tickmarks ); + } + } + + private: + void update( const QskScaleTickmarks& tickmarks ) + { + using T = QskScaleTickmarks::TickType; + + if ( m_geometry.vertexCount() != tickmarks.tickCount() ) + { + m_geometry.allocate( tickmarks.tickCount() * 2 ); + } + + QVector2D r1[ 3 ]; + QVector2D r2[ 3 ]; + + if ( m_alignment.testFlag( Qt::AlignBottom ) || m_alignment.testFlag( Qt::AlignLeft )) + { + for ( int i : { T::MinorTick, T::MediumTick, T::MajorTick } ) + { + r1[ i ] = m_radius; + r2[ i ] = m_radius.normalized() * ( m_radius.length() + m_height[ i ] ); + } + } + else if ( m_alignment.testFlag( Qt::AlignTop ) || m_alignment.testFlag( Qt::AlignRight )) + { + for ( int i : { T::MinorTick, T::MediumTick, T::MajorTick } ) + { + r1[ i ] = m_radius.normalized() * ( m_radius.length() - m_height[ i ] ); + r2[ i ] = m_radius; + } + } + else + { + for ( int i : { T::MinorTick, T::MediumTick, T::MajorTick } ) + { + r1[ i ] = m_radius.normalized() * ( m_radius.length() - m_height[ i ] / 2 ); + r2[ i ] = m_radius.normalized() * ( m_radius.length() + m_height[ i ] / 2 ); + } + } + + auto* vertexData = m_geometry.vertexDataAsPoint2D(); + + for ( auto type : { T::MinorTick, T::MediumTick, T::MajorTick } ) + { + for ( const auto tick : tickmarks.ticks( type ) ) + { + const auto i = static_cast< int >( type ); + const auto rad = qDegreesToRadians( tick ); + + const auto p1 = + r1[ i ] * QVector2D{ ( float ) qFastCos( rad ), ( float ) qFastSin( rad ) }; + + const auto p2 = + r2[ i ] * QVector2D{ ( float ) qFastCos( rad ), ( float ) qFastSin( rad ) }; + + vertexData[ 0 ].set( p1.x() + m_center.x(), p1.y() + m_center.y() ); + vertexData[ 1 ].set( p2.x() + m_center.x(), p2.y() + m_center.y() ); + vertexData += 2; + } + } + + m_geometry.markVertexDataDirty(); + markDirty( QSGNode::DirtyGeometry ); + } + + QSGGeometry m_geometry; + QSGFlatColorMaterial m_material; + + QVector2D m_radius = { 1.0f, 1.0f }; + QVector2D m_center = { 0.0f, 0.0f }; + QVector3D m_height = { 1.0f, 1.0f, 1.0f }; + Qt::Alignment m_alignment = Qt::AlignVCenter; + QskHashValue m_tickmarksHash{ 0 }; + }; +} + +RadialNodesSkinlet::RadialNodesSkinlet( QskSkin* const skin ) + : QskSkinlet( skin ) +{ + setNodeRoles( { Lines } ); +} + +QRectF RadialNodesSkinlet::subControlRect( const QskSkinnable* const skinnable, + const QRectF& contentsRect, const QskAspect::Subcontrol subControl ) const +{ + if ( subControl == RadialNodes::Text ) + { + return contentsRect.adjusted( +20, +20, -20, -20 ); + } + else if ( subControl == RadialNodes::Foreground ) + { + return contentsRect.adjusted( +10, +10, -10, -10 ); + } + else if ( subControl == RadialNodes::Lines ) + { + return contentsRect; + } + return QskSkinlet::subControlRect( skinnable, contentsRect, subControl ); +} + +QSGNode* RadialNodesSkinlet::updateSubNode( + const QskSkinnable* const skinnable, const quint8 nodeRole, QSGNode* const node ) const +{ + using Q = RadialNodes; + + switch ( static_cast< NodeRole >( nodeRole ) ) + { + case Text: + return updateTextNode( skinnable, node, "RadialNodes", RadialNodes::Text ); + case Foreground: + return updateBoxNode( skinnable, node, RadialNodes::Foreground ); + case Lines: { + const auto* const control = static_cast< const Q* >( skinnable ); + + QskScaleTickmarks tickmarks; + QVector< qreal > major, medium, minor; + for ( int deg = 0; deg < 360; deg += 1 ) + { + if ( deg % 10 == 0 ) + major << deg; + else if ( deg % 5 == 0 ) + medium << deg; + else + minor << deg; + } + tickmarks.setMajorTicks( major ); + tickmarks.setMediumTicks( medium ); + tickmarks.setMinorTicks( minor ); + + const auto subControlRect = control->subControlContentsRect( Q::Lines ); + const auto alignment = control->alignmentHint( Q::Lines ); + const auto size = control->strutSizeHint( Q::Lines ); + + const auto rX = static_cast< float >( subControlRect.width() / 2 ); + const auto rY = static_cast< float >( subControlRect.height() / 2 ); + const auto radius = QVector2D{ rX, rY }; + const auto height = + QVector3D{ + ( float ) size.height() * 0.50f, + ( float ) size.height() * 0.75f, ( float ) size.height() * 1.0f }; + const auto c = QVector2D{ ( float ) subControlRect.center().x(), + ( float ) subControlRect.center().y() }; + + auto* const root = QskSGNode::ensureNode< QskRadialTickmarksNode >( node ); + root->setMaterialProperties( skinnable->color( Q::Lines ) ); + root->setGeometryProperties( tickmarks, radius, height, c, alignment, size.width() ); + return root; + } + default: + return QskSkinlet::updateSubNode( skinnable, nodeRole, node ); + } +} + +#include "moc_RadialNodesSkinlet.cpp" \ No newline at end of file diff --git a/playground/nodes/RadialNodesSkinlet.h b/playground/nodes/RadialNodesSkinlet.h new file mode 100644 index 00000000..0714d255 --- /dev/null +++ b/playground/nodes/RadialNodesSkinlet.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +class RadialNodesSkinlet : public QskSkinlet +{ + Q_GADGET +public: + enum NodeRole + { + Text, + Foreground, + Lines, + RoleCount + }; + + Q_INVOKABLE RadialNodesSkinlet( QskSkin* skin = nullptr ); + +protected: + Q_REQUIRED_RESULT QRectF subControlRect( const QskSkinnable* skinnable, const QRectF& contentsRect, QskAspect::Subcontrol subControl) const override; + Q_REQUIRED_RESULT QSGNode* updateSubNode( const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node) const override; +}; \ No newline at end of file diff --git a/playground/nodes/main.cpp b/playground/nodes/main.cpp new file mode 100644 index 00000000..e23a53df --- /dev/null +++ b/playground/nodes/main.cpp @@ -0,0 +1,83 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "RadialNodes.h" +#include "RadialNodesSkinlet.h" + +int main( int argc, char* argv[] ) +{ +#ifdef ITEM_STATISTICS + QskObjectCounter counter( true ); +#endif + + QGuiApplication app( argc, argv ); + + SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); + + qskSkinManager->setPluginPaths( + { R"(C:\repositories\qskinny_rveh-install-win\plugins)" } ); + qskSetup->setItemUpdateFlag( QskQuickItem::PreferRasterForTextures, true ); + + QskWindow window; + window.resize( 800, 600 ); + + auto* const layout = new QskLinearBox(Qt::Horizontal, window.contentItem() ); + auto* const left = new QskLinearBox(Qt::Vertical, layout); + auto* const right = new QskLinearBox(Qt::Vertical, layout); + auto* const control = new RadialNodes( left ); + auto* const skinlet = new RadialNodesSkinlet; + { + (void) new QskTextLabel("Tickmark Alignment", right); + auto* const alignment = new QskSegmentedBar(right); + alignment->setOptions( { "Center", "Bottom", "Top" } ); + QObject::connect(alignment, &QskSegmentedBar::selectedIndexChanged, control, [=](const int i){ + static const Qt::Alignment a[ 3 ]{ Qt::AlignVCenter, Qt::AlignBottom, + Qt::AlignTop }; + control->setAlignmentHint(RadialNodes::Lines, a[i]); + }); + + (void) new QskTextLabel("Tickmark Size", right); + auto* const sliderW = new QskSlider(right); + auto* const sliderH = new QskSlider(right); + + sliderW->setMinimum(1.0); + sliderW->setMaximum(4.0); + sliderW->setValue(1.0); + sliderH->setValue( 0.5 ); + + auto updateStrutSizeHint = [=](const qreal){ + const auto width = sliderW->value(); + const auto height = sliderH->value() * control->height(); + control->setStrutSizeHint(RadialNodes::Lines, width, height ); + }; + + QObject::connect( sliderW, &QskSlider::valueChanged, control, updateStrutSizeHint ); + QObject::connect( sliderH, &QskSlider::valueChanged, control, updateStrutSizeHint ); + } + control->setSkinlet(skinlet); + skinlet->setOwnedBySkinnable( true ); + + window.show(); + return app.exec(); +} From 34a94e52f90d52e9cc1c686528da4ef53c5fb3f2 Mon Sep 17 00:00:00 2001 From: "Vogel, Rick" Date: Tue, 8 Aug 2023 15:17:57 +0200 Subject: [PATCH 2/3] rename and reduce example --- playground/nodes/RadialNodes.cpp | 9 ++------- playground/nodes/RadialNodes.h | 6 +++--- playground/nodes/RadialNodesSkinlet.cpp | 22 +++++----------------- playground/nodes/RadialNodesSkinlet.h | 6 ++---- playground/nodes/main.cpp | 8 ++++---- 5 files changed, 16 insertions(+), 35 deletions(-) diff --git a/playground/nodes/RadialNodes.cpp b/playground/nodes/RadialNodes.cpp index bc711741..2debd88e 100644 --- a/playground/nodes/RadialNodes.cpp +++ b/playground/nodes/RadialNodes.cpp @@ -1,15 +1,10 @@ #include "RadialNodes.h" -QSK_SUBCONTROL(RadialNodes, Foreground) -QSK_SUBCONTROL(RadialNodes, Text) -QSK_SUBCONTROL(RadialNodes, Lines) +QSK_SUBCONTROL(RadialTickmarks, Lines) -RadialNodes::RadialNodes( QQuickItem* const parent ) : QskControl( parent ) +RadialTickmarks::RadialTickmarks( QQuickItem* const parent ) : QskControl( parent ) { // TODO move into your skin - setColor(Background, Qt::lightGray); - setColor(Foreground, Qt::black); - setColor(Text, Qt::white); setColor(Lines, Qt::red); setStrutSizeHint( Lines, 2, 10 ); } diff --git a/playground/nodes/RadialNodes.h b/playground/nodes/RadialNodes.h index 11741a35..70a29af7 100644 --- a/playground/nodes/RadialNodes.h +++ b/playground/nodes/RadialNodes.h @@ -2,9 +2,9 @@ #include -class RadialNodes : public QskControl +class RadialTickmarks : public QskControl { public: - QSK_SUBCONTROLS(Foreground, Text, Lines) - explicit RadialNodes( QQuickItem* parent = nullptr ); + QSK_SUBCONTROLS(Lines) + explicit RadialTickmarks( QQuickItem* parent = nullptr ); }; \ No newline at end of file diff --git a/playground/nodes/RadialNodesSkinlet.cpp b/playground/nodes/RadialNodesSkinlet.cpp index c84e261b..e4c04286 100644 --- a/playground/nodes/RadialNodesSkinlet.cpp +++ b/playground/nodes/RadialNodesSkinlet.cpp @@ -164,41 +164,29 @@ namespace }; } -RadialNodesSkinlet::RadialNodesSkinlet( QskSkin* const skin ) +RadialTickmarksSkinlet::RadialTickmarksSkinlet( QskSkin* const skin ) : QskSkinlet( skin ) { setNodeRoles( { Lines } ); } -QRectF RadialNodesSkinlet::subControlRect( const QskSkinnable* const skinnable, +QRectF RadialTickmarksSkinlet::subControlRect( const QskSkinnable* const skinnable, const QRectF& contentsRect, const QskAspect::Subcontrol subControl ) const { - if ( subControl == RadialNodes::Text ) - { - return contentsRect.adjusted( +20, +20, -20, -20 ); - } - else if ( subControl == RadialNodes::Foreground ) - { - return contentsRect.adjusted( +10, +10, -10, -10 ); - } - else if ( subControl == RadialNodes::Lines ) + if ( subControl == RadialTickmarks::Lines ) { return contentsRect; } return QskSkinlet::subControlRect( skinnable, contentsRect, subControl ); } -QSGNode* RadialNodesSkinlet::updateSubNode( +QSGNode* RadialTickmarksSkinlet::updateSubNode( const QskSkinnable* const skinnable, const quint8 nodeRole, QSGNode* const node ) const { - using Q = RadialNodes; + using Q = RadialTickmarks; switch ( static_cast< NodeRole >( nodeRole ) ) { - case Text: - return updateTextNode( skinnable, node, "RadialNodes", RadialNodes::Text ); - case Foreground: - return updateBoxNode( skinnable, node, RadialNodes::Foreground ); case Lines: { const auto* const control = static_cast< const Q* >( skinnable ); diff --git a/playground/nodes/RadialNodesSkinlet.h b/playground/nodes/RadialNodesSkinlet.h index 0714d255..a9e0a672 100644 --- a/playground/nodes/RadialNodesSkinlet.h +++ b/playground/nodes/RadialNodesSkinlet.h @@ -2,19 +2,17 @@ #include -class RadialNodesSkinlet : public QskSkinlet +class RadialTickmarksSkinlet : public QskSkinlet { Q_GADGET public: enum NodeRole { - Text, - Foreground, Lines, RoleCount }; - Q_INVOKABLE RadialNodesSkinlet( QskSkin* skin = nullptr ); + Q_INVOKABLE RadialTickmarksSkinlet( QskSkin* skin = nullptr ); protected: Q_REQUIRED_RESULT QRectF subControlRect( const QskSkinnable* skinnable, const QRectF& contentsRect, QskAspect::Subcontrol subControl) const override; diff --git a/playground/nodes/main.cpp b/playground/nodes/main.cpp index e23a53df..af880ab4 100644 --- a/playground/nodes/main.cpp +++ b/playground/nodes/main.cpp @@ -45,8 +45,8 @@ int main( int argc, char* argv[] ) auto* const layout = new QskLinearBox(Qt::Horizontal, window.contentItem() ); auto* const left = new QskLinearBox(Qt::Vertical, layout); auto* const right = new QskLinearBox(Qt::Vertical, layout); - auto* const control = new RadialNodes( left ); - auto* const skinlet = new RadialNodesSkinlet; + auto* const control = new RadialTickmarks( left ); + auto* const skinlet = new RadialTickmarksSkinlet; { (void) new QskTextLabel("Tickmark Alignment", right); auto* const alignment = new QskSegmentedBar(right); @@ -54,7 +54,7 @@ int main( int argc, char* argv[] ) QObject::connect(alignment, &QskSegmentedBar::selectedIndexChanged, control, [=](const int i){ static const Qt::Alignment a[ 3 ]{ Qt::AlignVCenter, Qt::AlignBottom, Qt::AlignTop }; - control->setAlignmentHint(RadialNodes::Lines, a[i]); + control->setAlignmentHint(RadialTickmarks::Lines, a[i]); }); (void) new QskTextLabel("Tickmark Size", right); @@ -69,7 +69,7 @@ int main( int argc, char* argv[] ) auto updateStrutSizeHint = [=](const qreal){ const auto width = sliderW->value(); const auto height = sliderH->value() * control->height(); - control->setStrutSizeHint(RadialNodes::Lines, width, height ); + control->setStrutSizeHint(RadialTickmarks::Lines, width, height ); }; QObject::connect( sliderW, &QskSlider::valueChanged, control, updateStrutSizeHint ); From 680e176dc8adce9dcf1568bd4b5927f16e7b7b1a Mon Sep 17 00:00:00 2001 From: "Vogel, Rick" Date: Tue, 8 Aug 2023 15:40:45 +0200 Subject: [PATCH 3/3] make tickmarks configurable --- playground/nodes/RadialNodes.cpp | 11 +++ playground/nodes/RadialNodes.h | 6 ++ playground/nodes/RadialNodesSkinlet.cpp | 21 +---- playground/nodes/main.cpp | 100 ++++++++++++++++-------- 4 files changed, 89 insertions(+), 49 deletions(-) diff --git a/playground/nodes/RadialNodes.cpp b/playground/nodes/RadialNodes.cpp index 2debd88e..fc2bf160 100644 --- a/playground/nodes/RadialNodes.cpp +++ b/playground/nodes/RadialNodes.cpp @@ -9,4 +9,15 @@ RadialTickmarks::RadialTickmarks( QQuickItem* const parent ) : QskControl( paren setStrutSizeHint( Lines, 2, 10 ); } +void RadialTickmarks::setTickmarks( const QskScaleTickmarks& tickmarks ) +{ + m_tickmarks = tickmarks; + update(); +} + +QskScaleTickmarks RadialTickmarks::tickmarks() const +{ + return m_tickmarks; +} + #include "moc_RadialNodes.cpp" \ No newline at end of file diff --git a/playground/nodes/RadialNodes.h b/playground/nodes/RadialNodes.h index 70a29af7..e5f50aab 100644 --- a/playground/nodes/RadialNodes.h +++ b/playground/nodes/RadialNodes.h @@ -1,10 +1,16 @@ #pragma once #include +#include class RadialTickmarks : public QskControl { public: QSK_SUBCONTROLS(Lines) explicit RadialTickmarks( QQuickItem* parent = nullptr ); + void setTickmarks(const QskScaleTickmarks& tickmarks); + QskScaleTickmarks tickmarks() const; + +private: + QskScaleTickmarks m_tickmarks; }; \ No newline at end of file diff --git a/playground/nodes/RadialNodesSkinlet.cpp b/playground/nodes/RadialNodesSkinlet.cpp index e4c04286..6458ff9e 100644 --- a/playground/nodes/RadialNodesSkinlet.cpp +++ b/playground/nodes/RadialNodesSkinlet.cpp @@ -175,7 +175,8 @@ QRectF RadialTickmarksSkinlet::subControlRect( const QskSkinnable* const skinnab { if ( subControl == RadialTickmarks::Lines ) { - return contentsRect; + const auto a = skinnable->strutSizeHint(RadialTickmarks::Lines).height() / 2; + return contentsRect.adjusted(+a, +a, -a, -a); } return QskSkinlet::subControlRect( skinnable, contentsRect, subControl ); } @@ -189,22 +190,6 @@ QSGNode* RadialTickmarksSkinlet::updateSubNode( { case Lines: { const auto* const control = static_cast< const Q* >( skinnable ); - - QskScaleTickmarks tickmarks; - QVector< qreal > major, medium, minor; - for ( int deg = 0; deg < 360; deg += 1 ) - { - if ( deg % 10 == 0 ) - major << deg; - else if ( deg % 5 == 0 ) - medium << deg; - else - minor << deg; - } - tickmarks.setMajorTicks( major ); - tickmarks.setMediumTicks( medium ); - tickmarks.setMinorTicks( minor ); - const auto subControlRect = control->subControlContentsRect( Q::Lines ); const auto alignment = control->alignmentHint( Q::Lines ); const auto size = control->strutSizeHint( Q::Lines ); @@ -221,7 +206,7 @@ QSGNode* RadialTickmarksSkinlet::updateSubNode( auto* const root = QskSGNode::ensureNode< QskRadialTickmarksNode >( node ); root->setMaterialProperties( skinnable->color( Q::Lines ) ); - root->setGeometryProperties( tickmarks, radius, height, c, alignment, size.width() ); + root->setGeometryProperties( control->tickmarks(), radius, height, c, alignment, size.width() ); return root; } default: diff --git a/playground/nodes/main.cpp b/playground/nodes/main.cpp index af880ab4..1513c476 100644 --- a/playground/nodes/main.cpp +++ b/playground/nodes/main.cpp @@ -6,19 +6,19 @@ #include #include -#include -#include -#include -#include -#include -#include #include -#include +#include +#include +#include +#include +#include #include #include -#include +#include +#include #include #include +#include #include @@ -35,47 +35,85 @@ int main( int argc, char* argv[] ) SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); - qskSkinManager->setPluginPaths( - { R"(C:\repositories\qskinny_rveh-install-win\plugins)" } ); + qskSkinManager->setPluginPaths( { R"(C:\repositories\qskinny_rveh-install-win\plugins)" } ); qskSetup->setItemUpdateFlag( QskQuickItem::PreferRasterForTextures, true ); - + QskWindow window; window.resize( 800, 600 ); - auto* const layout = new QskLinearBox(Qt::Horizontal, window.contentItem() ); - auto* const left = new QskLinearBox(Qt::Vertical, layout); - auto* const right = new QskLinearBox(Qt::Vertical, layout); + auto* const layout = new QskLinearBox( Qt::Horizontal, window.contentItem() ); + auto* const left = new QskLinearBox( Qt::Vertical, layout ); + auto* const right = new QskLinearBox( Qt::Vertical, layout ); auto* const control = new RadialTickmarks( left ); auto* const skinlet = new RadialTickmarksSkinlet; { - (void) new QskTextLabel("Tickmark Alignment", right); - auto* const alignment = new QskSegmentedBar(right); - alignment->setOptions( { "Center", "Bottom", "Top" } ); - QObject::connect(alignment, &QskSegmentedBar::selectedIndexChanged, control, [=](const int i){ + ( void ) new QskTextLabel( "Tickmark Alignment", right ); + auto* const alignment = new QskSegmentedBar( right ); + alignment->setOptions( { "Center", "Bottom", "Top" } ); + QObject::connect( + alignment, &QskSegmentedBar::selectedIndexChanged, control, [ = ]( const int i ) { static const Qt::Alignment a[ 3 ]{ Qt::AlignVCenter, Qt::AlignBottom, Qt::AlignTop }; - control->setAlignmentHint(RadialTickmarks::Lines, a[i]); - }); + control->setAlignmentHint( RadialTickmarks::Lines, a[ i ] ); + } ); + alignment->setSelectedIndex(0); - (void) new QskTextLabel("Tickmark Size", right); - auto* const sliderW = new QskSlider(right); - auto* const sliderH = new QskSlider(right); + ( void ) new QskTextLabel( "Tickmark Size W / H", right ); + auto* const sliderW = new QskSlider( right ); + auto* const sliderH = new QskSlider( right ); - sliderW->setMinimum(1.0); - sliderW->setMaximum(4.0); - sliderW->setValue(1.0); + sliderW->setMinimum( 1.0 ); + sliderW->setMaximum( 4.0 ); + sliderW->setValue( 1.0 ); sliderH->setValue( 0.5 ); - auto updateStrutSizeHint = [=](const qreal){ + auto updateStrutSizeHint = [ = ]( const qreal ) { const auto width = sliderW->value(); - const auto height = sliderH->value() * control->height(); - control->setStrutSizeHint(RadialTickmarks::Lines, width, height ); + const auto height = sliderH->value() * qMin(control->height(), control->width()) / 2; + control->setStrutSizeHint( RadialTickmarks::Lines, width, height ); }; QObject::connect( sliderW, &QskSlider::valueChanged, control, updateStrutSizeHint ); - QObject::connect( sliderH, &QskSlider::valueChanged, control, updateStrutSizeHint ); + QObject::connect( sliderH, &QskSlider::valueChanged, control, updateStrutSizeHint ); + + ( void ) new QskTextLabel( "Tickmarks [min,max]", right ); + + auto* const tickmarksMin = new QskSlider( right ); + tickmarksMin->setMinimum( 0 ); + tickmarksMin->setMaximum( 360 ); + + auto* const tickmarksMax = new QskSlider( right ); + tickmarksMax->setMinimum( 0 ); + tickmarksMax->setMaximum( 360 ); + + auto updateTickmark = [ control, tickmarksMin, tickmarksMax ]( const qreal v ) { + QskScaleTickmarks tickmarks; + QVector< qreal > major, medium, minor; + + for ( int deg = tickmarksMin->value(); deg < tickmarksMax->value(); deg += 1 ) + { + if ( deg % 10 == 0 ) + major << deg; + else if ( deg % 5 == 0 ) + medium << deg; + else + minor << deg; + } + + tickmarks.setMajorTicks( major ); + tickmarks.setMediumTicks( medium ); + tickmarks.setMinorTicks( minor ); + control->setTickmarks( tickmarks ); + }; + + QObject::connect( tickmarksMin, &QskSlider::valueChanged, control, updateTickmark ); + QObject::connect( tickmarksMax, &QskSlider::valueChanged, control, updateTickmark ); + + tickmarksMin->setValue( 0 ); + tickmarksMax->setValue( 270 ); + } - control->setSkinlet(skinlet); + control->setSkinlet( skinlet ); skinlet->setOwnedBySkinnable( true ); window.show();