[Laszlo-checkins] r13292 - openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9
bargull@openlaszlo.org
bargull at openlaszlo.org
Sat Mar 14 19:03:20 PDT 2009
Author: bargull
Date: 2009-03-14 19:03:16 -0700 (Sat, 14 Mar 2009)
New Revision: 13292
Modified:
openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzInputTextSprite.as
openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzMouseKernel.as
openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzSprite.as
openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzTextSprite.as
Log:
Change 20090314-bargull-PHi by bargull at dell--p4--2-53 on 2009-03-14 13:44:14
in /home/Admin/src/svn/openlaszlo/trunk
for http://svn.openlaszlo.org/openlaszlo/trunk
Summary: swf9 textlinks patch
New Features:
Bugs Fixed: LPP-7551 (several text-link issues)
Technical Reviewer: hminsky, max
QA Reviewer: promanik
Doc Reviewer: (pending)
Documentation:
Release Notes:
Details:
Most things should be working now, but the current approach has got a few limitations, see testcases in LPP-7551.tar (attached at bugreport).
This is the plan:
Make TextFields mouseEnabled by default and whenever a MouseEvent occurs (and the TextSprite is neither clickable nor selectable) determine the next object under the mouse cursor and forward the mouse-event to that object. (mouseEnabled=true is necessary for text-links to be working.)
Tests:
testcases at bugreport
Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzInputTextSprite.as
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzInputTextSprite.as 2009-03-15 01:44:05 UTC (rev 13291)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzInputTextSprite.as 2009-03-15 02:03:16 UTC (rev 13292)
@@ -41,7 +41,6 @@
} else {
textfield.type = TextFieldType.DYNAMIC;
}
- textfield.mouseEnabled = false;
/*
TODO [hqm 2008-01]
Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzMouseKernel.as
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzMouseKernel.as 2009-03-15 01:44:05 UTC (rev 13291)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzMouseKernel.as 2009-03-15 02:03:16 UTC (rev 13292)
@@ -116,6 +116,11 @@
}
return __builtinCursors;
}
+
+ static function get hasGlobalCursor () :Boolean {
+ var gcursor:String = globalCursorResource;
+ return ! (gcursor == null || (gcursor == MouseCursor.AUTO && useBuiltinCursor));
+ }
}#
/**
Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzSprite.as
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzSprite.as 2009-03-15 01:44:05 UTC (rev 13291)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzSprite.as 2009-03-15 02:03:16 UTC (rev 13292)
@@ -41,6 +41,7 @@
import flash.media.ID3Info;
import flash.net.URLRequest;
import flash.system.LoaderContext;
+ import flash.text.TextField;
}#
#passthrough {
@@ -697,6 +698,18 @@
}
} else if (eventname == 'onmouseupoutside') {
this.__mousedown = false;
+ } else if (eventname == 'onmouseout' || eventname == 'onmouseover') {
+ var relObj:InteractiveObject = e.relatedObject;
+ if (relObj is TextField && relObj.parent is LzTextSprite) {
+ var lztext:LzTextSprite = LzTextSprite(relObj.parent);
+ if (lztext.forwardsMouse) {
+ var nextMouse:DisplayObject = lztext.getNextMouseObject(e);
+ if (nextMouse === this) {
+ // don't report onmouseover/out events if object didn't change
+ skipevent = true;
+ }
+ }
+ }
}
// cancel mouse event bubbling...
@@ -1397,7 +1410,8 @@
// background is required for:
// - LPP-7842 (SWF9: context-menu not shown for view without bgcolor/content)
// - LPP-7864 (SWF: cachebitmap interferes with mouse-events)
- return this.__contextmenu != null || (this.clickable && this.cacheAsBitmap);
+ // - LPP-7551 (several text-link issues)
+ return this.__contextmenu != null || this.clickable;
}
function updateBackground () :void {
Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzTextSprite.as
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzTextSprite.as 2009-03-15 01:44:05 UTC (rev 13291)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzTextSprite.as 2009-03-15 02:03:16 UTC (rev 13292)
@@ -10,16 +10,24 @@
*/
public class LzTextSprite extends LzSprite {
#passthrough (toplevel:true) {
+ import flash.display.Bitmap;
import flash.display.DisplayObject;
+ import flash.display.DisplayObjectContainer;
+ import flash.display.InteractiveObject;
+ import flash.display.SimpleButton;
+ import flash.display.Sprite;
+ import flash.display.Stage;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TextEvent;
+ import flash.geom.Point;
import flash.net.URLRequest;
import flash.text.AntiAliasType;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.text.TextLineMetrics;
+ import flash.ui.MouseCursor;
}#
#passthrough {
@@ -73,23 +81,220 @@
public function LzTextSprite (newowner:LzView = null, args:Object = null) {
super(newowner,false);
// owner:*, isroot:Boolean
- this.textfield = createTextField(0,0,400,20);
+ var tfield:TextField = this.textfield = createTextField(0,0,400,20);
+ tfield.addEventListener(TextEvent.LINK, textLinkHandler);
+ tfield.addEventListener(MouseEvent.CLICK, handleTextfieldMouse);
+ tfield.addEventListener(MouseEvent.DOUBLE_CLICK, handleTextfieldMouse);
+ tfield.addEventListener(MouseEvent.MOUSE_DOWN, handleTextfieldMouse);
+ tfield.addEventListener(MouseEvent.MOUSE_UP, handleTextfieldMouse);
+ tfield.addEventListener(MouseEvent.MOUSE_OVER, handleTextfieldMouse);
+ tfield.addEventListener(MouseEvent.MOUSE_OUT, handleTextfieldMouse);
+ }
+
+ private var _ignoreclick:Boolean = false;
+ private var _usecursor:Boolean = true;
+ private var _lastobject:DisplayObject = null;
+
+ private function handleTextfieldMouse (e:MouseEvent) :void {
+ // FIXME: changes to clickable or selectable while cursor
+ // is over text may break mouse-events
+ var type:String = e.type;
+ if (type == MouseEvent.MOUSE_UP && this._ignoreclick) {
+ // first MOUSE_UP ...
+ e.stopPropagation();
+ } else if (type == MouseEvent.CLICK && this._ignoreclick) {
+ // ... then CLICK, now clear flag
+ // FIXME: click-event may not be dispatched
+ // (e.g. if textfield is made invisible after onmousedown)
+ this._ignoreclick = false;
+ e.stopPropagation();
+ } else if (this.clickable) {
+ // clickable -> handle mouse-event
+ if (type == MouseEvent.DOUBLE_CLICK) {
+ this.handleMouse_DOUBLE_CLICK(e);
+ } else {
+ this.__mouseEvent(e);
+ }
+ } else if (this.textfield.selectable) {
+ // ignore mouse-event for swf8 compatibility
+ this.__ignoreMouseEvent(e);
+ } else {
+ // forward mouse-event to next sprite
+ this.__forwardMouseEventToSprite(e);
}
- override public function setClickable( c:Boolean ):void {
- if (this.clickable == c) return;
+ if (type == MouseEvent.MOUSE_OUT) {
+ if (this._usecursor) {
+ // TODO: restore also necessary for other events?
+ LzMouseKernel.restoreCursorLocal();
+ this._usecursor = false;
+ }
+ // clear _lastobject
+ this._lastobject = null;
+ }
+ }
- this.textfield.mouseEnabled = c || this.textfield.selectable;
- this.setCancelBubbling();
+ private function __ignoreMouseEvent (e:MouseEvent) :void {
+ if (e.type != MouseEvent.MOUSE_UP || LzMouseKernel.__lastMouseDown === this) {
+ // don't cancel "onmouseup" if another sprite was selected
+ e.stopPropagation();
+ }
+ }
- this.clickable = c;
- if (c) {
- attachMouseEvents(this.textfield);
+ private function __forwardMouseEventToSprite (e:MouseEvent) :void {
+ // find next object, default to last one
+ var obj:DisplayObject = this.getNextMouseObject(e) || this._lastobject;
+ if (obj != null) {
+ this._lastobject = obj;
+ if (obj is InteractiveObject) {
+ var type:String = e.type;
+ var forward:Boolean = true;
+ if (type == MouseEvent.MOUSE_OVER || type == MouseEvent.MOUSE_OUT) {
+ // don't report onmouseover/out events if object didn't change
+ var relObj:InteractiveObject = e.relatedObject;
+ if (relObj is TextField && relObj.parent is LzTextSprite) {
+ // not again a textfield!
+ var lztext:LzTextSprite = LzTextSprite(relObj.parent);
+ if (lztext.forwardsMouse) {
+ relObj = lztext.getNextMouseObject(e) as InteractiveObject;
+ }
+ }
+ if (relObj === obj) {
+ forward = false;
+ } else if (relObj is SimpleButton) {
+ var p:DisplayObjectContainer = relObj.parent;
+ if (p is LzSprite && p === obj) {
+ forward = false;
+ }
+ }
+ }
+
+ // display hand-cursor or custom cursor
+ if (type == MouseEvent.MOUSE_OVER) {
+ var cursor:String = null;
+ if (obj is Sprite) {
+ var sprite:Sprite = Sprite(obj);
+ if (sprite.buttonMode && sprite.useHandCursor) {
+ // need to respect global cursor setting
+ if (! LzMouseKernel.hasGlobalCursor) {
+ cursor = MouseCursor.BUTTON;
+ }
+ }
+ if (sprite is LzSprite) {
+ var lzsprite:LzSprite = LzSprite(sprite);
+ if (lzsprite.cursorResource != null) {
+ cursor = lzsprite.cursorResource;
+ }
+ }
+ }
+ if (cursor != null) {
+ this._usecursor = true;
+ LzMouseKernel.setCursorLocal(cursor);
+ }
+ }
+
+ e.stopPropagation();
+ if (forward) {
+ obj.dispatchEvent(e);
+ }
} else {
- removeMouseEvents(this.textfield);
+ // TODO: what else can this be? needs more testing!
+ // Debug.debug("%s: not InteractiveObject = %w (%w)", e.type, obj, this.owner);
+ e.stopPropagation();
+ obj.dispatchEvent(e);
+ }
+ } else {
+ // TODO: when is this possible?
+ // Debug.warn("%s: no forwarding possible (%w)", e.type, this.owner);
}
}
+ function get forwardsMouse () :Boolean {
+ return ! (this.clickable || this.textfield.selectable);
+ }
+
+ private static const ZERO_POINT:Point = new Point(0, 0);
+
+ function getNextMouseObject (e:MouseEvent) :DisplayObject {
+ const FUDGE:int = 1;
+ const FUDGE_WIDTH:int = 4; // needs to be 4, flash bug?
+ var tfield:TextField = this.textfield;
+ var stage:Stage = LFCApplication.stage;
+ var x:Number = e.stageX, y:Number = e.stageY;
+ if (e.type == MouseEvent.MOUSE_OUT) {
+ if (x == -1 && y == -1) {
+ // mouse left the screen, mouse-event values are invalid (-1, -1),
+ // need to use values from stage instead
+ x = stage.mouseX, y = stage.mouseY;
+ } else {
+ // we need to determine/approximate the point the cursor
+ // was before it left the textfield
+ var zero:Point = tfield.localToGlobal(ZERO_POINT);
+ x = Math.max(zero.x + FUDGE, Math.min(x, zero.x + tfield.width - FUDGE_WIDTH));
+ y = Math.max(zero.y + FUDGE, Math.min(y, zero.y + tfield.height - FUDGE));
+ }
+ } else if (e.type == MouseEvent.MOUSE_OVER) {
+ // some mouse-over events are sent too early, in which case the mouse-cursor
+ // isn't yet over the textfield, therefore need to adjust values
+ var zero:Point = tfield.localToGlobal(ZERO_POINT);
+ x = Math.max(zero.x + FUDGE, Math.min(x, zero.x + tfield.width - FUDGE_WIDTH));
+ y = Math.max(zero.y + FUDGE, Math.min(y, zero.y + tfield.height - FUDGE));
+ }
+
+ var tindex:int = -1;
+ var objs:Array = stage.getObjectsUnderPoint(new Point(x, y));
+ for (var i:int = objs.length - 1; i >= 0; --i) {
+ var obj:DisplayObject = objs[i];
+ if (obj === tfield) {
+ tindex = i;
+ break;
+ }
+ }
+
+ if (tindex == -1) {
+ // can happen if invisible...
+ return null;
+ }
+
+ for (var i:int = tindex - 1; i >= 0; --i) {
+ var obj:DisplayObject = objs[i];
+ if (obj is Bitmap) {
+ // need to use parent for Bitmap
+ obj = obj.parent;
+ } else if (obj is TextField && obj.parent is LzTextSprite) {
+ // skip all mouse-forwarding LzTextSprites
+ if (LzTextSprite(obj.parent).forwardsMouse) {
+ continue;
+ }
+ }
+ if (obj is InteractiveObject) {
+ var iobj:InteractiveObject = InteractiveObject(obj);
+ if (iobj.mouseEnabled) {
+ if (iobj is Sprite) {
+ // need to test hitArea for Sprite
+ var hitarea:Sprite = Sprite(iobj).hitArea;
+ if (hitarea != null) {
+ if (! hitarea.hitTestPoint(x, y)) {
+ continue;
+ }
+ }
+ }
+ return iobj;
+ }
+ } else {
+ // TODO: what else can this be? needs more testing!
+ return obj;
+ }
+ }
+
+ return null;
+ }
+
+ override public function setClickable( c:Boolean ):void {
+ if (this.clickable == c) return;
+ this.clickable = c;
+ }
+
public function addScrollEventListener():void {
this.textfield.addEventListener(Event.SCROLL, __handleScrollEvent);
}
@@ -117,49 +322,10 @@
}
}
-
- // turn on/off canceling of mouse event bubbling
- private function setCancelBubbling():void {
- var dobj:DisplayObject = this.textfield;
-
- // base on the displayobject's mouseenabled property - on for selectable
- var prevent = this.textfield.mouseEnabled;
- // if clickable is on, we don't want to cancel events
- if (this.clickable) prevent = false;
-
- if (prevent) {
- dobj.addEventListener(MouseEvent.CLICK, __ignoreMouseEvent);
- dobj.addEventListener(MouseEvent.DOUBLE_CLICK, __ignoreMouseEvent);
- dobj.addEventListener(MouseEvent.MOUSE_DOWN, __ignoreMouseEvent);
- dobj.addEventListener(MouseEvent.MOUSE_UP, __ignoreMouseEvent);
- dobj.addEventListener(MouseEvent.MOUSE_OVER, __ignoreMouseEvent);
- dobj.addEventListener(MouseEvent.MOUSE_OUT, __ignoreMouseEvent);
- } else {
- dobj.removeEventListener(MouseEvent.CLICK, __ignoreMouseEvent);
- dobj.removeEventListener(MouseEvent.DOUBLE_CLICK, __ignoreMouseEvent);
- dobj.removeEventListener(MouseEvent.MOUSE_DOWN, __ignoreMouseEvent);
- dobj.removeEventListener(MouseEvent.MOUSE_UP, __ignoreMouseEvent);
- dobj.removeEventListener(MouseEvent.MOUSE_OVER, __ignoreMouseEvent);
- dobj.removeEventListener(MouseEvent.MOUSE_OUT, __ignoreMouseEvent);
- }
- }
-
- private function __ignoreMouseEvent(e:MouseEvent) :void {
- if (e.type != MouseEvent.MOUSE_UP || LzMouseKernel.__lastMouseDown == this) {
- // don't cancel "onmouseup" if another sprite was selected
- e.stopPropagation();
- }
- }
-
- public function enableClickableLinks( enabled:Boolean):void {
- if (enabled) {
- addEventListener(TextEvent.LINK, textLinkHandler);
- } else {
- removeEventListener(TextEvent.LINK, textLinkHandler);
- }
- }
-
- public function textLinkHandler(e:TextEvent) {
+ public function textLinkHandler(e:TextEvent) :void {
+ // ignore the next onclick-event for swf8-compatibility
+ // Debug.write("textLinkHandler on %w", this);
+ this._ignoreclick = true;
this.owner.ontextlink.sendEvent(e.text);
}
@@ -191,7 +357,7 @@
tfield.width = w;
tfield.height = h;
tfield.border = false;
- tfield.mouseEnabled = false;
+ tfield.mouseEnabled = true;
tfield.tabEnabled = LFCApplication.textfieldTabEnabled;
//tfield.cacheAsBitmap = true;
addChild(tfield);
@@ -457,8 +623,6 @@
*/
public function setSelectable ( isSel:Boolean ):void {
this.textfield.selectable = isSel;
- this.textfield.mouseEnabled = isSel || this.clickable;
- this.setCancelBubbling();
}
public function getTextWidth ( ):Number {
More information about the Laszlo-checkins
mailing list