1 /* 2 * Copyright (C) 2015-2017, by Laszlo Szeremi under the Boost license. 3 * 4 * Pixel Perfect Engine, concrete.elements module 5 */ 6 7 module PixelPerfectEngine.concrete.elements; 8 9 import PixelPerfectEngine.graphics.bitmap; 10 public import PixelPerfectEngine.graphics.draw; 11 import PixelPerfectEngine.system.etc; 12 import PixelPerfectEngine.system.inputHandler; 13 import std.algorithm; 14 import std.stdio; 15 import std.conv; 16 import PixelPerfectEngine.concrete.stylesheet; 17 18 /** 19 * All Window elements inherit from this class. Provides basic interfacing with containers. 20 */ 21 abstract class WindowElement{ 22 //public ActionListener[] al; 23 protected dstring text; 24 protected string source; 25 ///DO NOT MODIFY IT EXTERNALLY! Contains the position of the element. 26 public Coordinate position; 27 ///Contains the output of the drawing functions 28 public BitmapDrawer output; 29 ///Points to the container for two-way communication 30 public ElementContainer elementContainer; 31 public StyleSheet customStyle; 32 protected bool state; 33 34 public static InputHandler inputHandler; ///Common input handler, must be set upon program initialization 35 public static PopUpHandler popUpHandler; ///Common pop-up handler 36 public static StyleSheet styleSheet; ///Basic stylesheet, all elements default to this if no alternative found 37 38 public static void delegate() onDraw; ///Called when drawing is finished 39 40 public void delegate(Event ev) onMouseLClickRel; ///Called on left mouseclick released 41 public void delegate(Event ev) onMouseRClickRel; ///Called on right mouseclick released 42 public void delegate(Event ev) onMouseMClickRel; ///Called on middle mouseclick released 43 public void delegate(Event ev) onMouseHover; ///Called if mouse is on object 44 public void delegate(Event ev) onMouseMove; ///Called if mouse is moved on object 45 public void delegate(Event ev) onMouseLClickPre; ///Called on left mouseclick pressed 46 public void delegate(Event ev) onMouseRClickPre; ///Called on right mouseclick pressed 47 public void delegate(Event ev) onMouseMClickPre; ///Called on middle mouseclick pressed 48 49 public void onClick(int offsetX, int offsetY, int state, ubyte button){ 50 51 } 52 public void onDrag(int x, int y, int relX, int relY, ubyte button){ 53 54 } 55 56 public void onScroll(int x, int y, int wX, int wY){ 57 58 } 59 60 @property @nogc @safe nothrow public int getX(){ 61 return position.width; 62 } 63 @property @nogc @safe nothrow public int getY(){ 64 return position.height; 65 } 66 @property @nogc @safe nothrow public Coordinate getPosition(){ 67 return position; 68 } 69 /** 70 * Updates the output. Every subclass must override it. 71 */ 72 public abstract void draw(); 73 74 /+protected void invokeActionEvent(int type, int value, wstring message = ""){ 75 foreach(ActionListener a; al){ 76 if(a) 77 a.actionEvent(new Event(source, null, null, null, text, value, type)); 78 } 79 } 80 81 protected void invokeActionEvent(Event e) { 82 foreach(ActionListener a; al){ 83 if(a) 84 a.actionEvent(e); 85 } 86 }+/ 87 /*private Bitmap16Bit getBrush(int style){ 88 return altStyleBrush.get(style, elementContainer.getStyleBrush(style)); 89 }*/ 90 public @nogc dstring getText(){ 91 return text; 92 } 93 public void setText(dstring s){ 94 text = s; 95 elementContainer.clearArea(this); 96 draw(); 97 98 } 99 100 public StyleSheet getAvailableStyleSheet(){ 101 if(customStyle !is null){ 102 return customStyle; 103 } 104 return styleSheet; 105 } 106 107 public void setCustomStyle(StyleSheet s){ 108 customStyle = s; 109 } 110 /** 111 * Enables (b = true) or disables (b = false) the element. All element is enabled by default. 112 */ 113 @nogc public void setState(bool b){ 114 state = !b; 115 } 116 /** 117 * Gets the state of the element. 118 */ 119 @nogc public bool getState(){ 120 return !state; 121 } 122 /** 123 * Returns the source string. 124 */ 125 @property public string getSource(){ 126 return source; 127 } 128 } 129 130 public class Button : WindowElement{ 131 private bool isPressed; 132 public bool enableRightButtonClick; 133 public bool enableMiddleButtonClick; 134 public this(dstring text, string source, Coordinate coordinates){ 135 position = coordinates; 136 //sizeX = coordinates.width(); 137 //sizeY = coordinates.height(); 138 this.text = text; 139 this.source = source; 140 output = new BitmapDrawer(coordinates.width, coordinates.height); 141 //brushPressed = 1; 142 //draw(); 143 } 144 public override void draw(){ 145 if(output.output.width != position.width || output.output.height != position.height) 146 output = new BitmapDrawer(position.width(), position.height()); 147 if(isPressed){ 148 output.drawFilledRectangle(1, position.width()-1, 1,position.height()-1, getAvailableStyleSheet().getColor("windowinactive")); 149 output.drawLine(0, position.width()-1, 0, 0, getAvailableStyleSheet().getColor("windowdescent")); 150 output.drawLine(0, 0, 0, position.height()-1, getAvailableStyleSheet().getColor("windowdescent")); 151 output.drawLine(0, position.width()-1, position.height()-1, position.height()-1, getAvailableStyleSheet().getColor("windowascent")); 152 output.drawLine(position.width()-1, position.width()-1, 0, position.height()-1, getAvailableStyleSheet().getColor("windowascent")); 153 }else{ 154 output.drawFilledRectangle(1, position.width()-1, 1,position.height()-1, getAvailableStyleSheet().getColor("window")); 155 output.drawLine(0, position.width()-1, 0, 0, getAvailableStyleSheet().getColor("windowascent")); 156 output.drawLine(0, 0, 0, position.height()-1, getAvailableStyleSheet().getColor("windowascent")); 157 output.drawLine(0, position.width()-1, position.height()-1, position.height()-1, getAvailableStyleSheet().getColor("windowdescent")); 158 output.drawLine(position.width()-1, position.width()-1, 0, position.height()-1, getAvailableStyleSheet().getColor("windowdescent")); 159 } 160 161 output.drawColorText(position.width/2, position.height/2, text, getAvailableStyleSheet().getFontset("default"), 162 getAvailableStyleSheet().getColor("normaltext"), FontFormat.HorizCentered | FontFormat.VertCentered); 163 elementContainer.drawUpdate(this); 164 if(onDraw !is null){ 165 onDraw(); 166 } 167 } 168 public override void onClick(int offsetX, int offsetY, int state, ubyte button){ 169 if(button == MouseButton.RIGHT && enableRightButtonClick){ 170 if(state == ButtonState.PRESSED){ 171 isPressed = true; 172 draw(); 173 //invokeActionEvent(EventType.CLICK, -1); 174 if(onMouseRClickPre !is null){ 175 onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 176 } 177 }else{ 178 isPressed = false; 179 draw(); 180 //invokeActionEvent(EventType.CLICK, 0); 181 if(onMouseRClickRel !is null){ 182 onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 183 } 184 } 185 }else if(button == MouseButton.MID && enableMiddleButtonClick){ 186 if(state == ButtonState.PRESSED){ 187 isPressed = true; 188 draw(); 189 //invokeActionEvent(EventType.CLICK, -1); 190 if(onMouseMClickPre !is null){ 191 onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 192 } 193 }else{ 194 isPressed = false; 195 draw(); 196 //invokeActionEvent(EventType.CLICK, 0); 197 if(onMouseMClickRel !is null){ 198 onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 199 } 200 } 201 }else{ 202 if(state == ButtonState.PRESSED){ 203 isPressed = true; 204 draw(); 205 //invokeActionEvent(EventType.CLICK, -1); 206 if(onMouseLClickPre !is null){ 207 onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 208 } 209 }else{ 210 isPressed = false; 211 draw(); 212 //invokeActionEvent(EventType.CLICK, 0); 213 if(onMouseLClickRel !is null){ 214 onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 215 } 216 } 217 } 218 219 } 220 } 221 222 public class SmallButton : WindowElement{ 223 private string iconPressed, iconUnpressed; 224 private bool isPressed; 225 public bool enableRightButtonClick; 226 public bool enableMiddleButtonClick; 227 public int brushPressed, brushNormal; 228 229 public this(string iconPressed, string iconUnpressed, string source, Coordinate coordinates){ 230 position = coordinates; 231 232 //this.text = text; 233 this.source = source; 234 this.iconPressed = iconPressed; 235 this.iconUnpressed = iconUnpressed; 236 output = new BitmapDrawer(coordinates.width, coordinates.height); 237 brushPressed = 1; 238 //draw(); 239 } 240 public override void draw(){ 241 output.drawFilledRectangle(0, position.width()-1, 0,position.height()-1, 0); 242 if(isPressed){ 243 output.insertBitmap(0,0,getAvailableStyleSheet().getImage(iconPressed)); 244 }else{ 245 output.insertBitmap(0,0,getAvailableStyleSheet().getImage(iconUnpressed)); 246 } 247 elementContainer.drawUpdate(this); 248 if(onDraw !is null){ 249 onDraw(); 250 } 251 } 252 public override void onClick(int offsetX, int offsetY, int state, ubyte button){ 253 if(button == MouseButton.RIGHT && enableRightButtonClick){ 254 if(state == ButtonState.PRESSED){ 255 isPressed = true; 256 draw(); 257 //invokeActionEvent(EventType.CLICK, -1); 258 if(onMouseRClickPre !is null){ 259 onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 260 } 261 }else{ 262 isPressed = false; 263 draw(); 264 //invokeActionEvent(EventType.CLICK, 0); 265 if(onMouseRClickRel !is null){ 266 onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 267 } 268 } 269 }else if(button == MouseButton.MID && enableMiddleButtonClick){ 270 if(state == ButtonState.PRESSED){ 271 isPressed = true; 272 draw(); 273 //invokeActionEvent(EventType.CLICK, -1); 274 if(onMouseMClickPre !is null){ 275 onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 276 } 277 }else{ 278 isPressed = false; 279 draw(); 280 //invokeActionEvent(EventType.CLICK, 0); 281 if(onMouseMClickRel !is null){ 282 onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 283 } 284 } 285 }else{ 286 if(state == ButtonState.PRESSED){ 287 isPressed = true; 288 draw(); 289 //invokeActionEvent(EventType.CLICK, -1); 290 if(onMouseLClickPre !is null){ 291 onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 292 } 293 }else{ 294 isPressed = false; 295 draw(); 296 //invokeActionEvent(EventType.CLICK, 0); 297 if(onMouseLClickRel !is null){ 298 onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 299 } 300 } 301 } 302 303 } 304 } 305 306 public class Label : WindowElement{ 307 public this(dstring text, string source, Coordinate coordinates){ 308 position = coordinates; 309 this.text = text; 310 this.source = source; 311 output = new BitmapDrawer(coordinates.width, coordinates.height); 312 //draw(); 313 } 314 public override void draw(){ 315 output = new BitmapDrawer(position.width, position.height); 316 output.drawColorText(0, 0, text, getAvailableStyleSheet().getFontset("default"), 317 getAvailableStyleSheet().getColor("normaltext"), 0); 318 elementContainer.drawUpdate(this); 319 if(onDraw !is null){ 320 onDraw(); 321 } 322 } 323 /*public override void onClick(int offsetX, int offsetY, int state, ubyte button){ 324 if(state == ButtonState.PRESSED) 325 invokeActionEvent(EventType.CLICK, 0); 326 }*/ 327 public override void setText(dstring s) { 328 output.destroy(); 329 output = new BitmapDrawer(position.width, position.height); 330 super.setText(s); 331 } 332 public override void onClick(int offsetX, int offsetY, int state, ubyte button){ 333 if(button == MouseButton.RIGHT){ 334 if(state == ButtonState.PRESSED){ 335 if(onMouseRClickPre !is null){ 336 onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 337 } 338 }else{ 339 if(onMouseRClickRel !is null){ 340 onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 341 } 342 } 343 }else if(button == MouseButton.MID){ 344 if(state == ButtonState.PRESSED){ 345 if(onMouseMClickPre !is null){ 346 onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 347 } 348 }else{ 349 if(onMouseMClickRel !is null){ 350 onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 351 } 352 } 353 }else{ 354 if(state == ButtonState.PRESSED){ 355 if(onMouseLClickPre !is null){ 356 onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 357 } 358 }else{ 359 if(onMouseLClickRel !is null){ 360 onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 361 } 362 } 363 } 364 365 } 366 } 367 368 public class TextBox : WindowElement, TextInputListener{ 369 private bool enableEdit, insert; 370 private uint pos; 371 //public int brush, textpos; 372 //public TextInputHandler tih; 373 public void delegate(Event ev) onTextInput; 374 375 public this(dstring text, string source, Coordinate coordinates){ 376 position = coordinates; 377 this.text = text; 378 this.source = source; 379 output = new BitmapDrawer(coordinates.width, coordinates.height); 380 //inputHandler.addTextInputListener(source, this); 381 //insert = true; 382 //draw(); 383 } 384 385 ~this(){ 386 //inputHandler.removeTextInputListener(source); 387 } 388 public deprecated void addTextInputHandler(TextInputHandler t){ /** DEPRECATED. Will be removed soon in favor of static input handlers. */ 389 /*tih = t;*/ 390 //inputHandler.addTextInputListener(source, this); 391 } 392 393 public override void onClick(int offsetX, int offsetY, int state, ubyte button){ 394 if(button == MouseButton.RIGHT){ 395 if(state == ButtonState.PRESSED){ 396 if(onMouseRClickPre !is null){ 397 onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 398 } 399 }else{ 400 if(onMouseRClickRel !is null){ 401 onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 402 } 403 } 404 }else if(button == MouseButton.MID){ 405 if(state == ButtonState.PRESSED){ 406 if(onMouseMClickPre !is null){ 407 onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 408 } 409 }else{ 410 if(onMouseMClickRel !is null){ 411 onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 412 } 413 } 414 }else{ 415 if(state == ButtonState.PRESSED){ 416 if(onMouseLClickPre !is null){ 417 onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 418 } 419 }else{ 420 if(onMouseLClickRel !is null){ 421 onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 422 } 423 } 424 } 425 if(!enableEdit && state == ButtonState.PRESSED && button == MouseButton.LEFT){ 426 //invokeActionEvent(EventType.READYFORTEXTINPUT, 0); 427 enableEdit = true; 428 inputHandler.startTextInput(this); 429 draw(); 430 } 431 } 432 public override void draw(){ 433 if(output.output.width != position.width || output.output.height != position.height) 434 output = new BitmapDrawer(position.width, position.height); 435 output.drawFilledRectangle(0, position.width - 1, 0, position.height - 1, getAvailableStyleSheet().getColor("window")); 436 output.drawRectangle(0, position.width - 1, 0, position.height - 1, getAvailableStyleSheet().getColor("windowascent")); 437 438 //draw cursor 439 if(enableEdit){ 440 const int x = getAvailableStyleSheet().getFontset("default").getTextLength(text[0..pos]) , 441 y = getAvailableStyleSheet().getFontset("default").getSize; 442 if(!insert){ 443 output.drawLine(x + 2, x + 2, 2, 2 + y, getAvailableStyleSheet().getColor("selection")); 444 }else{ 445 const int x0 = pos == text.length ? x + getAvailableStyleSheet().getFontset("default").chars[' '].xadvance : 446 getAvailableStyleSheet().getFontset("default").getTextLength(text[0..pos + 1]); 447 output.drawFilledRectangle(x + 2, x0 + 2, 2, 2 + y, getAvailableStyleSheet().getColor("selection")); 448 } 449 } 450 451 output.drawColorText(2, 2, text, getAvailableStyleSheet().getFontset("default"), 452 getAvailableStyleSheet().getColor("normaltext"), 0); 453 elementContainer.drawUpdate(this); 454 if(onDraw !is null){ 455 onDraw(); 456 } 457 } 458 459 private void deleteCharacter(int n){ 460 //text = remove(text, i); 461 dstring newtext; 462 for(int i; i < text.length; i++){ 463 if(i != n - 1){ 464 newtext ~= text[i]; 465 } 466 } 467 text = newtext; 468 } 469 public void textInputEvent(uint timestamp, uint windowID, dstring text){ 470 471 int j = pos; 472 dstring newtext; 473 for(int i ; i < pos ; i++){ 474 newtext ~= this.text[i]; 475 } 476 for(int i ; i < 32 ; i++){ 477 if(text[i] == 0){ 478 break; 479 } 480 else{ 481 newtext ~= text[i]; 482 pos++; 483 if(insert){ 484 j++; 485 } 486 } 487 } 488 for( ; j < this.text.length ; j++){ 489 newtext ~= this.text[j]; 490 } 491 this.text = newtext; 492 draw(); 493 } 494 495 public void dropTextInput(){ 496 enableEdit = false; 497 //inputHandler.stopTextInput(source); 498 draw(); 499 //invokeActionEvent(EventType.TEXTINPUT, 0, text); 500 if(onTextInput !is null) 501 onTextInput(new Event(source, null, null, null, text, 0, EventType.TEXTINPUT, null, this)); 502 } 503 504 505 public void textInputKeyEvent(uint timestamp, uint windowID, TextInputKey key, ushort modifier = 0){ 506 if(key == TextInputKey.ESCAPE || key == TextInputKey.ENTER){ 507 enableEdit = false; 508 inputHandler.stopTextInput(this); 509 draw(); 510 //invokeActionEvent(EventType.TEXTINPUT, 0, text); 511 if(onTextInput !is null){ 512 onTextInput(new Event(source, null, null, null, text, 0, EventType.TEXTINPUT, null, this)); 513 } 514 }else if(key == TextInputKey.BACKSPACE){ 515 if(pos > 0){ 516 deleteCharacter(pos); 517 pos--; 518 draw(); 519 } 520 /*if(pos > 0){ 521 if(pos == text.length){ 522 text.length--; 523 pos--; 524 525 } 526 }*/ 527 }else if(key == TextInputKey.DELETE){ 528 deleteCharacter(pos + 1); 529 draw(); 530 }else if(key == TextInputKey.CURSORLEFT){ 531 if(pos > 0){ 532 --pos; 533 draw(); 534 } 535 }else if(key == TextInputKey.CURSORRIGHT){ 536 if(pos < text.length){ 537 ++pos; 538 draw(); 539 } 540 }else if(key == TextInputKey.INSERT){ 541 insert = !insert; 542 draw(); 543 }else if(key == TextInputKey.HOME){ 544 pos = 0; 545 draw(); 546 }else if(key == TextInputKey.END){ 547 pos = cast(uint)text.length; 548 draw(); 549 } 550 } 551 } 552 553 /** 554 * Displays multiple columns of data, also provides general text input. 555 */ 556 public class ListBox : WindowElement, ElementContainer{ 557 //public ListBoxColumn[] columns; 558 public ListBoxHeader header; 559 public ListBoxItem[] items; 560 public int[] columnWidth; 561 public int selection, brushHeader, brush, fontHeader; 562 public ushort selectionColor; 563 private bool fullRedraw, bodyDrawn, enableTextInput, textInputMode, insert, dragMid; 564 private VSlider vSlider; 565 private HSlider hSlider; 566 private Slider dragSld; 567 private int fullX, hposition, vposition, sliderX, sliderY, startY, endY, selectedColumn, textPos, previousEvent; 568 private BitmapDrawer textArea, headerArea; 569 private Coordinate textInputArea; 570 public void delegate(Event ev) onTextInput; 571 public void delegate(Event ev) onItemSelect; 572 public void delegate(Event ev) onScrolling; 573 574 public this(string source, Coordinate coordinates, ListBoxItem[] items, ListBoxHeader header, int rowHeight, 575 bool enableTextInput = false){ 576 this(source, coordinates, items, header, enableTextInput); 577 } 578 579 public this(string source,Coordinate coordinates,ListBoxItem[] items,ListBoxHeader header,bool enableTextInput=false){ 580 position = coordinates; 581 this.source = source; 582 //this.rowHeight = rowHeight; 583 this.items = items; 584 this.header = header; 585 updateColumns(); 586 587 foreach(int i; columnWidth){ 588 fullX += i; 589 } 590 if(fullX < position.width()){ 591 fullX = position.width(); 592 } 593 594 output = new BitmapDrawer(position.width, position.height); 595 596 597 this.enableTextInput = enableTextInput; 598 //inputHandler.addTextInputListener(source, this); 599 600 } 601 602 private void textInput(Event ev){ 603 items[selection].setText(selectedColumn, ev.text); 604 //invokeActionEvent(new Event(source, null, null, null, event.text, selection,EventType.TEXTINPUT, items[selection])); 605 if(onTextInput !is null){ 606 onTextInput(new Event(source, null, null, null, ev.text, selection,EventType.TEXTINPUT, items[selection], this)); 607 } 608 updateColumns(); 609 draw(); 610 } 611 private void scrollHoriz(Event ev){ 612 draw(); 613 if(onScrolling !is null){ 614 onScrolling(ev); 615 } 616 } 617 private void scrollVert(Event ev){ 618 draw(); 619 if(onScrolling !is null){ 620 onScrolling(ev); 621 } 622 } 623 public void drawUpdate(WindowElement sender){ 624 output.insertBitmap(sender.getPosition().left,sender.getPosition().top,sender.output.output); 625 626 if(!fullRedraw){ 627 /*output.insertBitmapSlice(0,0,headerArea.output,Coordinate(vposition,0,vposition + fullX - 1, rowHeight - 1)); 628 output.insertBitmapSlice(0, rowHeight, textArea.output, Coordinate(vposition,hposition * rowHeight,vposition + fullX - 1 , hposition * rowHeight + (sizeY - hSlider.getPosition().getYSize) - rowHeight));*/ 629 elementContainer.drawUpdate(this); 630 } 631 } 632 public Coordinate getAbsolutePosition(WindowElement sender){ 633 return sender.position; 634 } 635 /** 636 * Updates the columns with the given data. 637 */ 638 public void updateColumns(ListBoxItem[] items){ 639 this.items = items; 640 updateColumns(); 641 draw(); 642 } 643 /** 644 * Updates the columns with the given data and header. 645 */ 646 public void updateColumns(ListBoxItem[] items, ListBoxHeader header){ 647 this.items = items; 648 this.header = header; 649 updateColumns(); 650 draw(); 651 } 652 /** 653 * Clears the content of the ListBox. 654 */ 655 public void clearData(){ 656 items.length = 0; 657 updateColumns(); 658 draw(); 659 } 660 public void updateColumns(){ 661 const int rowHeight = getStyleSheet().drawParameters["ListBoxRowHeight"]; 662 fullX = header.getFullWidth(); 663 selection = 0; 664 665 if(fullX < position.width()){ 666 fullX = cast(int)position.width(); 667 } 668 int foo2 = cast(int)(rowHeight * this.items.length); 669 if(foo2 < position.height()) 670 foo2 = position.height(); 671 672 textArea = new BitmapDrawer(fullX, foo2); 673 headerArea = new BitmapDrawer(fullX, rowHeight); 674 675 this.vSlider = new VSlider(cast(uint)items.length - 1, ((position.height()-17-rowHeight) / rowHeight), "vslider", 676 Coordinate(position.width() - 16, 0, position.width(), position.height() - 16)); 677 this.hSlider = new HSlider(fullX - 16, position.width() - 16, "hslider", Coordinate(0, position.height() - 16, 678 position.width() - 16, position.height())); 679 this.vSlider.onScrolling = &scrollVert; 680 this.vSlider.elementContainer = this; 681 sliderX = vSlider.getX(); 682 683 684 this.hSlider.onScrolling = &scrollHoriz; 685 this.hSlider.elementContainer = this; 686 sliderY = hSlider.getY(); 687 bodyDrawn = false; 688 } 689 690 public StyleSheet getStyleSheet(){ 691 return getAvailableStyleSheet; 692 } 693 694 private void drawBody(){ 695 const int rowHeight = getStyleSheet().drawParameters["ListBoxRowHeight"]; 696 int foo; 697 for(int i; i < header.getNumberOfColumns(); i++){ 698 int bar; 699 for(int j; j < items.length; j++){ 700 701 textArea.drawColorText(foo + 1, bar, items[j].getText(i), getStyleSheet().getFontset("default"), 702 getAvailableStyleSheet().getColor("normaltext"), 0); 703 704 bar += rowHeight; 705 } 706 foo += header.getColumnWidth(i); 707 708 textArea.drawLine(foo, foo, 0, textArea.output.height-2, getStyleSheet().getColor("windowascent")); 709 } 710 } 711 712 public override void draw(){ 713 const int rowHeight = getStyleSheet().drawParameters["ListBoxRowHeight"]; 714 if(output.output.width != position.width || output.output.height != position.height){ 715 output = new BitmapDrawer(position.width(), position.height()); 716 bodyDrawn = false; 717 updateColumns(); 718 } 719 fullRedraw = true; 720 int areaX, areaY; 721 722 vposition = vSlider.value; 723 areaX = position.width - vSlider.getPosition().width(); 724 725 726 hposition = hSlider.value; 727 areaY = position.height - hSlider.getPosition().height(); 728 729 output.drawFilledRectangle(0, position.width(), 0, position.height(),getStyleSheet().getColor("window")); 730 output.drawRectangle(0, position.width() - 1, 0, position.height() - 1,getStyleSheet().getColor("windowascent")); 731 732 733 // draw the header 734 // TODO: Draw the header only once!!! 735 output.drawLine(0, position.width() - 1, rowHeight, rowHeight, getStyleSheet().getColor("windowascent")); 736 int foo; 737 for(int i; i < header.getNumberOfColumns(); i++){ 738 headerArea.drawColorText(foo + 1, 0, header.getText(i), getStyleSheet().getFontset("default"), 739 getAvailableStyleSheet().getColor("normaltext"), 0); 740 foo += header.getColumnWidth(i); 741 headerArea.drawLine(foo, foo, 0, rowHeight, getStyleSheet().getColor("windowascent")); 742 } 743 744 output.insertBitmapSlice(0,0,headerArea.output,Coordinate(hposition,0,hposition + position.width() - 17, 745 rowHeight - 1)); 746 747 //draw the selector 748 if(selection - vposition >= 0 && vposition + ((position.height()-17-rowHeight) / rowHeight) >= selection && 749 items.length != 0) 750 output.drawFilledRectangle(1, position.width() - 2, 1 + rowHeight + (rowHeight * (selection - vposition)), 751 (rowHeight * 2) + (rowHeight * (selection - vposition)), getStyleSheet().getColor("selection")); 752 753 // draw the body 754 if(!bodyDrawn){ 755 bodyDrawn = true; 756 drawBody(); 757 } 758 759 output.insertBitmapSlice(0, rowHeight, textArea.output, Coordinate(hposition,vposition * rowHeight,hposition + 760 position.width() - 17 , vposition * rowHeight + areaY - rowHeight)); 761 762 vSlider.draw(); 763 hSlider.draw(); 764 elementContainer.drawUpdate(this); 765 766 fullRedraw = false; 767 if(onDraw !is null){ 768 onDraw(); 769 } 770 } 771 public override void onClick(int offsetX, int offsetY, int state, ubyte button){ 772 const int rowHeight = getStyleSheet().drawParameters["ListBoxRowHeight"]; 773 if(button == MouseButton.RIGHT){ 774 if(state == ButtonState.PRESSED){ 775 if(onMouseRClickPre !is null){ 776 onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 777 } 778 }else{ 779 if(onMouseRClickRel !is null){ 780 onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 781 } 782 } 783 }else if(button == MouseButton.MID){ 784 if(state == ButtonState.PRESSED){ 785 if(onMouseMClickPre !is null){ 786 onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 787 } 788 }else{ 789 if(onMouseMClickRel !is null){ 790 onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 791 } 792 } 793 }else{ 794 if(state == ButtonState.PRESSED){ 795 if(onMouseLClickPre !is null){ 796 onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 797 } 798 }else{ 799 if(onMouseLClickRel !is null){ 800 onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 801 } 802 } 803 } 804 if(state == ButtonState.PRESSED){ 805 if(button == MouseButton.LEFT){ 806 if(offsetX > (vSlider.getPosition().left) && offsetY > (vSlider.getPosition().top)){ 807 vSlider.onClick(offsetX - vSlider.getPosition().left, offsetY - vSlider.getPosition().top, state, button); 808 dragSld = vSlider; 809 return; 810 811 }else if(offsetX > (hSlider.getPosition().left) && offsetY > (hSlider.getPosition().top)){ 812 hSlider.onClick(offsetX - hSlider.getPosition().left, offsetY - hSlider.getPosition().top, state, button); 813 dragSld = hSlider; 814 return; 815 816 }else if(offsetY > rowHeight && button == MouseButton.LEFT){ 817 offsetY -= rowHeight; 818 819 if(selection == (offsetY / rowHeight) + vposition){ 820 //invokeActionEvent(EventType.TEXTBOXSELECT, (offsetY / rowHeight) + vposition); 821 if(!enableTextInput){ 822 //invokeActionEvent(new Event(source, null, null, null, null, (offsetY / rowHeight) + vposition,EventType.TEXTBOXSELECT, items[selection])); 823 if(onItemSelect !is null){ 824 onItemSelect(new Event(source, null, null, null, null, (offsetY / rowHeight) + vposition, 825 EventType.TEXTBOXSELECT, items[selection], this)); 826 } 827 }else{ 828 offsetX += hposition; 829 selectedColumn = header.getColumnNumFromX(offsetX); 830 831 if(selectedColumn != -1){ 832 if(items[selection].getTextInputType(selectedColumn) != TextInputType.DISABLE){ 833 text = items[selection].getText(selectedColumn); 834 //invokeActionEvent(EventType.READYFORTEXTINPUT,selectedColumn); 835 PopUpTextInput p = new PopUpTextInput("textInput",text,Coordinate(0,0,header.getColumnWidth(selectedColumn),20)); 836 p.onTextInput = &textInput; 837 popUpHandler.addPopUpElement(p); 838 839 840 } 841 if(onItemSelect !is null){ 842 onItemSelect(new Event(source, null, null, null, null, (offsetY / rowHeight) + vposition, 843 EventType.TEXTBOXSELECT, items[selection], this)); 844 845 } 846 } 847 } 848 }else{ 849 if((offsetY / rowHeight) + vposition < items.length){ 850 selection = (offsetY / rowHeight) + vposition; 851 draw(); 852 } 853 } 854 } 855 }else if(button == MouseButton.MID){ 856 dragMid = true; 857 } 858 }else{ 859 dragMid = false; 860 dragSld = null; 861 } 862 } 863 public override void onDrag(int x, int y, int relX, int relY, ubyte button){ 864 if(dragMid){ 865 hSlider.value += x; 866 vSlider.value += y; 867 }else if(dragSld){ 868 dragSld.onDrag(x,y,relX,relY,button); 869 } 870 } 871 public override void onScroll(int x, int y, int wX, int wY){ 872 if(textInputMode) return; 873 vSlider.onScroll(x,y,0,0); 874 hSlider.onScroll(x,y,0,0); 875 } 876 /** 877 * Returns a line. 878 */ 879 public @nogc ListBoxItem readLine(int line){ 880 return items[line]; 881 } 882 /** 883 * Adds a line to the bottom of the list. 884 */ 885 public void addLine(ListBoxItem i){ 886 items ~= i; 887 } 888 /** 889 * Inserts a line to a given point of the list. 890 */ 891 public void addLine(ListBoxItem i, int n){ 892 if(n == items.length){ 893 items ~= i; 894 }else{ 895 items.length++; 896 for(int j = cast(int)items.length - 1; j > n; j++){ 897 items[j] = items[j - 1]; 898 } 899 items[n] = i; 900 } 901 } 902 /** 903 * Removes a line from the list. 904 */ 905 public void removeLine(int n){ 906 items.remove(n); 907 } 908 public void clearArea(WindowElement sender){ 909 910 } 911 } 912 /** 913 * A simple toggle button. 914 */ 915 public class CheckBox : WindowElement{ 916 public int iconChecked, iconUnchecked; 917 private bool checked; 918 public int[] brush; 919 public void delegate(Event ev) onToggle; 920 921 public this(dstring text, string source, Coordinate coordinates, bool checked = false){ 922 position = coordinates; 923 this.text = text; 924 this.source = source; 925 brush ~= 2; 926 brush ~= 3; 927 output = new BitmapDrawer(position.width, position.height); 928 this.checked = checked; 929 //draw(); 930 } 931 932 public override void draw(){ 933 if(output.output.width != position.width || output.output.height != position.height) 934 output = new BitmapDrawer(position.width, position.height); 935 output.drawRectangle(getAvailableStyleSheet().getImage("checkBoxA").width, output.output.width - 1, 0, 936 output.output.height - 1, 0x0); 937 output.drawColorText(getAvailableStyleSheet().getImage("checkBoxA").width, 0, text, 938 getAvailableStyleSheet().getFontset("default"), getAvailableStyleSheet().getColor("normaltext"), 0); 939 if(checked){ 940 output.insertBitmap(0, 0, getAvailableStyleSheet().getImage("checkBoxB")); 941 }else{ 942 output.insertBitmap(0, 0, getAvailableStyleSheet().getImage("checkBoxA")); 943 } 944 elementContainer.drawUpdate(this); 945 if(onDraw !is null){ 946 onDraw(); 947 } 948 } 949 950 public override void onClick(int offsetX, int offsetY, int state, ubyte button){ 951 /*if(state == ButtonState.PRESSED && button == MouseButton.LEFT){ 952 checked = !checked; 953 draw(); 954 invokeActionEvent(EventType.CHECKBOX, checked); 955 }*/ 956 if(button == MouseButton.RIGHT){ 957 if(state == ButtonState.PRESSED){ 958 if(onMouseRClickPre !is null){ 959 onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 960 } 961 }else{ 962 if(onMouseRClickRel !is null){ 963 onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 964 } 965 } 966 }else if(button == MouseButton.MID){ 967 if(state == ButtonState.PRESSED){ 968 if(onMouseMClickPre !is null){ 969 onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 970 } 971 }else{ 972 if(onMouseMClickRel !is null){ 973 onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 974 } 975 } 976 }else{ 977 if(state == ButtonState.PRESSED){ 978 checked = !checked; 979 draw(); 980 if(onMouseLClickPre !is null){ 981 onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 982 } 983 if(onToggle !is null){ 984 onToggle(new Event(source, null, null, null, null, checked ? 1 : 0, EventType.CHECKBOX, null, this)); 985 } 986 }else{ 987 if(onMouseLClickRel !is null){ 988 onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 989 } 990 } 991 } 992 } 993 /** 994 * Returns the current value (whether it's checked or not) as a boolean. 995 */ 996 public @nogc @property bool value(){ 997 return checked; 998 } 999 /** 1000 * Sets the new value (whether it's checked or not) as a boolean. 1001 */ 1002 public @property bool value(bool b){ 1003 checked = b; 1004 draw(); 1005 return checked; 1006 } 1007 } 1008 /** 1009 * Radio buttons, for selecting from multiple options. 1010 */ 1011 public class RadioButtonGroup : WindowElement{ 1012 public int iconChecked, iconUnchecked; 1013 private int bposition, rowHeight, buttonpos; 1014 public dstring[] options; 1015 public int[] brush; 1016 public ushort border, background; 1017 public void delegate(Event ev) onToggle; 1018 1019 public this(dstring text, string source, Coordinate coordinates, dstring[] options, int rowHeight, int buttonpos){ 1020 this.position = coordinates; 1021 this.text = text; 1022 this.source = source; 1023 this.options = options; 1024 this.rowHeight = rowHeight; 1025 brush ~= 4; 1026 brush ~= 5; 1027 output = new BitmapDrawer(position.width, position.height); 1028 //draw(); 1029 } 1030 1031 public override void draw(){ 1032 //output.drawFilledRectangle(0, sizeX-1, 0, sizeY-1, background); 1033 if(output.output.width != position.width || output.output.height != position.height) 1034 output = new BitmapDrawer(position.width, position.height); 1035 output.drawRectangle(0, position.width-1, 0, position.height-1, getAvailableStyleSheet().getColor("windowascent")); 1036 output.drawColorText(16,0,text, getAvailableStyleSheet().getFontset("default"), 1037 getAvailableStyleSheet().getColor("normaltext"),1); 1038 for(int i; i < options.length; i++){ 1039 1040 output.drawColorText(16, rowHeight * (i+1),options[i],getAvailableStyleSheet().getFontset("default"), 1041 getAvailableStyleSheet().getColor("normaltext"),0); 1042 if(bposition == i){ 1043 output.insertBitmap(1, rowHeight * (i+1),getAvailableStyleSheet.getImage("radioButtonB")); 1044 }else{ 1045 output.insertBitmap(1, rowHeight * (i+1),getAvailableStyleSheet.getImage("radioButtonA")); 1046 } 1047 } 1048 elementContainer.drawUpdate(this); 1049 if(onDraw !is null){ 1050 onDraw(); 1051 } 1052 } 1053 1054 public override void onClick(int offsetX, int offsetY, int state, ubyte button){ 1055 if(button == MouseButton.RIGHT){ 1056 if(state == ButtonState.PRESSED){ 1057 if(onMouseRClickPre !is null){ 1058 onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1059 } 1060 }else{ 1061 if(onMouseRClickRel !is null){ 1062 onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1063 } 1064 } 1065 }else if(button == MouseButton.MID){ 1066 if(state == ButtonState.PRESSED){ 1067 if(onMouseMClickPre !is null){ 1068 onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1069 } 1070 }else{ 1071 if(onMouseMClickRel !is null){ 1072 onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1073 } 1074 } 1075 }else{ 1076 if(state == ButtonState.PRESSED){ 1077 if(onMouseLClickPre !is null){ 1078 onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1079 } 1080 bposition = (offsetY) / 16; 1081 bposition--; 1082 draw(); 1083 if(onToggle !is null){ 1084 onToggle(new Event(source, null, null, null, null, bposition, EventType.RADIOBUTTON, null, this)); 1085 } 1086 }else{ 1087 if(onMouseLClickRel !is null){ 1088 onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1089 } 1090 } 1091 } 1092 } 1093 public @property @nogc int value(){ 1094 return bposition; 1095 } 1096 public @property int value(int newval){ 1097 bposition = newval; 1098 draw(); 1099 return bposition; 1100 } 1101 } 1102 1103 abstract class Slider : WindowElement{ 1104 public int[] brush; 1105 1106 public int value, maxValue, barLength; 1107 public void delegate(Event ev) onScrolling; 1108 1109 /** 1110 * Returns the slider position. If barLenght > 1, then it returns the lower value. 1111 */ 1112 public @nogc @property int sliderPosition(){ 1113 return value; 1114 } 1115 public @property int sliderPosition(int newval){ 1116 if(newval < maxValue){ 1117 value = newval; 1118 draw(); 1119 } 1120 return value; 1121 } 1122 } 1123 /** 1124 * Vertical slider. 1125 */ 1126 public class VSlider : Slider{ 1127 //public int[] brush; 1128 1129 //private int value, maxValue, barLength; 1130 1131 public this(int maxValue, int barLenght, string source, Coordinate coordinates){ 1132 position = coordinates; 1133 //this.text = text; 1134 this.source = source; 1135 this.maxValue = maxValue; 1136 this.barLength = barLenght; 1137 output = new BitmapDrawer(position.width, position.height); 1138 brush ~= 6; 1139 brush ~= 8; 1140 //brush ~= 10; 1141 //draw(); 1142 } 1143 public override void draw(){ 1144 //draw background 1145 //Bitmap16Bit sliderStyle = elementContainer.getStyleBrush(brush[2]); 1146 //ushort backgroundColor = sliderStyle.readPixel(0,0), sliderColor = sliderStyle.readPixel(1,0); 1147 if(output.output.width != position.width || output.output.height != position.height) 1148 output = new BitmapDrawer(position.width, position.height); 1149 output.drawFilledRectangle(0, position.width , 0, position.height , getAvailableStyleSheet.getColor("windowinactive")); 1150 //draw upper arrow 1151 output.insertBitmap(0,0,getAvailableStyleSheet.getImage("upArrowA")); 1152 //draw lower arrow 1153 output.insertBitmap(0, position.height - getAvailableStyleSheet.getImage("downArrowA").height,getAvailableStyleSheet.getImage("downArrowA")); 1154 //draw slider 1155 if(maxValue > barLength){ 1156 double sliderlength = position.height() - (getAvailableStyleSheet.getImage("upArrowA")).height*2, unitlength = sliderlength/maxValue; 1157 double sliderpos = unitlength * value, bl = unitlength * barLength; 1158 int posA = to!int(sliderpos) + getAvailableStyleSheet.getImage("upArrowA").height, posB = to!int(bl + sliderpos) + getAvailableStyleSheet.getImage("upArrowA").height; 1159 1160 output.drawFilledRectangle(0,position.width,posA, posB, getAvailableStyleSheet.getColor("windowascent")); 1161 } 1162 elementContainer.drawUpdate(this); 1163 if(onDraw !is null){ 1164 onDraw(); 1165 } 1166 } 1167 1168 1169 public override void onClick(int offsetX, int offsetY, int state, ubyte button){ 1170 if(button == MouseButton.RIGHT){ 1171 if(state == ButtonState.PRESSED){ 1172 if(onMouseRClickPre !is null){ 1173 onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1174 } 1175 }else{ 1176 if(onMouseRClickRel !is null){ 1177 onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1178 } 1179 } 1180 }else if(button == MouseButton.MID){ 1181 if(state == ButtonState.PRESSED){ 1182 if(onMouseMClickPre !is null){ 1183 onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1184 } 1185 }else{ 1186 if(onMouseMClickRel !is null){ 1187 onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1188 } 1189 } 1190 }else{ 1191 if(state == ButtonState.PRESSED){ 1192 if(onMouseLClickPre !is null){ 1193 onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1194 } 1195 if(offsetY <= getAvailableStyleSheet.getImage("upArrowA").height){ 1196 if(value != 0) value--; 1197 }else if(position.height-getAvailableStyleSheet.getImage("upArrowA").height <= offsetY){ 1198 if(value < maxValue - barLength) value++; 1199 }else{ 1200 offsetY -= getAvailableStyleSheet.getImage("upArrowA").height; 1201 double sliderlength = position.height() - (getAvailableStyleSheet.getImage("upArrowA").height*2), unitlength = sliderlength/maxValue; 1202 int v = to!int(offsetY / unitlength); 1203 //value = ((sizeY - (elementContainer.getStyleBrush(brush[1]).getY() * 2)) - offsetY) * (value / maxValue); 1204 if(v < maxValue - barLength) value = v; 1205 else value = maxValue - barLength; 1206 1207 } 1208 draw(); 1209 if(onScrolling !is null){ 1210 onScrolling(new Event(source, null, null, null, null, value, EventType.SLIDER, null, this)); 1211 } 1212 }else{ 1213 if(onMouseLClickRel !is null){ 1214 onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1215 } 1216 } 1217 } 1218 1219 } 1220 public override void onScroll(int x, int y, int wX, int wY){ 1221 1222 if(x == 1){ 1223 if(value != 0) value--; 1224 }else if(x == -1){ 1225 if(value < maxValue - barLength) value++; 1226 } 1227 draw(); 1228 if(onScrolling !is null){ 1229 onScrolling(new Event(source, null, null, null, null, value, EventType.SLIDER, null, this)); 1230 } 1231 } 1232 override public void onDrag(int x,int y,int relX,int relY,ubyte button) { 1233 value+=relY; 1234 if(value >= maxValue - barLength) 1235 value = maxValue; 1236 else if(value < 0) 1237 value = 0; 1238 draw(); 1239 if(onScrolling !is null){ 1240 onScrolling(new Event(source, null, null, null, null, value, EventType.SLIDER, null, this)); 1241 } 1242 1243 } 1244 } 1245 /** 1246 * Horizontal slider. 1247 */ 1248 public class HSlider : Slider{ 1249 public this(int maxValue, int barLenght, string source, Coordinate coordinates){ 1250 position = coordinates; 1251 //this.text = text; 1252 this.source = source; 1253 this.maxValue = maxValue; 1254 this.barLength = barLenght; 1255 1256 output = new BitmapDrawer(position.width, position.height); 1257 brush ~= 14; 1258 brush ~= 16; 1259 //brush ~= 10; 1260 //draw(); 1261 } 1262 public override void draw(){ 1263 //draw background 1264 //Bitmap16Bit sliderStyle = elementContainer.getStyleBrush(brush[2]); 1265 //ushort backgroundColor = sliderStyle.readPixel(0,0), sliderColor = sliderStyle.readPixel(1,0); 1266 if(output.output.width != position.width || output.output.height != position.height) 1267 output = new BitmapDrawer(position.width, position.height); 1268 output.drawFilledRectangle(0, position.width , 0, position.height , getAvailableStyleSheet().getColor("windowinactive")); 1269 //draw left arrow 1270 output.insertBitmap(0,0,getAvailableStyleSheet.getImage("leftArrowA")); 1271 //draw right arrow 1272 output.insertBitmap(position.width - getAvailableStyleSheet.getImage("rightArrowA").width,0,getAvailableStyleSheet.getImage("rightArrowA")); 1273 //draw slider 1274 if(maxValue > barLength){ 1275 double sliderlength = position.width() - (getAvailableStyleSheet.getImage("rightArrowA").width*2), unitlength = sliderlength/maxValue; 1276 double sliderpos = unitlength * value, bl = unitlength * barLength; 1277 1278 int posA = to!int(sliderpos) + getAvailableStyleSheet.getImage("rightArrowA").height, posB = to!int(bl + sliderpos) + getAvailableStyleSheet.getImage("rightArrowA").height; 1279 1280 output.drawFilledRectangle(posA, posB, 0, position.height(),getAvailableStyleSheet().getColor("windowascent")); 1281 } 1282 elementContainer.drawUpdate(this); 1283 if(onDraw !is null){ 1284 onDraw(); 1285 } 1286 } 1287 public override void onClick(int offsetX, int offsetY, int state, ubyte button){ 1288 if(button == MouseButton.RIGHT){ 1289 if(state == ButtonState.PRESSED){ 1290 if(onMouseRClickPre !is null){ 1291 onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1292 } 1293 }else{ 1294 if(onMouseRClickRel !is null){ 1295 onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1296 } 1297 } 1298 }else if(button == MouseButton.MID){ 1299 if(state == ButtonState.PRESSED){ 1300 if(onMouseMClickPre !is null){ 1301 onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1302 } 1303 }else{ 1304 if(onMouseMClickRel !is null){ 1305 onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1306 } 1307 } 1308 }else{ 1309 if(state == ButtonState.PRESSED){ 1310 if(onMouseLClickPre !is null){ 1311 onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1312 } 1313 if(offsetX <= getAvailableStyleSheet.getImage("rightArrowA").width){ 1314 if(value != 0) value--; 1315 } 1316 else if(position.width-getAvailableStyleSheet.getImage("rightArrowA").width <= offsetX){ 1317 if(value < maxValue - barLength) value++; 1318 } 1319 else{ 1320 offsetX -= getAvailableStyleSheet.getImage("rightArrowA").width; 1321 double sliderlength = position.width() - (elementContainer.getStyleSheet.getImage("rightArrowA").width*2), unitlength = sliderlength/maxValue; 1322 int v = to!int(offsetX / unitlength); 1323 if(v < maxValue - barLength) value = v; 1324 else value = maxValue - barLength; 1325 } 1326 draw(); 1327 if(onScrolling !is null){ 1328 onScrolling(new Event(source, null, null, null, null, value, EventType.SLIDER, null, this)); 1329 } 1330 }else{ 1331 if(onMouseLClickRel !is null){ 1332 onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1333 } 1334 } 1335 } 1336 } 1337 public override void onScroll(int x, int y, int wX, int wY){ 1338 if(y == -1){ 1339 if(value != 0) value--; 1340 }else if(y == 1){ 1341 if(value < maxValue - barLength) value++; 1342 } 1343 draw(); 1344 if(onScrolling.ptr){ 1345 onScrolling(new Event(source, null, null, null, null, value, EventType.SLIDER, null, this)); 1346 } 1347 } 1348 override public void onDrag(int x,int y,int relX,int relY,ubyte button) { 1349 value+=relX; 1350 if(value >= maxValue - barLength) 1351 value = maxValue; 1352 else if(value < 0) 1353 value = 0; 1354 draw(); 1355 if(onScrolling.ptr){ 1356 onScrolling(new Event(source, null, null, null, null, value, EventType.SLIDER, null, this)); 1357 } 1358 } 1359 1360 } 1361 /** 1362 * Menubar containing menus in a tree-like structure. 1363 */ 1364 public class MenuBar: WindowElement{ 1365 private PopUpMenuElement[] menus; 1366 //private wstring[] menuNames; 1367 private int[] menuWidths; 1368 //private PopUpHandler popUpHandler; 1369 private int select, usedWidth; 1370 public this(string source, Coordinate position, PopUpMenuElement[] menus){ 1371 this.source = source; 1372 this.position = position; 1373 //this.popUpHandler = popUpHandler; 1374 this.menus = menus; 1375 select = -1; 1376 } 1377 public override void draw() { 1378 StyleSheet ss = getAvailableStyleSheet(); 1379 Fontset!Bitmap8Bit f = ss.getFontset("default"); 1380 if (output is null){ 1381 usedWidth = 1; 1382 output = new BitmapDrawer(position.width(),position.height()); 1383 foreach(m ; menus){ 1384 menuWidths ~= usedWidth; 1385 usedWidth += f.getTextLength(m.text) + (ss.drawParameters["MenuBarHorizPadding"] * 2); 1386 1387 } 1388 output.drawFilledRectangle(0, position.width(), 0, position.height(), ss.getColor("window")); 1389 }else{ 1390 output.drawFilledRectangle(0, usedWidth, 0, position.height(), ss.getColor("window")); 1391 } 1392 if(select != -1){ 1393 1394 } 1395 int x = ss.drawParameters["MenuBarHorizPadding"] + 1; 1396 foreach(m ; menus){ 1397 output.drawColorText(x, ss.drawParameters["MenuBarVertPadding"],m.text,f,ss.getColor("normaltext"),0); 1398 x += f.getTextLength(m.text) + ss.drawParameters["MenuBarHorizPadding"]; 1399 //output.drawLine(x, x, 0, position.height() - 1, ss.getColor("MenuBarSeparatorColor")); 1400 x += ss.drawParameters["MenuBarHorizPadding"]; 1401 } 1402 output.drawLine(0, 0, 0, position.height()-1, ss.getColor("windowascent")); 1403 output.drawLine(0, position.width()-1, 0, 0, ss.getColor("windowascent")); 1404 output.drawLine(0, position.width()-1, position.height()-1, position.height()-1, ss.getColor("windowdescent")); 1405 output.drawLine(position.width()-1, position.width()-1, 0, position.height()-1, ss.getColor("windowdescent")); 1406 elementContainer.drawUpdate(this); 1407 if(onDraw !is null){ 1408 onDraw(); 1409 } 1410 } 1411 private void redirectIncomingEvents(Event ev){ 1412 if(onMouseLClickPre !is null){ 1413 onMouseLClickPre(ev); 1414 } 1415 } 1416 override public void onClick(int offsetX,int offsetY,int state,ubyte button){ 1417 if(button == MouseButton.RIGHT){ 1418 if(state == ButtonState.PRESSED){ 1419 if(onMouseRClickPre !is null){ 1420 onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1421 } 1422 }else{ 1423 if(onMouseRClickRel !is null){ 1424 onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1425 } 1426 } 1427 }else if(button == MouseButton.MID){ 1428 if(state == ButtonState.PRESSED){ 1429 if(onMouseMClickPre !is null){ 1430 onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1431 } 1432 }else{ 1433 if(onMouseMClickRel !is null){ 1434 onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1435 } 1436 } 1437 }else{ 1438 if(state == ButtonState.PRESSED){ 1439 if(onMouseLClickPre !is null){ 1440 onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1441 } 1442 }else{ 1443 if(onMouseLClickRel !is null){ 1444 onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK, null, this)); 1445 } 1446 } 1447 } 1448 1449 if(offsetX < usedWidth && button == MouseButton.LEFT && state == ButtonState.PRESSED){ 1450 for(int i = cast(int)menuWidths.length - 1 ; i >= 0 ; i--){ 1451 if(menuWidths[i] < offsetX){ 1452 PopUpMenu p = new PopUpMenu(menus[i].getSubElements(), menus[i].source); 1453 //p.al = al; 1454 p.onMouseClick = onMouseLClickPre;//&redirectIncomingEvents; 1455 Coordinate c = elementContainer.getAbsolutePosition(this); 1456 popUpHandler.addPopUpElement(p, c.left + menuWidths[i], position.height()); 1457 return; 1458 } 1459 } 1460 } 1461 1462 } 1463 1464 } 1465 /** 1466 * For creating pop-up elements like menus. 1467 */ 1468 public abstract class PopUpElement{ 1469 //public ActionListener[] al; 1470 public BitmapDrawer output; 1471 public static InputHandler inputhandler; 1472 public static StyleSheet styleSheet; 1473 public Coordinate coordinates; 1474 public StyleSheet customStyle; 1475 protected PopUpHandler parent; 1476 protected string source; 1477 protected dstring text; 1478 /*public void delegate(Event ev) onMouseLClickRel; 1479 public void delegate(Event ev) onMouseRClickRel; 1480 public void delegate(Event ev) onMouseMClickRel; 1481 public void delegate(Event ev) onMouseHover; 1482 public void delegate(Event ev) onMouseMove; 1483 public void delegate(Event ev) onMouseLClickPre; 1484 public void delegate(Event ev) onMouseRClickPre; 1485 public void delegate(Event ev) onMouseMClickPre;*/ 1486 1487 public static void delegate() onDraw; ///Called when the element finished drawing 1488 public void delegate(Event ev) onMouseClick; ///Called on mouse click on element 1489 1490 public abstract void draw(); ///Called to draw the element 1491 ///Mouse click events passed here 1492 public void onClick(int offsetX, int offsetY, int type = 0){ 1493 1494 } 1495 ///Mouse scroll events passed here 1496 public void onScroll(int x, int y, int wX, int wY){ 1497 1498 } 1499 ///Mouse movement events passed here 1500 public void onMouseMovement(int x, int y){ 1501 1502 } 1503 public void addParent(PopUpHandler p){ 1504 parent = p; 1505 } 1506 1507 protected StyleSheet getStyleSheet(){ 1508 if(customStyle !is null){ 1509 return customStyle; 1510 } 1511 if(styleSheet !is null){ 1512 return styleSheet; 1513 } 1514 return parent.getStyleSheet(); 1515 } 1516 ///Returns the output of the element. 1517 ///This method is preferred over directly accessing output.output, which won't be available in later versions. 1518 public ABitmap getOutput() @safe{ 1519 return output.output; 1520 } 1521 } 1522 1523 /** 1524 * To create drop-down lists, menu bars, etc. 1525 */ 1526 public class PopUpMenu : PopUpElement{ 1527 //private wstring[] texts; 1528 //private string[] sources; 1529 1530 //private uint[int] hotkeyCodes; 1531 protected Bitmap8Bit[int] icons; 1532 protected int minwidth, width, height, iconWidth, select; 1533 PopUpMenuElement[] elements; 1534 1535 public this(PopUpMenuElement[] elements, string source, int iconWidth = 0){ 1536 this.elements = elements; 1537 this.source = source; 1538 this. iconWidth = iconWidth; 1539 select = -1; 1540 } 1541 public override void draw(){ 1542 StyleSheet ss = getStyleSheet(); 1543 if(output is null){ 1544 1545 minwidth = (ss.drawParameters["PopUpMenuVertPadding"] * 2) + ss.drawParameters["PopUpMenuMinTextSpace"] + iconWidth; 1546 width = minwidth; 1547 foreach(e; elements){ 1548 const int newwidth = ss.getFontset("default").getTextLength(e.text~e.secondaryText) + iconWidth; 1549 if(newwidth > width){ 1550 width = newwidth; 1551 } 1552 height += ss.getFontset("default").getSize() + (ss.drawParameters["PopUpMenuVertPadding"] * 2); 1553 } 1554 width += (ss.drawParameters["PopUpMenuHorizPadding"] * 2) + ss.drawParameters["PopUpMenuMinTextSpace"]; 1555 height += ss.drawParameters["PopUpMenuVertPadding"] * 2; 1556 output = new BitmapDrawer(width, height); 1557 coordinates = Coordinate(0, 0, width, height); 1558 } 1559 output.drawFilledRectangle(0,width - 1,0,height - 1,ss.getColor("window")); 1560 1561 if(select > -1){ 1562 int y0 = cast(int)((height / elements.length) * select); 1563 int y1 = cast(int)((height / elements.length) + y0); 1564 output.drawFilledRectangle(1, width - 1, y0 + 1, y1 + 1, ss.getColor("selection")); 1565 } 1566 1567 1568 int y = 1 + ss.drawParameters["PopUpMenuVertPadding"]; 1569 foreach(e; elements){ 1570 if(e.secondaryText !is null){ 1571 output.drawColorText(width - ss.drawParameters["PopUpMenuHorizPadding"] - 1, y, e.secondaryText, 1572 ss.getFontset("default"), ss.getColor("PopUpMenuSecondaryTextColor"), FontFormat.RightJustified); 1573 } 1574 output.drawColorText(ss.drawParameters["PopUpMenuHorizPadding"] + iconWidth, y, e.text, ss.getFontset("default"), 1575 ss.getColor("normaltext"), 0); 1576 if(e.getIcon() !is null){ 1577 output.insertBitmap(ss.drawParameters["PopUpMenuHorizPadding"], y, e.getIcon()); 1578 } 1579 y += ss.getFontset("default").getSize() + (ss.drawParameters["PopUpMenuVertPadding"] * 2); 1580 } 1581 1582 //output.drawRectangle(1,1,height-1,width-1,ss.getColor("windowascent")); 1583 output.drawLine(0,0,0,height-1,ss.getColor("windowascent")); 1584 output.drawLine(0,width-1,0,0,ss.getColor("windowascent")); 1585 output.drawLine(0,width-1,height-1,height-1,ss.getColor("windowdescent")); 1586 output.drawLine(width-1,width-1,0,height-1,ss.getColor("windowdescent")); 1587 if(onDraw !is null){ 1588 onDraw(); 1589 } 1590 } 1591 public override void onClick(int offsetX, int offsetY, int type = 0){ 1592 offsetY /= height / elements.length; 1593 if(elements[offsetY].source == "\\submenu\\"){ 1594 PopUpMenu m = new PopUpMenu(elements[offsetY].subElements, this.source, elements[offsetY].iconWidth); 1595 m.onMouseClick = onMouseClick; 1596 //parent.getAbsolutePosition() 1597 parent.addPopUpElement(m, coordinates.left + width, coordinates.top + offsetY * cast(int)(height / elements.length)); 1598 //parent.closePopUp(this); 1599 }else{ 1600 //invokeActionEvent(new Event(elements[offsetY].source, source, null, null, null, offsetY, EventType.CLICK)); 1601 if(onMouseClick !is null) 1602 onMouseClick(new Event(elements[offsetY].source, source, null, null, null, offsetY, EventType.CLICK, null, this)); 1603 parent.endPopUpSession(); 1604 //parent.closePopUp(this); 1605 } 1606 1607 } 1608 public override void onMouseMovement(int x , int y) { 1609 if(x == -1){ 1610 if(select != -1){ 1611 select = -1; 1612 draw; 1613 } 1614 }else{ 1615 y /= height / elements.length; 1616 if(y < elements.length){ 1617 select = y; 1618 } 1619 draw(); 1620 } 1621 } 1622 1623 } 1624 /** 1625 * Defines a single MenuElement, also can contain multiple subelements. 1626 */ 1627 public class PopUpMenuElement{ 1628 public string source; 1629 public dstring text, secondaryText; 1630 protected Bitmap8Bit icon; 1631 private PopUpMenuElement[] subElements; 1632 private ushort keymod; 1633 private int keycode; 1634 public int iconWidth; 1635 1636 public this(string source, dstring text, dstring secondaryText = null, Bitmap8Bit icon = null, int iconWidth = 0){ 1637 this.source = source; 1638 this.text = text; 1639 this.secondaryText = secondaryText; 1640 this.icon = icon; 1641 this.iconWidth = iconWidth; 1642 } 1643 public this(string source, dstring text, dstring secondaryText, PopUpMenuElement[] subElements){ 1644 this.source = source; 1645 this.text = text; 1646 this.secondaryText = secondaryText; 1647 this.subElements = subElements; 1648 /+this.icon = icon; 1649 this.iconWidth = iconWidth;+/ 1650 } 1651 public this(string source, dstring text, dstring secondaryText, PopUpMenuElement[] subElements, Bitmap8Bit icon = null, 1652 int iconWidth = 0){ 1653 this.source = source; 1654 this.text = text; 1655 this.secondaryText = secondaryText; 1656 this.subElements = subElements; 1657 /+this.icon = icon; 1658 this.iconWidth = iconWidth;+/ 1659 } 1660 public Bitmap8Bit getIcon(){ 1661 return icon; 1662 } 1663 public void setIcon(Bitmap8Bit icon){ 1664 this.icon = icon; 1665 } 1666 public PopUpMenuElement[] getSubElements(){ 1667 return subElements; 1668 } 1669 public void loadSubElements(PopUpMenuElement[] e){ 1670 subElements = e; 1671 } 1672 public PopUpMenuElement opIndex(size_t i){ 1673 return subElements[i]; 1674 } 1675 public PopUpMenuElement opIndexAssign(PopUpMenuElement value, size_t i){ 1676 subElements[i] = value; 1677 return value; 1678 } 1679 public PopUpMenuElement opOpAssign(string op)(PopUpMenuElement value){ 1680 static if(op == "~"){ 1681 subElements ~= value; 1682 return value; 1683 }else static assert("Operator " ~ op ~ " not supported!"); 1684 } 1685 public size_t getLength(){ 1686 return subElements.length; 1687 } 1688 public void setLength(int l){ 1689 subElements.length = l; 1690 } 1691 1692 } 1693 /** 1694 * Text input in pop-up fashion. 1695 */ 1696 public class PopUpTextInput : PopUpElement, TextInputListener{ 1697 protected bool enableEdit, insert; 1698 protected int textPos; 1699 public void delegate(Event ev) onTextInput; 1700 1701 public this(string source, dstring text, Coordinate coordinates){ 1702 this.source = source; 1703 this.text = text; 1704 this.coordinates = coordinates; 1705 enableEdit = true; 1706 output = new BitmapDrawer(coordinates.width, coordinates.height); 1707 inputhandler.startTextInput(this); 1708 } 1709 public override void draw(){ 1710 output.drawFilledRectangle(0, coordinates.width - 1, 0, coordinates.height - 1, getStyleSheet().getColor("window")); 1711 output.drawRectangle(0, coordinates.width - 1, 0, coordinates.height - 1, getStyleSheet().getColor("windowascent")); 1712 1713 //draw cursor 1714 if(enableEdit){ 1715 const int x = getStyleSheet().getFontset("default").getTextLength(text[0..textPos]) , 1716 y = getStyleSheet().getFontset("default").getSize; 1717 if(!insert){ 1718 output.drawLine(x + 2, x + 2, 2, 2 + y, getStyleSheet().getColor("selection")); 1719 }else{ 1720 const int x0 = textPos == text.length ? x + getStyleSheet().getFontset("default").chars[' '].xadvance : 1721 getStyleSheet().getFontset("default").getTextLength(text[0..textPos + 1]); 1722 output.drawFilledRectangle(x + 2, x0 + 2, 2, 2 + y, getStyleSheet().getColor("selection")); 1723 } 1724 } 1725 1726 output.drawColorText(2, 2, text, getStyleSheet().getFontset("default"), getStyleSheet().getColor("normaltext"), 0); 1727 1728 if(onDraw !is null){ 1729 onDraw(); 1730 } 1731 } 1732 private void deleteCharacter(int n){ 1733 //text = remove(text, i); 1734 dstring newtext; 1735 for(int i; i < text.length; i++){ 1736 if(i != n - 1){ 1737 newtext ~= text[i]; 1738 } 1739 } 1740 text = newtext; 1741 } 1742 public void textInputEvent(uint timestamp, uint windowID, dstring text){ 1743 int j = textPos; 1744 dstring newtext; 1745 for(int i ; i < textPos ; i++){ 1746 newtext ~= this.text[i]; 1747 } 1748 for(int i ; i < 32 ; i++){ 1749 if(text[i] == 0){ 1750 break; 1751 } 1752 else{ 1753 newtext ~= text[i]; 1754 textPos++; 1755 if(insert){ 1756 j++; 1757 } 1758 } 1759 } 1760 for( ; j < this.text.length ; j++){ 1761 newtext ~= this.text[j]; 1762 } 1763 this.text = newtext; 1764 draw(); 1765 } 1766 public void textInputKeyEvent(uint timestamp, uint windowID, TextInputKey key, ushort modifier = 0){ 1767 switch(key){ 1768 case TextInputKey.ESCAPE: 1769 inputhandler.stopTextInput(this); 1770 /*draw(); 1771 invokeActionEvent(EventType.TEXTINPUT, 0, text);*/ 1772 break; 1773 case TextInputKey.ENTER: 1774 inputhandler.stopTextInput(this); 1775 //invokeActionEvent(new Event(source, null, null, null, text, text.length, EventType.TEXTINPUT)); 1776 if(onTextInput !is null) 1777 onTextInput(new Event(source, null, null, null, text, cast(int)text.length, EventType.TEXTINPUT, null, this)); 1778 break; 1779 case TextInputKey.BACKSPACE: 1780 if(textPos > 0){ 1781 deleteCharacter(textPos); 1782 textPos--; 1783 draw(); 1784 } 1785 break; 1786 case TextInputKey.DELETE: 1787 deleteCharacter(textPos + 1); 1788 draw(); 1789 break; 1790 case TextInputKey.CURSORLEFT: 1791 if(textPos > 0){ 1792 --textPos; 1793 draw(); 1794 } 1795 break; 1796 case TextInputKey.CURSORRIGHT: 1797 if(textPos < text.length){ 1798 ++textPos; 1799 draw(); 1800 } 1801 break; 1802 case TextInputKey.INSERT: 1803 insert = !insert; 1804 draw(); 1805 break; 1806 case TextInputKey.HOME: 1807 textPos = 0; 1808 draw(); 1809 break; 1810 case TextInputKey.END: 1811 textPos = cast(int)text.length; 1812 draw(); 1813 break; 1814 default: 1815 break; 1816 1817 } 1818 } 1819 public void dropTextInput(){ 1820 parent.endPopUpSession(); 1821 //inputHandler.stopTextInput(source); 1822 /*draw(); 1823 invokeActionEvent(EventType.TEXTINPUT, 0, text);*/ 1824 } 1825 } 1826 1827 public interface PopUpHandler : StyleSheetContainer{ 1828 public void addPopUpElement(PopUpElement p); 1829 public void addPopUpElement(PopUpElement p, int x, int y); 1830 public void endPopUpSession(); 1831 public void closePopUp(PopUpElement p); 1832 //public Coordinate getAbsolutePosition(PopUpElement sender); 1833 //public void drawUpdate(PopUpElement sender); 1834 //public StyleSheet getDefaultStyleSheet(); 1835 1836 } 1837 1838 /** 1839 * Defines the header of a ListBox. 1840 */ 1841 public class ListBoxHeader{ 1842 private dstring[] text; 1843 private int[] width; 1844 private uint[] textInputType; 1845 private int iconColumn; 1846 public this(dstring[] text, int[] width, int iconColumn = 0){ 1847 this.width = width; 1848 this.text = text; 1849 this.iconColumn = iconColumn; 1850 } 1851 /// Returns the number of columns before drawing 1852 @nogc public int getNumberOfColumns(){ 1853 return cast(int)this.text.length; 1854 } 1855 /// Returns the text at the given point 1856 @nogc public dstring getText(int i){ 1857 return text[i]; 1858 } 1859 /// Returns the width of the column 1860 @nogc public int getColumnWidth(int i){ 1861 return width[i]; 1862 } 1863 /// Sets the width of the column 1864 @nogc public void setRowWidth(int i, int x){ 1865 width[i] = x; 1866 } 1867 /// Returns the number of column that contains the icon 1868 @nogc public int getIconColumn(){ 1869 return iconColumn; 1870 } 1871 /// Returns the whole width of the header 1872 @nogc public int getFullWidth(){ 1873 int result; 1874 foreach(int i; width){ 1875 result += i; 1876 } 1877 return result; 1878 } 1879 /// Returns the column number from width, or -1 if x can't fit into any range 1880 @nogc public int getColumnNumFromX(int x){ 1881 int result = -1; 1882 if(width[0] > x) return 0; 1883 for(int i = 1; i < width.length; i++){ 1884 if(width[i - 1] <= x || width[i] > x){ 1885 result = i; 1886 } 1887 } 1888 return result; 1889 } 1890 /// Returns the width of the columns in a given range 1891 @nogc public int getRangeWidth(int begin, int end){ 1892 int result; 1893 for(; begin < end ; begin++){ 1894 result += width[begin]; 1895 } 1896 return result; 1897 } 1898 /// Returns the TextInputType for the column 1899 @nogc public uint getTextInputType(int column){ 1900 return textInputType[column]; 1901 } 1902 } 1903 /** 1904 * Defines a single row of a ListBox. Can be passed through the Event class. 1905 */ 1906 public class NewListBoxItem { 1907 1908 } 1909 /** 1910 * Defines a single cell in a NewListBoxItem. 1911 */ 1912 public struct ListBoxCell { 1913 /** 1914 * Defines the currently held type of the cell. 1915 */ 1916 public enum TypeID : ubyte { 1917 text, 1918 decimalI, 1919 decimalF, 1920 hexadecimal, 1921 bitmap, 1922 } 1923 } 1924 /** 1925 * Defines an item in the row of a ListBox. Can be passed through the Event class 1926 * TO BE DEPRECATED. 1927 */ 1928 public class OldListBoxItem { 1929 private dstring[] text; 1930 private uint[] textInputType; ///If value or array is null, the ListBoxHeader's textInputType is referred 1931 private Bitmap8Bit icon; /// If used, replaces the texts in the column defined by the ListBoxHeader, otherwise defaults to the text. 1932 public this(dstring[] text, Bitmap8Bit icon = null, uint[] textInputType = null){ 1933 this.text = text; 1934 this.icon = icon; 1935 this.textInputType = textInputType; 1936 } 1937 public this(dstring[] text, uint[] textInputType){ 1938 this.text = text; 1939 this.icon = null; 1940 this.textInputType = textInputType; 1941 } 1942 /// Returns the text at the given column 1943 @nogc public dstring getText(int column){ 1944 return text[column]; 1945 } 1946 /// Sets the text in the given column 1947 @nogc public void setText(int column, dstring text){ 1948 this.text[column] = text; 1949 } 1950 /// Returns the icon 1951 public Bitmap8Bit getIcon(){ 1952 return icon; 1953 } 1954 /// Returns the input type of the given column. Refer to ListBoxHeader if return value = TextInputType.NULL 1955 @nogc public uint getTextInputType(int column){ 1956 return textInputType[column]; 1957 } 1958 public override string toString(){ 1959 dstring result; 1960 foreach(ws; text) 1961 result ~= ws; 1962 return to!string(result); 1963 } 1964 } 1965 alias ListBoxItem = OldListBoxItem; 1966 /* 1967 * For use with ListBoxes and similar types. Currently left here for legacy purposes, being replaced with the classes ListBoxHeader and ListBoxElement 1968 * 1969 public struct ListBoxColumn{ 1970 public wstring header; 1971 public wstring[] elements; 1972 1973 this(wstring header, wstring[] elements){ 1974 this.header = header; 1975 this.elements = elements; 1976 } 1977 1978 / 1979 public void removeByNumber(int i){ 1980 elements = remove(elements, i); 1981 } 1982 }*/ 1983 1984 /** 1985 * Defines an action event in the concrete GUI. 1986 */ 1987 public class Event{ 1988 public string source, subsource, path, filename; 1989 public dstring text; 1990 public int value, type; 1991 public Object aux; 1992 public Object sender; 1993 /** 1994 *If a field is unneeded, leave it blank by setting it to null. 1995 */ 1996 this(string source, string subsource, string path, string filename, dstring textinput, int value, int type, 1997 Object aux = null, Object sender = null){ 1998 this.source = source; 1999 this.subsource = subsource; 2000 this.path = path; 2001 this.filename = filename; 2002 this.text = textinput; 2003 this.value = value; 2004 this.type = type; 2005 this.aux = aux; 2006 this.sender = sender; 2007 } 2008 /** 2009 * Returns the full path including the filename 2010 */ 2011 public @property string getFullPath(){ 2012 return path ~ filename; 2013 } 2014 } 2015 2016 /+public interface ActionListener{ 2017 /** 2018 * Invoked mostly by WindowElements, Dialogs, and PopUpElements. Used to run the code and pass the eventdata. 2019 */ 2020 public void actionEvent(Event event); 2021 }+/ 2022 2023 public interface ElementContainer : StyleSheetContainer{ 2024 public Coordinate getAbsolutePosition(WindowElement sender); 2025 public void clearArea(WindowElement sender); 2026 } 2027 2028 public interface StyleSheetContainer{ 2029 public StyleSheet getStyleSheet(); 2030 public void drawUpdate(WindowElement sender); 2031 } 2032 /** 2033 * TODO: Use this for implement tabbing and etc. 2034 */ 2035 public interface Focusable{ 2036 public void focusGiven(); 2037 public void focusLost(); 2038 public void tabPressed(bool reverse); 2039 } 2040 2041 public enum EventType{ 2042 CLICK = 0, 2043 TEXTINPUT = 1, 2044 SLIDER = 2, 2045 TEXTBOXSELECT = 3, 2046 CHECKBOX = 4, 2047 RADIOBUTTON = 5, 2048 FILEDIALOGEVENT = 6, 2049 2050 }