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 }