Changeset 193
- Timestamp:
- 07/05/10 23:15:46 (2 years ago)
- Files:
-
- trunk/build/buildyage.d (modified) (2 diffs)
- trunk/src/demo1/main.d (modified) (2 diffs)
- trunk/src/demo2/main.d (modified) (3 diffs)
- trunk/src/yage/core/array.d (modified) (3 diffs)
- trunk/src/yage/core/types.d (modified) (4 diffs)
- trunk/src/yage/gui/all.d (modified) (1 diff)
- trunk/src/yage/gui/style.d (modified) (1 diff)
- trunk/src/yage/gui/surface.d (modified) (18 diffs)
- trunk/src/yage/gui/textblock.d (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/build/buildyage.d
r192 r193 10 10 */ 11 11 12 const char[] app = "demo 2"; // set which program to build against yage.12 const char[] app = "demo1"; // set which program to build against yage. 13 13 //const char[] app = "tests/integration/main.d"; 14 14 … … 427 427 if (co.run) 428 428 { System.execute("./" ~ co.of, run_args); 429 version(Windows) // give dmd windows time to release the lock.429 version(Windows) // Hack: give dmd windows time to release the lock. 430 430 if (compiler=="dmd") 431 431 System.sleep(.1); trunk/src/demo1/main.d
r189 r193 159 159 160 160 scene.ship.keyDown(key); 161 return true;161 return false; 162 162 }; 163 163 164 164 view.onKeyUp = (Surface self, int key, int modifier){ 165 165 scene.ship.keyUp(key); 166 return true;167 }; 168 169 view.onMouseDown = (Surface self, byte buttons, Vec2i coordinates , char[] href){166 return false; 167 }; 168 169 view.onMouseDown = (Surface self, byte buttons, Vec2i coordinates){ 170 170 scene.ship.acceptInput = !scene.ship.acceptInput; 171 171 self.grabMouse(scene.ship.acceptInput); 172 return true;173 }; 174 view.onMouseMove = (Surface self, byte buttons, Vec2i rel , char[] href){172 return false; 173 }; 174 view.onMouseMove = (Surface self, byte buttons, Vec2i rel){ 175 175 if(scene.ship.acceptInput) 176 176 scene.ship.input.mouseDelta += rel; 177 return true;177 return false; 178 178 }; 179 179 … … 184 184 185 185 //window.style.backgroundImage = scene.camera.getTexture(); 186 info.onMouseDown = delegate bool(Surface self, byte buttons, Vec2i coordinates , char[] href) {186 info.onMouseDown = delegate bool(Surface self, byte buttons, Vec2i coordinates) { 187 187 self.raise(); 188 188 self.focus(); 189 return true;190 }; 191 info.onMouseMove = delegate bool(Surface self, byte buttons, Vec2i amount , char[] href) {189 return false; // don't propagate upward 190 }; 191 info.onMouseMove = delegate bool(Surface self, byte buttons, Vec2i amount) { 192 192 if(buttons == 1) 193 193 self.move(cast(Vec2f)amount, true); 194 return true;195 }; 196 info.onMouseUp = delegate bool(Surface self, byte buttons, Vec2i coordinates , char[] href) {194 return false; 195 }; 196 info.onMouseUp = delegate bool(Surface self, byte buttons, Vec2i coordinates) { 197 197 self.blur(); 198 return true;198 return false; 199 199 }; 200 200 info.onMouseOver = delegate bool(Surface self, byte buttons, Vec2i coordinates) { 201 201 self.style.set("border-image: url('gui/skin/clear3.png')"); 202 return true;202 return false; 203 203 }; 204 204 info.onMouseOut = delegate bool(Surface self, byte buttons, Vec2i coordinates) { 205 205 self.style.set("border-image: url('gui/skin/clear2.png')"); 206 return true;206 return false; 207 207 }; 208 208 trunk/src/demo2/main.d
r191 r193 53 53 return true; 54 54 }; 55 view.onMouseDown = delegate bool(Surface self, byte buttons, Vec2i coordinates , char[] href) {55 view.onMouseDown = delegate bool(Surface self, byte buttons, Vec2i coordinates) { 56 56 self.grabMouse(!self.getGrabbedMouse()); 57 57 return true; … … 70 70 info.style.overflowY = Style.Overflow.HIDDEN; 71 71 72 info.onMouseDown = delegate bool(Surface self, byte buttons, Vec2i coordinates , char[] href){72 info.onMouseDown = delegate bool(Surface self, byte buttons, Vec2i coordinates){ 73 73 self.raise(); 74 74 self.focus(); 75 return true;75 return false; 76 76 }; 77 info.onMouseMove = delegate bool(Surface self, byte buttons, Vec2i amount , char[] href) {77 info.onMouseMove = delegate bool(Surface self, byte buttons, Vec2i amount) { 78 78 if(buttons == 1) 79 79 self.move(cast(Vec2f)amount, true); 80 return true;80 return false; 81 81 }; 82 info.onMouseUp = delegate bool(Surface self, byte buttons, Vec2i coordinates , char[] href) {82 info.onMouseUp = delegate bool(Surface self, byte buttons, Vec2i coordinates) { 83 83 self.blur(); 84 return true;84 return false; 85 85 }; 86 86 info.onMouseOver = delegate bool(Surface self, byte buttons, Vec2i coordinates) { 87 87 self.style.set("border-image: url('gui/skin/clear3.png')"); 88 return true;88 return false; 89 89 }; 90 90 info.onMouseOut = delegate bool(Surface self, byte buttons, Vec2i coordinates) { 91 91 self.style.set("border-image: url('gui/skin/clear2.png')"); 92 return true;92 return false; 93 93 }; 94 94 //info.style.transform = Matrix().scale(Vec3f(.5, .5, .5)); … … 109 109 Timer frame = new Timer(true); 110 110 while(!System.isAborted()) 111 { 111 { 112 112 Input.processAndSendTo(view); 113 113 auto stats = Render.scene(camera, window); trunk/src/yage/core/array.d
r188 r193 17 17 module yage.core.array; 18 18 19 import tango.stdc.stdlib : malloc, free; 20 import tango.core.Traits; 21 import tango.math.Math; 22 import tango.text.convert.Format; 19 23 import yage.core.format; 20 24 import yage.core.math.math; 21 25 import yage.core.types; 22 26 import yage.core.timer; 23 import tango.stdc.stdlib : malloc, free; 24 import tango.core.Traits; 25 import tango.text.convert.Format; 27 import yage.system.log; 26 28 27 29 /** … … 482 484 /// TODO: This returns a copy, so a[i].b = 3; doesn't work!! 483 485 T* opIndex(size_t i) 484 { assert(i<size );486 { assert(i<size, format("array index %s out of bounds", i)); 485 487 return &array[i]; 486 488 } … … 521 523 { array.reverse; 522 524 return *this; 525 } 526 527 /** 528 * Add and remove elements from the array, in-place 529 * Params: 530 * index = 531 * remove = Number of elements to remove, including and after index 532 * insert = Element to insert before index, after elements have been removed. */ 533 void splice(size_t index, size_t remove, T[] insert ...) 534 { assert(index+remove <= size, format("%s index + %s remove is greater than %s size", index, remove, size)); 535 536 int difference = insert.length - remove; 537 if (difference > 0) // if array will be longer 538 { length(size+difference); // grow to fit 539 long i = (cast(long)size)-difference-1; 540 for (; i>=index; i--) // shift elements 541 // if (i>=0 && i+difference < size) 542 data[i + difference] = data[i]; 543 544 } 545 546 if (difference < 0) // if array will be shorter 547 { for (int i=index; i<size+difference; i++) // shift elements 548 data[i] = data[i - difference]; 549 length(size + difference); // shrink to fit 550 } 551 552 // Insert new elements 553 for (int i=0; i<insert.length; i++) 554 data[i+index] = insert[i]; 555 } 556 unittest { 557 auto test = ArrayBuilder!(int)([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); 558 test.splice(3, 3); 559 assert(test.data == [0, 1, 2, 6, 7, 8, 9]); 560 test.splice(3, 0, [3, 4, 5]); 561 assert(test.data == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); 562 test.splice(0, 3, [2, 1, 0]); 563 assert(test.data == [2, 1, 0, 3, 4, 5, 6, 7, 8, 9]); 564 test.splice(test.length, 0, 10); 565 assert(test.data == [2, 1, 0, 3, 4, 5, 6, 7, 8, 9, 10]); 566 567 auto test2 = ArrayBuilder!(int)(); 568 test2.splice(0, 0, 1); 569 assert(test2.data == [1]); 523 570 } 524 571 trunk/src/yage/core/types.d
r160 r193 7 7 module yage.core.types; 8 8 9 import tango.stdc.string : memcpy; 10 import tango.math.Math; 9 11 import yage.core.math.math; 10 12 import yage.core.parse; 11 13 import yage.core.math.vector; 12 14 import yage.core.math.vector:Vec4f; 13 import tango.stdc.string : memcpy;14 15 15 16 /** … … 34 35 static word opCall(T)(T i) 35 36 { word res; 36 static if(T.sizeof < 2) 37 throw new Exception("Variable must be at least 2 bytes to be converted to a word."); 38 memcpy(&res.s, &i, 2); 37 memcpy(&res.s, &i, min(2, T.sizeof)); 39 38 return res; 40 39 } … … 65 64 static dword opCall(T)(T i) 66 65 { dword res; 67 static if(T.sizeof < 4) 68 throw new Exception("Variable must be at least 4 bytes to be converted to a dword."); 69 memcpy(&res.i, &i, 4); 70 66 memcpy(&res.i, &i, min(4, T.sizeof)); 71 67 return res; 72 68 } … … 99 95 static qword opCall(T)(T i) 100 96 { qword res; 101 static if(T.sizeof < 8) 102 throw new Exception("Variable must be at least 8 bytes to be converted to a qword."); 103 memcpy(&res.l, &i, 8); 97 memcpy(&res.l, &i, min(8, T.sizeof)); 104 98 return res; 105 99 } trunk/src/yage/gui/all.d
r192 r193 5 5 * 6 6 * Import every module in the yage.gui package. 7 * 8 * Yage's GUI framework allows building a heirarchy of Surfaces which accept CSS for positioning/style and XHTML 9 * for their content. From there, Geometry and Materials are created that can be used by the engine's Renderer. 7 10 */ 8 11 trunk/src/yage/gui/style.d
r192 r193 507 507 { static if (is (T==Style.TextAlign)) 508 508 switch (string) 509 { case "left": return TextAlign.LEFT; 509 { case "auto": return TextAlign.AUTO; 510 case "left": return TextAlign.LEFT; 510 511 case "center": return TextAlign.CENTER; 511 512 case "right": return TextAlign.RIGHT; 512 513 case "justify": return TextAlign.JUSTIFY; 514 default: throw new CSSException("Unsupported text-alignment %s", string); 513 515 } 514 516 static if (is (T==Style.TextDecoration)) 515 517 switch(string) 516 { case "none": return TextDecoration.NONE; 518 { case "auto": return TextDecoration.AUTO; 519 case "none": return TextDecoration.NONE; 517 520 case "underline": return TextDecoration.UNDERLINE; 518 521 case "overline": return TextDecoration.OVERLINE; 519 522 case "line-through": return TextDecoration.LINETHROUGH; 523 default: throw new CSSException("Unsupported text-decoration %s", string); 520 524 } 521 525 static if (is (T==Style.FontStyle)) 522 526 switch(string) 523 { case "normal":return FontStyle.NORMAL; 524 case "italic": return FontStyle.ITALIC; 527 { case "auto": return FontStyle.AUTO; 528 case "normal":return FontStyle.NORMAL; 529 case "italic": 525 530 case "oblique": return FontStyle.ITALIC; 531 default: throw new CSSException("Unsupported font-style %s", string); 526 532 } 527 533 static if (is (T==Style.FontWeight)) 528 return string=="normal" ? FontWeight.NORMAL : FontWeight.BOLD; 534 switch(string) 535 { case "auto": return FontWeight.AUTO; 536 case "normal":return FontWeight.NORMAL; 537 case "bold": return FontWeight.BOLD; 538 default: throw new CSSException("Unsupported font-weight %s", string); 539 } 529 540 } 530 541 trunk/src/yage/gui/surface.d
r192 r193 34 34 Style style; 35 35 36 char[] text; /// This html text will be rendered inside the surface. 37 38 bool editable = true; /// The text of this surface is editable. 36 char[] text; /// This html text will be rendered inside the surface. 37 bool editable = false; /// The text of this surface is editable. 39 38 bool mouseChildren = true; /// Allow the mouse to interact with this Surface's children. 40 39 TextCursor textCursor; /// … … 43 42 bool delegate(Surface self) onBlur; /// 44 43 bool delegate(Surface self) onFocus; /// 45 bool delegate(Surface self, byte buttons, Vec2i coordinates) onClick; /// unfinished44 bool delegate(Surface self, byte buttons, Vec2i coordinates) onClick; /// When a mouse button is pressed and released without moving the mouse. 46 45 bool delegate(Surface self, byte buttons, Vec2i coordinates) onDblCick; /// unfinished 47 46 bool delegate(Surface self, int key, int modifier) onKeyDown; /// Triggered once when a key is pressed down … … 52 51 * Unlike onKeyDown and onKeyUp, key is the unicode value of the key press, instead of the sdl key code. */ 53 52 bool delegate(Surface self, dchar key, int modifier) onKeyPress; 54 bool delegate(Surface self, byte buttons, Vec2i coordinates , char[] href) onMouseDown; ///55 bool delegate(Surface self, byte buttons, Vec2i coordinates , char[] href) onMouseUp; ///56 bool delegate(Surface self, byte buttons, Vec2i amount , char[] href) onMouseMove; ///53 bool delegate(Surface self, byte buttons, Vec2i coordinates) onMouseDown; /// 54 bool delegate(Surface self, byte buttons, Vec2i coordinates) onMouseUp; /// 55 bool delegate(Surface self, byte buttons, Vec2i amount) onMouseMove; /// 57 56 bool delegate(Surface self, byte buttons, Vec2i coordinates) onMouseOver; /// 58 57 bool delegate(Surface self, byte buttons, Vec2i coordinates) onMouseOut; /// … … 89 88 90 89 protected bool mouseIn; // used to track mouseover/mouseout 90 protected bool mouseMoved; // used for click() event. 91 91 protected bool resizeDirty = true; 92 92 93 93 protected SurfaceGeometry geometry; // geometry used to render this surface 94 p rotected TextBlock textLayout;94 public TextBlock textBlock; 95 95 96 96 protected static Style defaultStyle; // Used as a cache by getDefaultStyle() … … 102 102 this() 103 103 { geometry = new SurfaceGeometry(); 104 updateDimensions(getC alculatedStyle());104 updateDimensions(getComputedStyle()); 105 105 if (!focusSurface) 106 106 focus(); … … 192 192 /** 193 193 * Get a style with all auto/null/inherit/% values replaced with absolute values. */ 194 Style getC alculatedStyle()194 Style getComputedStyle() 195 195 { 196 Style cs = style; // c alculated style197 Style pcs = parent ? parent.getC alculatedStyle() : getDefaultStyle();196 Style cs = style; // computed style 197 Style pcs = parent ? parent.getComputedStyle() : getDefaultStyle(); 198 198 199 199 // Font and text properties … … 343 343 } 344 344 345 updateDimensions(getC alculatedStyle()); // dragging breaks w/o this.345 updateDimensions(getComputedStyle()); // dragging breaks w/o this. 346 346 } 347 347 … … 350 350 void update() 351 351 { 352 Style cs = getC alculatedStyle();353 //alias c alculatedStyle cs;352 Style cs = getComputedStyle(); 353 //alias computedStyle cs; 354 354 updateDimensions(cs); 355 355 if (resizeDirty) … … 370 370 int height = cast(int)height(); 371 371 372 text Layout.update(text, cs, width, height);373 Image textImage = text Layout.render(cs, true); // TODO: Change true to Probe.NextPow2372 textBlock.update(text, cs, width, height); 373 Image textImage = textBlock.render(cs, true); // TODO: Change true to Probe.NextPow2 374 374 assert(textImage !is null); 375 375 … … 398 398 399 399 resizeDirty = false; 400 } 401 402 /** 403 * Release focus from this surface and call the onBlur callback function if set. */ 404 void blur() 405 { if (this is focusSurface) 406 { if(onBlur) 407 onBlur(this); 408 Surface.focusSurface = null; 409 } 400 410 } 401 411 … … 414 424 } 415 425 416 /** 417 * Release focus from this surface and call the onBlur callback function if set. */ 418 void blur() 419 { if (this==focusSurface) 420 { if(onBlur) 421 onBlur(this); 422 Surface.focusSurface = null; 423 } 424 } 426 /// 427 void click(byte buttons, Vec2i coordinates, bool allowFocus=true) 428 { bool propagate = true; 429 if(onClick) 430 propagate = onClick(this, buttons, coordinates); 431 if (allowFocus && Surface.focusSurface !is this) 432 focus(); // give focus on click if not already focussed. 433 if(parent && propagate) 434 parent.click(buttons, coordinates, false); 435 } 436 425 437 426 438 /** … … 431 443 if(onKeyDown) 432 444 propagate = onKeyDown(this, key, mod); 433 elseif(parent && propagate)445 if(parent && propagate) 434 446 parent.keyDown(key, mod); 435 447 } … … 442 454 if(onKeyUp) 443 455 propagate = onKeyUp(this, key, mod); 444 elseif(parent && propagate)456 if(parent && propagate) 445 457 parent.keyUp(key, mod); 446 458 } … … 456 468 { if (editable) 457 469 { 458 text = textLayout.input(key, mod, unicode, textCursor); 470 textBlock.input(key, mod, unicode, textCursor, getComputedStyle()); 471 text = textBlock.toString(); // TODO: Do this lazily? 459 472 } 460 473 if(parent) … … 466 479 * Trigger a mouseDown event and call the onMouseDown callback function if set. 467 480 * If the onMouseDown function is not set, call the parent's mouseDown function.*/ 468 void mouseDown(byte buttons, Vec2i coordinates, char[] href=null){ 481 void mouseDown(byte buttons, Vec2i coordinates){ 482 mouseMoved = false; 469 483 bool propagate = true; 470 484 if(onMouseDown) 471 propagate = onMouseDown(this, buttons, coordinates , href);472 elseif(parent && propagate)473 parent.mouseDown(buttons, coordinates , href);485 propagate = onMouseDown(this, buttons, coordinates); 486 if(parent && propagate) 487 parent.mouseDown(buttons, coordinates); 474 488 } 475 489 … … 477 491 * Trigger a mouseUp event and call the onMouseUp callback function if set. 478 492 * If the onMouseUp function is not set, call the parent's mouseUp function.*/ 479 void mouseUp(byte buttons, Vec2i coordinates , char[] href=null){493 void mouseUp(byte buttons, Vec2i coordinates){ 480 494 bool propagate = true; 481 495 if(onMouseUp) 482 propagate = onMouseUp(this, buttons, coordinates, href); 483 else if(parent && propagate) 484 parent.mouseUp(buttons, coordinates, href); 496 propagate = onMouseUp(this, buttons, coordinates); 497 if (!mouseMoved) // trigger the click event if the mouse button went down and up without the mouse moving. 498 click(buttons, coordinates); 499 if(parent && propagate) 500 parent.mouseUp(buttons, coordinates); 485 501 } 486 502 487 503 /** 488 504 * Trigger a mouseMove event and call the onMouseMove callback function if set. */ 489 void mouseMove(byte buttons, Vec2i amount, char[] href=null){ 505 void mouseMove(byte buttons, Vec2i amount){ 506 mouseMoved = true; 490 507 bool propagate = true; 491 508 if(onMouseMove) 492 propagate = onMouseMove(this, buttons, amount , href);493 elseif(parent && propagate)494 parent.mouseMove(buttons, amount , href);509 propagate = onMouseMove(this, buttons, amount); 510 if(parent && propagate) 511 parent.mouseMove(buttons, amount); 495 512 } 496 513 … … 498 515 * Trigger a mouseOver event and call the onMouseOver callback function if set. */ 499 516 void mouseOver(byte buttons, Vec2i coordinates) { 500 if(!mouseIn )517 if(!mouseIn) 501 518 { bool propagate = true; 502 519 … … 661 678 resize(size-old_size); // trigger resize event. 662 679 foreach (c; children) 663 c.updateDimensions(c.getC alculatedStyle());680 c.updateDimensions(c.getComputedStyle()); 664 681 } 665 682 } trunk/src/yage/gui/textblock.d
r192 r193 53 53 54 54 private char[] text; 55 p rivate InlineStyle style; // base style of entire text block55 package InlineStyle style; // base style of entire text block 56 56 private int width; 57 57 private int height; 58 58 59 // Deprecated in favor of TextCursor60 int cursorPosition;61 int selectionStart;62 int selectionEnd;63 64 // Previous settings65 /*66 struct Previous67 { char[] text;68 InlineStyle style;69 int width;70 int height;71 }72 Previous previous;73 */74 75 59 private ArrayBuilder!(Line) lines; 76 60 private ArrayBuilder!(Letter) letters; 77 private ArrayBuilder!(InlineStyle) styles; // A style for each letter 61 private ArrayBuilder!(InlineStyle) styles; // Styles pointed to by the letters 62 63 /** 64 * Get a line number and the position in that line from a position relative to the start of the TextBlock 65 * Params: 66 * position = Character position from the beginning of the TextBlock 67 * After the function executes, this will be the position on the line returned. 68 * Returns: The line number. If position is after the last line, then the number of the last line +1 is returned.*/ 69 int positionToLine(inout int position) 70 { foreach (i, line; lines.data) 71 { if (position < line.letters.length) 72 return i; 73 position -= line.letters.length; 74 } 75 return lines.length; 76 } 77 78 /** 79 * Get cursor position from the beginning of the TextBlock based on a line number and the position in that line. 80 * Params: 81 * line = 82 * position = Position from the beginning of the line. 83 * Returns: */ 84 int lineToPosition(int line, int position) 85 { int m = min(line, lines.length); 86 for (int i=0; i<m; i++) 87 position += lines[i].letters.length; 88 return position; 89 } 78 90 79 91 /** … … 83 95 * mod = modifier key. 84 96 * unicode = Unicode value of the pressed key. 85 * cursor 86 * Returns: new html text. 97 * cursor = The Surface's TextCursor. 87 98 */ 88 char[] input(int key, int mod, dchar unicode, inout TextCursor cursor)89 { 90 Log.trace("%s %s", cursor.position, letters.length);99 void input(int key, int mod, dchar unicode, inout TextCursor cursor, Style computedStyle) 100 { 101 style = InlineStyle(computedStyle); 91 102 assert(cursor.position <= letters.length); 92 103 104 // Get the x position in pixels of a character on a line. 105 int positionToX(int line, int position) 106 { assert (line < lines.length); 107 int x; 108 int last = min(lines[line].letters.length, position); 109 for (int i=0; i<last; i++) 110 x+= lines[line].letters[i].advanceX; 111 return x; 112 } 113 114 // Get the nearest character position on a line from an x poxition in pixels 115 int xToPosition(int line, int x) 116 { int position; 117 for (int i=0; i<lines[line].letters.length; i++) 118 { x-= lines[line].letters[i].advanceX; 119 if (x<0) // TODO: More accurate rounding 120 return i; 121 } 122 } 123 93 124 // Position cursor 125 int position = cursor.position; 126 int currentLine = positionToLine(position); 94 127 switch(key) 95 { 96 case SDLK_LEFT: if (cursorPosition>0) cursorPosition--; break; 97 case SDLK_RIGHT: if (cursorPosition<letters.length) cursorPosition++; break; 98 case SDLK_UP: break; 99 case SDLK_DOWN: break; 100 case SDLK_HOME: break; 101 case SDLK_END: break; 102 103 default: break; 128 { 129 // Positioning keys 130 case SDLK_LEFT: if (cursor.position>0) cursor.position--; break; 131 case SDLK_RIGHT: if (cursor.position<letters.length) cursor.position++; break; 132 case SDLK_UP: 133 if (currentLine > 0) 134 { int x = positionToX(currentLine, position); 135 currentLine--; 136 cursor.position = lineToPosition(currentLine, xToPosition(currentLine, x)); 137 } 138 break; 139 case SDLK_DOWN: 140 if (currentLine < lines.length-1) 141 { int x = positionToX(currentLine, position); 142 currentLine++; 143 cursor.position = lineToPosition(currentLine, xToPosition(currentLine, x)); 144 } 145 break; 146 case SDLK_HOME: 147 positionToLine(position); // position is now relativeto the beginning of the line. 148 cursor.position -= position; 149 break; 150 case SDLK_END: 151 positionToLine(position); 152 cursor.position += (lines[currentLine].letters.length - position); 153 break; 154 155 // Editing Keys 156 case SDLK_INSERT: break; 157 case SDLK_BACKSPACE: 158 if (cursor.position > 0) 159 { letters.splice(cursor.position-1, 1); 160 cursor.position--; 161 } 162 break; 163 case SDLK_DELETE: break; 164 if (cursor.position < letters.length) // doesn't work 165 letters.splice(cursor.position, 1); 166 // New letters 167 default: 168 if (unicode) 169 { 170 // Get the style to use for a new letter 171 InlineStyle *style; 172 if (cursor.position > 0) // get style from previous letter 173 style = cast(InlineStyle*)letters[cursor.position-1].extra; 174 else if (letters.length && cursor.position < letters.length-1) // get style from next letter 175 style = cast(InlineStyle*)letters[cursor.position].extra; 176 else // get base style of the TextBlock. 177 style = &this.style; 178 179 Letter l = style.fontFamily.getLetter(unicode, style.fontSize); 180 l.extra = style; 181 letters.splice(cursor.position, 0, l); 182 cursor.position++; 183 } 184 break; 104 185 // ctrl+a, z, x, c, v 105 } 106 107 108 if (unicode) 109 { InlineStyle style; 110 111 /* 112 case SDLK_INSERT: break; 113 case SDLK_BACKSPACE: break; 114 case SDLK_DELETE: break; 115 */ 116 117 Letter l = style.fontFamily.getLetter(unicode, 10, 10); // style.fontFamily is null. 118 letters ~= l; 119 } 120 121 lines = lettersToLines(letters.data, width, lines); 122 123 return toString(); 186 } 187 188 189 190 //lines = lettersToLines(letters.data, width, lines); 191 192 //return toString(); 124 193 } 125 194 … … 213 282 } 214 283 215 216 284 /** 217 285 * Reverse the normal function of TextLayout and convert letters[] back to a string of html text. 218 * The text may use different tags (since some information is lost) 219 * but will be functionally the same. 220 * TODO: Move this to lettersToHtml(), since it's the opposite of htmlToLetters() 221 */ 286 * The text may use different tags than the original html, (since some information is lost) 287 * but will be functionally the same. */ 222 288 char[] toString() 223 289 { … … 241 307 if (style.fontFamily && style.fontFamily != newStyle.fontFamily) 242 308 styleString ~= swritef(`font-family: url('%s')`, newStyle.fontFamily); 243 if (dword(style.fontSize) != dword(newStyle.fontSize)) // BUG: converts % font size to px.309 if (dword(style.fontSize) != dword(newStyle.fontSize)) 244 310 styleString ~= swritef(`font-size: %spx`, newStyle.fontSize); 245 311 if (style.color != newStyle.color) … … 274 340 * height = 275 341 * Returns: True if the text will need to be re-rendered, false otherwise. 276 * TODO: Should this be a constructor to maintain RAII? Doing so will cause more allocations of letters and lines! 277 */ 342 * TODO: Should this be a constructor to maintain RAII? */ 278 343 bool update(char[] text, Style style, int width, int height) 279 344 { … … 306 371 307 372 /* 308 *309 373 * Params: 310 374 * letters =
