1 /*
2  *    Copyright 2012, 2013 Thomas Schöps
3  *    Copyright 2012-2019 Kai Pastor
4  *
5  *    This file is part of OpenOrienteering.
6  *
7  *    OpenOrienteering is free software: you can redistribute it and/or modify
8  *    it under the terms of the GNU General Public License as published by
9  *    the Free Software Foundation, either version 3 of the License, or
10  *    (at your option) any later version.
11  *
12  *    OpenOrienteering is distributed in the hope that it will be useful,
13  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *    GNU General Public License for more details.
16  *
17  *    You should have received a copy of the GNU General Public License
18  *    along with OpenOrienteering.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 
22 #ifndef OPENORIENTEERING_TEXT_SYMBOL_H
23 #define OPENORIENTEERING_TEXT_SYMBOL_H
24 
25 #include "symbol.h"
26 
27 #include <vector>
28 
29 #include <Qt>
30 #include <QFont>
31 #include <QFontMetricsF>
32 #include <QString>
33 
34 class QXmlStreamReader;
35 class QXmlStreamWriter;
36 // IWYU pragma: no_forward_declare QFontMetricsF
37 
38 namespace OpenOrienteering {
39 
40 class Map;
41 class MapColor;
42 class MapColorMap;
43 class Object;
44 class ObjectRenderables;
45 class SymbolPropertiesWidget;
46 class SymbolSettingDialog;
47 class TextObject;
48 class VirtualCoordVector;
49 
50 
51 
52 /** Symbol for text, can be applied to TextObjects.
53  *
54  * NOTE: Uses a hack to disable hinting for fonts:
55  * Uses a big internal font size, internal_point_size, where hinting is
56  * neglegible and scales it down for output.
57  * TODO: A maybe better solution would be to use FreeType directly.
58  */
59 class TextSymbol : public Symbol
60 {
61 friend class TextSymbolSettings;
62 friend class PointSymbolEditorWidget;
63 friend class OCAD8FileImport;
64 public:
65 	/** Modes for text framing */
66 	enum FramingMode
67 	{
68 		/** Only the text itself is displayed. */
69 		NoFraming = 0,
70 
71 		/**
72 		 * The text path is drawn with a QPainter with active QPen in addition
73 		 * to the normal fill, resulting in a line around the letters.
74 		 */
75 		LineFraming = 1,
76 
77 		/**
78 		 * The text is drawn a second time with a slight offset to the main
79 		 * text, creating a shadow effect.
80 		 */
81 		ShadowFraming = 2
82 	};
83 
84 	/** Creates an empty text symbol. */
85 	TextSymbol();
86 	~TextSymbol() override;
87 
88 protected:
89 	explicit TextSymbol(const TextSymbol& proto);
90 	TextSymbol* duplicate() const override;
91 
92 public:
93 	void createRenderables(
94 	        const Object *object,
95 	        const VirtualCoordVector &coords,
96 	        ObjectRenderables &output,
97 	        Symbol::RenderableOptions options) const override;
98 
99 	using Symbol::createBaselineRenderables;
100 	void createBaselineRenderables(
101 	        const TextObject* text_object,
102 	        const VirtualCoordVector &coords,
103 	        ObjectRenderables &output) const;
104 
105 	void createLineBelowRenderables(const Object* object, ObjectRenderables& output) const;
106 	void colorDeletedEvent(const MapColor* color) override;
107 	bool containsColor(const MapColor* color) const override;
108 	const MapColor* guessDominantColor() const override;
109 	void replaceColors(const MapColorMap& color_map) override;
110 	void scale(double factor) override;
111 
112 	/** Updates the internal QFont from the font settings. */
113 	void updateQFont();
114 
115 	/** Calculates the factor to convert from the real font size to the internal font size */
calculateInternalScaling()116 	inline double calculateInternalScaling() const {return internal_point_size / (0.001 * font_size);}
117 
118 	// Getters
getColor()119 	inline const MapColor* getColor() const {return color;}
setColor(const MapColor * color)120 	inline void setColor(const MapColor* color) {this->color = color;}
getFontFamily()121 	inline const QString& getFontFamily() const {return font_family;}
getFontSize()122 	inline double getFontSize() const {return 0.001 * font_size;}
isBold()123 	inline bool isBold() const {return bold;}
isItalic()124 	inline bool isItalic() const {return italic;}
isUnderlined()125 	inline bool isUnderlined() const {return underline;}
getLineSpacing()126 	inline float getLineSpacing() const {return line_spacing;}
getParagraphSpacing()127 	inline double getParagraphSpacing() const {return 0.001 * paragraph_spacing;}
getCharacterSpacing()128 	inline double getCharacterSpacing() const {return 0.001 * character_spacing;}
usesKerning()129 	inline bool usesKerning() const {return kerning;}
130 	QString getIconText() const; // returns a default text if no custom text is set.
usesFraming()131 	inline bool usesFraming() const {return framing;}
getFramingColor()132 	inline const MapColor* getFramingColor() const {return framing_color;}
getFramingMode()133 	inline int getFramingMode() const {return framing_mode;}
getFramingLineHalfWidth()134 	inline int getFramingLineHalfWidth() const {return framing_line_half_width;}
getFramingShadowXOffset()135 	inline int getFramingShadowXOffset() const {return framing_shadow_x_offset;}
getFramingShadowYOffset()136 	inline int getFramingShadowYOffset() const {return framing_shadow_y_offset;}
hasLineBelow()137 	inline bool hasLineBelow() const {return line_below;}
getLineBelowColor()138 	inline const MapColor* getLineBelowColor() const {return line_below_color;}
getLineBelowWidth()139 	inline double getLineBelowWidth() const {return 0.001 * line_below_width;}
getLineBelowDistance()140 	inline double getLineBelowDistance() const {return 0.001 * line_below_distance;}
getNumCustomTabs()141 	inline int getNumCustomTabs() const {return (int)custom_tabs.size();}
getCustomTab(int index)142 	inline int getCustomTab(int index) const {return custom_tabs[index];}
getQFont()143 	inline const QFont& getQFont() const {return qfont;}
getFontMetrics()144 	inline const QFontMetricsF& getFontMetrics() const { return metrics; }
145 
146 	double getNextTab(double pos) const;
147 
148 	constexpr static qreal internal_point_size = 256;
149 
150 	SymbolPropertiesWidget* createPropertiesWidget(SymbolSettingDialog* dialog) override;
151 
152 protected:
153 	void saveImpl(QXmlStreamWriter& xml, const Map& map) const override;
154 	bool loadImpl(QXmlStreamReader& xml, const Map& map, SymbolDictionary& symbol_dict, int version) override;
155 	bool equalsImpl(const Symbol* other, Qt::CaseSensitivity case_sensitivity) const override;
156 
157 
158 	// Members ordered for minimizing padding
159 
160 	QFont qfont;
161 	QFontMetricsF metrics;
162 	QString font_family;
163 	QString icon_text;			// text to be drawn in the symbol's icon
164 
165 	const MapColor* color;
166 	const MapColor* framing_color;
167 	const MapColor* line_below_color;
168 
169 	std::vector<int> custom_tabs;
170 
171 	double tab_interval;		/// default tab interval length in text coordinates
172 	float line_spacing;			// as factor of original line spacing
173 	float character_spacing;	// as a factor of the space character width
174 	int font_size;				// this defines the font size in 1000 mm. How big the letters really are depends on the design of the font though
175 	int paragraph_spacing;		// in mm
176 	int framing_mode;
177 	int framing_line_half_width;
178 	int framing_shadow_x_offset;
179 	int framing_shadow_y_offset;
180 	int line_below_width;
181 	int line_below_distance;
182 	bool bold;
183 	bool italic;
184 	bool underline;
185 	bool kerning;
186 	bool framing;
187 	bool line_below;
188 
189 };
190 
191 
192 }  // namespace OpenOrienteering
193 
194 #endif
195