1 // Written by Christopher E. Miller
2 // See the included license.txt for copyright and license details.
3 
4 module dfl.label;
5 import core.sys.windows.windows;
6 
7 import dfl.base;
8 import dfl.control;
9 import dfl.event;
10 import dfl.drawing;
11 import dfl.internal.dlib;
12 
13 class Label : Control {
14    this() {
15       resizeRedraw = true; // Word wrap and center correctly.
16 
17       tfmt = new TextFormat(TextFormatFlags.WORD_BREAK | TextFormatFlags.LINE_LIMIT);
18    }
19 
20    @property void borderStyle(BorderStyle bs) {
21       final switch (bs) {
22          case BorderStyle.FIXED_3D:
23             _style(_style() & ~WS_BORDER);
24             _exStyle(_exStyle() | WS_EX_CLIENTEDGE);
25             break;
26 
27          case BorderStyle.FIXED_SINGLE:
28             _exStyle(_exStyle() & ~WS_EX_CLIENTEDGE);
29             _style(_style() | WS_BORDER);
30             break;
31 
32          case BorderStyle.NONE:
33             _style(_style() & ~WS_BORDER);
34             _exStyle(_exStyle() & ~WS_EX_CLIENTEDGE);
35             break;
36       }
37 
38       if (isHandleCreated) {
39          redrawEntire();
40       }
41    }
42 
43 
44    @property BorderStyle borderStyle() {
45       if (_exStyle() & WS_EX_CLIENTEDGE) {
46          return BorderStyle.FIXED_3D;
47       } else if (_style() & WS_BORDER) {
48          return BorderStyle.FIXED_SINGLE;
49       }
50       return BorderStyle.NONE;
51    }
52 
53    final @property void useMnemonic(bool byes) {
54       if (byes) {
55          tfmt.formatFlags = tfmt.formatFlags & ~TextFormatFlags.NO_PREFIX;
56          _style(_style() & ~SS_NOPREFIX);
57       } else {
58          tfmt.formatFlags = tfmt.formatFlags | TextFormatFlags.NO_PREFIX;
59          _style(_style() | SS_NOPREFIX);
60       }
61 
62       if (isHandleCreated) {
63          invalidate();
64       }
65    }
66 
67 
68    final @property bool useMnemonic() {
69       return (tfmt.formatFlags & TextFormatFlags.NO_PREFIX) == 0;
70    }
71 
72    @property Size preferredSize() {
73       Size result;
74       Graphics g;
75       g = isHandleCreated ? createGraphics() : Graphics.getScreen();
76       result = g.measureText(text, font, tfmt);
77       g.dispose();
78       return result;
79    }
80 
81    private void doAutoSize(Dstring text) {
82       //if(isHandleCreated)
83       {
84          clientSize = preferredSize;
85       }
86    }
87 
88    override @property void text(Dstring newText) {
89       super.text = newText;
90 
91       if (autosz) {
92          doAutoSize(newText);
93       }
94 
95       invalidate(false);
96    }
97 
98    alias text = Control.text; // Overload.
99 
100    @property void autoSize(bool byes) {
101       if (byes != autosz) {
102          autosz = byes;
103 
104          if (byes) {
105             doAutoSize(text);
106          }
107       }
108    }
109 
110 
111    @property bool autoSize() {
112       return autosz;
113    }
114 
115    @property void textAlign(ContentAlignment calign) {
116       final switch (calign) {
117          case ContentAlignment.TOP_LEFT:
118             tfmt.alignment = TextAlignment.TOP | TextAlignment.LEFT;
119             break;
120 
121          case ContentAlignment.BOTTOM_CENTER:
122             tfmt.alignment
123                = TextAlignment.BOTTOM | TextAlignment.CENTER;
124             break;
125 
126          case ContentAlignment.BOTTOM_LEFT:
127             tfmt.alignment = TextAlignment.BOTTOM | TextAlignment.LEFT;
128             break;
129 
130          case ContentAlignment.BOTTOM_RIGHT:
131             tfmt.alignment = TextAlignment.BOTTOM | TextAlignment.RIGHT;
132             break;
133 
134          case ContentAlignment.MIDDLE_CENTER:
135             tfmt.alignment
136                = TextAlignment.MIDDLE | TextAlignment.CENTER;
137             break;
138 
139          case ContentAlignment.MIDDLE_LEFT:
140             tfmt.alignment = TextAlignment.MIDDLE | TextAlignment.LEFT;
141             break;
142 
143          case ContentAlignment.MIDDLE_RIGHT:
144             tfmt.alignment = TextAlignment.MIDDLE | TextAlignment.RIGHT;
145             break;
146 
147          case ContentAlignment.TOP_CENTER:
148             tfmt.alignment = TextAlignment.TOP | TextAlignment.CENTER;
149             break;
150 
151          case ContentAlignment.TOP_RIGHT:
152             tfmt.alignment = TextAlignment.TOP | TextAlignment.RIGHT;
153             break;
154       }
155 
156       invalidate(); // ?
157    }
158 
159 
160    @property ContentAlignment textAlign() {
161       TextAlignment ta;
162       ta = tfmt.alignment;
163 
164       if (ta & TextAlignment.BOTTOM) {
165          if (ta & TextAlignment.RIGHT) {
166             return ContentAlignment.BOTTOM_RIGHT;
167          } else if (ta & TextAlignment.CENTER) {
168             return ContentAlignment.BOTTOM_CENTER;
169          } else { // Left.
170             return ContentAlignment.BOTTOM_LEFT;
171          }
172       } else if (ta & TextAlignment.MIDDLE) {
173          if (ta & TextAlignment.RIGHT) {
174             return ContentAlignment.MIDDLE_RIGHT;
175          } else if (ta & TextAlignment.CENTER) {
176             return ContentAlignment.MIDDLE_CENTER;
177          } else { // Left.
178             return ContentAlignment.MIDDLE_LEFT;
179          }
180       } else { // Top.
181          if (ta & TextAlignment.RIGHT) {
182             return ContentAlignment.TOP_RIGHT;
183          } else if (ta & TextAlignment.CENTER) {
184             return ContentAlignment.TOP_CENTER;
185          } else { // Left.
186             return ContentAlignment.TOP_LEFT;
187          }
188       }
189    }
190 
191    protected override @property Size defaultSize() {
192       return Size(100, 23);
193    }
194 
195    protected override void onPaint(PaintEventArgs ea) {
196       int x, y, w, h;
197       Dstring text;
198 
199       text = this.text;
200 
201       if (tfmt.alignment & TextAlignment.MIDDLE) {
202          // Graphics.drawText() does not support middle alignment
203          // if the text is multiline, so need to do extra work.
204          Size sz;
205          sz = ea.graphics.measureText(text, font, tfmt);
206          x = 0;
207          //if(sz.height >= this.clientSize.height)
208          // y = 0;
209          //else
210          y = (this.clientSize.height - sz.height) / 2;
211          w = clientSize.width;
212          h = sz.height;
213       } else if (tfmt.alignment & TextAlignment.BOTTOM) {
214          // Graphics.drawText() does not support bottom alignment
215          // if the text is multiline, so need to do extra work.
216          Size sz;
217          sz = ea.graphics.measureText(text, font, tfmt);
218          x = 0;
219          //if(sz.height >= this.clientSize.height)
220          // y = 0;
221          //else
222          y = this.clientSize.height - sz.height;
223          w = clientSize.width;
224          h = sz.height;
225       } else {
226          x = 0;
227          y = 0;
228          w = clientSize.width;
229          h = clientSize.height;
230       }
231 
232       Color c;
233       //c = foreColor;
234       c = foreColor.solidColor(backColor);
235 
236       if (enabled) {
237          ea.graphics.drawText(text, font, c, Rect(x, y, w, h), tfmt);
238       } else {
239          version (LABEL_GRAYSTRING) {
240             // GrayString() is pretty ugly.
241             GrayStringA(ea.graphics.handle, null, &_disabledOutputProc,
242                   cast(LPARAM) cast(void*) this, -1, x, y, w, h);
243          } else {
244             ea.graphics.drawTextDisabled(text, font, c, backColor, Rect(x, y, w, h),
245                   tfmt);
246          }
247       }
248 
249       super.onPaint(ea);
250    }
251 
252    /+
253       protected override void onHandleCreated(EventArgs ea) {
254          super.onHandleCreated(ea);
255 
256          /+
257             if(autosz) {
258                doAutoSize(text);
259             }
260          +/
261       }
262    +/
263 
264       protected override void onEnabledChanged(EventArgs ea) {
265          invalidate(false);
266 
267          super.onEnabledChanged(ea);
268       }
269 
270    protected override void onFontChanged(EventArgs ea) {
271       if (autosz) {
272          doAutoSize(text);
273       }
274 
275       invalidate(false);
276 
277       super.onFontChanged(ea);
278    }
279 
280    protected override void wndProc(ref Message m) {
281       switch (m.msg) {
282          case WM_GETDLGCODE:
283             super.wndProc(m);
284             //if(useMnemonic)
285             m.result |= DLGC_STATIC;
286             break;
287 
288          default:
289             super.wndProc(m);
290       }
291    }
292 
293    protected override bool processMnemonic(dchar charCode) {
294       if (visible && enabled) {
295          if (isMnemonic(charCode, text)) {
296             select(true, true);
297             return true;
298          }
299       }
300       return false;
301    }
302 
303    private:
304    TextFormat _tfmt;
305    bool autosz = false;
306 
307    final @property void tfmt(TextFormat tf) {
308       _tfmt = tf;
309    }
310 
311    final @property TextFormat tfmt() {
312       /+
313          // This causes it to invert.
314          if(rightToLeft) {
315             _tfmt.formatFlags = _tfmt.formatFlags | TextFormatFlags.DIRECTION_RIGHT_TO_LEFT;
316          } else {
317             _tfmt.formatFlags = _tfmt.formatFlags & ~TextFormatFlags.DIRECTION_RIGHT_TO_LEFT;
318          }
319       +/
320 
321          return _tfmt;
322    }
323 }
324 
325 version (LABEL_GRAYSTRING) {
326    private extern (Windows) BOOL _disabledOutputProc(HDC hdc, LPARAM lpData, int cchData) {
327       BOOL result = TRUE;
328       try {
329          scope Graphics g = new Graphics(hdc, false);
330          Label l;
331          with (l = cast(Label) cast(void*) lpData) {
332             g.drawText(text, font, foreColor, Rect(0, 0, clientSize.width,
333                      clientSize.height), tfmt);
334          }
335       }
336       catch (DThrowable e) {
337          Application.onThreadException(e);
338          result = FALSE;
339       }
340       return result;
341    }
342 }