-<!-- Copyright 2002 Adam Megacz, see the COPYING file for licensing [LGPL] -->
+<!-- Copyright 2002 NeuronForge Pty Ltd, see COPYING file for licensing [LGPL] -->
<xwt>
+ A single-line or multi-line edit widget. Only handles text with one font and one color, and is capable of line or word wrapping.
- A text edit box.
+ TRAPS:
- multiline : boolean -- if true, lines will be broken at newline characters
- editable : boolean -- if false, the text cannot be changed, although it can be copied
+ - multiline : boolean -- If true, edit widget will expand vertically to handle newlines.
+ - editable : boolean -- If true, the user can insert, paste and delete text.
+ - disabled : boolean -- If false, user can select text and copy to clipboard.
+ - wrap : string -- Either "none", "line" or "word", specifing the form of text wrap to use.
+ - selection : string -- Returns the currently selected text. Putting values does nothing, see FUNCTIONS, selectText().
+ - text : string -- Represents the complete text of this edit widget. Can be read and written to.
+ - limit : int -- A limit imposed on the total number of characters in the edit widget. 0 > limit means no limit.
+ - textcolor : color -- Color of the text.
+ - selectcolor : color -- Background Color of the currently selected text.
+ - selecttextcolor : color -- Color of the currently selected text.
+ - textChanged : boolean -- Set to true when the contents of the edit widget has changed.
- <redirect target="self"/>
- <static>
- var boxen = [];
- var cr_regexp = /[\n\r]/g;
- var nonwhitespace = /\S/;
- </static>
+ FUNCTIONS:
- <template textcolor="black" orient="vertical" vpad="2" editable="true" multiline="false" text="" cursor="text">
+ If you wish to directly manipulate the contents of the edit widget consider using these functions to speed up manipulation.
+ All line references are based on hard carrige returns. You do not have to consider soft line wraps when making calculations.
- // Structural Stuff //////////////////////////////////////////////////////////////////////
+ - insertText(line, index, text) - Insert text at given char index on given line.
+ - deleteText(startline, startindex, endline, endindex) - Delete text in given range.
+ - selectText(startline, startindex, endline, endindex) - Select text in given range.
+ - clearSelection() - Deselect any current selection.
+ - deleteSelection() - Delete the text within the current selection range.
+ - moveCursor(line, index) - Move the cursor to the given position.
- // Cursor1 is the cursor -- when there is no selection, its width is
- // 1, and its height is the height of one line. When the user selects
- // a one-line region, Cursor1 is expanded to cover that region (but
- // placed behind the text on the z-axis). When the user selects more
- // than one line, Cursor1 covers the background of the first line of
- // the selection, Cursor3 covers the last line, and the intermediate
- // lines get their color set to "blue".
- var curs = $curs; // the main cursor
- var curs2 = $curs2; // the "backup" cursor for multiline selections
- var numcursors = 2; // the number of non-textline children of this box
- var master = 0;
+ THEME NOTES:
- <box text="" align="topleft"/>
- <box id="curs" absolute="true" textcolor="white" color="blue" width="1" y="0" x="1" invisible="true"/>
- <box id="curs2" absolute="true" textcolor="white" color="blue" width="1" y="0" x="1" invisible="true"/>
+ - Most of the implementation of this widget does not need to be considered in a theme, however a particular theme may wish
+ to override _KeyPressed to add extra theme features (eg. Monopoly word skip on Ctrl+Left Arrow).
- // Cursor Manipulation //////////////////////////////////////////////////////////////////////
- // cx1, cy1 is the coordinates (in characters, not pixels) of the start of the selection
- // cx2, cy2 is the coordinates (in characters, not pixels) of the end of the selection
- cx2 = cx1 = cy2 = cy1 = 0;
+ IMPLEMENTATION NOTES:
- // the x-coordinate of the beginning of the selection, in characters
- _cx1 = function(a) {
- a = xwt.math.floor(a);
- if (0 > a) { if (cy1 > 0) cy1--; a = thisbox[cy1].text.length; }
- if (numchildren - numcursors > cy1 and a > thisbox[cy1].text.length) { cy1++; a = 0; }
- curs.x = xwt.textwidth(font, thisbox[cy1].text.substring(0, a));
- arguments.cascade(a);
- sync();
- }
-
- // the x-coordinate of the end of the selection, in characters
- _cx2 = function(a) {
- a = xwt.math.floor(a);
- if (0 > a) { cy2--; a = thisbox[cy2].text.length; }
- if (numchildren - numcursors > cy2 and a > thisbox[cy2].text.length) { cy2++; a = 0; }
- arguments.cascade(a);
- sync();
- }
-
- // the y-coordinate of the beginning of the selection, in characters
- _cy1 = function(a) {
- a = xwt.math.floor(a);
- if (0 > a) { a = 0; cx1 = 0; }
- arguments.cascade(a);
- if (cx1 > thisbox[a].text.length) cx1 = thisbox[a].text.length;
- sync();
- }
-
- // the y-coordinate of the end of the selection, in characters
- _cy2 = function(a) {
- a = xwt.math.floor(a);
- arguments.cascade(a);
- while (a >= numchildren - numcursors) {
- var b = getbox();
- b.text = "";
- thisbox[numchildren - numcursors] = b;
- }
- if (cx2 > thisbox[a].text.length) cx2 = thisbox[a].text.length;
- sync();
- }
-
- // the x-coordinate of the beginning of the selection, measured in _pixels_
- __px1 = function() {
- if (cy1 > numchildren || thisbox[cy1].text == null) return 0;
- return xwt.textwidth(font, thisbox[cy1].text.substring(0, cx1));
- }
+ - In the implementation of the edit widget, there are two systems (loosely similar to model-view) used to reference text.
+
+ The first, referencing each 'hard' line (from one carrige return to the next) as a box inside $content
+ with the string property fulltext representing the contents of the row is used as the text model.
+ Text is inserted, removed and read using the $content[cl].fulltext properties.
- // the x-coordinate of the end of the selection, measured in _pixels_
- __px2 = function() {
- if (cy2 > numchildren || thisbox[cy2].text == null) return 0;
- return xwt.textwidth(font, thisbox[cy2].text.substring(0, cx2));
- }
+ The second is the on screen reprsentation of the text. Each $content[cl] box can have any number of children ( must be > 0)
+ called 'soft' lines. These softlines are created/managed at the discretion of the $content[cl]._fulltext trap. This means
+ different wrapping systems can be completely isolated inside the _fulltext trap. The only components of the system that
+ work outside of the model are cursor and selection positioning. The functions that manipulate these features have public
+ functions that mimic the 'model' style functions, but also have private internal functions that use cy and px variables
+ to reference location.
- // on the r-th row, this will determine how many characters are to the left of a
- // point b pixels from the left edge of the edit Algorithm is a binary search,
- // making educated guesses based on the average width of a character on that line.
- getboundary = function(r, b) {
+ - A reference to each cursor is stored in the static area, and a global thread is used to call the _blink trap on cursors.
- if (o >= b) return 0;
- var s = thisbox[r].text;
+ - Boxes are also stored in a static array when unused, however the effective value of this is questionable, and should be
+ properly benchmarked.
- var left = 0; // the left boundary of the search region, in characters
- var right = s.length; // the right boundary of the search region, in characters
- var start = 0; // the left boundary of the search region, in pixels
- // the right boundary of the search region, in pixels
- var end = xwt.textwidth(font, s);
- if (b >= end) return right; // short circuit if we're off the end
+ - If moving the cursor to a different cl line after changing the structure of the edit box, be sure to call the funciton from
+ a background thread. Otherwise, the position x,y values will be wrong.
- var avgwidth = end / right; // average width of one character
- while(true) {
- var middle = left + (b - start) / avgwidth; // make a guess at where we should look
+ TODO:
+ - keep length value up to date so limit checking works.
+ - insert key
- // extra safety guard against infinite loops
- if (left == right) return left;
- if (left >= middle) middle = left + 1;
- if (middle >= right) middle = left - 1;
+ <preapply name="org.xwt.builtin.edit_lib"/>
- start = xwt.textwidth(font, s.substring(0, middle));
- if (start > b) {
- right = middle;
- } else if (b >= start + xwt.textwidth(font, s.charAt(middle))) {
- left = middle;
- } else {
- return middle;
- }
- }
- }
+ <template multiline="false" disabled="false" editable="true" wrap="none" font="sansserif"
+ selectcolor="blue" selecttextcolor="#FFFFFF" color="#FFFFFF" orient="vertical">
- // returns the row containing the point yp pixels from the top of the widget
- getrow = function(yp) { return xwt.math.min(numchildren - numcursors - 1, xwt.math.floor(yp / lineheight)); }
-
- sync = function() {
- curs.x = px1;
- curs.y = thisbox[cy1].y; //lineheight * cy1 + thisbox[0].y;
- curs.width = px2 - px1;
- if (1 > curs.width) { curs.width = 1; curs.text = ""; }
- curs2.invisible = true;
-
- if (cy1 != cy2) {
- curs.width = width - curs.x;
- curs2.invisible = false;
- curs2.x = 0;
- curs2.y = thisbox[cy2].y; //lineheight * cy2;
- curs2.height = lineheight;
- curs2.width = px2;
- }
+ content = $content;
+ curs = $curs;
+ sel1 = $sel1;
+ sel2 = $sel2;
- for(var i=0; numchildren - numcursors>i; i++) {
- if (i>cy1 and cy2>i) {
- thisbox[i].textcolor = "white";
- thisbox[i].color = "blue";
- } else {
- thisbox[i].textcolor = "black";
- thisbox[i].color = null;
- }
+ // Handles key events that occur in the surrounding whitespace.
+ $vspace._Press1 = function(v) { ref_press(content[content.numchildren -1]); }
+ $hspace._Press1 = function(v) {
+ for (var i=0; content.numchildren > i; i++) {
+ if (content[i].y + content[i].height >= content.mousey) { ref_press(content[i]); return; }
}
-
- curs.text = (thisbox[cy1] == null || thisbox[cy1].text == null) ? null :
- thisbox[cy1].text.substring(getboundary(cy1, curs.x),
- getboundary(cy1, curs.x + curs.width));
-
- curs2.text = (thisbox[cy2] == null || thisbox[cy2].text == null) ? null :
- thisbox[cy2].text.substring(getboundary(cy2, curs2.x),
- getboundary(cy2, curs2.x + curs2.width));
+ ref_press(content[content.numchildren -1]);
}
-
-
- // Externally Visible Traps //////////////////////////////////////////////////////////
-
_focused = function(f) {
- if (!f) {
- if (curs.width == 1) curs.invisible = true;
- } else {
- curs.invisible = false;
- }
- }
-
- // returns the currently-selected text
- __selection = function() {
- var ret = "";
- if (cy1 == cy2) {
- ret += thisbox[cy1].text.substring(cx1, cx2);
- } else {
- ret += thisbox[cy1].text.substring(cx1) + "\n";
- for(var i=cy1 + 1; cy2 > i; i++) ret += thisbox[i].text + "\n";
- ret += thisbox[cy2].text.substring(0, cx2);
- }
- return ret;
- }
-
- _font = function(f) {
- curs.height = curs2.height = lineheight = f == null ? xwt.textheight() : xwt.textheight(f);
- for(var i=0; numchildren>i; i++) {
- thisbox[i].font = f;
- if (numchildren - numcursors > i) thisbox[i].minheight = lineheight;
- }
- }
- font = null;
-
- _editable = function(e) {
- if (e) {
- auto_focus = true;
- color = "white";
- } else {
- auto_focus = false;
- focused = false;
- curs.invisible = true;
- curs2.invisible = true;
- }
- }
-
- _multiline = function(m) {
- if (m and m != "false") {
- while(numchildren > numcursors + 1) thisbox[1].thisbox = null;
- arguments.cascade(true);
- } else {
- arguments.cascade(false);
- }
- }
-
- __text = function(t) {
- if (arguments.length == 0) {
- var ret = "";
- for(var i=0; numchildren - numcursors>i; i++) ret = ret + thisbox[i].text + "\n";
- return ret.substring(0, ret.length - 1); // chop off trailing CR
- }
- var me = this;
- for(var i = numchildren - numcursors - 1; i >= 0; i--) {
- static.boxen[static.boxen.length] = me[i];
- me[i].thisbox = null;
- }
- cy1 = 0; cy2 = 0; cx1 = 0; cx2 = 0;
- xwt.thread = function() {
- try { insert_text(t); } catch (e) { xwt.println(e); }
- }
- }
-
- last_was_a_kill = false; // indicates if the last "action" was a kill -- lets us know if we
- // we should append newly killed text to the kill buffer or clear it
-
-
-
- // Text Manipulation /////////////////////////////////////////////////////////////
-
- // deletes the region between the start and end of the selection
- var nuke_selection = function() {
- if (cy1 != cy2 and thisbox[cy1].text != null and thisbox[cy2].text != null) {
- thisbox[cy1].text = thisbox[cy1].text.substring(0, cx1) + thisbox[cy2].text.substring(cx2);
- for(var i=cy1 + 1; cy2 >= i; i++) thisbox[cy1 + 1].thisbox = null;
- cy2 = cy1;
- cx2 = cx1;
- } else {
- thisbox[cy1].text = thisbox[cy1].text.substring(0, cx1) + thisbox[cy1].text.substring(cx2);
- cx2 = cx1;
- }
- }
-
- var getbox = function() {
- if (static.boxen.length == 0) static.boxen[0] = xwt.newBox();
- var ret = static.boxen[static.boxen.length - 1];
- static.boxen.length--;
- ret.minheight = lineheight;
- ret.vshrink = true;
- ret.textcolor = "black";
- ret.font = font;
- ret.align = "topleft";
- ret.invisible = false;
- ret.absolute = false;
- return ret;
- }
-
- // nukes the selected region and inserts arg in its place
- var insert_text = function(arg) {
- var mine = master = xwt.math.random();
- if (!multiline) arg = (arg + "").replace(static.cr_regexp, "");
- if (curs.width > 1) nuke_selection();
- while(!(arg == null || arg == "" || arg.replace == null)) {
- cy2 = cy1; cx2 = cx1;
- // insert a new line if necessary
- if (arg.charAt(0) == '\n') {
- var n = getbox();
- thisbox[cy1 + 1] = n;
- n.text = thisbox[cy1].text.substring(cx1);
- thisbox[cy1].text = thisbox[cy1].text.substring(0, cx1);
- cy1++; cy2 = cy1; cx1 = 0; cx2 = 0;
- arg = arg.substring(1);
- xwt.yield();
- if (master != mine) return;
+ curs.focused = f; arguments.cascade(f); curs.blink = false;
+ if (!f) { clearSelection(); }
+ }
+
+ _disabled = function(d) { if (d) { cursor = "default"; } else { cursor = "text"; } }
+
+ _keypress = function(k) {
+ if (k == null || disabled) return;
+
+ var key = k.substring(k.lastIndexOf('-')+1).toLowerCase();
+
+ if (key.length == 1) {
+ if (xwt.control) {
+ if (key == 'a') {
+ selectText(0, 0, content.numchildren -1, content[content.numchildren -1].fulltext.length);
+ arguments.cascade(null);
+ } else if (key == 'x') {
+ xwt.clipboard = selection; deleteSelection();
+ arguments.cascade(null);
+ } else if (key == 'c') {
+ xwt.clipboard = selection;
+ arguments.cascade(null);
+ } else if (key == 'v') {
+ deleteSelection(); insertText(curs.cl, curs.cx, xwt.clipboard);
+ textChangd = true;
+ arguments.cascade(null);
+ } else {
+ arguments.cascade(k);
+ }
+ } else {
+ arguments.cascade(k);
}
- var upto = arg.indexOf('\n') == -1 ? arg.length : arg.indexOf('\n');
- var itext = arg.substring(0, upto);
- thisbox[cy1].text = thisbox[cy1].text.substring(0, cx1) + itext + thisbox[cy1].text.substring(cx1);
- cx1 += itext.length;
- arg = arg.substring(upto);
- }
- cy2 = cy1;
- cx2 = cx1;
- master = 0;
- }
-
-
- // XWT Event Handlers //////////////////////////////////////////////////////////////
-
-_Press2 = function() {
-xwt.println("curs.x = " + curs.x);
-xwt.println("curs.y = " + curs.y);
-xwt.println("curs.w = " + curs.width);
-xwt.println("curs.h = " + curs.height);
-xwt.println("curs.i = " + curs.invisible);
-xwt.println("curs[] = " + indexof(curs));
-xwt.println("numchi = " + numchildren);
-}
-
- _Press1 = function() {
- focused = true;
- if (master != 0) return;
- last_was_a_kill = false;
-
- root._Move = function() {
- curs.invisible = false;
- var mousey_row = getrow(mousey);
- var pressy_row = getrow(pressy);
-
- if (pressy_row > mousey_row || (mousey_row == pressy_row and pressx > mousex)) {
- cy1 = mousey_row;
- cy2 = pressy_row;
- cx1 = getboundary(cy1, mousex);
- cx2 = getboundary(cy2, pressx);
-
+ } else if (key == "left") {
+ var cl, cx;
+
+ if (xwt.control) {
+ // Skip word algorithm. Ugly to look at.
+ cl = curs.cl; cx = curs.cx;
+
+ while (true) {
+ for (cx--; cx >= 0; cx--) { if (content[cl].fulltext.charAt(cx) != ' ') break; }
+ if (0 > cx) { if (cl > 0) { cl--; cx = content[cl].fulltext.length; } else { break; } }
+
+ findendchar: for (cx--; cx >= 0; cx--) {
+ switch (content[cl].fulltext.charAt(cx)) {
+ case ' ': break findendchar;
+ case '-': break findendchar;
+ }
+ }
+ cx++; break;
+ }
} else {
- var newcy2 = mousey_row;
- if (newcy2 > numchildren - numcursors - 1) newcy2 = numchildren - numcursors - 1;
- cy2 = newcy2;
- cy1 = pressy_row;
- cx2 = xwt.math.min(getboundary(cy2, mousex), thisbox[cy2].text.length);
- cx1 = getboundary(cy1, pressx);
+ // Use right boundry of selection, otherwise use the cursor.
+ if (sel1.cl != -1) { cl = sel1.cl; cx = calcCx(cl, sel1.cy, sel1.px) -1; }
+ else { cl = curs.cl; cx = curs.cx -1; }
}
- }
-
- root.__Release1 = function() {
- root._Move = null;
- root._Release1 = null;
- if (cx1 != cx2 || cy1 != cy2) xwt.clipboard = selection;
- }
-
- pressx = mousex;
- pressy = mousey;
- cy1 = getrow(mousey);
- cy2 = getrow(mousey);
- cx2 = xwt.math.min(getboundary(cy1, mousex), thisbox[cy1].text.length);
- cx1 = xwt.math.min(getboundary(cy1, mousex), thisbox[cy1].text.length);
- }
-
- __Press3 = function() {
- last_was_a_kill = false;
- cy1 = cy2 = getrow(mousey);
- cx2 = cx1 = xwt.math.min(getboundary(cy1, mousex), thisbox[cy1].text.length);
- if (xwt.clipboard != null and editable) insert_text(xwt.clipboard);
- }
-
- _DoubleClick1 = function() {
- cy1 = cy2 = getrow(mousey);
- cx1 = 0; cx2 = thisbox[cy1].text.length;
- xwt.clipboard = selection;
- }
- var key_C_Q = function() {
-
- // C-q => fill
- var start = cy1;
- var stop = cy2;
-
- // if a region wasn't selected, fill this paragraph alone
- if (cy1 == cy2) {
- while (start > 0 and thisbox[start].text.match(static.nonwhitespace)) start--;
- while (numchildren - numcursors > stop and thisbox[stop].text.match(static.nonwhitespace)) stop++;
- }
-
- // pull out the text-to-be filled
- var filltext = "";
- for(var i=start; stop >= i; i++) {
- filltext += thisbox[start].text + "\n";
- if (numchildren > numcursors) {
- static.boxen[static.boxen.length] = thisbox[start];
- thisbox[start].thisbox = null;
+ if (xwt.shift) { updateSelectionCx(cl, cx); }
+ else { clearSelection(); moveCursor(cl, cx); }
+ arguments.cascade(null);
+
+ } else if (key == "right") {
+ var cl, cx;
+
+ if (xwt.control) {
+ // Skip word algorithm. Ugly to look at.
+ cl = curs.cl; cx = curs.cx;
+
+ while (true) {
+ for (cx++; content[cl].fulltext.length > cx; cx++) { if (content[cl].fulltext.charAt(cx) != ' ') break; }
+ if (cx > content[cl].fulltext.length) { if (content.numchildren > cl) { cl++; cx = 0; } else { break; } }
+
+ findendchar: for (cx++; content[cl].fulltext.length > cx; cx++) {
+ switch (content[cl].fulltext.charAt(cx)) {
+ case ' ': break findendchar;
+ case '-': break findendchar;
+ }
+ }
+ break;
+ }
} else {
- thisbox[start].text = "";
+ // Use right boundry of selection, otherwise use the cursor.
+ if (sel2.cl != -1) { cl = sel2.cl; cx = calcCx(cl, sel2.cy, sel2.px) +1; }
+ else { cl = curs.cl; cx = curs.cx +1; }
}
- }
- xwt.println("prefill text:\n" + filltext);
+ if (xwt.shift) { updateSelectionCx(cl, cx); }
+ else { clearSelection(); moveCursor(cl, cx); }
+ arguments.cascade(null);
+
+ } else if (key == "down") {
+ var cl, cy;
+ if (xwt.control) { cl = content.numchildren -1; cy = content[cl].numchildren -1; }
+ else { if (curs.cy == content[curs.cl].numchildren -1) { cl = curs.cl +1; cy = 0; } else { cl = curs.cl; cy = curs.cy + 1; } }
+
+ if (xwt.shift) { updateSelection(cl, cy, curs.px); }
+ else { var px = curs.px; clearSelection(); moveCursorToCy(cl, cy, px); }
+ arguments.cascade(null);
+
+ } else if (key == "up") {
+ var cl, cy;
+ if (xwt.control) { cl = 0; cy = content[0].numchildren -1; }
+ else {
+ if (curs.cy == 0) { if (curs.cl == 0) { cl=0; cy=0; } else { cl = curs.cl -1; cy = content[cl].numchildren -1; } }
+ else { cl = curs.cl; cy = curs.cy -1; }
+ }
- filltext = filltext.replace(/^\\s+/);
+ if (xwt.shift) { updateSelection(cl, cy, curs.px); }
+ else { var px = curs.px; clearSelection(); moveCursorToCy(cl, cy, px); }
+ arguments.cascade(null);
- var quoted = false;
- if (filltext.substring(0, 2) == "> ") {
- filltext = filltext.substring(2).replace(/\n> /g, "\n");
- quoted = true;
- }
+ } else if (key == "home") {
+ var cy;
+ if (xwt.control) { cy = 0; }
+ else { cy = curs.cy; }
- filltext = filltext.replace(/\s+/g, " ");
+ if (xwt.shift) { updateSelection(curs.cl, cy, 0); }
+ else { var cl = curs.cl; clearSelection(); moveCursorToCy(cl, cy, 0); }
+ arguments.cascade(null);
- var newfilltext = "";
+ } else if (key == "end") {
+ var cy;
+ if (xwt.control) { cy = content[curs.cl].numchildren -1; }
+ else { cy = curs.cy; }
- while (filltext.length > 0) {
- var tmp = filltext.substring(0, 78);
- var tmp2;
- if (tmp.lastIndexOf(' ') != -1) {
- filltext = tmp.substring(tmp.lastIndexOf(' ') + 1) + filltext.substring(78);
- tmp2 = tmp.substring(0, tmp.lastIndexOf(' '));
- } else {
- tmp2 = filltext;
- filltext = "";
- }
- newfilltext += (quoted ? "> " : "") + tmp2 + "\n";
- }
+ if (xwt.shift) { updateSelection(curs.cl, cy, content[curs.cl][cy].text.length); }
+ else { var cl = curs.cl; clearSelection(); moveCursorToCy(cl, cy, content[cl][cy].text.length); }
+ arguments.cascade(null);
- cy1 = start; cy2 = start;
- cx1 = 0; cx2 = 0;
-
- xwt.println("newfilltext:\n" + newfilltext);
-
- insert_text("\n" + newfilltext + "\n");
- }
-
- var key_C_W = function() { if (xwt.clipboard != null) xwt.clipboard = selection;
- if (editable) nuke_selection();
- }
- var key_C_K = function() { if (!editable) return;
- if (1 >= curs.width and cx1 == thisbox[cy1].text.length) cx2++;
- else if (1 >= curs.width) cx2 = thisbox[cy2].text.length;
- if (!last_was_a_kill and xwt.clipboard != null) xwt.clipboard = "";
- if (xwt.clipboard != null) xwt.clipboard += selection;
- else xwt.clipboard = selection;
- nuke_selection();
- }
-
- _KeyPressed = function(key) {
- if (master != 0) return;
- if (!focused) return;
- var kill = false;
- if (key == "C-a") { cx1 = 0; cx2 = 0; }
- else if (key == "C-e") { cx1 = thisbox[cy2].text.length; cx2 = cx1; cy2 = cy1; }
- else if (key == "C-d" || key == "delete") { if (!editable) return; if (1 >= curs.width) cx2++; nuke_selection(); }
- else if (key == "C-y") { if (xwt.clipboard != null and editable) insert_text(xwt.clipboard); }
- else if (key == "C-k") key_C_K();
- else if (key == "C-w") key_C_W();
- else if (key == "C-h" || key == "back_space") {
- if (!editable) return;
- if (cx1 == 0 and cx2 == 0 and cy1 == 0 and cy2 == 0) return;
- if (1 >= curs.width) cx1--;
- nuke_selection();
+ } else if (key == "insert") {
+ xwt.println("NOT YET IMPLEMENTED: insert key"); // TODO
+ arguments.cascade(null);
}
- else if (key == "C-b" || key == "left") { cx1--; cy2 = cy1; cx2 = cx1; }
- else if (key == "C-p" || key == "up") { cy1--; cy2 = cy1; cx2 = cx1; }
- else if (key == "C-f" || key == "right") { cx2++; cy1 = cy2; cx1 = cx2; }
- else if (key == "C-m" || key == "C-o" || key == "enter" || key == "C-j") { if (editable) insert_text("\n"); }
- else if (key == "C-n" || key == "down") { cy2++; cy1 = cy2; cx1 = cx2; }
- else if (key == "C-q") key_C_Q();
- else if (key.length == 1) {
- if (!editable) return;
- if (curs.width > 1) nuke_selection();
- thisbox[cy1].text = thisbox[cy1].text.substring(0, cx1) +
- key +
- thisbox[cy1].text.substring(cx1);
- cx2 = cx1 + 1; cx1 = cx2;
- }
-
- last_was_a_kill = key == "C-k";
}
-
+
+ <box orient="horizontal">
+ <box id="content" hpad="0" vpad="0" align="topleft" orient="vertical" shrink="true"/>
+ <box id="hspace"/>
+ </box>
+ <box id="vspace"/>
+
+ <box absolute="true" id="sel1" cl="0" cy="0" px="0" shrink="true"/>
+ <box absolute="true" id="sel2" cl="0" cy="0" px="0" shrink="true"/>
+ <box absolute="true" id="curs" cl="0" cx="0" cy="0" px="0" width="1" blink="false" color="black">
+ _blink = function(v) { invisible = (focused and !disabled) ? v : true; }
+ </box>
</template>
</xwt>
-