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