1 <!-- Copyleft 2004 - see COPYING for details [LGPL] -->
5 // Returns number of chars the pixel position pos is into text t.
9 // t : string -- basis for character counting
10 // pxpos : int -- pixel position on the text from string t
11 // pxlen : int -- pixel width of text t (often box width)
12 // tfont : font -- name of font used for width of text
13 // tsize : int -- size of font used for width of text
14 static.getpos = function(t, pxpos, pxlen, tfont, tsize) {
15 // short circuit extremes
16 if (0 >= pxpos) return 0;
17 if (pxpos >= pxlen) return t.length;
19 // inital guess based on average character width
20 var guessch = ibex.math.min(t.length, ibex.math.floor(pxpos / (pxlen / t.length)));
21 var guesspx = ibex.ui.font.width(tfont, tsize, t.substring(0, guessch));
23 if (guesspx > pxpos) {
24 while (guesspx > pxpos) {
25 // textwidth of individual character must account for font kerning
26 guesspx -= ibex.ui.font.width(tfont, tsize, t.substring(guessch -1, guessch +1));
27 guesspx += ibex.ui.font.width(tfont, tsize, t.charAt(guessch));
30 } else if (pxpos > guesspx) {
31 while (pxpos > guesspx) {
33 if (guessch >= t.length) break;
34 guesspx += ibex.ui.font.width(tfont, tsize, t.substring(guessch -1, guessch+1));
35 guesspx -= ibex.ui.font.width(tfont, tsize, t.charAt(guessch));
37 guessch--; // round down
44 <ui:box shrink="true">
46 // add and remove cursor traps as the cursor box changes
47 thisbox.cur ++= function(newcur) {
50 cur.posx --= cur_posx_read;
51 cur.posx --= cur_posx_write;
54 newcur.pos ++= cur_pos;
55 newcur.posx ++= cur_posx_read;
56 newcur.posx ++= cur_posx_write;
60 // add and remove selection traps as the selection box changes
61 thisbox.sel ++= function(newsel) {
63 sel.pos1 --= sel_pos1;
64 sel.pos2 --= sel_pos2;
67 newsel.pos1 ++= sel_pos1;
68 newsel.pos2 ++= sel_pos2;
72 // designed to trap cur.pos -- updates position of the cursor
73 // based on the character position stored in cur.pos
74 var cur_pos = function(newpos) {
75 //ibex.log.info("cur.pos trap put "+newpos+", text.length="+text.length);
76 if (newpos > text.length) newpos = text.length;
77 else if (0 > newpos) newpos = 0;
79 if (newpos > 0) ibex.thread = function() {
80 ibex.ui.font.wait(font, fontsize, text);
81 cur.x = ibex.ui.font.width(font, fontsize, text.substring(0, newpos));
84 if (focused) cur.visible = true;
87 // designed to trap cur.posx --
88 // returns the pixel based position of the cursor
89 var cur_posx_read = function() { return cur.x; }
91 // designed to trap cur.posx -- updates cur.pos
92 // based on the pixel value stored in cur.posx
94 // this two-step put to the x value is designed to normalise
95 // the position of the cursor to being between characters
96 var cur_posx_write = function(newx) {
97 // calculate the cursor position in terms of characters
98 ibex.thread = function() {
99 ibex.ui.font.wait(font, fontsize, text);
101 // short circuit limits
102 if (0 >= newx) { cur.pos = 0; return; }
103 if (newx > width) { cur.pos = text.length; return; }
105 var pos = static.getpos(text, newx, width, font, fontsize);
107 // getpos always rounds down see if we can get closer
108 // to the mark by skipping over a char
109 if (text.length > pos) {
110 var diff = newx - ibex.ui.font.width(font, fontsize, text.substring(0, pos));
111 if (diff > ibex.ui.font.width(font, fontsize, text.charAt(pos)) / 2) pos++;
118 // designed to trap sel.pos1 -- resets the selection and
119 // prepares it to start again from the given character position
120 var sel_pos1 = function(v) {
124 // designed to trap sel.pos2 -- obtains the second selection
126 var sel_pos2 = function(v) {
127 ibex.log.info("pos2 trapped, new value="+v+", (pos1="+sel.pos1+")");
129 if (v > sel.pos1) { p1 = sel.pos1; p2 = v; }
130 else { p2 = sel.pos1; p1 = v; }
132 // update selected text
133 sel.text = text.substring(p1, p2);
134 sel.x = ibex.ui.font.width(font, fontsize, text.substring(0, p1));
137 // designed to be applied to thisbox.Move
138 var move = function(v) {
140 ibex.thread = function() { sel.pos2 = cur.pos; }
143 focused ++= function(v) {
147 Press1 ++= function(v) {
148 ibex.log.info("Press1 in ibex.lib.text");
150 // TODO: enable selection
151 ibex.thread = function() {
157 // TODO: use surface.Release1
158 Release1 ++= function(v) {
159 ibex.log.info("Release1 in ibex.lib.text");
163 KeyPressed ++= function(v) {
164 ibex.log.info("KeyPressed called with value: "+v);
166 // TODO: check for casing and for prefix modifers (eg. C-Y, a-g)
167 if (v.length > 1) switch (v) {
169 case "left": cur.pos--; return;
171 case "c-left": return;
173 case "right": cur.pos++; return;
175 case "c-right": return;
177 case "home": cur.pos = 0; return;
178 case "end": cur.pos = text.length; return;
181 text = text.substring(0, cur.pos - 1) + text.substring(cur.pos);
186 text = text.substring(0, cur.pos) + text.substring(cur.pos + 1);
188 case "shift": ibex.log.warn("not-yet-implemented"); return;
189 case "alt": ibex.log.warn("not-yet-implemented"); return;
190 case "ctrl": ibex.log.warn("not-yet-implemented"); return;
191 case "insert": ibex.log.warn("not-yet-implemented"); return;
192 case "tab": ibex.log.warn("not-yet-implemented"); return;
196 ibex.log.info("KeyPressed resulting in text insertion of "+v);
197 text = text.substring(0, cur.pos) + v + text.substring(cur.pos);