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