Merge 680e176dc8
into 16754b4f9d
This commit is contained in:
commit
afdec44a80
|
@ -6,6 +6,7 @@ add_subdirectory(invoker)
|
||||||
add_subdirectory(shadows)
|
add_subdirectory(shadows)
|
||||||
add_subdirectory(shapes)
|
add_subdirectory(shapes)
|
||||||
add_subdirectory(charts)
|
add_subdirectory(charts)
|
||||||
|
add_subdirectory(nodes)
|
||||||
|
|
||||||
if (BUILD_INPUTCONTEXT)
|
if (BUILD_INPUTCONTEXT)
|
||||||
add_subdirectory(inputpanel)
|
add_subdirectory(inputpanel)
|
||||||
|
|
|
@ -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
|
||||||
|
)
|
|
@ -0,0 +1,23 @@
|
||||||
|
#include "RadialNodes.h"
|
||||||
|
|
||||||
|
QSK_SUBCONTROL(RadialTickmarks, Lines)
|
||||||
|
|
||||||
|
RadialTickmarks::RadialTickmarks( QQuickItem* const parent ) : QskControl( parent )
|
||||||
|
{
|
||||||
|
// TODO move into your skin
|
||||||
|
setColor(Lines, Qt::red);
|
||||||
|
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"
|
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QskControl.h>
|
||||||
|
#include <QskScaleTickmarks.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
|
@ -0,0 +1,217 @@
|
||||||
|
#include "RadialNodesSkinlet.h"
|
||||||
|
#include "RadialNodes.h"
|
||||||
|
|
||||||
|
#include <QskFunctions.h>
|
||||||
|
#include <QskSGNode.h>
|
||||||
|
#include <QskScaleTickmarks.h>
|
||||||
|
|
||||||
|
#include <QSGFlatColorMaterial>
|
||||||
|
#include <QSGGeometryNode>
|
||||||
|
#include <qmath.h>
|
||||||
|
|
||||||
|
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 };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
RadialTickmarksSkinlet::RadialTickmarksSkinlet( QskSkin* const skin )
|
||||||
|
: QskSkinlet( skin )
|
||||||
|
{
|
||||||
|
setNodeRoles( { Lines } );
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF RadialTickmarksSkinlet::subControlRect( const QskSkinnable* const skinnable,
|
||||||
|
const QRectF& contentsRect, const QskAspect::Subcontrol subControl ) const
|
||||||
|
{
|
||||||
|
if ( subControl == RadialTickmarks::Lines )
|
||||||
|
{
|
||||||
|
const auto a = skinnable->strutSizeHint(RadialTickmarks::Lines).height() / 2;
|
||||||
|
return contentsRect.adjusted(+a, +a, -a, -a);
|
||||||
|
}
|
||||||
|
return QskSkinlet::subControlRect( skinnable, contentsRect, subControl );
|
||||||
|
}
|
||||||
|
|
||||||
|
QSGNode* RadialTickmarksSkinlet::updateSubNode(
|
||||||
|
const QskSkinnable* const skinnable, const quint8 nodeRole, QSGNode* const node ) const
|
||||||
|
{
|
||||||
|
using Q = RadialTickmarks;
|
||||||
|
|
||||||
|
switch ( static_cast< NodeRole >( nodeRole ) )
|
||||||
|
{
|
||||||
|
case Lines: {
|
||||||
|
const auto* const control = static_cast< const Q* >( skinnable );
|
||||||
|
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( control->tickmarks(), radius, height, c, alignment, size.width() );
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return QskSkinlet::updateSubNode( skinnable, nodeRole, node );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_RadialNodesSkinlet.cpp"
|
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QskSkinlet.h>
|
||||||
|
|
||||||
|
class RadialTickmarksSkinlet : public QskSkinlet
|
||||||
|
{
|
||||||
|
Q_GADGET
|
||||||
|
public:
|
||||||
|
enum NodeRole
|
||||||
|
{
|
||||||
|
Lines,
|
||||||
|
RoleCount
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_INVOKABLE RadialTickmarksSkinlet( 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;
|
||||||
|
};
|
|
@ -0,0 +1,121 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include <SkinnyShapeProvider.h>
|
||||||
|
#include <SkinnyShortcut.h>
|
||||||
|
|
||||||
|
#include <QskAnimationHint.h>
|
||||||
|
#include <QskBox.h>
|
||||||
|
#include <QskFocusIndicator.h>
|
||||||
|
#include <QskLinearBox.h>
|
||||||
|
#include <QskObjectCounter.h>
|
||||||
|
#include <QskSegmentedBar.h>
|
||||||
|
#include <QskSetup.h>
|
||||||
|
#include <QskSkin.h>
|
||||||
|
#include <QskSkinManager.h>
|
||||||
|
#include <QskSkinTransition.h>
|
||||||
|
#include <QskSlider.h>
|
||||||
|
#include <QskTextLabel.h>
|
||||||
|
#include <QskWindow.h>
|
||||||
|
|
||||||
|
#include <QGuiApplication>
|
||||||
|
|
||||||
|
#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 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 ) {
|
||||||
|
static const Qt::Alignment a[ 3 ]{ Qt::AlignVCenter, Qt::AlignBottom,
|
||||||
|
Qt::AlignTop };
|
||||||
|
control->setAlignmentHint( RadialTickmarks::Lines, a[ i ] );
|
||||||
|
} );
|
||||||
|
alignment->setSelectedIndex(0);
|
||||||
|
|
||||||
|
( 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 );
|
||||||
|
sliderH->setValue( 0.5 );
|
||||||
|
|
||||||
|
auto updateStrutSizeHint = [ = ]( const qreal ) {
|
||||||
|
const auto width = sliderW->value();
|
||||||
|
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 );
|
||||||
|
|
||||||
|
( 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 );
|
||||||
|
skinlet->setOwnedBySkinnable( true );
|
||||||
|
|
||||||
|
window.show();
|
||||||
|
return app.exec();
|
||||||
|
}
|
Loading…
Reference in New Issue