1 /**
2  * Text specific module.
3  *
4  * License:
5  *     MIT. See LICENSE for full details.
6  */
7 module tkd.widget.common.canvas.textspecific;
8 
9 /**
10  * These are common commands that apply to all widgets that have them injected.
11  */
12 mixin template TextSpecific()
13 {
14 	import std.conv;
15 	import std.typecons : Nullable;
16 
17 	/**
18 	 * The angle of the text.
19 	 */
20 	private Nullable!(double) _angle;
21 
22 	/**
23 	 * The font.
24 	 */
25 	private string _font;
26 
27 	/**
28 	 * The alignment.
29 	 */
30 	private string _alignment;
31 
32 	/**
33 	 * The text.
34 	 */
35 	private string _text;
36 
37 	/**
38 	 * The maximum line length.
39 	 */
40 	private Nullable!(int) _maxLineLength;
41 
42 	/**
43 	 * Get the text angle.
44 	 *
45 	 * Returns:
46 	 *     The text angle.
47 	 */
48 	public double getAngle()
49 	{
50 		if (this._parent)
51 		{
52 			this._tk.eval("%s itemcget %s -angle", this._parent.id, this.id);
53 			this._angle = this._tk.getResult!(double);
54 		}
55 
56 		return this._angle.isNull ? 0.0 : this._angle.get;
57 	}
58 
59 	/**
60 	 * Specifies how many degrees to rotate the text anticlockwise about the 
61 	 * positioning point for the text; it may have any floating-point value 
62 	 * from 0.0 to 360.0. For example, if rotationDegrees is 90, then the text 
63 	 * will be drawn vertically from bottom to top. This option defaults to 
64 	 * 0.0. Degrees is given in units of degrees measured counter-clockwise 
65 	 * from the 3-o'clock position; it may be either positive or negative.
66 	 *
67 	 * Params:
68 	 *    angle = The text angle.
69 	 *
70 	 * Returns:
71 	 *     This item to aid method chaining.
72 	 */
73 	public auto setAngle(this T, A)(A angle) if (is(A == double) || is(A == Nullable!(double)))
74 	{
75 		static if (is(A == Nullable!(double)))
76 		{
77 			if (angle.isNull)
78 			{
79 				return cast(T) this;
80 			}
81 		}
82 
83 		this._angle = angle;
84 
85 		if (this._parent)
86 		{
87 			this._tk.eval("%s itemconfigure %s -angle %s", this._parent.id, this.id, this._angle);
88 		}
89 
90 		return cast(T) this;
91 	}
92 
93 	/**
94 	 * Get the font.
95 	 *
96 	 * Returns:
97 	 *     The font.
98 	 */
99 	public string getFont()
100 	{
101 		if (this._parent)
102 		{
103 			this._tk.eval("%s itemcget %s -font", this._parent.id, this.id);
104 			this._font = this._tk.getResult!(string);
105 		}
106 
107 		return this._font;
108 	}
109 
110 	/**
111 	 * Specifies the font to use for the text item. The format of the string to 
112 	 * pass when specifing a font is as follows.
113 	 *
114 	 * "Times New Roman" [[12] [bold] [italic] [overstrike] [underline]]
115 	 *
116 	 * Params:
117 	 *    font = The font.
118 	 *
119 	 * Returns:
120 	 *     This item to aid method chaining.
121 	 */
122 	public auto setFont(this T)(string font)
123 	{
124 		this._font = font;
125 
126 		if (this._parent && this._font.length)
127 		{
128 			// String concatentation is used here to avoid the character escaping done on args.
129 			this._tk.eval("%s itemconfigure %s -font {"~ this._font ~"}", this._parent.id, this.id);
130 		}
131 
132 		return cast(T) this;
133 	}
134 
135 	/**
136 	 * Get the alignment
137 	 *
138 	 * Returns:
139 	 *     The alignment.
140 	 */
141 	public string getAlignment()
142 	{
143 		if (this._parent)
144 		{
145 			this._tk.eval("%s itemcget %s -justify", this._parent.id, this.id);
146 			this._alignment = this._tk.getResult!(string);
147 		}
148 
149 		return this._alignment;
150 	}
151 
152 	/**
153 	 * Specifies how to justify the text within its bounding region.
154 	 *
155 	 * Params:
156 	 *    alignment = The alignment.
157 	 *
158 	 * Returns:
159 	 *     This item to aid method chaining.
160 	 *
161 	 * See_Also:
162 	 *     $(LINK2 ./alignment.html, tkd.widget.alignment)
163 	 */
164 	public auto setAlignment(this T)(string alignment)
165 	{
166 		this._alignment = alignment;
167 
168 		if (this._parent && this._alignment.length)
169 		{
170 			this._tk.eval("%s itemconfigure %s -justify {%s}", this._parent.id, this.id, this._alignment);
171 		}
172 
173 		return cast(T) this;
174 	}
175 
176 	/**
177 	 * Get the text.
178 	 *
179 	 * Returns:
180 	 *     The text.
181 	 */
182 	public string getText()
183 	{
184 		if (this._parent)
185 		{
186 			this._tk.eval("%s itemcget %s -text", this._parent.id, this.id);
187 			this._text = this._tk.getResult!(string);
188 		}
189 
190 		return this._text;
191 	}
192 
193 	/**
194 	 * Specifies the characters to be displayed in the text item.  Newline 
195 	 * characters cause line breaks.
196 	 *
197 	 * Params:
198 	 *    text = The text.
199 	 *
200 	 * Returns:
201 	 *     This item to aid method chaining.
202 	 */
203 	public auto setText(this T)(string text)
204 	{
205 		this._text = text;
206 
207 		if (this._parent && this._text.length)
208 		{
209 			// String concatenation is used to build the script here instead of 
210 			// using format specifiers to enable supporting input which 
211 			// includes Tcl/Tk reserved characters and elements that could be 
212 			// construed as format specifiers.
213 			string script = std.conv.text(this._parent.id, ` itemconfigure `, this.id, ` -text "`, this._tk.escape(this._text), `"`);
214 			this._tk.eval(script);
215 		}
216 
217 		return cast(T) this;
218 	}
219 
220 	/**
221 	 * Get max line length.
222 	 *
223 	 * Returns:
224 	 *     The max line length.
225 	 */
226 	public int getMaxLineLength()
227 	{
228 		if (this._parent)
229 		{
230 			this._tk.eval("%s itemcget %s -width", this._parent.id, this.id);
231 			this._maxLineLength = this._tk.getResult!(int);
232 		}
233 
234 		return this._maxLineLength.isNull ? 0 : this._maxLineLength.get;
235 	}
236 
237 	/**
238 	 * Specifies a maximum line length for the text. If this option is zero 
239 	 * (the default) the text is broken into lines only at newline characters.  
240 	 * However, if this option is non-zero then any line that would be longer 
241 	 * than line length is broken just before a space character to make the 
242 	 * line shorter than lineLength; the space character is treated as if it 
243 	 * were a newline character.
244 	 *
245 	 * Params:
246 	 *    maxLineLength = The max line length.
247 	 *
248 	 * Returns:
249 	 *     This item to aid method chaining.
250 	 */
251 	public auto setMaxLineLength(this T, L)(L maxLineLength) if (is(L == int) || is(L == Nullable!(int)))
252 	{
253 		static if (is(L == Nullable!(int)))
254 		{
255 			if (maxLineLength.isNull)
256 			{
257 				return cast(T) this;
258 			}
259 		}
260 
261 		this._maxLineLength = maxLineLength;
262 
263 		if (this._parent)
264 		{
265 			this._tk.eval("%s itemconfigure %s -width %s", this._parent.id, this.id, this._maxLineLength);
266 		}
267 
268 		return cast(T) this;
269 	}
270 }