From 457660f731024833fc8aea9b0154eae578b51600 Mon Sep 17 00:00:00 2001 From: megacz Date: Fri, 30 Jan 2004 07:43:04 +0000 Subject: [PATCH] 2003/12/21 08:50:38 darcs-hash:20040130074304-2ba56-7ca5b039e4eafb489f2095c8982a6be40fb17620.gz --- src/org/xwt/Box.java | 139 +++++++++++++++++++++++++++----------------- src/org/xwt/Scheduler.java | 5 +- src/org/xwt/Surface.java | 139 +++++++++++++++++++------------------------- 3 files changed, 149 insertions(+), 134 deletions(-) diff --git a/src/org/xwt/Box.java b/src/org/xwt/Box.java index 6f96cc2..25dc935 100644 --- a/src/org/xwt/Box.java +++ b/src/org/xwt/Box.java @@ -72,6 +72,7 @@ public final class Box extends JSScope implements Scheduler.Task { DEFAULT_FONT = f; } + // FIXME update these // box properties can not be trapped static final String[] props = new String[] { "fill", "stroke", "image", "tile", "fixedaspect", "text", "path", "font", @@ -82,6 +83,7 @@ public final class Box extends JSScope implements Scheduler.Task { "mouseinside", "root", "thisbox", "indexof" }; + // FIXME update these // events can have write traps, but not read traps static final String[] events = new String[] { "Press1", "Press2", "Press3", @@ -90,9 +92,7 @@ public final class Box extends JSScope implements Scheduler.Task { "DoubleClick1", "DoubleClick2", "DoubleClick3", "Enter", "Leave", "Move", "KeyPressed", "KeyReleased", "PosChange", "SizeChange", - "childadded", "childremoved", - "Focused", "Maximized", "Minimized", "Close", "icon", "titlebar", "toback", "tofront" }; @@ -122,13 +122,14 @@ public final class Box extends JSScope implements Scheduler.Task { static final int ALIGNS = 0x0000f000; static final int CURSOR = 0x00010000; // if true, this box has a cursor in the cursor hash; FEATURE: GC issues? static final int NOCLIP = 0x00020000; + static final int STOP_UPWARD_PROPAGATION = 0x00040000; // Instance Data ////////////////////////////////////////////////////////////////////// Box parent = null; Box redirect = this; - int flags = VISIBLE | PACKED | REPACK | REFLOW | RESIZE | FIXED /* ROWS */; + int flags = VISIBLE | PACKED | REPACK | REFLOW | RESIZE | FIXED /* ROWS */ | STOP_UPWARD_PROPAGATION; private String text = null; private Font font = DEFAULT_FONT; @@ -202,25 +203,6 @@ public final class Box extends JSScope implements Scheduler.Task { } } - /** update MOUSEINSIDE, check for Enter/Leave/Move */ - void Move(int oldmousex, int oldmousey, int mousex, int mousey) { Move(oldmousex, oldmousey, mousex, mousey, false); } - void Move(int oldmousex, int oldmousey, int mousex, int mousey, boolean forceleave) { - boolean wasinside = test(MOUSEINSIDE); - boolean isinside = test(VISIBLE) && inside(mousex, mousey) && !forceleave; - if (isinside) set(MOUSEINSIDE); else clear(MOUSEINSIDE); - if (!wasinside && !isinside) return; - - if (isinside && test(CURSOR)) Surface.fromBox(getRoot()).cursor = (String)boxToCursor.get(this); - if (!wasinside && isinside && getTrap("Enter") != null) putAndTriggerTrapsAndCatchExceptions("Enter", T); - else if (wasinside && !isinside && getTrap("Leave") != null) putAndTriggerTrapsAndCatchExceptions("Leave", T); - else if (wasinside && isinside && (mousex != oldmousex || mousey != oldmousey) && getTrap("Move")!= null) - putAndTriggerTrapsAndCatchExceptions("Move", T); - for(Box b = getChild(treeSize() - 1); b != null; b = b.prevSibling()) { - b.Move(oldmousex - b.x, oldmousey - b.y, mousex - b.x, mousey - b.y, forceleave); - if (b.inside(mousex - b.x, mousey - b.y)) forceleave = true; - } - } - // Reflow //////////////////////////////////////////////////////////////////////////////////////// @@ -492,18 +474,6 @@ public final class Box extends JSScope implements Scheduler.Task { case "align": clear(ALIGNS); setAlign(value == null ? "center" : value); MARK_RESIZE; case "cursor": setCursor(value); case "fill": setFill(value); - case "Press1": mouseEvent("Press1", value); - case "Press2": mouseEvent("Press2", value); - case "Press3": mouseEvent("Press3", value); - case "Release1": mouseEvent("Release1", value); - case "Release2": mouseEvent("Release2", value); - case "Release3": mouseEvent("Release3", value); - case "Click1": mouseEvent("Click1", value); - case "Click2": mouseEvent("Click2", value); - case "Click3": mouseEvent("Click3", value); - case "DoubleClick1": mouseEvent("DoubleClick1", value); - case "DoubleClick2": mouseEvent("DoubleClick2", value); - case "DoubleClick3": mouseEvent("DoubleClick3", value); case "Minimized": if (parent == null && getSurface() != null) getSurface().minimized = toBoolean(value); // FEATURE case "Maximized": if (parent == null && getSurface() != null) getSurface().maximized = toBoolean(value); // FEATURE case "Close": if (parent == null && getSurface() != null) getSurface().dispose(true); @@ -514,14 +484,49 @@ public final class Box extends JSScope implements Scheduler.Task { case "fontsize": font = Font.getFont(font == null ? null : font.res, toInt(value)); MARK_RESIZE; dirty(); case "x": if (parent==null && Surface.fromBox(this)!=null) { CHECKSET_INT(x); } else { if (test(PACKED) && parent != null) return; CHECKSET_INT(x); dirty(); MARK_RESIZE; dirty(); } case "y": if (parent==null && Surface.fromBox(this)!=null) { CHECKSET_INT(y); } else { if (test(PACKED) && parent != null) return; CHECKSET_INT(y); dirty(); MARK_RESIZE; dirty(); } - case "KeyPressed": return; // prevent stuff from hitting the Hash - case "KeyReleased": return; // prevent stuff from hitting the Hash - case "PosChange": return; // prevent stuff from hitting the Hash - case "SizeChange": return; // prevent stuff from hitting the Hash - case "childadded": return; // prevent stuff from hitting the Hash - case "childremoved": return; // prevent stuff from hitting the Hash - case "thisbox": if (value == null) removeSelf(); - default: super.put(name, value); + + case "Press1": if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value); + case "Press2": if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value); + case "Press3": if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value); + case "Release1": if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value); + case "Release2": if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value); + case "Release3": if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value); + case "Click1": if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value); + case "Click2": if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value); + case "Click3": if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value); + case "DoubleClick1": if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value); + case "DoubleClick2": if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value); + case "DoubleClick3": if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value); + case "KeyPressed": if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value); + case "KeyReleased": if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value); + case "Move": if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value); + case "Enter": if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value); + case "Leave": if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value); + + case "_Move": propagateDownward(name, value, false); + case "_Press1": propagateDownward(name, value, false); + case "_Press2": propagateDownward(name, value, false); + case "_Press3": propagateDownward(name, value, false); + case "_Release1": propagateDownward(name, value, false); + case "_Release2": propagateDownward(name, value, false); + case "_Release3": propagateDownward(name, value, false); + case "_Click1": propagateDownward(name, value, false); + case "_Click2": propagateDownward(name, value, false); + case "_Click3": propagateDownward(name, value, false); + case "_DoubleClick1": propagateDownward(name, value, false); + case "_DoubleClick2": propagateDownward(name, value, false); + case "_DoubleClick3": propagateDownward(name, value, false); + case "_KeyPressed": propagateDownward(name, value, false); + case "_KeyReleased": propagateDownward(name, value, false); + + case "PosChange": return; + case "SizeChange": return; + case "childadded": return; + case "childremoved": return; + + case "thisbox": if (value == null) removeSelf(); + + default: super.put(name, value); //#end } @@ -562,7 +567,8 @@ public final class Box extends JSScope implements Scheduler.Task { boxToCursor.put(this, value); Surface surface = getSurface(); String tempcursor = surface.cursor; - Move(surface.mousex, surface.mousey, surface.mousex, surface.mousey); + // FIXME + //Move(surface.mousex, surface.mousey, surface.mousex, surface.mousey); if (surface.cursor != tempcursor) surface.syncCursor(); } @@ -580,15 +586,42 @@ public final class Box extends JSScope implements Scheduler.Task { texture = Picture.load((Res)value, this); } - - private void mouseEvent(String name, Object value) { - Surface surface = getSurface(); - if (surface == null) return; - int mousex = globalToLocalX(surface.mousex); - int mousey = globalToLocalY(surface.mousey); - for(Box c = prevSibling(); c != null; c = c.prevSibling()) - if (c.inside(mousex - c.x, mousey - c.y)) { c.putAndTriggerTrapsAndCatchExceptions(name, value); return; } - if (parent != null) parent.putAndTriggerTrapsAndCatchExceptions(name, value); + + /** + * Handles events which propagate down the box tree. If obscured + * is set, then we merely check for Enter/Leave. + */ + private void propagateDownward(Object name_, Object value, boolean obscured) { + + String name = (String)name_; + if (getSurface() == null) return; + int x = globalToLocalX(getSurface().mousex); + int y = globalToLocalY(getSurface().mousey); + boolean wasinside = test(MOUSEINSIDE); + boolean isinside = test(VISIBLE) && inside(x, y) && !obscured; + if (!wasinside && isinside) { set(MOUSEINSIDE); putAndTriggerTrapsAndCatchExceptions("Enter", T); } + if (wasinside && !isinside) { clear(MOUSEINSIDE); putAndTriggerTrapsAndCatchExceptions("Leave", T); } + + boolean found = false; + if (wasinside || isinside) + for(Box child = getChild(treeSize() - 1); child != null; child = child.prevSibling()) { + boolean save_stop = child.test(STOP_UPWARD_PROPAGATION); + if (obscured || !child.inside(x - child.x, y - child.y)) { + child.propagateDownward(name, value, true); + } else try { + found = true; + child.clear(STOP_UPWARD_PROPAGATION); + child.putAndTriggerTrapsAndCatchExceptions(name, value); + } finally { + if (save_stop) child.set(STOP_UPWARD_PROPAGATION); else child.clear(STOP_UPWARD_PROPAGATION); + } + if (child.inside(x - child.x, y - child.y)) + if (name.equals("_Move")) obscured = true; + else break; + } + + if (!obscured && !found) + if (!name.equals("_Move") || wasinside) putAndTriggerTrapsAndCatchExceptions(name.substring(1), value); } private static int stringToColor(String s) { @@ -755,7 +788,7 @@ public final class Box extends JSScope implements Scheduler.Task { } } - private void putAndTriggerTrapsAndCatchExceptions(Object name, Object val) { + void putAndTriggerTrapsAndCatchExceptions(Object name, Object val) { try { putAndTriggerTraps(name, val); } catch (Exception e) { diff --git a/src/org/xwt/Scheduler.java b/src/org/xwt/Scheduler.java index 3dcc7f5..5000287 100644 --- a/src/org/xwt/Scheduler.java +++ b/src/org/xwt/Scheduler.java @@ -8,6 +8,8 @@ import org.xwt.util.*; /** Implements cooperative multitasking */ public class Scheduler { + // FIXME: prepending events messes with keysate -- make a "no re-ordering" invariant? + // Public API Exposed to org.xwt ///////////////////////////////////////////////// private static Scheduler singleton; @@ -42,7 +44,8 @@ public class Scheduler { try { t.perform(); // FEATURE: be smarter about this - if (t != Surface.renderAll) add(Surface.renderAll); + //if (t != Surface.renderAll) add(Surface.renderAll); + Surface.renderAll.perform(); } catch (JSExn e) { Log.log(Scheduler.class, "a JavaScript thread spawned with xwt.thread() threw an exception:"); Log.log(Scheduler.class, e.toString()); diff --git a/src/org/xwt/Surface.java b/src/org/xwt/Surface.java index f3891ad..fe5844f 100644 --- a/src/org/xwt/Surface.java +++ b/src/org/xwt/Surface.java @@ -42,8 +42,6 @@ public abstract class Surface extends PixelBuffer implements Scheduler.Task { // Instance Data /////////////////////////////////////////////////////////////////////// - Vec keywatchers = new Vec(); - public Box root; ///< The Box at the root of this surface public String cursor = "default"; ///< The active cursor to switch to when syncCursor() is called public int mousex; ///< x position of the mouse, in Scheduler-time @@ -88,14 +86,14 @@ public abstract class Surface extends PixelBuffer implements Scheduler.Task { else if (button == 2) button2 = true; else if (button == 3) button3 = true; - if (button == 1) new SimpleMessage("Press1", T, Box.whoIs(root, mousex, mousey)); - else if (button == 2) new SimpleMessage("Press2", T, Box.whoIs(root, mousex, mousey)); + if (button == 1) new SimpleMessage("_Press1", T, root); + else if (button == 2) new SimpleMessage("_Press2", T, root); else if (button == 3) { - final Box who = Box.whoIs(root, mousex, mousey); + final Box who = root; Scheduler.add(new Scheduler.Task() { public void perform() throws JSExn { Platform.clipboardReadEnabled = true; try { - root.putAndTriggerTraps("Press3", T); + root.putAndTriggerTraps("_Press3", T); } finally { Platform.clipboardReadEnabled = false; } @@ -108,9 +106,9 @@ public abstract class Surface extends PixelBuffer implements Scheduler.Task { else if (button == 2) button2 = false; else if (button == 3) button3 = false; - if (button == 1) new SimpleMessage("Release1", T, Box.whoIs(root, mousex, mousey)); - else if (button == 2) new SimpleMessage("Release2", T, Box.whoIs(root, mousex, mousey)); - else if (button == 3) new SimpleMessage("Release3", T, Box.whoIs(root, mousex, mousey)); + if (button == 1) new SimpleMessage("_Release1", T, root); + else if (button == 2) new SimpleMessage("_Release2", T, root); + else if (button == 3) new SimpleMessage("_Release3", T, root); if (Platform.needsAutoClick() && Math.abs(last_press_x - mousex) < 5 && Math.abs(last_press_y - mousey) < 5) Click(button); last_press_x = Integer.MAX_VALUE; @@ -118,9 +116,9 @@ public abstract class Surface extends PixelBuffer implements Scheduler.Task { } protected final void Click(int button) { - if (button == 1) new SimpleMessage("Click1", T, Box.whoIs(root, mousex, mousey)); - else if (button == 2) new SimpleMessage("Click2", T, Box.whoIs(root, mousex, mousey)); - else if (button == 3) new SimpleMessage("Click3", T, Box.whoIs(root, mousex, mousey)); + if (button == 1) new SimpleMessage("_Click1", T, root); + else if (button == 2) new SimpleMessage("_Click2", T, root); + else if (button == 3) new SimpleMessage("_Click3", T, root); if (Platform.needsAutoDoubleClick()) { long now = System.currentTimeMillis(); if (lastClickButton == button && now - lastClickTime < 350) DoubleClick(button); @@ -129,65 +127,9 @@ public abstract class Surface extends PixelBuffer implements Scheduler.Task { } } - protected final void DoubleClick(int button) { - if (button == 1) new SimpleMessage("DoubleClick1", T, Box.whoIs(root, mousex, mousey)); - else if (button == 2) new SimpleMessage("DoubleClick2", T, Box.whoIs(root, mousex, mousey)); - else if (button == 3) new SimpleMessage("DoubleClick3", T, Box.whoIs(root, mousex, mousey)); - } - - /** Send a KeyPressed message; subclasses should not add the C- or A- prefixes or should they capitalize alphabet chars */ - protected final void KeyPressed(String key) { - if (key == null) return; - if (key.toLowerCase().endsWith("shift")) shift = true; else if (shift) key = key.toUpperCase(); - if (key.toLowerCase().equals("alt")) alt = true; else if (alt) key = "A-" + key; - if (key.toLowerCase().endsWith("control")) control = true; else if (control) key = "C-" + key; - Scheduler.add(new KMessage(key)); - } - - // This is implemented as a private static class instead of an anonymous class to work around a GCJ bug - private class KMessage implements Scheduler.Task { - String key = null; - public KMessage(String k) { key = k; } - public void perform() { - if (key.equals("C-v") || key.equals("A-v")) Platform.clipboardReadEnabled = true; - outer: for(int i=0; i