Advertisement
Guest User

Untitled

a guest
Jan 11th, 2018
121
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Haxe 26.32 KB | None | 0 0
  1. package haxe.ui.backend.kha;
  2.  
  3. import kha.Color;
  4. import kha.Font;
  5. import kha.Scheduler;
  6. import kha.StringExtensions;
  7. import kha.graphics2.Graphics;
  8. import kha.input.KeyCode;
  9. import kha.input.Keyboard;
  10. import kha.input.Mouse;
  11.  
  12. typedef CharPosition = {
  13.     row:Int,
  14.     column:Int
  15. }
  16.  
  17. typedef CaretInfo = {
  18.     > CharPosition,
  19.     visible:Bool,
  20.     force:Bool,
  21.     timerId:Int
  22. }
  23.  
  24. typedef SelectionInfo = {
  25.     start:CharPosition,
  26.     end:CharPosition
  27. }
  28.  
  29. class TextField {
  30.     public static inline var SPACE:Int = 32;
  31.     public static inline var CR:Int = 10;
  32.     public static inline var LF:Int = 13;
  33.    
  34.     private var _selectionInfo:SelectionInfo = {start: {row: -1, column: -1}, end: {row: -1, column: -1}};
  35.     private var _caretInfo:CaretInfo = {row: -1, column: -1, visible: false, force: false, timerId: -1};
  36.    
  37.     public function new() {
  38.         Mouse.get().notify(onMouseDown, null, null, null, null);
  39.         Keyboard.get().notify(onKeyDown, onKeyUp, onKeyPress);
  40.     }
  41.  
  42.     //*****************************************************************************************************************//
  43.     // PUBLIC API                                                                                                      //
  44.     //*****************************************************************************************************************//
  45.     public var left:Float = 0;
  46.     public var top:Float = 0;
  47.  
  48.     public var editable:Bool = true;
  49.    
  50.     public var textColor:Color = Color.Black;
  51.     public var backgroundColor:Color = Color.White;
  52.  
  53.     public var selectedTextColor:Color = Color.White;
  54.     public var selectedBackgroundColor:Color = 0xFF3390FF;
  55.  
  56.     public var scrollTop:Int = 0;
  57.     public var scrollLeft:Float = 0;
  58.    
  59.     private var _textChanged:String->Void = null;
  60.     private var _caretMoved:CharPosition->Void = null;
  61.     public function notify(textChanged:String->Void, caretMoved:CharPosition->Void) {
  62.         _textChanged = textChanged;
  63.         _caretMoved = caretMoved;
  64.     }
  65.    
  66.     private function notifyTextChanged() {
  67.         if (_textChanged != null) {
  68.             _textChanged(_text);
  69.         }
  70.     }
  71.    
  72.     private function notifyCaretMoved() {
  73.         if (_caretMoved != null) {
  74.             _caretMoved(_caretInfo);
  75.         }
  76.     }
  77.    
  78.     private var _lines:Array<Array<Int>> = null;
  79.     private var _text:String = null;
  80.     public var text(get, set):String;
  81.     private function get_text():String {
  82.         return _text;
  83.     }
  84.     private function set_text(value:String):String {
  85.         if (value == _text) {
  86.             return value;
  87.         }
  88.  
  89.         _text = value;
  90.         recalc();
  91.         notifyTextChanged();
  92.         return value;
  93.     }
  94.  
  95.     private var _width:Float = 200;
  96.     public var width(get, set):Float;
  97.     private function get_width():Float {
  98.         return _width;
  99.     }
  100.     private function set_width(value:Float):Float {
  101.         if (value == _width) {
  102.             return value;
  103.         }
  104.        
  105.         _width = value;
  106.         recalc();
  107.         return value;
  108.     }
  109.    
  110.     private var _height:Float = 100;
  111.     public var height(get, set):Float;
  112.     private function get_height():Float {
  113.         return _height;
  114.     }
  115.     private function set_height(value:Float):Float {
  116.         if (value == _height) {
  117.             return value;
  118.         }
  119.        
  120.         _height = value;
  121.         recalc();
  122.         return value;
  123.     }
  124.    
  125.     private var _font:Font;
  126.     public var font(get, set):Font;
  127.     private function get_font():Font {
  128.         return _font;
  129.     }
  130.     private function set_font(value:Font):Font {
  131.         if (value == _font) {
  132.             return value;
  133.         }
  134.        
  135.         _font = value;
  136.         recalc();
  137.         return value;
  138.     }
  139.    
  140.     private var _fontSize:Int = 14;
  141.     public var fontSize(get, set):Int;
  142.     private function get_fontSize():Int {
  143.         return _fontSize;
  144.     }
  145.     private function set_fontSize(value:Int):Int {
  146.         if (value == _fontSize) {
  147.             return value;
  148.         }
  149.        
  150.         _fontSize = value;
  151.         recalc();
  152.         return value;
  153.     }
  154.    
  155.     private var _multiline:Bool = true;
  156.     public var multiline(get, set):Bool;
  157.     private function get_multiline():Bool {
  158.         return _multiline;
  159.     }
  160.     private function set_multiline(value:Bool):Bool {
  161.         if (value == _multiline) {
  162.             return value;
  163.         }
  164.        
  165.         _multiline = value;
  166.         recalc();
  167.         return value;
  168.     }
  169.    
  170.     private var _wordWrap:Bool = true;
  171.     public var wordWrap(get, set):Bool;
  172.     private function get_wordWrap():Bool {
  173.         return _wordWrap;
  174.     }
  175.     private function set_wordWrap(value:Bool):Bool {
  176.         if (value == _wordWrap) {
  177.             return value;
  178.         }
  179.        
  180.         _wordWrap = value;
  181.         recalc();
  182.         return value;
  183.     }
  184.    
  185.     private var _autoHeight:Bool;
  186.     public var autoHeight(get, set):Bool;
  187.     private function get_autoHeight():Bool {
  188.         return _autoHeight;
  189.     }
  190.     private function set_autoHeight(value:Bool):Bool {
  191.         if (value == _autoHeight) {
  192.             return value;
  193.         }
  194.        
  195.         _autoHeight = value;
  196.         recalc();
  197.         return value;
  198.     }
  199.    
  200.     public var maxVisibleLines(get, null):Int;
  201.     private inline function get_maxVisibleLines():Int {
  202.         return Math.round(height / font.height(fontSize));
  203.     }
  204.    
  205.     public var numLines(get, null):Int;
  206.     private inline function get_numLines():Int {
  207.         return _lines.length;
  208.     }
  209.    
  210.     private function resetSelection() {
  211.         _selectionInfo.start.row = -1;
  212.         _selectionInfo.start.column = -1;
  213.         _selectionInfo.end.row = -1;
  214.         _selectionInfo.end.column = -1;
  215.     }
  216.    
  217.     public var hasSelection(get, null):Bool;
  218.     private function get_hasSelection():Bool {
  219.         return (_selectionInfo.start.row > -1 && _selectionInfo.start.column > -1
  220.                 && _selectionInfo.end.row > -1 && _selectionInfo.end.column > -1);
  221.     }
  222.  
  223.     public var selectionStart(get, null):Int;
  224.     private function get_selectionStart():Int {
  225.         return posToIndex(_selectionInfo.start);
  226.     }
  227.    
  228.     public var selectionEnd(get, null):Int;
  229.     private function get_selectionEnd():Int {
  230.         return posToIndex(_selectionInfo.end);
  231.     }
  232.    
  233.     public var caretPosition(get, set):Int;
  234.     private function get_caretPosition():Int {
  235.         return posToIndex(_caretInfo);
  236.     }
  237.     private function set_caretPosition(value:Int):Int {
  238.         var pos = indexToPos(value);
  239.         _caretInfo.row = pos.row;
  240.         _caretInfo.column = pos.column;
  241.         scrollToCaret();
  242.         return value;
  243.     }
  244.    
  245.     //*****************************************************************************************************************//
  246.     // HELPERS                                                                                                         //
  247.     //*****************************************************************************************************************//
  248.     private static var _currentFocus:TextField;
  249.     public var isActive(get, null):Bool;
  250.     private function get_isActive():Bool {
  251.         return (_currentFocus == this);
  252.     }
  253.    
  254.     private function recalc() {
  255.         splitLines();
  256.         if (autoHeight == true && _font != null) {
  257.             height = requiredHeight;
  258.         }
  259.     }
  260.    
  261.     private function inBounds(x:Float, y:Float):Bool {
  262.         if (x >= left && y >= top && x <= left + width && y <= top + height) {
  263.             return true;
  264.         }
  265.         return false;
  266.     }
  267.  
  268.     public var requiredWidth(get, null):Float;
  269.     private function get_requiredWidth():Float {
  270.         var rw:Float = 0;
  271.         for (line in _lines) {
  272.             var lineWidth = font.widthOfCharacters(fontSize, line, 0, line.length);
  273.             if (lineWidth > rw) {
  274.                 rw = lineWidth;
  275.             }
  276.         }
  277.         return rw;
  278.     }
  279.    
  280.     public var requiredHeight(get, null):Float;
  281.     private function get_requiredHeight():Float {
  282.         return _lines.length * font.height(fontSize);
  283.     }
  284.    
  285.     private function handleNegativeSelection() {
  286.         if (caretPosition < selectionStart) {
  287.             _selectionInfo.start.row = _caretInfo.row;
  288.             _selectionInfo.start.column = _caretInfo.column;
  289.         } else {
  290.             _selectionInfo.end.row = _caretInfo.row;
  291.             _selectionInfo.end.column = _caretInfo.column;
  292.         }
  293.     }
  294.    
  295.     private function handlePositiveSelection() {
  296.         if (caretPosition > selectionEnd) {
  297.             _selectionInfo.end.row = _caretInfo.row;
  298.             _selectionInfo.end.column = _caretInfo.column;
  299.         } else {
  300.             _selectionInfo.start.row = _caretInfo.row;
  301.             _selectionInfo.start.column = _caretInfo.column;
  302.         }
  303.     }
  304.    
  305.     private function performKeyOperation(code:KeyCode) {
  306.         var orginalCaretPos:CharPosition = { row: _caretInfo.row, column: _caretInfo.column };
  307.        
  308.         switch (code) {
  309.             case Left:
  310.                 if (_caretInfo.column > 0) {
  311.                     _caretInfo.column--;
  312.                 } else if (_caretInfo.row > 0) {
  313.                     _caretInfo.row--;
  314.                     var line = _lines[_caretInfo.row];
  315.                     _caretInfo.column = line.length;
  316.                 }
  317.                
  318.                 scrollToCaret();
  319.  
  320.                 if (_shift == true) {
  321.                     handleNegativeSelection();
  322.                 } else {
  323.                     resetSelection();
  324.                 }
  325.                
  326.             case Right:
  327.                 var line = _lines[_caretInfo.row];
  328.                 if (_caretInfo.column < line.length) {
  329.                     _caretInfo.column++;
  330.                 } else if (_caretInfo.row < _lines.length - 1) {
  331.                     _caretInfo.column = 0;
  332.                     _caretInfo.row++;
  333.                 }
  334.                 scrollToCaret();
  335.                
  336.                 if (_shift == true) {
  337.                     handlePositiveSelection();
  338.                 } else {
  339.                     resetSelection();
  340.                 }
  341.  
  342.             case Up:
  343.                 if (_caretInfo.row > 0) {
  344.                     _caretInfo.column = findClosestColumn(_caretInfo, -1);
  345.                     _caretInfo.row--;
  346.                 }
  347.                 scrollToCaret();
  348.  
  349.                 if (_shift == true) {
  350.                     handleNegativeSelection();
  351.                 } else {
  352.                     resetSelection();
  353.                 }
  354.                
  355.             case Down:
  356.                 if (_caretInfo.row < _lines.length - 1) {
  357.                     _caretInfo.column = findClosestColumn(_caretInfo, 1);
  358.                     _caretInfo.row++;
  359.                 }
  360.                 scrollToCaret();
  361.  
  362.                 if (_shift == true) {
  363.                     handlePositiveSelection();
  364.                 } else {
  365.                     resetSelection();
  366.                 }
  367.            
  368.             case Backspace:
  369.                 if (hasSelection) {
  370.                     insertText("");
  371.                 } else {
  372.                     deleteCharsFromCaret(-1);
  373.                 }
  374.                
  375.             case Delete:
  376.                 if (hasSelection) {
  377.                     insertText("");
  378.                 } else {
  379.                     deleteCharsFromCaret(1, false);
  380.                 }
  381.  
  382.             case Home:
  383.                 scrollLeft = 0;
  384.                 _caretInfo.column = 0;
  385.                 scrollToCaret();
  386.                
  387.                 if (_shift == true) {
  388.                     handleNegativeSelection();
  389.                 } else {
  390.                     resetSelection();
  391.                 }
  392.                
  393.             case End:
  394.                 var line = _lines[_caretInfo.row];
  395.                 scrollLeft = font.widthOfCharacters(fontSize, line, 0, line.length) - width + caretWidth;
  396.                 if (scrollLeft < 0) {
  397.                     scrollLeft = 0;
  398.                 }
  399.                 _caretInfo.column = line.length;
  400.                 scrollToCaret();
  401.                
  402.                 if (_shift == true) {
  403.                     handlePositiveSelection();
  404.                 } else {
  405.                     resetSelection();
  406.                 }
  407.                
  408.             case _:
  409.         }
  410.        
  411.         if (_caretInfo.row != orginalCaretPos.row || _caretInfo.column != orginalCaretPos.column) {
  412.            notifyCaretMoved();
  413.         }
  414.     }
  415.    
  416.     private function insertText(s:String) {
  417.         var start:CharPosition = _caretInfo;
  418.         var end:CharPosition = _caretInfo;
  419.         if (_selectionInfo.start.row != -1 && _selectionInfo.start.column != -1) {
  420.             start = _selectionInfo.start;
  421.         }
  422.         if (_selectionInfo.end.row != -1 && _selectionInfo.end.column != -1) {
  423.             end = _selectionInfo.end;
  424.         }
  425.  
  426.        
  427.         var startIndex = posToIndex(start);
  428.         var endIndex = posToIndex(end);
  429.        
  430.         var before = text.substring(0, startIndex);
  431.         var after = text.substring(endIndex, text.length);
  432.        
  433.         text = before + s + after;
  434.         var delta = s.length - (endIndex - startIndex);
  435.  
  436.         caretPosition = endIndex + delta;
  437.         resetSelection();
  438.     }
  439.    
  440.     private var caretLeft(get, null):Float;
  441.     private function get_caretLeft():Float {
  442.         var line = _lines[_caretInfo.row];
  443.         var xpos:Float = left - scrollLeft;
  444.         return xpos + font.widthOfCharacters(fontSize, line, 0, _caretInfo.column);
  445.     }
  446.    
  447.     private var caretTop(get, null):Float;
  448.     private function get_caretTop():Float {
  449.         var ypos:Float = top;
  450.         return ypos + ((_caretInfo.row - scrollTop) * font.height(fontSize));
  451.     }
  452.    
  453.     private var caretWidth(get, null):Float;
  454.     private function get_caretWidth():Float {
  455.         return 2;
  456.     }
  457.    
  458.     private var caretHeight(get, null):Float;
  459.     private function get_caretHeight():Float {
  460.         return font.height(fontSize);
  461.     }
  462.    
  463.     //*****************************************************************************************************************//
  464.     // EVENTS                                                                                                          //
  465.     //*****************************************************************************************************************//
  466.     private static inline var REPEAT_TIMER_GROUP:Int = 1234;
  467.     private var _repeatTimerId:Int = -1;
  468.     private var _downKey:KeyCode = KeyCode.Unknown;
  469.     private var _shift:Bool = false;
  470.     private var _ctrl:Bool = false;
  471.     private function onKeyDown(code:KeyCode) {
  472.         if (isActive == false) {
  473.             return;
  474.         }
  475.        
  476.         if ((code == CR || code == LF) && multiline == false) {
  477.             return;
  478.         }
  479.        
  480.         switch (code) {
  481.             case Shift:
  482.                 _selectionInfo.start.row = _caretInfo.row;
  483.                 _selectionInfo.start.column = _caretInfo.column;
  484.                 _selectionInfo.end.row = _caretInfo.row;
  485.                 _selectionInfo.end.column = _caretInfo.column;
  486.                 _shift = true;
  487.             case Control:
  488.                 _ctrl = true;
  489.             case _:    
  490.         }
  491.        
  492.         _downKey = code;
  493.         _caretInfo.force = true;
  494.         _caretInfo.visible = true;
  495.  
  496.         performKeyOperation(code);
  497.  
  498.         Scheduler.removeTimeTasks(REPEAT_TIMER_GROUP);
  499.         Scheduler.addTimeTaskToGroup(REPEAT_TIMER_GROUP, function() {
  500.             if (_downKey != KeyCode.Unknown) {
  501.                 Scheduler.addTimeTaskToGroup(REPEAT_TIMER_GROUP, onKeyRepeat, 0, 1 / 20);
  502.             }
  503.         }, .6);
  504.     }
  505.  
  506.     private function onKeyRepeat() {
  507.         if (_downKey != KeyCode.Unknown) {
  508.             performKeyOperation(_downKey);
  509.         }
  510.     }
  511.  
  512.     private function onKeyPress(character:String) {
  513.         if (isActive == false) {
  514.             return;
  515.         }
  516.        
  517.         if ((character.charCodeAt(0) == CR || character.charCodeAt(0) == LF) && multiline == false) {
  518.             return;
  519.         }
  520.        
  521.         insertText(character);
  522.        
  523.         _caretInfo.force = false;
  524.         _caretInfo.visible = true;
  525.         _downKey = KeyCode.Unknown;
  526.         Scheduler.removeTimeTasks(REPEAT_TIMER_GROUP);
  527.     }
  528.    
  529.     private function onKeyUp(code:KeyCode) {
  530.         if (isActive == false) {
  531.             return;
  532.         }
  533.        
  534.         switch (code) {
  535.             case Shift:
  536.                 _shift = false;
  537.             case Control:
  538.                 _ctrl = false;
  539.             case _:    
  540.         }
  541.        
  542.         _caretInfo.force = false;
  543.         _caretInfo.visible = true;
  544.         _downKey = KeyCode.Unknown;
  545.         Scheduler.removeTimeTask(_repeatTimerId);
  546.         Scheduler.removeTimeTasks(REPEAT_TIMER_GROUP);
  547.     }
  548.    
  549.     private function onMouseDown(button:Int, x:Int, y:Int) {
  550.         if (inBounds(x, y) == false) {
  551.             return;
  552.         }
  553.  
  554.         if (_currentFocus != null && _currentFocus != this) {
  555.             _currentFocus.onBlur();
  556.         }
  557.         _currentFocus = this;
  558.        
  559.         var localX = x - left + scrollLeft;
  560.         var localY = y - top;
  561.  
  562.         resetSelection();
  563.        
  564.         _caretInfo.row = scrollTop + Std.int(localY / font.height(fontSize));
  565.         if (_caretInfo.row > _lines.length - 1) {
  566.             _caretInfo.row = _lines.length - 1;
  567.         }
  568.         var line = _lines[_caretInfo.row];
  569.         var totalWidth:Float = 0;
  570.         var i = 0;
  571.         var inText = false;
  572.         for (ch in line) {
  573.             var charWidth = font.widthOfCharacters(fontSize, [ch], 0, 1);
  574.             if (totalWidth + charWidth > localX) {
  575.                 _caretInfo.column = i;
  576.                 var delta = localX - totalWidth;
  577.                 if (delta > charWidth * 0.6) {
  578.                     _caretInfo.column++;
  579.                 }
  580.                 inText = true;
  581.                 break;
  582.             } else {
  583.                 totalWidth += charWidth;
  584.             }
  585.             i++;
  586.         }
  587.        
  588.         if (inText == false) {
  589.             _caretInfo.column = line.length;
  590.         }
  591.        
  592.         scrollToCaret();
  593.         _currentFocus.onFocus();
  594.     }
  595.  
  596.     private function onFocus() {
  597.         if (_caretInfo.timerId == -1) {
  598.             _caretInfo.timerId = Scheduler.addTimeTask(function() {
  599.                 _caretInfo.visible = !_caretInfo.visible;
  600.             }, 0, .4);
  601.         }
  602.     }
  603.    
  604.     private function onBlur() {
  605.         Scheduler.removeTimeTask(_caretInfo.timerId);
  606.         _caretInfo.timerId = -1;
  607.         _caretInfo.visible = false;
  608.     }
  609.    
  610.     //*****************************************************************************************************************//
  611.     // UTIL                                                                                                            //
  612.     //*****************************************************************************************************************//
  613.     private function splitLines() {
  614.         _lines = [];
  615.        
  616.         if (text == null || _font == null) {
  617.             return;
  618.         }
  619.  
  620.         if (multiline == false) {
  621.             _lines.push(StringExtensions.toCharArray(text.split("\n").join("").split("\r").join("")));
  622.         } else if (wordWrap == false) {
  623.             var arr = StringTools.replace(StringTools.replace(text, "\r\n", "\n"), "\r", "\n").split("\n");
  624.             for (a in arr) {
  625.                 _lines.push(StringExtensions.toCharArray(a));
  626.             }
  627.         } else if (wordWrap == true) {
  628.             var totalWidth:Float = 0;
  629.             var spaceIndex:Int = -1;
  630.             var start = 0;
  631.             for (i in 0...text.length) {
  632.                 var charCode = text.charCodeAt(i);
  633.                 if (charCode == SPACE) {
  634.                     spaceIndex = i;
  635.                 } else if (charCode == CR || charCode == LF) {
  636.                     _lines.push(StringExtensions.toCharArray(text.substring(start, i)));
  637.                     start = i + 1;
  638.                     totalWidth = 0;
  639.                     spaceIndex = -1;
  640.                     continue;
  641.                 }
  642.                
  643.                 var charWidth = font.widthOfCharacters(fontSize, [charCode], 0, 1);
  644.                 if (totalWidth + charWidth > width) {
  645.                     _lines.push(StringExtensions.toCharArray(text.substring(start, spaceIndex)));
  646.                     start = spaceIndex + 1;
  647.                     var remain = StringExtensions.toCharArray(text.substring(spaceIndex + 1, i + 1));
  648.                     totalWidth = font.widthOfCharacters(fontSize, remain, 0, remain.length);
  649.                 } else {
  650.                     totalWidth += charWidth;
  651.                 }
  652.             }
  653.            
  654.             if (start < text.length) {
  655.                 _lines.push(StringExtensions.toCharArray(text.substring(start, text.length)));
  656.             }
  657.         }
  658.     }
  659.  
  660.     private function deleteCharsFromCaret(count:Int = 1, moveCaret:Bool = true) {
  661.         deleteChars(count, _caretInfo, moveCaret);
  662.     }
  663.    
  664.     private function deleteChars(count:Int, from:CharPosition, moveCaret:Bool = true) {
  665.         var fromIndex = posToIndex(from);
  666.         var toIndex = fromIndex + count;
  667.        
  668.         var startIndex = fromIndex;
  669.         var endIndex = toIndex;
  670.         if (startIndex > endIndex) {
  671.             startIndex = toIndex;
  672.             endIndex = fromIndex;
  673.         }
  674.        
  675.         var before = text.substring(0, startIndex);
  676.         var after = text.substring(endIndex, text.length);
  677.        
  678.         text = before + after;
  679.         if (moveCaret == true) {
  680.             caretPosition = endIndex + count;
  681.         }
  682.     }
  683.    
  684.     private function posToIndex(pos:CharPosition) {
  685.         var index = 0;
  686.         var i = 0;
  687.         for (line in _lines) {
  688.             if (i == pos.row) {
  689.                 index += pos.column;
  690.                 break;
  691.             } else {
  692.                 index += line.length + 1;
  693.             }
  694.             i++;
  695.         }
  696.  
  697.         return index;
  698.     }
  699.  
  700.     private function indexToPos(index:Int):CharPosition {
  701.         var pos:CharPosition = { row: 0, column: 0 };
  702.        
  703.         var count:Int = 0;
  704.         for (line in _lines) {
  705.             if (index <= line.length) {
  706.                 pos.column = index;
  707.                 break;
  708.             } else {
  709.                 index -= (line.length + 1);
  710.                 pos.row++;
  711.             }
  712.         }
  713.        
  714.         return pos;
  715.     }
  716.    
  717.     private function scrollToCaret() {
  718.         ensureRowVisible(_caretInfo.row);
  719.  
  720.         var line = _lines[_caretInfo.row];
  721.         if (caretLeft - left > width) {
  722.             scrollLeft += 50;
  723.             if (scrollLeft + width > font.widthOfCharacters(fontSize, line, 0, line.length)) {
  724.                 scrollLeft = font.widthOfCharacters(fontSize, line, 0, line.length) - width + caretWidth;
  725.                 if (scrollLeft < 0) {
  726.                     scrollLeft = 0;
  727.                 }
  728.             }
  729.         } else if (caretLeft - left < 0) {
  730.             scrollLeft += (caretLeft - left);
  731.             if (font.widthOfCharacters(fontSize, line, 0, line.length) <= width) {
  732.                 scrollLeft = 0;
  733.             }
  734.         }
  735.     }
  736.  
  737.     private function ensureRowVisible(row:Int) {
  738.         if (row >= scrollTop && row <= scrollTop + maxVisibleLines - 1) {
  739.             return;
  740.         }
  741.  
  742.         if (row < scrollTop + maxVisibleLines) {
  743.             scrollTop = row;
  744.         } else {
  745.             scrollTop = row - maxVisibleLines + 1;
  746.         }
  747.     }
  748.  
  749.     private function findClosestColumn(origin:CharPosition, offset:Int) {
  750.         var closestColumn = origin.column;
  751.         var offsetLine = _lines[origin.row + offset];
  752.         if (closestColumn > offsetLine.length) {
  753.             closestColumn = offsetLine.length;
  754.         }
  755.         return closestColumn;
  756.     }
  757.  
  758.     //*****************************************************************************************************************//
  759.     // RENDER                                                                                                          //
  760.     //*****************************************************************************************************************//
  761.     public function render(g:Graphics) {
  762.         g.color = backgroundColor;
  763.         g.fillRect(left, top, width, height);
  764.  
  765.         g.scissor(Math.round(left), Math.round(top), Math.round(width), Math.round(height));
  766.  
  767.         g.font = font;
  768.         g.fontSize = fontSize;
  769.  
  770.         var xpos:Float = left - scrollLeft;
  771.         var ypos:Float = top;
  772.  
  773.         var start = scrollTop;
  774.         var end = start + maxVisibleLines;
  775.  
  776.         if (start > 0) {
  777.             start--; // show one less line so it looks nicer
  778.             ypos -= font.height(fontSize);
  779.         }
  780.         if (end > _lines.length) {
  781.             end = _lines.length;
  782.         }
  783.         if (end < _lines.length) {
  784.             end++; // show one additonal line so it looks nicer
  785.         }
  786.  
  787.         for (i in start...end) {
  788.             xpos = left - scrollLeft;
  789.             var line = _lines[i];
  790.  
  791.             if (i >= _selectionInfo.start.row && i <= _selectionInfo.end.row) {
  792.                 if (i == _selectionInfo.start.row && _selectionInfo.start.row == _selectionInfo.end.row) {
  793.                     g.color = textColor;
  794.                     g.drawCharacters(line, 0, _selectionInfo.start.column, xpos, ypos);
  795.                     xpos += font.widthOfCharacters(fontSize, line, 0, _selectionInfo.start.column);
  796.                    
  797.                     g.color = selectedBackgroundColor;
  798.                     g.fillRect(xpos, ypos, font.widthOfCharacters(fontSize, line, _selectionInfo.start.column, (_selectionInfo.end.column) - (_selectionInfo.start.column)), font.height(fontSize));
  799.  
  800.                     g.color = selectedTextColor;
  801.                     g.drawCharacters(line, _selectionInfo.start.column, (_selectionInfo.end.column) - (_selectionInfo.start.column), xpos, ypos);
  802.                     xpos += font.widthOfCharacters(fontSize, line, _selectionInfo.start.column, (_selectionInfo.end.column) - (_selectionInfo.start.column));
  803.                    
  804.                     g.color = textColor;
  805.                     g.drawCharacters(line, _selectionInfo.end.column, line.length, xpos, ypos);
  806.                 } else if (i == _selectionInfo.start.row && _selectionInfo.start.row != _selectionInfo.end.row) {
  807.                     g.color = textColor;
  808.                     g.drawCharacters(line, 0, _selectionInfo.start.column, xpos, ypos);
  809.                     xpos += font.widthOfCharacters(fontSize, line, 0, _selectionInfo.start.column);
  810.  
  811.                     g.color = selectedBackgroundColor;
  812.                     g.fillRect(xpos, ypos, font.widthOfCharacters(fontSize, line, _selectionInfo.start.column, line.length - (_selectionInfo.start.column)), font.height(fontSize));
  813.  
  814.                     g.color = selectedTextColor;
  815.                     g.drawCharacters(line, _selectionInfo.start.column, line.length - (_selectionInfo.start.column), xpos, ypos);
  816.                 } else if (i == _selectionInfo.end.row && _selectionInfo.start.row != _selectionInfo.end.row) {
  817.                     g.color = selectedBackgroundColor;
  818.                     g.fillRect(xpos, ypos, font.widthOfCharacters(fontSize, line, 0, _selectionInfo.end.column), font.height(fontSize));
  819.  
  820.                     g.color = selectedTextColor;
  821.                     g.drawCharacters(line, 0, _selectionInfo.end.column, xpos, ypos);
  822.                     xpos += font.widthOfCharacters(fontSize, line, 0, _selectionInfo.end.column);
  823.  
  824.                     g.color = textColor;
  825.                     g.drawCharacters(line, _selectionInfo.end.column, line.length - (_selectionInfo.end.column), xpos, ypos);
  826.                 } else {
  827.                     g.color = selectedBackgroundColor;
  828.                     g.fillRect(xpos, ypos, font.widthOfCharacters(fontSize, line, 0, line.length), font.height(fontSize));
  829.                    
  830.                     g.color = selectedTextColor;
  831.                     g.drawCharacters(line, 0, line.length, xpos, ypos);
  832.                 }
  833.                
  834.             } else {
  835.                 g.color = textColor;
  836.                 g.drawCharacters(line, 0, line.length, xpos, ypos);
  837.             }
  838.  
  839.             ypos += font.height(fontSize);
  840.         }
  841.  
  842.         if (_caretInfo.row > -1 && _caretInfo.column > -1 && (_caretInfo.visible == true || _caretInfo.force == true)) {
  843.             g.color = textColor;
  844.             g.fillRect(caretLeft, caretTop, caretWidth, caretHeight);
  845.         }
  846.  
  847.         g.disableScissor();
  848.     }
  849. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement