QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskGraduationNode.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskGraduationNode.h"
7#include "QskTickmarks.h"
8#include "QskIntervalF.h"
9#include "QskGraduationMetrics.h"
10
11#include <QTransform>
12
13namespace
14{
15 using Points = QSGGeometry::Point2D;
16
17 class Renderer
18 {
19 public:
20 inline Renderer( bool isHorizontal )
21 : m_isHorizontal( isHorizontal )
22 {
23 }
24
25 inline Points* addBackbone( Points* points,
26 qreal pos, qreal v1, qreal v2 ) const
27 {
28 if ( m_isHorizontal )
29 setLine( points, v1, pos, v2, pos );
30 else
31 setLine( points, pos, v1, pos, v2 );
32
33 return points + 2;
34 }
35
36 inline Points* addTickLine( Points* points,
37 qreal pos, qreal tick, qreal tickLength ) const
38 {
39 if ( m_isHorizontal )
40 setLine( points, tick, pos, tick, pos + tickLength );
41 else
42 setLine( points, pos, tick, pos + tickLength, tick );
43
44 return points + 2;
45 }
46
47 private:
48
49 inline void setLine( Points* points,
50 qreal x1, qreal y1, qreal x2, qreal y2 ) const
51 {
52 points[ 0 ].set( x1, y1 );
53 points[ 1 ].set( x2, y2 );
54 }
55
56 const bool m_isHorizontal;
57 };
58}
59
60class QskGraduationNode::PrivateData
61{
62 public:
63 inline qreal map( qreal v ) const
64 {
65 if ( isHorizontal )
66 return transform.dx() + transform.m11() * v;
67 else
68 return transform.dy() + transform.m22() * v;
69 }
70
71 inline qreal origin( qreal length ) const
72 {
73 switch( alignment )
74 {
75 case QskGraduationNode::Leading:
76 return pos - length;
77
78 case QskGraduationNode::Centered:
79 return pos - 0.5 * length;
80
81 default:
82 return pos;
83 }
84 }
85
86 bool isHorizontal = true;
87 qreal pos;
88
89 QskIntervalF backbone;
90 QTransform transform;
91
92 QskGraduationNode::Alignment alignment = QskGraduationNode::Centered;
93 QskGraduationMetrics graduationMetrics;
94
95 QskHashValue hash = 0;
96
97 bool dirty = true;
98};
99
100QskGraduationNode::QskGraduationNode()
101 : m_data( new PrivateData() )
102{
103}
104
105QskGraduationNode::~QskGraduationNode()
106{
107}
108
109void QskGraduationNode::setAxis( Qt::Orientation orientation,
110 qreal pos, const QTransform& transform )
111{
112 const bool isHorizontal = ( orientation == Qt::Horizontal );
113
114 if( isHorizontal != m_data->isHorizontal
115 || pos != m_data->pos || transform != m_data->transform )
116 {
117 m_data->isHorizontal = isHorizontal;
118 m_data->pos = pos;
119 m_data->transform = transform;
120
121 m_data->dirty = true;
122 }
123}
124
125void QskGraduationNode::setTickMetrics(
126 Alignment alignment, const QskGraduationMetrics& metrics )
127{
128
129 if( metrics != m_data->graduationMetrics || alignment != m_data->alignment )
130 {
131 setLineWidth( metrics.tickWidth() );
132
133 m_data->graduationMetrics = metrics;
134 m_data->alignment = alignment;
135
136 m_data->dirty = true;
137 }
138}
139
140void QskGraduationNode::update( const QskTickmarks& tickmarks,
141 const QskIntervalF& backbone )
142{
143 const auto hash = tickmarks.hash( 17435 );
144 if ( m_data->hash != hash || m_data->backbone != backbone )
145 {
146 m_data->hash = hash;
147 m_data->backbone = backbone;
148 m_data->dirty = true;
149 }
150
151 if( !m_data->dirty )
152 return;
153
154 QSGGeometry::Point2D* points;
155
156 {
157 auto lineCount = tickmarks.tickCount();
158 if ( !backbone.isEmpty() )
159 lineCount++;
160
161 geometry()->allocate( lineCount * 2 );
162 points = geometry()->vertexDataAsPoint2D();
163 }
164
165 const Renderer renderer( m_data->isHorizontal );
166
167 if ( !m_data->backbone.isEmpty() )
168 {
169 const auto v1 = m_data->map( backbone.lowerBound() );
170 const auto v2 = m_data->map( backbone.upperBound() );
171
172 points = renderer.addBackbone( points, m_data->pos, v1, v2 );
173 }
174
175 for( int i = QskTickmarks::MinorTick;
176 i <= QskTickmarks::MajorTick; i++ )
177 {
178 const auto tickType = static_cast< QskTickmarks::TickType >( i );
179
180 const auto len = m_data->graduationMetrics.tickLength( tickType );
181 const auto origin = m_data->origin( len );
182
183 const auto ticks = tickmarks.ticks( tickType );
184 for( auto tick : ticks )
185 {
186 tick = m_data->map( tick );
187 points = renderer.addTickLine( points, origin, tick, len );
188 }
189 }
190
191 geometry()->markVertexDataDirty();
192 markDirty( QSGNode::DirtyGeometry );
193 m_data->dirty = false;
194}