1 /* 2 * Stellarium 3 * Copyright (C) 2008 Matthew Gates 4 * Copyright (C) 2015 Georg Zotti (min/max limits) 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 8 * as published by the Free Software Foundation; either version 2 9 * of 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, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 19 */ 20 21 #ifndef ANGLESPINBOX_HPP 22 #define ANGLESPINBOX_HPP 23 24 #include <QAbstractSpinBox> 25 #include <QString> 26 #include <cmath> 27 28 //! @class AngleSpinBox 29 //! A spin box for displaying/entering angular values. 30 //! This class can accept angles in various formats commonly used in astronomy 31 //! including decimal degrees, DMS and HMS. 32 //! You should set upper and lower limits (maximum, minimum) and 33 //! decide whether the values wrap around or are blocked at the limits (wrapping). 34 class AngleSpinBox : public QAbstractSpinBox 35 { 36 Q_OBJECT 37 38 public: 39 //! @enum DisplayFormat 40 //! Used to decide how to display the angle. 41 enum DisplayFormat 42 { 43 DMSLetters, //!< Degrees, minutes and seconds, e.g. 180d 4m 8s, with negative values, [-360..360d] 44 DMSSymbols, //!< Degrees, minutes and seconds, e.g. 180° 4' 8", with negative values, [-360..360°] 45 DMSLettersUnsigned, //!< Degrees, minutes and seconds, e.g. 180d 4m 8s, [0..360d] 46 DMSSymbolsUnsigned, //!< Degrees, minutes and seconds, e.g. 180° 4' 8", [0..360°] 47 HMSLetters, //!< Hours, minutes and seconds, e.g. 12h 4m 6s 48 HMSSymbols, //!< Hours, minutes and seconds, e.g. 12h 4' 6s" 49 DecimalDeg //!< Decimal degrees, e.g. 180.06888 50 }; 51 52 //! @enum PrefixType 53 //! Determines how positive and negative values are indicated. 54 enum PrefixType 55 { 56 Normal, //!< negative values have '-' prefix 57 NormalPlus, //!< positive values have '+' prefix, negative values have '-' prefix. 58 Longitude, //!< positive values have 'E' prefix, negative values have 'W' prefix. 59 Latitude, //!< positive values have 'N' prefix, negative values have 'S' prefix. 60 Unknown 61 }; 62 63 AngleSpinBox(QWidget* parent=Q_NULLPTR, DisplayFormat format=DMSSymbols, PrefixType prefix=Normal); 64 ~AngleSpinBox() Q_DECL_OVERRIDE; 65 66 // QAbstractSpinBox virtual members 67 virtual void stepBy(int steps) Q_DECL_OVERRIDE; 68 virtual QValidator::State validate(QString& input, int& pos) const Q_DECL_OVERRIDE; 69 70 //! Get the angle held in the AngleSpinBox 71 //! @return the angle in radians 72 double valueRadians() const; 73 //! Get the angle held in the AngleSpinBox 74 //! @return the angle in degrees 75 double valueDegrees() const; 76 77 //! Set the number of decimal places to express float values to (e.g. seconds in DMSLetters format). 78 //! @param places the number of decimal places to use. setDecimals(int places)79 void setDecimals(int places) { decimalPlaces = places; } 80 81 //! Get the number of decimal places to express float values to (e.g. seconds in DMSLetters format). 82 //! @return the number of decimal places used. decimals() const83 int decimals() const { return decimalPlaces; } 84 85 //! Set the display format. 86 //! @param format the new format to use. setDisplayFormat(DisplayFormat format)87 void setDisplayFormat(DisplayFormat format) { angleSpinBoxFormat=format; formatText(); } 88 89 //! Get the current display format. 90 //! @return the current DisplayFormat. displayFormat() const91 DisplayFormat displayFormat() const { return angleSpinBoxFormat; } 92 93 //! Set the prefix type. 94 //! @param prefix the new prefix type to use. setPrefixType(PrefixType prefix)95 void setPrefixType(PrefixType prefix) { currentPrefixType=prefix; formatText(); } 96 97 //! Get the current display format. 98 //! @return the current DisplayFormat. prefixType() const99 PrefixType prefixType() const { return currentPrefixType; } 100 101 //! Set the minimum value. 102 //! @param min the new minimum value 103 //! @param isDegrees true if the new minimum value is given in degrees, else min is understood as radians. setMinimum(const double min,const bool isDegrees=false)104 void setMinimum(const double min, const bool isDegrees=false) {minRad = min * (isDegrees? M_PI/180.0 : 1.); } 105 //! Get the minimum value. 106 //! @return the current minimum value 107 //! @param isDegrees true if the minimum value is required in degrees, else min is returned as radians. getMinimum(const bool isDegrees) const108 double getMinimum(const bool isDegrees) const { return minRad * (isDegrees ? 180.0/M_PI : 1.0); } 109 110 //! Set the maximum value. 111 //! @param max the new maximum value 112 //! @param isDegrees true if the new maximum value is given in degrees, else max is understood as radians. setMaximum(const double max,const bool isDegrees=false)113 void setMaximum(const double max, const bool isDegrees=false) {maxRad = max * (isDegrees? M_PI/180.0 : 1.); } 114 //! Get the maximum value. 115 //! @return the current maximum value 116 //! @param isDegrees true if the maximum value is required in degrees, else max is returned as radians. getMaximum(const bool isDegrees) const117 double getMaximum(const bool isDegrees) const { return maxRad * (isDegrees ? 180.0/M_PI : 1.0); } 118 119 public slots: 120 //! Set the value to default 0 angle. 121 virtual void clear() Q_DECL_OVERRIDE; 122 123 //! Set the value of the spin box in radians. 124 //! @param radians the value to set, in radians. 125 void setRadians(double radians); 126 127 //! Set the value of the spin box in decimal degrees. 128 //! @param degrees the value to set, in decimal degrees. 129 void setDegrees(double degrees); 130 131 signals: 132 //! Emitted when the value changes. 133 void valueChanged(); 134 void valueChangedDeg(double); 135 void valueChangedRad(double); 136 137 protected: 138 virtual StepEnabled stepEnabled() const Q_DECL_OVERRIDE; 139 140 private slots: 141 //! Updates radAngle (internal representation of the angle) and calls formatText 142 void updateValue(void); 143 144 private: 145 //! Convert a string value to an angle in radians. 146 //! This function can be used to validate a string as expressing an angle. Accepted 147 //! are any formats which the AngleSpinBox understands. 148 //! @param input the string value to be converted / validated. 149 //! @param state a pointer to a QValidator::State value which is set according to the validation. 150 //! @param prefix the kind of prefix to use for conversion. 151 //! @return the value of the angle expressed in input in radians. 152 double stringToDouble(QString input, QValidator::State* state, PrefixType prefix=Unknown) const; 153 154 //! @enum AngleSpinboxSection 155 enum AngleSpinboxSection 156 { 157 SectionPrefix, //! Section of the S/W or E/W or +/- 158 SectionDegreesHours, //! Section of the degree or hours 159 SectionMinutes, //! Section of the minutes (of degree or of hours) 160 SectionSeconds, //! Section of the seconds (of degree or of hours) 161 SectionNone //! No matching section, e.g. between 2 sections 162 }; 163 164 //! Get the current section in which the line edit cursor is. 165 AngleSpinboxSection getCurrentSection() const; 166 167 //! Reformats the input according to the current value of angleSpinBoxFormat/ 168 //! This is called whenever an editingFinished() signal is emitted, 169 //! e.g. when RETURN is pressed. 170 void formatText(void); 171 172 static const QString positivePrefix(PrefixType prefix); 173 static const QString negativePrefix(PrefixType prefix); 174 175 DisplayFormat angleSpinBoxFormat; 176 PrefixType currentPrefixType; 177 int decimalPlaces; 178 double radAngle; 179 // min/max angles (radians), users should not be able to enter more/less. 180 // Use together with the wrapping() property! 181 double minRad; 182 double maxRad; 183 }; 184 185 #endif // ANGLESPINBOX_HPP 186