1 /* 2 * Copyright 2012, 2013, 2015, 2017, 2019 Kai Pastor 3 * 4 * This file is part of OpenOrienteering. 5 * 6 * OpenOrienteering is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * OpenOrienteering 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 OpenOrienteering. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 21 #ifndef OPENORIENTEERING_UTIL_GUI_H 22 #define OPENORIENTEERING_UTIL_GUI_H 23 24 #include <QtGlobal> 25 #include <QDoubleValidator> 26 #include <QString> 27 #include <QValidator> 28 29 class QCheckBox; 30 class QDoubleSpinBox; 31 class QLabel; 32 class QObject; 33 class QPainter; 34 class QPointF; 35 class QSpacerItem; 36 class QSpinBox; 37 class QWidget; 38 39 namespace OpenOrienteering { 40 41 class MapCoordF; 42 43 44 /** Double validator for line edit widgets, 45 * ensures that only valid doubles can be entered. */ 46 class DoubleValidator : public QDoubleValidator // clazy:exclude=missing-qobject-macro 47 { 48 public: 49 DoubleValidator(double bottom, double top = 10e10, QObject* parent = nullptr, int decimals = 20); 50 51 ~DoubleValidator() override; 52 53 State validate(QString& input, int& pos) const override; 54 }; 55 56 57 58 /** 59 * A collection of GUI utility functions. 60 */ 61 namespace Util 62 { 63 64 /** 65 * Converts millimeters to pixels using the physical dpi setting of 66 * Mapper's settings. This should be used to calculate sizes of map elements. 67 * @sa mmToPixelLogical() 68 */ 69 qreal mmToPixelPhysical(qreal millimeters); 70 71 /** Inverse of mmToPixelPhysical(). */ 72 qreal pixelToMMPhysical(qreal pixels); 73 74 75 /** 76 * Converts millimeters to pixels using the "logical" dpi setting of 77 * the operating system. This should be used to calculate sizes of UI 78 * elements. 79 * @sa mmToPixelPhysical() 80 */ 81 qreal mmToPixelLogical(qreal millimeters); 82 83 /** Inverse of mmToPixelLogical(). */ 84 qreal pixelToMMLogical(qreal pixels); 85 86 87 /** Returns true for low-dpi screens, false for high-dpi screens. */ 88 bool isAntialiasingRequired(); 89 90 /** Returns true for low-dpi screens, false for high-dpi screens. */ 91 bool isAntialiasingRequired(qreal ppi); 92 93 94 95 /** 96 * Show the manual in Qt assistant. 97 * 98 * @param filename_latin1 the name of the manual page html file 99 * @param anchor_latin1 the anchor in the specified file to jump to 100 */ 101 void showHelp(QWidget* dialog_parent, const char* filename_latin1, const char* anchor_latin1); 102 103 /** 104 * Show the manual in Qt assistant. 105 * 106 * The anchor may be left out or given with the filename. 107 * 108 * @param file_and_anchor_latin1 the name of the manual page html file, optionally including an anchor 109 */ 110 void showHelp(QWidget* dialog_parent, const char* file_and_anchor_latin1 = "index.html"); 111 112 /** 113 * Show the manual in Qt assistant. 114 * 115 * The anchor may be left out or given with the filename. 116 * 117 * @param file_and_anchor the name of the manual page html file, optionally including an anchor 118 */ 119 void showHelp(QWidget* dialog_parent, const QString& file_and_anchor); 120 121 122 123 /** 124 * Creates a What's-this text "See more" linking to the given page and 125 * fragment in the manual. 126 */ 127 QString makeWhatThis(const char* reference_latin1); 128 129 130 131 /** 132 * Provides information about the properties of Mapper types 133 * for the purpose of customizing input widgets. 134 * 135 * The generic class is empty. 136 * Template specializations provide the actual values. 137 * See InputProperties<MapCoordF> for an example. 138 */ 139 template< class T > 140 struct InputProperties 141 { 142 // intentionally left empty 143 }; 144 145 146 /** 147 * Provides information about the properties of MapCoordF 148 * for the purpose of customizing input widgets. 149 */ 150 template< > 151 struct InputProperties< MapCoordF > 152 { 153 /** The underlying fundamental type. */ 154 typedef double basetype; 155 156 /** The minimum input value. */ 157 constexpr static double min() noexcept { return -99999999.99; } 158 159 /** The maximum input value. */ 160 constexpr static double max() noexcept { return +99999999.99; } 161 162 /** The spinbox step width. */ 163 constexpr static double step() noexcept { return 1.0; } 164 165 /** The number of decimals. */ 166 constexpr static int decimals() noexcept { return 2; } 167 168 /** If true, spin box fields are meant to wrap at boundaries. */ 169 constexpr static bool wrapping() noexcept { return false; } 170 171 /** The unit of measurement, translated in context UnitOfMeasurement. */ 172 static QString unit(); 173 }; 174 175 176 /** Identifies the type double representing real meters */ 177 struct RealMeters 178 { 179 // intentionally left empty 180 }; 181 182 183 /** 184 * Provides information about the type double representing real meters 185 * for the purpose of customizing input widgets. 186 */ 187 template< > 188 struct InputProperties< RealMeters > 189 { 190 /** The underlying fundamental type. */ 191 typedef double basetype; 192 193 /** The minimum input value. */ 194 static constexpr double min() noexcept { return -99999999.99; } 195 196 /** The maximum input value. */ 197 constexpr static double max() noexcept { return +99999999.99; } 198 199 /** The spinbox step width. */ 200 constexpr static double step() noexcept { return 1.0; } 201 202 /** The number of decimals. */ 203 constexpr static int decimals() noexcept { return 2; } 204 205 /** If true, spin box fields are meant to wrap at boundaries. */ 206 constexpr static bool wrapping() noexcept { return false; } 207 208 /** The unit of measurement, translated in context UnitOfMeasurement. */ 209 static QString unit(); 210 }; 211 212 213 214 /** Identifies the type double representing a rotation angle in degrees */ 215 struct RotationalDegrees 216 { 217 // intentionally left empty 218 }; 219 220 221 /** 222 * Provides information about the type double representing a rotation angle 223 * for the purpose of customizing input widgets. 224 */ 225 template< > 226 struct InputProperties< RotationalDegrees > 227 { 228 /** The underlying fundamental type. */ 229 typedef double basetype; 230 231 /** The minimum input value. */ 232 static constexpr double min() noexcept { return -180.0; } 233 234 /** The maximum input value. */ 235 constexpr static double max() noexcept { return +180.0; } 236 237 /** The spinbox step width. */ 238 constexpr static double step() noexcept { return 1.0; } 239 240 /** The number of decimals. */ 241 constexpr static int decimals() noexcept { return 2; } 242 243 /** If true, spin box fields are meant to wrap at boundaries. */ 244 constexpr static bool wrapping() noexcept { return true; } 245 246 /** The unit of measurement, translated in context UnitOfMeasurement. */ 247 static QString unit(); 248 }; 249 250 251 252 namespace Marker 253 { 254 /** Center marker sign for rotate and scale tools. */ 255 void drawCenterMarker(QPainter* painter, const QPointF& center); 256 } // namespace Marker 257 258 259 namespace Headline 260 { 261 /** 262 * Creates a QLabel which is styled as a headline. 263 * 264 * This headline is intended for use in dialogs. 265 */ 266 QLabel* create(const QString& text); 267 268 /** 269 * Creates a QLabel which is styled as a headline. 270 * 271 * This headline is intended for use in dialogs. 272 */ 273 QLabel* create(const char* text_utf8); 274 } 275 276 277 278 namespace SpacerItem 279 { 280 /** 281 * Creates a QSpacerItem which takes up a style dependent width 282 * and height. 283 * 284 * This spacer item is intended for use with QFormLayout which 285 * does not offer a direct mean for extra spacing. 286 */ 287 QSpacerItem* create(const QWidget* widget); 288 } 289 290 291 292 namespace SpinBox 293 { 294 /** 295 * Creates and initializes a QSpinBox. 296 * 297 * This method allows to initialize the most frequent options of 298 * QSpinBox in a single call: 299 * the lower and upper bound of the valid range, 300 * the unit of measurement (optional), 301 * the step width of the spinbox buttons (optional), 302 * the wrapping property of the spinbox (optional). 303 */ 304 QSpinBox* create(int min, int max, const QString &unit = {}, int step = 0); 305 306 /** 307 * Creates and initializes a QDoubleSpinBox. 308 * 309 * This method allows to initialize the most frequent options of 310 * QDoubleSpinBox in a single call: 311 * the number of decimals, 312 * the lower and upper bound of the valid range, 313 * the unit of measurement (optional), 314 * the step width of the spinbox buttons (optional; dependent on 315 * the number of decimals if not specified), 316 * the wrapping property of the spinbox (optional). 317 */ 318 QDoubleSpinBox* create(int decimals, double min, double max, const QString &unit = {}, double step = 0.0); 319 320 /** 321 * Creates and initializes a QDoubleSpinBox. 322 * 323 * This method allows to initialize the most frequent options of 324 * QDoubleSpinBox in a single call, determining the actual properties 325 * via InputProperties<T>. 326 */ 327 template< class T > 328 QDoubleSpinBox* create() 329 { 330 typedef InputProperties<T> P; 331 auto* spinbox = create(P::decimals(), P::min(), P::max(), P::unit(), P::step()); 332 if (P::wrapping()) 333 spinbox->setWrapping(true); 334 return spinbox; 335 } 336 337 /** 338 * @deprecated Transitional method. 339 * 340 * Creates and initializes a QDoubleSpinBox. 341 * 342 * This method allows to initialize the most frequent options of 343 * QDoubleSpinBox in a single call, determining the actual properties 344 * via InputProperties<T>. 345 * 346 * The unit of measurement is taken from the actual parameter. This is 347 * meant to support the transition from code where the translation of 348 * units still exists in the context of the client code, instead of 349 * in the context UnitOfMeasurement. 350 */ 351 template< class T > 352 QDoubleSpinBox* create(const QString& unit) 353 { 354 typedef InputProperties<T> P; 355 auto* spinbox = create(P::decimals(), P::min(), P::max(), unit, P::step()); 356 if (P::wrapping()) 357 spinbox->setWrapping(true); 358 return spinbox; 359 } 360 } 361 362 363 364 namespace TristateCheckbox 365 { 366 void setDisabledAndChecked(QCheckBox* checkbox, bool checked); 367 368 void setEnabledAndChecked(QCheckBox* checkbox, bool checked); 369 } 370 371 372 373 /** 374 * Remove any HTML markup from the input text. 375 * 376 * \see QTextDocument::toPlainText 377 */ 378 QString plainText(QString maybe_markup); 379 380 } 381 382 383 } // namespace OpenOrienteering 384 #endif 385