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