1 /*
2  * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB.  All rights reserved.
3  *
4  * This file is part of the KD Chart library.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef KCHARTPOSITION_H
21 #define KCHARTPOSITION_H
22 
23 #include <QDebug>
24 #include <Qt>
25 #include <QMetaType>
26 #include <QCoreApplication>
27 #include "KChartGlobal.h"
28 #include "KChartEnums.h"
29 
30 QT_BEGIN_NAMESPACE
31 class QStringList;
32 class QByteArray;
33 template <typename T> class QList;
34 QT_END_NAMESPACE
35 
36 namespace KChart {
37 
38 /**
39  * \class Position KChartPosition.h
40  * \brief Defines a position, using compass terminology.
41  *
42  * Using KChart::Position you can specify one of nine
43  * pre-defined, logical points (see the \c static \c const getter
44  * methods below), in a similar way, as you would use a
45  * compass to navigate on a map.
46  *
47  * For each piece (slice/bar, etc.) of a chart for example, you can specify the position of the value
48  * labels. Figure 1 illustrates which cardinal points refer to which points
49  * on a pie or bar chart, resp. In the graphic, "N" stands for North, "S" for South, etc.
50  *
51  * \image html position-alignments.png "Figure 1: Different interpretations of KChart::Position within KChart"
52  *
53  * \note Often you will declare a \c Position together with the
54  * RelativePosition class, to specify a logical point,
55  * which then will be used to layout your chart at runtime,
56  * e.g. for specifying the location of a floating Legend box.
57  *
58  * For comparing a Position's value with a switch () statement,
59  * you can use numeric values defined in KChartEnums, like this:
60 \verbatim
61 switch ( yourPosition().value() ) {
62     case KChartEnums::PositionNorthWest:
63         // your code ...
64         break;
65     case KChartEnums::PositionNorth:
66         // your code ...
67         break;
68 }
69 \endverbatim
70  * \sa RelativePosition, KChartEnums::PositionValue
71  */
72 class KCHART_EXPORT Position
73 {
74     Q_DECLARE_TR_FUNCTIONS( Position )
75     Position( int value );
76 public:
77     Position();
78     Position( KChartEnums::PositionValue value ); // intentionally non-explicit
79 
80     KChartEnums::PositionValue value() const;
81 
82     const char *name() const;
83     QString printableName() const;
84 
85     bool isUnknown() const;
86 
87     bool isWestSide() const;
88     bool isNorthSide() const;
89     bool isEastSide() const;
90     bool isSouthSide() const;
91 
92     bool isCorner() const;
93     bool isPole() const;
94 
95     bool isFloating() const;
96 
97     static const Position& Unknown;
98     static const Position& Center;
99     static const Position& NorthWest;
100     static const Position& North;
101     static const Position& NorthEast;
102     static const Position& East;
103     static const Position& SouthEast;
104     static const Position& South;
105     static const Position& SouthWest;
106     static const Position& West;
107 
108     static const Position& Floating;
109 
110     // boolean flags: 1, 2, 4, 8, ...
111     enum Option {
112         IncludeCenter   = 0x1,
113         IncludeFloating = 0x2 };
114     Q_DECLARE_FLAGS( Options, Option )
115 
116     // Unfortunately the following typecast from int to Options is needed
117     // as the | operator is not defined yet, this will be done by
118     // the makro Q_DECLARE_OPERATORS_FOR_FLAGS( KChart::Position::Options )
119     // at the bottom of this file.
120     static QList<QByteArray> names( Options options    = Options(IncludeCenter | IncludeFloating) );
121     static QStringList printableNames( Options options = Options(IncludeCenter | IncludeFloating) );
122 
123     static Position fromName(const char * name);
124     static Position fromName(const QByteArray & name);
125 
126     bool operator==( const Position& ) const;
127     bool operator==( int ) const;
128     bool operator!=( const Position& ) const;
129     bool operator!=( int ) const;
130 
131 private:
132     int m_value;
133 }; // End of class Position
134 
135 inline bool Position::operator!=( const Position & other ) const { return !operator==( other ); }
136 inline bool Position::operator!=( int other ) const { return !operator==( other ); }
137 
138 /**
139   * @brief Stores the absolute target points of a Position
140   * \internal
141   */
142 class KCHART_EXPORT PositionPoints
143 {
144   public:
PositionPoints()145     PositionPoints() {} // all points get initialized with the default automatically
146 
PositionPoints(QPointF center,QPointF northWest,QPointF north,QPointF northEast,QPointF east,QPointF southEast,QPointF south,QPointF southWest,QPointF west)147     PositionPoints(
148         QPointF center,
149         QPointF northWest,
150         QPointF north,
151         QPointF northEast,
152         QPointF east,
153         QPointF southEast,
154         QPointF south,
155         QPointF southWest,
156         QPointF west )
157       : mPositionCenter( center )
158       , mPositionNorthWest( northWest )
159       , mPositionNorth( north )
160       , mPositionNorthEast( northEast )
161       , mPositionEast( east )
162       , mPositionSouthEast( southEast )
163       , mPositionSouth( south )
164       , mPositionSouthWest( southWest )
165       , mPositionWest( west )
166         {}
PositionPoints(const QPointF & onePointForAllPositions)167     PositionPoints(
168         const QPointF& onePointForAllPositions )
169       : mPositionCenter( onePointForAllPositions )
170       , mPositionNorthWest( onePointForAllPositions )
171       , mPositionNorth( onePointForAllPositions )
172       , mPositionNorthEast( onePointForAllPositions )
173       , mPositionEast( onePointForAllPositions )
174       , mPositionSouthEast( onePointForAllPositions )
175       , mPositionSouth( onePointForAllPositions )
176       , mPositionSouthWest( onePointForAllPositions )
177       , mPositionWest( onePointForAllPositions )
178         {}
PositionPoints(const QRectF & rect)179     PositionPoints(
180         const QRectF& rect )
181     {
182         const QRectF r( rect.normalized() );
183         mPositionCenter    = r.center();
184         mPositionNorthWest = r.topLeft();
185         mPositionNorth     = QPointF(r.center().x(), r.top());
186         mPositionNorthEast = r.topRight();
187         mPositionEast      = QPointF(r.right(), r.center().y());
188         mPositionSouthEast = r.bottomRight();
189         mPositionSouth     = QPointF(r.center().x(), r.bottom());
190         mPositionSouthWest = r.bottomLeft();
191         mPositionWest      = QPointF(r.left(), r.center().y());
192     }
PositionPoints(QPointF northWest,QPointF northEast,QPointF southEast,QPointF southWest)193     PositionPoints(
194         QPointF northWest,
195         QPointF northEast,
196         QPointF southEast,
197         QPointF southWest )
198       : mPositionCenter( (northWest + southEast) / 2.0 )
199       , mPositionNorthWest( northWest )
200       , mPositionNorth( (northWest + northEast) / 2.0 )
201       , mPositionNorthEast( northEast )
202       , mPositionEast( (northEast + southEast) / 2.0 )
203       , mPositionSouthEast( southEast )
204       , mPositionSouth( (southWest + southEast) / 2.0 )
205       , mPositionSouthWest( southWest )
206       , mPositionWest( (northWest + southWest) / 2.0 )
207         {}
208 
setDegrees(KChartEnums::PositionValue pos,qreal degrees)209     void setDegrees( KChartEnums::PositionValue pos, qreal degrees )
210     {
211         mapOfDegrees[pos] = degrees;
212     }
213 
214 #if defined(Q_COMPILER_MANGLES_RETURN_TYPE)
degrees(KChartEnums::PositionValue pos)215     const qreal degrees( KChartEnums::PositionValue pos ) const
216 #else
217     qreal degrees( KChartEnums::PositionValue pos ) const
218 #endif
219     {
220         if ( mapOfDegrees.contains(pos) )
221             return mapOfDegrees[pos];
222         return 0.0;
223     }
224 
225 #if defined(Q_COMPILER_MANGLES_RETURN_TYPE)
point(Position position)226     const QPointF point( Position position ) const
227 #else
228     QPointF point( Position position ) const
229 #endif
230     {
231       //qDebug() << "point( " << position.name() << " )";
232       if ( position ==  Position::Center)
233         return mPositionCenter;
234       if ( position ==  Position::NorthWest)
235         return mPositionNorthWest;
236       if ( position ==  Position::North)
237         return mPositionNorth;
238       if ( position ==  Position::NorthEast)
239         return mPositionNorthEast;
240       if ( position ==  Position::East)
241         return mPositionEast;
242       if ( position ==  Position::SouthEast)
243         return mPositionSouthEast;
244       if ( position ==  Position::South)
245         return mPositionSouth;
246       if ( position ==  Position::SouthWest)
247         return mPositionSouthWest;
248       if ( position ==  Position::West)
249         return mPositionWest;
250       return mPositionUnknown;
251     }
252 
isNull()253     bool isNull() const
254     {
255         return
256             mPositionUnknown.isNull() &&
257             mPositionCenter.isNull() &&
258             mPositionNorthWest.isNull() &&
259             mPositionNorth.isNull() &&
260             mPositionNorthEast.isNull() &&
261             mPositionEast.isNull() &&
262             mPositionSouthEast.isNull() &&
263             mPositionSouth.isNull() &&
264             mPositionSouthWest.isNull() &&
265             mPositionWest.isNull();
266     }
267 
268     QPointF mPositionUnknown;
269     QPointF mPositionCenter;
270     QPointF mPositionNorthWest;
271     QPointF mPositionNorth;
272     QPointF mPositionNorthEast;
273     QPointF mPositionEast;
274     QPointF mPositionSouthEast;
275     QPointF mPositionSouth;
276     QPointF mPositionSouthWest;
277     QPointF mPositionWest;
278     QMap<KChartEnums::PositionValue, qreal> mapOfDegrees;
279 
280 }; // End of class PositionPoints
281 
282 
283 }
284 
285 
286 #if !defined(QT_NO_DEBUG_STREAM)
287 KCHART_EXPORT QDebug operator<<(QDebug, const KChart::Position& );
288 #endif /* QT_NO_DEBUG_STREAM */
289 
290 QT_BEGIN_NAMESPACE
291 Q_DECLARE_TYPEINFO( KChart::Position, Q_MOVABLE_TYPE );
292 Q_DECLARE_OPERATORS_FOR_FLAGS( KChart::Position::Options )
293 QT_END_NAMESPACE
294 
295 Q_DECLARE_METATYPE( KChart::Position )
296 
297 #endif // KCHARTPOSITION_H
298