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