2002/05/16 04:22:24
[org.ibex.core.git] / src / org / xwt / SpecialBoxProperty.java
1 // Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
2 package org.xwt;
3
4 import org.mozilla.javascript.*;
5 import org.xwt.util.*;
6 import java.util.*;
7 import java.net.*;
8 import java.text.*;
9
10 /** 
11  *  A helper class for properties of Box which require special
12  *  handling.
13  *
14  *  To avoid excessive use of String.equals(), the Box.get() and
15  *  Box.put() methods employ a Hash keyed on property names that
16  *  require special handling. The value stored in the Hash is an
17  *  instance of an anonymous subclass of SpecialBoxProperty, which knows
18  *  how to handle get()s and put()s for that property name. There
19  *  should be one anonymous subclass of SpecialBoxProperty for each
20  *  specially-handled property on Box.
21  */
22 class SpecialBoxProperty {
23
24     SpecialBoxProperty() { }
25     private static final int NUMINTS = Box.NUMINTS;
26     private static final int dmax = Box.dmax;
27     private static final int dmin = Box.dmin;
28     private static final int cmin = Box.cmin;
29     private static final int abs = Box.abs;
30     private static final int pos = Box.pos;
31     private static final int size = Box.size;
32     private static final int oldpos = Box.oldpos;
33     private static final int oldsize = Box.oldsize;
34     private static final int pad = Box.pad;
35
36     /** stores instances of SpecialBoxProperty; keyed on property name */
37     static Hash specialBoxProperties = new Hash(200, 3);
38
39     /** this method defines the behavior when the property is get()ed from b */
40     Object get(Box b) { return null; }
41
42     /** this method defines the behavior when the property is put() to b */
43     void put(Box b, Object value) { }
44
45     /** this method defines the behavior when the property is put() to b, allows a single SpecialBoxProperty to serve multiple properties */
46     void put(String name, Box b, Object value) { put(b, value); }
47
48     // 'ye olde IBM CGA colours', as defined in the XWT reference
49     static final int black = 0xFF000000;
50     static final int blue = 0xFF000088;
51     static final int green = 0xFF008800;
52     static final int cyan = 0xFF008888;
53     static final int red = 0xFF880000;
54     static final int magenta = 0xFF880088;
55     static final int brown = 0xFF888800;
56     static final int lightGray = 0xFFBDBEBD;
57     static final int darkGray = 0xFF242424;
58     static final int brightBlue = 0xFF0000FF;
59     static final int brightGreen = 0xFF00FF00;
60     static final int brightCyan = 0xFF00FFFF;
61     static final int brightRed = 0xFFFF0000;
62     static final int pink = 0xFFFF00FF;
63     static final int yellow = 0xFFFFFF00;
64     static final int white = 0xFFFFFFFF;
65
66     static {
67
68         specialBoxProperties.put("color", new SpecialBoxProperty() {
69                 public Object get(Box b) {
70                     if ((b.color & 0xFF000000) == 0) return null;
71                     String red = Integer.toHexString((b.color & 0x00FF0000) >> 16);
72                     String green = Integer.toHexString((b.color & 0x0000FF00) >> 8);
73                     String blue = Integer.toHexString(b.color & 0x000000FF);
74                     if (red.length() < 2) red = "0" + red;
75                     if (blue.length() < 2) blue = "0" + blue;
76                     if (green.length() < 2) green = "0" + green;
77                     return "#" + red + green + blue;
78                 }
79                 public void put(Box b, Object value) {
80                     int newcolor = b.color;
81                     String s = value == null ? null : value.toString();
82                     if (value == null) newcolor = 0x00000000;
83                     else if (s.length() > 0 && s.charAt(0) == '#')
84                         newcolor = 0xFF000000 |
85                             (Integer.parseInt(s.substring(1, 3), 16) << 16) |
86                             (Integer.parseInt(s.substring(3, 5), 16) << 8) |
87                             Integer.parseInt(s.substring(5, 7), 16);
88                     else if (s.equals("black")) newcolor = black;
89                     else if (s.equals("blue")) newcolor = blue;
90                     else if (s.equals("green")) newcolor = green;
91                     else if (s.equals("cyan")) newcolor = cyan;
92                     else if (s.equals("red")) newcolor = red;
93                     else if (s.equals("magenta")) newcolor = magenta;
94                     else if (s.equals("brown")) newcolor = brown;
95                     else if (s.equals("lightGray")) newcolor = lightGray;
96                     else if (s.equals("darkGray")) newcolor = darkGray;
97                     else if (s.equals("brightBlue")) newcolor = brightBlue;
98                     else if (s.equals("brightGreen")) newcolor = brightGreen;
99                     else if (s.equals("brightCyan")) newcolor = brightCyan;
100                     else if (s.equals("brightRed")) newcolor = brightRed;
101                     else if (s.equals("pink")) newcolor = pink;
102                     else if (s.equals("yellow")) newcolor = yellow;
103                     else if (s.equals("white")) newcolor = white;
104                     else if (Log.on) Log.log(this, "invalid color " + s);
105
106                     if (newcolor == b.color) return;
107                     b.color = newcolor;
108                     b.dirty();
109                 } });
110         
111         
112         specialBoxProperties.put("textcolor", new SpecialBoxProperty() {
113                 public Object get(Box b) {
114                     if ((b.textcolor & 0xFF000000) == 0) return null;
115                     String red = Integer.toHexString((b.textcolor & 0x00FF0000) >> 16);
116                     String green = Integer.toHexString((b.textcolor & 0x0000FF00) >> 8);
117                     String blue = Integer.toHexString(b.textcolor & 0x000000FF);
118                     if (red.length() < 2) red = "0" + red;
119                     if (blue.length() < 2) blue = "0" + blue;
120                     if (green.length() < 2) green = "0" + green;
121                     return "#" + red + green + blue;
122                 }
123                 public void put(Box b, Object value) {
124                     int newtextcolor = b.color;
125                     if (value == null) return;
126                     String s = value.toString();
127                     if (s.length() > 0 && s.charAt(0) == '#')
128                         newtextcolor = 0xFF000000 |
129                             (Integer.parseInt(s.substring(1, 3), 16) << 16) |
130                             (Integer.parseInt(s.substring(3, 5), 16) << 8) |
131                             Integer.parseInt(s.substring(5, 7), 16);
132                     else if (s.equals("black")) newtextcolor = black;
133                     else if (s.equals("blue")) newtextcolor = blue;
134                     else if (s.equals("green")) newtextcolor = green;
135                     else if (s.equals("cyan")) newtextcolor = cyan;
136                     else if (s.equals("red")) newtextcolor = red;
137                     else if (s.equals("magenta")) newtextcolor = magenta;
138                     else if (s.equals("brown")) newtextcolor = brown;
139                     else if (s.equals("lightGray")) newtextcolor = lightGray;
140                     else if (s.equals("darkGray")) newtextcolor = darkGray;
141                     else if (s.equals("brightBlue")) newtextcolor = brightBlue;
142                     else if (s.equals("brightGreen")) newtextcolor = brightGreen;
143                     else if (s.equals("brightCyan")) newtextcolor = brightCyan;
144                     else if (s.equals("brightRed")) newtextcolor = brightRed;
145                     else if (s.equals("pink")) newtextcolor = pink;
146                     else if (s.equals("yellow")) newtextcolor = yellow;
147                     else if (s.equals("white")) newtextcolor = white;
148                     else if (Log.on) Log.log(this, "invalid textcolor " + s);
149
150                     if (newtextcolor == b.textcolor) return;
151                     b.textcolor = newtextcolor;
152                     b.dirty();
153                 } });
154         
155         specialBoxProperties.put("text", new SpecialBoxProperty() {
156                 public Object get(Box b) { return b.text; }
157                 public void put(Box b, Object value) {
158                     String t = value == null ? "null" : value.toString();
159                     if (t.equals(b.text)) return;
160
161                     for(int i=0; i<t.length(); i++)
162                         if (Character.isISOControl(t.charAt(i))) {
163                             if (Log.on) Log.log(this, 
164                                                 "ISO Control characters are not permitted in box text strings; offending character is ASCII " +
165                                                ((int)t.charAt(i)));
166                             /* FIXME: reinstate
167                             return;
168                             */
169                         }
170
171                     // FIXME: don't know why this is needed
172                     b.dirty();
173
174                     b.text = t;
175                     b.textupdate();
176                     b.dirty();
177                 } });
178         
179         specialBoxProperties.put("thisbox", new SpecialBoxProperty() {
180                 public Object get(Box b) { return b; }
181                 public void put(Box b, Object value) {
182                     if (value == null) b.remove();
183                     else if (value.equals("window")) Platform.createSurface(b, false, true);
184                     else if (value.equals("frame")) Platform.createSurface(b, true, true);
185                     else if (Log.on) Log.log(this, "put invalid value to 'thisbox' property: " + value);
186                 }
187             });
188
189         specialBoxProperties.put("orient", new SpecialBoxProperty() {
190                 public Object get(Box b) {
191                     if (b.redirect == null) return "horizontal";
192                     else if (b.redirect != b) return get(b.redirect);
193                     else if (b.o == 1) return "vertical";
194                     else return "horizontal";
195                 }
196                 public void put(Box b, Object value) {
197                     if (value == null) return;
198                     if (b.redirect == null) return;
199                     if (b.redirect != b) {
200                         put(b.redirect, value);
201                         return;
202                     }
203                     if (value.equals("vertical")) {
204                         if (b.o == 1) return;
205                         b.o = 1;
206                         b.xo = 0;
207                     } else if (value.equals("horizontal")) {
208                         if (b.o == 0) return;
209                         b.o = 0;
210                         b.xo = 1;
211                     } else if (Log.on)
212                         Log.log(this, "invalid value put to orient property: " + value);
213                     b.mark_for_prerender();
214                     b.sync_cmin_to_children();
215                 } });
216
217         specialBoxProperties.put("static", new SpecialBoxProperty() {
218                 public Object get(Box b) {
219                     String cfsn = JSObject.getCurrentFunctionSourceName();
220                     for(int i=0; i<cfsn.length() - 1; i++)
221                         if (cfsn.charAt(i) == '.' && (cfsn.charAt(i+1) == '_' || Character.isDigit(cfsn.charAt(i+1)))) {
222                             cfsn = cfsn.substring(0, i);
223                             break;
224                         }
225                     return Static.getStatic(cfsn);
226                 }
227                 public void put(Box b, Object value) { }
228             });
229
230         specialBoxProperties.put("sizetoimage", new SpecialBoxProperty() {
231                 public Object get(Box b) { return b.sizetoimage ? Boolean.TRUE : Boolean.FALSE; }
232                 public void put(Box b, Object value) {
233                     if (stob(value)) {
234                         if (b.sizetoimage) return;
235                         b.sizetoimage = true;
236                         b.syncSizeToImage();
237                     } else {
238                         b.sizetoimage = false;
239                     }
240                 } });
241         
242         specialBoxProperties.put("shrink", new SpecialBoxProperty() {
243                 public Object get(Box b) { return (b.vshrink && b.hshrink) ? Boolean.TRUE : Boolean.FALSE; }
244                 public void put(Box b, Object value) {
245                     boolean newshrink = stob(value);
246                     if (b.hshrink == newshrink && b.vshrink == newshrink) return;
247                     b.hshrink = b.vshrink = newshrink;
248                     if (b.hshrink) b.set(b.dmax, 0, Box.max(b.cmin(0), b.textdim(0) + 2 * b.pad(0), b.dmin(0)));
249                     if (b.vshrink) b.set(b.dmax, 1, Box.max(b.cmin(1), b.textdim(1) + 2 * b.pad(1), b.dmin(1)));
250                 } });
251         
252         specialBoxProperties.put("hshrink", new SpecialBoxProperty() {
253                 public Object get(Box b) { return new Boolean(b.hshrink); }
254                 public void put(Box b, Object value) {
255                     boolean newshrink = stob(value);
256                     if (b.hshrink == newshrink) return;
257                     b.hshrink = newshrink;
258                     if (b.hshrink) b.set(b.dmax, 0, Box.max(b.cmin(0), b.textdim(0) + 2 * b.pad(0), b.dmin(0)));
259                 }
260             });
261         
262         specialBoxProperties.put("vshrink", new SpecialBoxProperty() {
263                 public Object get(Box b) { return b.vshrink ? Boolean.TRUE : Boolean.FALSE; }
264                 public void put(Box b, Object value) {
265                     boolean newshrink = stob(value);
266                     if (b.vshrink == newshrink) return;
267                     b.vshrink = newshrink;
268                     if (b.vshrink) b.set(b.dmax, 1, Box.max(b.cmin(1), b.textdim(1) + 2 * b.pad(1), b.dmin(1)));
269                 }
270             });
271         
272         specialBoxProperties.put("x", new SpecialBoxProperty() {
273                 public Object get(Box b) {
274                     if (b.surface == null) return new Integer(0);
275                     if (b.invisible) return new Integer(0);
276                     return new Integer(b.abs(0));
277                 }
278                 public void put(Box b, Object value) {
279                     if (b.getParent() == null && b.surface != null) {
280                         b.surface.setLocation(stoi(value), b.abs(1));
281                         b.surface.centerSurfaceOnRender = false;
282                     }
283                     b.set(abs, 0, stosh(value));
284                 }
285             });
286         
287         specialBoxProperties.put("y", new SpecialBoxProperty() {
288                 public Object get(Box b) {
289                     if (b.surface == null) return new Integer(0);
290                     if (b.invisible) return new Integer(0);
291                     return new Integer(b.abs(1));
292                 }
293                 public void put(Box b, Object value) {
294                     if (b.getParent() == null && b.surface != null) {
295                         b.surface.setLocation(b.abs(0), stoi(value));
296                         b.surface.centerSurfaceOnRender = false;
297                     }
298                     b.set(abs, 1, stosh(value));
299                 }
300             });
301
302         specialBoxProperties.put("width", new SpecialBoxProperty() {
303                 public Object get(Box b) { return new Integer(b.size(0)); }
304                 public void put(Box b, Object value) {
305                     if (b.sizetoimage) return;
306                     if (b.getParent() == null && b.surface != null) {
307                         b.set(size, 0, Box.max(Surface.scarPicture.getWidth(), stosh(value)));
308                         b.mark_for_prerender();
309                     } else {
310                         b.set(dmax, 0, stosh(value));
311                         b.set(dmin, 0, stosh(value));
312                     }
313                 } });
314         
315         specialBoxProperties.put("height", new SpecialBoxProperty() {
316                 public Object get(Box b) { return new Integer(b.size(1)); }
317                 public void put(Box b, Object value) {
318                     if (b.sizetoimage) return;
319                     if (b.getParent() == null && b.surface != null) {
320                         b.set(size, 1, Box.max(Surface.scarPicture.getHeight(), stosh(value)));
321                         b.mark_for_prerender();
322                     } else {
323                         b.set(dmax, 1, stosh(value));
324                         b.set(dmin, 1, stosh(value));
325                     }
326                 } });
327
328         specialBoxProperties.put("flex", new SpecialBoxProperty() {
329                 public Object get(Box b) { return new Double(b.flex); }
330                 public void put(Box b, Object value) {
331                     if (value == null) return;
332                     int newflex = stoi(value);
333                     if (newflex == b.flex) return;
334                     b.flex = newflex;
335                     b.mark_for_prerender();
336                 } });
337         
338         specialBoxProperties.put("tile", new SpecialBoxProperty() {
339                 public Object get(Box b) { return b.tile ? Boolean.TRUE : Boolean.FALSE; }
340                 public void put(Box b, Object value) {
341                     boolean newtile = stob(value);
342                     if (newtile == b.tile) return;
343                     b.tile = newtile;
344                     b.dirty();
345                 } });
346         
347         specialBoxProperties.put("align", new SpecialBoxProperty() {
348                 public Object get(Box b) {
349                     if (b.align == -1) return "topleft";
350                     else if (b.align == 1) return "bottomright";
351                     else return "center";
352                 }
353                 public void put(Box b, Object value) {
354                     String s = value == null ? "" : value.toString();
355                     byte newalign = b.align;
356                     if (s.equals("topleft")) newalign = -1;
357                     else if (s.equals("bottomright")) newalign = 1;
358                     else if (s.equals("center")) newalign = 0;
359                     else if (Log.on) Log.log(this, "invalid value put to align property: " + value);
360                     if (newalign == b.align) return;
361                     b.align = newalign;
362                     if (b.getParent() != null) b.getParent().mark_for_prerender();
363                 } });
364         
365         specialBoxProperties.put("invisible", new SpecialBoxProperty() {
366                 public Object get(Box b) { return b.invisible ? Boolean.TRUE : Boolean.FALSE; }
367                 public void put(Box b, Object value) {
368                     boolean newinvisible = stob(value);
369                     if (newinvisible == b.invisible) return;
370                     b.invisible = newinvisible;
371                     if (b.getParent() == null) {
372                         if (b.surface != null) b.surface.setInvisible(newinvisible);
373                     } else {
374                         b.dirty();
375                         b.getParent().mark_for_prerender();
376                         b.getParent().sync_cmin_to_children();
377                         b.getParent().dirty(b.pos(0), b.pos(1), b.size(0), b.size(1));
378                         b.getParent().dirty(b.oldpos(0), b.oldpos(1), b.oldsize(0), b.oldsize(1));
379                     }
380                 }});
381         
382         specialBoxProperties.put("absolute", new SpecialBoxProperty() {
383                 public Object get(Box b) { return b.absolute ? Boolean.TRUE : Boolean.FALSE; }
384                 public void put(Box b, Object value) {
385                     boolean newabsolute = stob(value);
386                     if (newabsolute == b.absolute) return;
387                     b.absolute = newabsolute;
388                     if (b.getParent() != null) {
389                         b.getParent().mark_for_prerender();
390                         b.getParent().sync_cmin_to_children();
391                     }
392                 } });
393         
394         specialBoxProperties.put("image", new SpecialBoxProperty() {
395                 public Object get(Box b) { return b.image == null ? null : Box.imageToNameMap.get(b.image); }
396                 public void put(Box b, Object value) { b.setImage(value == null ? null : value.toString()); }
397             });
398
399         specialBoxProperties.put("border", new SpecialBoxProperty() {
400                 public Object get(Box b) { return b.border == null ? null : Box.imageToNameMap.get(b.border); }
401                 public void put(Box b, Object value) { b.setBorder(value == null ? null : value.toString()); }
402             });
403
404         specialBoxProperties.put("font", new SpecialBoxProperty() {
405                 public Object get(Box b) { return b.font; }
406                 public void put(Box b, Object value) {
407                     if (value == null) value = Platform.getDefaultFont();
408                     b.font = value.toString();
409                     b.textupdate();
410                     b.dirty();
411                 } });
412         
413         specialBoxProperties.put("globalx", new SpecialBoxProperty() {
414                 public Object get(Box b) { return new Integer(b.getParent() == null || b.surface == null ? 0 : b.pos(0)); }
415                 public void put(Box b, Object value) {
416                     if (b.surface == null || b.getParent() == null) return;
417                     b.put("x", null, new Integer(stoi(value) - stoi(get(b.getParent()))));
418                 }
419             });
420         
421         specialBoxProperties.put("globaly", new SpecialBoxProperty() {
422                 public Object get(Box b) { return new Integer(b.getParent() == null || b.surface == null ? 0 : b.pos(1)); }
423                 public void put(Box b, Object value) {
424                     if (b.surface == null || b.getParent() == null) return;
425                     b.put("y", null, new Integer(stoi(value) - stoi(get(b.getParent()))));
426                 }
427             });
428         
429         specialBoxProperties.put("cursor", new SpecialBoxProperty() {
430                 public Object get(Box b) { return b.cursor; } 
431                 public void put(Box b, Object value) {
432                     b.cursor = (String)value;
433                     if (b.surface == null) return;
434
435                     // see if we need to update the surface cursor
436                     String tempcursor = b.surface.cursor;
437                     b.Move(b.surface.mousex, b.surface.mousey, b.surface.mousex, b.surface.mousey);
438                     if (b.surface.cursor != tempcursor) b.surface.syncCursor();
439                 } 
440             });
441         
442         specialBoxProperties.put("mousex", new SpecialBoxProperty() {
443                 public Object get(Box b) { return new Integer(b.surface == null ? 0 : b.surface.mousex - b.pos(0)); }
444             });
445         
446         specialBoxProperties.put("mousey", new SpecialBoxProperty() {
447                 public Object get(Box b) { return new Integer(b.surface == null ? 0 : b.surface.mousey - b.pos(1)); }
448             });
449         
450         specialBoxProperties.put("xwt", new SpecialBoxProperty() {
451                 public Object get(Box b) { return XWT.singleton; }
452             });
453         
454         specialBoxProperties.put("mouseinside", new SpecialBoxProperty() {
455                 public Object get(Box b) { return b.mouseinside ? Boolean.TRUE : Boolean.FALSE; }
456             });
457         
458         specialBoxProperties.put("numchildren", new SpecialBoxProperty() {
459                 public Object get(Box b) {
460                     if (b.redirect == null) return new Integer(0);
461                     if (b.redirect != b) return get(b.redirect);
462                     return new Integer(b.numChildren());
463                 } });
464         
465         SpecialBoxProperty mouseEventHandler = new SpecialBoxProperty() {
466                 public void put(String name, Box b, Object value) {
467                     if (b.surface == null) return;
468                     if (b.getParent() == null) {
469                         if (b.surface.boxContainingMouse.getParent() != null)
470                             b.surface.boxContainingMouse.put(name, b.surface.boxContainingMouse, value);
471                     } else {
472                         // check siblings
473                         for(Box c = b.prevSibling(); c != null; c = c.prevSibling())
474                             if (c.inside(c.surface.mousex, c.surface.mousey)) {
475                                 c.put(name, c, value);
476                                 return;
477                             }
478                         // move up a level
479                         if (b.getParent() != null && b.getParent().getParent() != null)
480                             b.getParent().put(name, b.getParent(), value);
481                     }
482                 }};
483
484         specialBoxProperties.put("Press1", mouseEventHandler);
485         specialBoxProperties.put("Press2", mouseEventHandler);
486         specialBoxProperties.put("Press3", mouseEventHandler);
487         specialBoxProperties.put("Release1", mouseEventHandler);
488         specialBoxProperties.put("Release2", mouseEventHandler);
489         specialBoxProperties.put("Release3", mouseEventHandler);
490         specialBoxProperties.put("Click1", mouseEventHandler);
491         specialBoxProperties.put("Click2", mouseEventHandler);
492         specialBoxProperties.put("Click3", mouseEventHandler);
493         specialBoxProperties.put("DoubleClick1", mouseEventHandler);
494         specialBoxProperties.put("DoubleClick2", mouseEventHandler);
495         specialBoxProperties.put("DoubleClick3", mouseEventHandler);
496
497         specialBoxProperties.put("root", new SpecialBoxProperty() {
498                 public Object get(Box b) {
499                     if (b.surface == null) return null;
500                     else if (b.getRoot() == null) return null;
501                     else return b.getRoot().getRootProxy();
502                 } });
503
504         specialBoxProperties.put("Minimized", new SpecialBoxProperty() {
505                 public Object get(Box b) {
506                     if (b.getParent() == null && b.surface != null) return b.surface.minimized ? Boolean.TRUE : Boolean.FALSE;
507                     else return null;
508                 }
509                 public void put(Box b, Object value) {
510                     if (b.surface == null) return;
511                     boolean val = stob(value);
512                     if (b.getParent() == null && b.surface.minimized != val) b.surface.setMinimized(val);
513                 }
514             });
515
516         specialBoxProperties.put("Maximized", new SpecialBoxProperty() {
517                 public Object get(Box b) {
518                     if (b.getParent() == null && b.surface != null) return b.surface.maximized ? Boolean.TRUE : Boolean.FALSE;
519                     else return null;
520                 }
521                 public void put(Box b, Object value) {
522                     if (b.surface == null) return;
523                     boolean val = stob(value);
524                     if (b.getParent() == null && b.surface.maximized != val) b.surface.setMaximized(val);
525                 }
526             });
527
528         specialBoxProperties.put("toback", new SpecialBoxProperty() {
529                 public void put(Box b, Object value) {
530                     if (b.getParent() == null && stob(value) && b.surface != null) b.surface.toBack();
531                 }
532             });
533
534         specialBoxProperties.put("tofront", new SpecialBoxProperty() {
535                 public void put(Box b, Object value) {
536                     if (b.getParent() == null && stob(value) && b.surface != null) b.surface.toFront();
537                 }
538             });
539
540         specialBoxProperties.put("hscar", new SpecialBoxProperty() {
541                 public void put(Box b, Object value) {
542                     if (b.getParent() == null && b.surface != null) {
543                         b.surface.hscar = stoi(value);
544                         b.surface.dirty(0, 0, b.surface.width, b.surface.height);
545                         b.surface.Refresh();
546                     }
547                 }
548             });
549
550         specialBoxProperties.put("vscar", new SpecialBoxProperty() {
551                 public void put(Box b, Object value) {
552                     if (b.getParent() == null && b.surface != null) {
553                         b.surface.vscar = stoi(value);
554                         b.surface.dirty(0, 0, b.surface.width, b.surface.height);
555                         b.surface.Refresh();
556                     }
557                 }
558             });
559
560         specialBoxProperties.put("Close", new SpecialBoxProperty() {
561                 public void put(Box b, Object value) {
562                     if (b.getParent() == null && b.surface != null) b.surface.dispose();
563                 }
564             });
565
566         // these are all do-nothings; just to prevent space from getting taken up in the params Hash.
567         specialBoxProperties.put("KeyPressed", new SpecialBoxProperty());
568         specialBoxProperties.put("KeyReleased", new SpecialBoxProperty());
569         specialBoxProperties.put("PosChange", new SpecialBoxProperty());
570         specialBoxProperties.put("SizeChange", new SpecialBoxProperty());
571
572         specialBoxProperties.put("hpad", new SpecialBoxProperty() {
573                 public Object get(Box b) {
574                     if (b.redirect == null) return new Integer(0);
575                     if (b.redirect != b) return get(b.redirect);
576                     return new Integer(b.pad(0));
577                 }
578                 public void put(Box b, Object value) {
579                     if (b.redirect == null) return;
580                     if (b.redirect != b) { put(b.redirect, value); return; }
581                     short newval = stosh(value);
582                     if (newval == b.pad(0)) return;
583                     b.set(pad, 0, newval);
584                 }
585             });
586
587         specialBoxProperties.put("vpad", new SpecialBoxProperty() {
588                 public Object get(Box b) {
589                     if (b.redirect == null) return new Integer(0);
590                     if (b.redirect != b) return get(b.redirect);
591                     return new Integer(b.pad(1));
592                 }
593                 public void put(Box b, Object value) {
594                     if (b.redirect == null) return;
595                     if (b.redirect != b) { put(b.redirect, value); return; }
596                     short newval = stosh(value);
597                     if (newval == b.pad(1)) return;
598                     b.set(pad, 1, newval);
599                 }
600             });
601
602         specialBoxProperties.put("indexof", new SpecialBoxProperty() {
603                 public Object get(Box b) { return b.indexof(); }
604             });
605
606         specialBoxProperties.put("minwidth", new SpecialBoxProperty() {
607                 public Object get(Box b) { return new Integer(b.dmin(0)); }
608                 public void put(Box b, Object value) {
609                     if (b.sizetoimage) return;
610                     b.set(dmin, 0, stosh(value));
611                 }
612             });
613
614         specialBoxProperties.put("maxwidth", new SpecialBoxProperty() {
615                 public Object get(Box b) { return new Integer(b.dmax(0)); }
616                 public void put(Box b, Object value) {
617                     if (b.sizetoimage) return;
618                     b.set(dmax, 0, stosh(value));
619                 }
620             });
621
622         specialBoxProperties.put("minheight", new SpecialBoxProperty() {
623                 public Object get(Box b) { return new Integer(b.dmin(1)); }
624                 public void put(Box b, Object value) {
625                     if (b.sizetoimage) return;
626                     b.set(dmin, 1, stosh(value));
627                 }
628             });
629
630         specialBoxProperties.put("maxheight", new SpecialBoxProperty() {
631                 public Object get(Box b) { return new Integer(b.dmax(1)); }
632                 public void put(Box b, Object value) {
633                     if (b.sizetoimage) return;
634                     b.set(dmax, 1, stosh(value));
635                 }
636             });
637     }
638
639         
640     /** helper that converts a String to a boolean according to JavaScript coercion rules */
641     public static boolean stob(Object o) {
642         if (o == null) return false;
643         return Boolean.TRUE.equals(o) || "true".equals(o);
644     }
645
646     /** helper that converts a String to an int according to JavaScript coercion rules */
647     public static int stoi(Object o) {
648         if (o == null) return 0;
649         if (o instanceof Integer) return ((Integer)o).intValue();
650
651         String s;
652         if (!(o instanceof String)) s = o.toString();
653         else s = (String)o;
654
655         try { return Integer.parseInt(s.indexOf('.') == -1 ? s : s.substring(0, s.indexOf('.'))); }
656         catch (NumberFormatException e) { return 0; }
657     }
658         
659     /** helper that converts a String to a short according to JavaScript coercion rules */
660     public static short stosh(Object o) {
661         if (o == null) return 0;
662         if (o instanceof Number) return ((Number)o).shortValue();
663
664         String s;
665         if (!(o instanceof String)) s = o.toString();
666         else s = (String)o;
667
668         try { return Short.parseShort(s.indexOf('.') == -1 ? s : s.substring(0, s.indexOf('.'))); }
669         catch (NumberFormatException e) { return 0; }
670     }
671         
672 }
673
674         
675