bc9b9d45c36c126bcf5216417ead781758310725
[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 java.util.*;
5 import java.net.*;
6 import java.text.*;
7 import org.xwt.js.*;
8 import org.xwt.util.*;
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 + "\" at " + JS.getCurrentFunctionSourceName());
105                     if (newcolor == b.color) return;
106                     b.color = newcolor;
107                     b.dirty();
108                 } });
109         
110         
111         specialBoxProperties.put("textcolor", new SpecialBoxProperty() {
112                 public Object get(Box b) {
113                     if ((b.textcolor & 0xFF000000) == 0) return null;
114                     String red = Integer.toHexString((b.textcolor & 0x00FF0000) >> 16);
115                     String green = Integer.toHexString((b.textcolor & 0x0000FF00) >> 8);
116                     String blue = Integer.toHexString(b.textcolor & 0x000000FF);
117                     if (red.length() < 2) red = "0" + red;
118                     if (blue.length() < 2) blue = "0" + blue;
119                     if (green.length() < 2) green = "0" + green;
120                     return "#" + red + green + blue;
121                 }
122                 public void put(Box b, Object value) {
123                     int newtextcolor = b.color;
124                     if (value == null) return;
125                     String s = value.toString();
126                     if (s.length() > 0 && s.charAt(0) == '#')
127                         newtextcolor = 0xFF000000 |
128                             (Integer.parseInt(s.substring(1, 3), 16) << 16) |
129                             (Integer.parseInt(s.substring(3, 5), 16) << 8) |
130                             Integer.parseInt(s.substring(5, 7), 16);
131                     else if (s.equals("black")) newtextcolor = black;
132                     else if (s.equals("blue")) newtextcolor = blue;
133                     else if (s.equals("green")) newtextcolor = green;
134                     else if (s.equals("cyan")) newtextcolor = cyan;
135                     else if (s.equals("red")) newtextcolor = red;
136                     else if (s.equals("magenta")) newtextcolor = magenta;
137                     else if (s.equals("brown")) newtextcolor = brown;
138                     else if (s.equals("lightGray")) newtextcolor = lightGray;
139                     else if (s.equals("darkGray")) newtextcolor = darkGray;
140                     else if (s.equals("brightBlue")) newtextcolor = brightBlue;
141                     else if (s.equals("brightGreen")) newtextcolor = brightGreen;
142                     else if (s.equals("brightCyan")) newtextcolor = brightCyan;
143                     else if (s.equals("brightRed")) newtextcolor = brightRed;
144                     else if (s.equals("pink")) newtextcolor = pink;
145                     else if (s.equals("yellow")) newtextcolor = yellow;
146                     else if (s.equals("white")) newtextcolor = white;
147                     else if (Log.on) Log.log(this, "invalid color \"" + s + "\" at " + JS.getCurrentFunctionSourceName());
148                     if (newtextcolor == b.textcolor) return;
149                     b.textcolor = newtextcolor;
150                     b.dirty();
151                 } });
152         
153         specialBoxProperties.put("text", new SpecialBoxProperty() {
154                 public Object get(Box b) { return b.text; }
155                 public void put(Box b, Object value) {
156                     String t = value == null ? "null" : value.toString();
157                     if (t.equals(b.text)) return;
158
159                     for(int i=0; i<t.length(); i++)
160                         if (Character.isISOControl(t.charAt(i))) {
161                             if (Log.on) Log.log(this, 
162                                                 "ISO Control characters are not permitted in box text strings; offending character is ASCII " +
163                                                ((int)t.charAt(i)));
164                             return;
165                         }
166
167                     // FEATURE: try removing the following line; it appears to be redundant
168                     b.dirty();
169                     b.text = t;
170                     b.textupdate();
171                     b.dirty();
172                 } });
173         
174         specialBoxProperties.put("thisbox", new SpecialBoxProperty() {
175                 public Object get(Box b) { return b; }
176                 public void put(Box b, Object value) {
177                     if (value == null) b.remove();
178                     else if (value.equals("window") || value.equals("frame")) {
179                         if (b.redirect != b && Log.on)
180                             Log.log(this, "WARNING: you have created a surface whose root box's redirect is not itself " +
181                                     "-- this isn't usually a good idea");
182                         Platform.createSurface(b, value.equals("frame"), true);
183                     } else if (Log.on) Log.log(this, "put invalid value to 'thisbox' property: " + value);
184                 }
185             });
186
187         specialBoxProperties.put("orient", new SpecialBoxProperty() {
188                 public Object get(Box b) {
189                     if (b.redirect == null) return "horizontal";
190                     else if (b.redirect != b) return get(b.redirect);
191                     else if (b.o == 1) return "vertical";
192                     else return "horizontal";
193                 }
194                 public void put(Box b, Object value) {
195                     if (value == null) return;
196                     if (b.redirect == null) return;
197                     if (b.redirect != b) {
198                         put(b.redirect, value);
199                         return;
200                     }
201                     if (value.equals("vertical")) {
202                         if (b.o == 1) return;
203                         b.o = 1;
204                         b.xo = 0;
205                     } else if (value.equals("horizontal")) {
206                         if (b.o == 0) return;
207                         b.o = 0;
208                         b.xo = 1;
209                     } else if (Log.on)
210                         Log.log(this, "invalid value put to orient property: " + value);
211                     b.mark_for_prerender();
212                     b.sync_cmin_to_children();
213                 } });
214
215         specialBoxProperties.put("static", new SpecialBoxProperty() {
216                 public Object get(Box b) {
217                     String cfsn = JS.getCurrentFunction().getSourceName();
218                     for(int i=0; i<cfsn.length() - 1; i++)
219                         if (cfsn.charAt(i) == '.' && (cfsn.charAt(i+1) == '_' || Character.isDigit(cfsn.charAt(i+1)))) {
220                             cfsn = cfsn.substring(0, i);
221                             break;
222                         }
223                     return Static.getStatic(cfsn);
224                 }
225                 public void put(Box b, Object value) { }
226             });
227
228         specialBoxProperties.put("sizetoimage", new SpecialBoxProperty() {
229                 public Object get(Box b) { return b.sizetoimage ? Boolean.TRUE : Boolean.FALSE; }
230                 public void put(Box b, Object value) {
231                     if (stob(value)) {
232                         if (b.sizetoimage) return;
233                         b.sizetoimage = true;
234                         b.syncSizeToImage();
235                     } else {
236                         b.sizetoimage = false;
237                     }
238                 } });
239         
240         specialBoxProperties.put("fixedaspect", new SpecialBoxProperty() {
241                 public Object get(Box b) { return b.sizetoimage ? Boolean.TRUE : Boolean.FALSE; }
242                 public void put(Box b, Object value) {
243                     boolean newval = stob(value);
244                     if (newval == b.fixedaspect) return;
245                     b.fixedaspect = newval;
246                     b.dirty();
247                 } });
248         
249         specialBoxProperties.put("shrink", new SpecialBoxProperty() {
250                 public Object get(Box b) { return (b.vshrink && b.hshrink) ? Boolean.TRUE : Boolean.FALSE; }
251                 public void put(Box b, Object value) {
252                     boolean newshrink = stob(value);
253                     if (b.hshrink == newshrink && b.vshrink == newshrink) return;
254                     b.hshrink = b.vshrink = newshrink;
255                     b.mark_for_prerender();
256                 } });
257         
258         specialBoxProperties.put("hshrink", new SpecialBoxProperty() {
259                 public Object get(Box b) { return new Boolean(b.hshrink); }
260                 public void put(Box b, Object value) {
261                     boolean newshrink = stob(value);
262                     if (b.hshrink == newshrink) return;
263                     b.hshrink = newshrink;
264                     b.mark_for_prerender();
265                 }
266             });
267         
268         specialBoxProperties.put("vshrink", new SpecialBoxProperty() {
269                 public Object get(Box b) { return b.vshrink ? Boolean.TRUE : Boolean.FALSE; }
270                 public void put(Box b, Object value) {
271                     boolean newshrink = stob(value);
272                     if (b.vshrink == newshrink) return;
273                     b.vshrink = newshrink;
274                     b.mark_for_prerender();
275                 }
276             });
277         
278         specialBoxProperties.put("x", new SpecialBoxProperty() {
279                 public Object get(Box b) {
280                     if (b.surface == null) return new Integer(0);
281                     if (b.invisible) return new Integer(0);
282                     return new Integer(b.abs(0));
283                 }
284                 public void put(Box b, Object value) {
285                     if (b.getParent() == null && b.surface != null) {
286                         b.surface.setLocation(stoi(value), b.abs(1));
287                         b.surface.centerSurfaceOnRender = false;
288                     }
289                     b.set(abs, 0, stoi(value));
290                 }
291             });
292         
293         specialBoxProperties.put("y", new SpecialBoxProperty() {
294                 public Object get(Box b) {
295                     if (b.surface == null) return new Integer(0);
296                     if (b.invisible) return new Integer(0);
297                     return new Integer(b.abs(1));
298                 }
299                 public void put(Box b, Object value) {
300                     if (b.getParent() == null && b.surface != null) {
301                         b.surface.setLocation(b.abs(0), stoi(value));
302                         b.surface.centerSurfaceOnRender = false;
303                     }
304                     b.set(abs, 1, stoi(value));
305                 }
306             });
307
308         specialBoxProperties.put("width", new SpecialBoxProperty() {
309                 public Object get(Box b) { return new Integer(b.size(0)); }
310                 public void put(Box b, Object value) {
311                     if (b.sizetoimage) return;
312                     if (b.getParent() == null && b.surface != null) {
313                         b.set(size, 0, Box.max(Surface.scarPicture.getWidth(), stoi(value)));
314                         b.mark_for_prerender();
315                     } else {
316                         b.set(dmax, 0, stoi(value));
317                         b.set(dmin, 0, stoi(value));
318                     }
319                 } });
320         
321         specialBoxProperties.put("height", new SpecialBoxProperty() {
322                 public Object get(Box b) { return new Integer(b.size(1)); }
323                 public void put(Box b, Object value) {
324                     if (b.sizetoimage) return;
325                     if (b.getParent() == null && b.surface != null) {
326                         b.set(size, 1, Box.max(Surface.scarPicture.getHeight(), stoi(value)));
327                         b.mark_for_prerender();
328                     } else {
329                         b.set(dmax, 1, stoi(value));
330                         b.set(dmin, 1, stoi(value));
331                     }
332                 } });
333
334         specialBoxProperties.put("flex", new SpecialBoxProperty() {
335                 public Object get(Box b) { return new Double(b.flex); }
336                 public void put(Box b, Object value) {
337                     if (value == null) return;
338                     int newflex = stoi(value);
339                     if (newflex == b.flex) return;
340                     b.flex = newflex;
341                     b.mark_for_prerender();
342                 } });
343         
344         specialBoxProperties.put("tile", new SpecialBoxProperty() {
345                 public Object get(Box b) { return b.tile ? Boolean.TRUE : Boolean.FALSE; }
346                 public void put(Box b, Object value) {
347                     boolean newtile = stob(value);
348                     if (newtile == b.tile) return;
349                     b.tile = newtile;
350                     b.dirty();
351                 } });
352         
353         specialBoxProperties.put("align", new SpecialBoxProperty() {
354                 public Object get(Box b) {
355                     if (b.align == -1) return "topleft";
356                     else if (b.align == 1) return "bottomright";
357                     else return "center";
358                 }
359                 public void put(Box b, Object value) {
360                     String s = value == null ? "" : value.toString();
361                     byte newalign = b.align;
362                     if (s.equals("topleft")) newalign = -1;
363                     else if (s.equals("bottomright")) newalign = 1;
364                     else if (s.equals("center")) newalign = 0;
365                     else if (Log.on) Log.log(this, "invalid value put to align property: " + value);
366                     if (newalign == b.align) return;
367                     b.align = newalign;
368                     if (b.getParent() != null) b.getParent().mark_for_prerender();
369                 } });
370         
371         specialBoxProperties.put("invisible", new SpecialBoxProperty() {
372                 public Object get(Box b) {
373                     for (Box cur = b; cur != null; cur = cur.getParent()) { if (cur.invisible) return Boolean.TRUE; }
374                     return Boolean.FALSE;
375                 }
376                 public void put(Box b, Object value) {
377                     boolean newinvisible = stob(value);
378                     if (newinvisible == b.invisible) return;
379                     b.invisible = newinvisible;
380                     if (b.getParent() == null) {
381                         if (b.surface != null) b.surface.setInvisible(newinvisible);
382                     } else {
383                         b.dirty();
384                         b.getParent().mark_for_prerender();
385                         b.getParent().sync_cmin_to_children();
386                         b.getParent().dirty(b.pos(0), b.pos(1), b.size(0), b.size(1));
387                         b.getParent().dirty(b.oldpos(0), b.oldpos(1), b.oldsize(0), b.oldsize(1));
388                     }
389                 }});
390         
391         specialBoxProperties.put("absolute", new SpecialBoxProperty() {
392                 public Object get(Box b) { return b.absolute ? Boolean.TRUE : Boolean.FALSE; }
393                 public void put(Box b, Object value) {
394                     boolean newabsolute = stob(value);
395                     if (newabsolute == b.absolute) return;
396                     b.absolute = newabsolute;
397                     if (b.getParent() != null) {
398                         b.getParent().mark_for_prerender();
399                         b.getParent().sync_cmin_to_children();
400                     }
401                 } });
402         
403         specialBoxProperties.put("image", new SpecialBoxProperty() {
404                 public Object get(Box b) { return b.image == null ? null : Box.imageToNameMap.get(b.image); }
405                 public void put(Box b, Object value) { b.setImage(value == null ? null : value.toString()); }
406             });
407
408         specialBoxProperties.put("border", new SpecialBoxProperty() {
409                 public Object get(Box b) { return b.border == null ? null : Box.imageToNameMap.get(b.border); }
410                 public void put(Box b, Object value) { b.setBorder(value == null ? null : value.toString()); }
411             });
412
413         specialBoxProperties.put("font", new SpecialBoxProperty() {
414                 public Object get(Box b) { return b.font; }
415                 public void put(Box b, Object value) {
416                     b.font = value == null ? null : value.toString();
417                     b.fontChanged();
418                     b.dirty();
419                 } });
420         
421         specialBoxProperties.put("globalx", new SpecialBoxProperty() {
422                 public Object get(Box b) { return new Integer(b.getParent() == null || b.surface == null ? 0 : b.pos(0)); }
423                 public void put(Box b, Object value) {
424                     if (b.surface == null || b.getParent() == null) return;
425                     b.put("x", new Integer(stoi(value) - stoi(get(b.getParent()))));
426                 }
427             });
428         
429         specialBoxProperties.put("globaly", new SpecialBoxProperty() {
430                 public Object get(Box b) { return new Integer(b.getParent() == null || b.surface == null ? 0 : b.pos(1)); }
431                 public void put(Box b, Object value) {
432                     if (b.surface == null || b.getParent() == null) return;
433                     b.put("y", new Integer(stoi(value) - stoi(get(b.getParent()))));
434                 }
435             });
436         
437         specialBoxProperties.put("cursor", new SpecialBoxProperty() {
438                 public Object get(Box b) { return b.cursor; } 
439                 public void put(Box b, Object value) {
440                     b.cursor = (String)value;
441                     if (b.surface == null) return;
442
443                     // see if we need to update the surface cursor
444                     String tempcursor = b.surface.cursor;
445                     b.Move(b.surface.mousex, b.surface.mousey, b.surface.mousex, b.surface.mousey);
446                     if (b.surface.cursor != tempcursor) b.surface.syncCursor();
447                 } 
448             });
449         
450         specialBoxProperties.put("mousex", new SpecialBoxProperty() {
451                 public Object get(Box b) { return new Integer(b.surface == null ? 0 : b.surface.mousex - b.pos(0)); }
452             });
453         
454         specialBoxProperties.put("mousey", new SpecialBoxProperty() {
455                 public Object get(Box b) { return new Integer(b.surface == null ? 0 : b.surface.mousey - b.pos(1)); }
456             });
457         
458         specialBoxProperties.put("xwt", new SpecialBoxProperty() {
459                 public Object get(Box b) { return XWT.singleton; }
460             });
461         
462         specialBoxProperties.put("mouseinside", new SpecialBoxProperty() {
463                 public Object get(Box b) { return b.mouseinside ? Boolean.TRUE : Boolean.FALSE; }
464             });
465         
466         specialBoxProperties.put("numchildren", new SpecialBoxProperty() {
467                 public Object get(Box b) {
468                     if (b.redirect == null) return new Integer(0);
469                     if (b.redirect != b) return get(b.redirect);
470                     return new Integer(b.numChildren());
471                 } });
472         
473         SpecialBoxProperty mouseEventHandler = new SpecialBoxProperty() {
474                 public void put(String name, Box b, Object value) {
475                     if (b.surface == null) return;
476                     for(Box c = b.prevSibling(); c != null; c = c.prevSibling()) {
477                         Box siblingChild = c.whoIs(c.surface.mousex, c.surface.mousey);
478                         if (siblingChild != null) {
479                             siblingChild.put(name, value);
480                             return;
481                         }
482                     }
483                     if (b.getParent() != null)
484                         b.getParent().put(name, value);
485                 }};
486
487         specialBoxProperties.put("Press1", mouseEventHandler);
488         specialBoxProperties.put("Press2", mouseEventHandler);
489         specialBoxProperties.put("Press3", mouseEventHandler);
490         specialBoxProperties.put("Release1", mouseEventHandler);
491         specialBoxProperties.put("Release2", mouseEventHandler);
492         specialBoxProperties.put("Release3", mouseEventHandler);
493         specialBoxProperties.put("Click1", mouseEventHandler);
494         specialBoxProperties.put("Click2", mouseEventHandler);
495         specialBoxProperties.put("Click3", mouseEventHandler);
496         specialBoxProperties.put("DoubleClick1", mouseEventHandler);
497         specialBoxProperties.put("DoubleClick2", mouseEventHandler);
498         specialBoxProperties.put("DoubleClick3", mouseEventHandler);
499
500         specialBoxProperties.put("root", new SpecialBoxProperty() {
501                 public Object get(Box b) {
502                     if (b.surface == null) return null;
503                     else if (b.getRoot() == null) return null;
504                     else if (b.getParent() == null) return b;
505                     else return b.getRoot().getRootProxy();
506                 } });
507
508         specialBoxProperties.put("Minimized", new SpecialBoxProperty() {
509                 public Object get(Box b) {
510                     if (b.getParent() == null && b.surface != null) return b.surface.minimized ? Boolean.TRUE : Boolean.FALSE;
511                     else return null;
512                 }
513                 public void put(Box b, Object value) {
514                     if (b.surface == null) return;
515                     boolean val = stob(value);
516                     if (b.getParent() == null && b.surface.minimized != val) b.surface.setMinimized(val);
517                 }
518             });
519
520         specialBoxProperties.put("Maximized", new SpecialBoxProperty() {
521                 public Object get(Box b) {
522                     if (b.getParent() == null && b.surface != null) return b.surface.maximized ? Boolean.TRUE : Boolean.FALSE;
523                     else return null;
524                 }
525                 public void put(Box b, Object value) {
526                     if (b.surface == null) return;
527                     boolean val = stob(value);
528                     if (b.getParent() == null && b.surface.maximized != val) b.surface.setMaximized(val);
529                 }
530             });
531
532         specialBoxProperties.put("toback", new SpecialBoxProperty() {
533                 public void put(Box b, Object value) {
534                     if (b.getParent() == null && stob(value) && b.surface != null) b.surface.toBack();
535                 }
536             });
537
538         specialBoxProperties.put("tofront", new SpecialBoxProperty() {
539                 public void put(Box b, Object value) {
540                     if (b.getParent() == null && stob(value) && b.surface != null) b.surface.toFront();
541                 }
542             });
543
544         specialBoxProperties.put("hscar", new SpecialBoxProperty() {
545                 public void put(Box b, Object value) {
546                     if (b.getParent() == null && b.surface != null) {
547                         b.surface.hscar = stoi(value);
548                         b.surface.dirty(0, 0, b.surface.width, b.surface.height);
549                         b.surface.Refresh();
550                     }
551                 }
552             });
553
554         specialBoxProperties.put("vscar", new SpecialBoxProperty() {
555                 public void put(Box b, Object value) {
556                     if (b.getParent() == null && b.surface != null) {
557                         b.surface.vscar = stoi(value);
558                         b.surface.dirty(0, 0, b.surface.width, b.surface.height);
559                         b.surface.Refresh();
560                     }
561                 }
562             });
563
564         specialBoxProperties.put("Close", new SpecialBoxProperty() {
565                 public void put(Box b, Object value) {
566                     if (b.getParent() == null && b.surface != null) b.surface.dispose(true);
567                 }
568             });
569
570         // these are all do-nothings; just to prevent space from getting taken up in the params Hash.
571         specialBoxProperties.put("KeyPressed", new SpecialBoxProperty());
572         specialBoxProperties.put("KeyReleased", new SpecialBoxProperty());
573         specialBoxProperties.put("PosChange", new SpecialBoxProperty());
574         specialBoxProperties.put("SizeChange", new SpecialBoxProperty());
575
576         specialBoxProperties.put("hpad", new SpecialBoxProperty() {
577                 public Object get(Box b) {
578                     if (b.redirect == null) return new Integer(0);
579                     if (b.redirect != b) return get(b.redirect);
580                     return new Integer(b.pad(0));
581                 }
582                 public void put(Box b, Object value) {
583                     if (b.redirect == null) return;
584                     if (b.redirect != b) { put(b.redirect, value); return; }
585                     int newval = stoi(value);
586                     if (newval == b.pad(0)) return;
587                     b.set(pad, 0, newval);
588                 }
589             });
590
591         specialBoxProperties.put("vpad", new SpecialBoxProperty() {
592                 public Object get(Box b) {
593                     if (b.redirect == null) return new Integer(0);
594                     if (b.redirect != b) return get(b.redirect);
595                     return new Integer(b.pad(1));
596                 }
597                 public void put(Box b, Object value) {
598                     if (b.redirect == null) return;
599                     if (b.redirect != b) { put(b.redirect, value); return; }
600                     int newval = stoi(value);
601                     if (newval == b.pad(1)) return;
602                     b.set(pad, 1, newval);
603                 }
604             });
605
606         specialBoxProperties.put("indexof", new SpecialBoxProperty() {
607                 public Object get(Box b) { return b.indexof(); }
608             });
609
610         specialBoxProperties.put("minwidth", new SpecialBoxProperty() {
611                 public Object get(Box b) { return new Integer(b.dmin(0)); }
612                 public void put(Box b, Object value) {
613                     if (b.sizetoimage) return;
614                     b.set(dmin, 0, stoi(value));
615                 }
616             });
617
618         specialBoxProperties.put("maxwidth", new SpecialBoxProperty() {
619                 public Object get(Box b) { return new Integer(b.dmax(0)); }
620                 public void put(Box b, Object value) {
621                     if (b.sizetoimage) return;
622                     b.set(dmax, 0, stoi(value));
623                 }
624             });
625
626         specialBoxProperties.put("minheight", new SpecialBoxProperty() {
627                 public Object get(Box b) { return new Integer(b.dmin(1)); }
628                 public void put(Box b, Object value) {
629                     if (b.sizetoimage) return;
630                     b.set(dmin, 1, stoi(value));
631                 }
632             });
633
634         specialBoxProperties.put("maxheight", new SpecialBoxProperty() {
635                 public Object get(Box b) { return new Integer(b.dmax(1)); }
636                 public void put(Box b, Object value) {
637                     if (b.sizetoimage) return;
638                     b.set(dmax, 1, stoi(value));
639                 }
640             });
641
642         specialBoxProperties.put("redirect", new SpecialBoxProperty() {
643                 public void put(Box b, Object value) { }
644                 public Object get(Box b) {
645                     if (b.redirect == null) return null;
646                     if (b.redirect == b) return Boolean.TRUE;
647                     return get(b.redirect);
648                 }
649             });
650
651         specialBoxProperties.put("apply", new SpecialBoxProperty() {
652                 public void put(Box b, Object value) { }
653                 public Object get(Box b) { return new Apply(b); }
654             });
655
656         specialBoxProperties.put("id", new SpecialBoxProperty() {
657                 public void put(Box b, Object value) { }
658                 public Object get(Box b) { return b.id; }
659             });
660     }
661
662         
663     /** helper that converts a String to a boolean according to JavaScript coercion rules */
664     public static boolean stob(Object o) {
665         if (o == null) return false;
666         return Boolean.TRUE.equals(o) || "true".equals(o);
667     }
668
669     /** helper that converts a String to an int according to JavaScript coercion rules */
670     public static int stoi(Object o) {
671         if (o == null) return 0;
672         if (o instanceof Integer) return ((Integer)o).intValue();
673
674         String s;
675         if (!(o instanceof String)) s = o.toString();
676         else s = (String)o;
677
678         try { return Integer.parseInt(s.indexOf('.') == -1 ? s : s.substring(0, s.indexOf('.'))); }
679         catch (NumberFormatException e) { return 0; }
680     }
681         
682     /** helper that converts a String to a int according to JavaScript coercion rules */
683     public static class Apply extends JS.Function {
684
685         Box b;
686         public Apply(Box b) { this.b = b; }
687
688         public Object _call(JS.Array args) throws JS.Exn {
689
690             // apply a template
691             if (args.elementAt(0) instanceof String) {
692                 String templatename = (String)args.elementAt(0);
693                 Template t = Template.getTemplate(templatename, null);
694                 if (t == null) {
695                     if (Log.on) Log.log(this, "template " + templatename + " not found at " + JS.getFileAndLine());
696                 } else {
697                     if (ThreadMessage.suspendThread()) try {
698                         JS.Function callback = args.length() < 2 ? null : (Function)args.elementAt(1);
699                         t.apply(b, null, null, callback, 0, t.numUnits());
700                     } finally {
701                         ThreadMessage.resumeThread();
702                     }
703                 }
704
705             // apply a list of properties
706             } else if (args.elementAt(0) instanceof JS && !(args.elementAt(0) instanceof Box)) {
707                 JS s = (JS)args.elementAt(0);
708                 Object[] keys = s.keys();
709                 for(int j=0; j<keys.length; j++) b.put(keys[j].toString(), s);
710             }
711
712             return b;
713         }
714     }
715
716 }
717
718         
719