Flex topLevelApplication and SuperTabNavigator mouse event handler - actionscript-3

I am using the flex SuperTabNavigator and want on closing the tab check if the control button was pressed. I tried:
public static var CONTROL_PRESSED:Boolean = false;
public function init():void {
var clickListener:Function = function _clickListener(event:MouseEvent):void{
trace(event.ctrlKey);
if(event.ctrlKey){
CONTROL_PRESSED = true;
}else{
CONTROL_PRESSED = false;
}
};
FlexGlobals.topLevelApplication.addEventListener(MouseEvent.CLICK, clickListener);
}
The problem with this is that the mouse click is called everywhere in the application except on the tab. I also tried the same code but addEventListener(MouseEvent.CLICK, clickListener); to add the listener to the SuperTabNavigator and it did not work at all. Is there another way to catch the mouse click?

This is because the SuperTabNavigator has a private mouse click handler function that hides the MouseEvent:
private function closeClickHandler(event:MouseEvent):void {
if(this.enabled) {
dispatchEvent(new Event(CLOSE_TAB_EVENT));
}
event.stopImmediatePropagation();
event.stopPropagation();
}
You'll need to modify the SuperTab class in the SuperTabNavigator source to dispatch some CustomEvent with the data you want instead of a plain new Event(CLOSE_TAB_EVENT).
Then change the onCloseTabClicked function in SuperTabBar to know about your CustomEvent. Then you can pass that to your application code (by adding it to the SuperTabEvent, perhaps).

Related

Set object's `visible` to `true` when a `tap` event is performed then set it back to `false`

I have an object as MovieClip and I have a button as Button on my flash timeline.
When the button is tapped, I want to set the object.visible to true then when the button is not tapped, I want to set it back to false.
How can I do that?
I have tried this code, but it won't works as I want. I only can show the object but cannot hide it back.
button1.addEventListener(TouchEvent.TOUCH_TAP, touchTap);
function touchTap(e:TouchEvent): void {
mcObj.visible = true;
stage.addEventListener(TouchEvent.TOUCH_END, touchEnd);
}
function touchEnd(e:TouchEvent): void {
mcObj.visible = false;
stage.removeEventListener(TouchEvent.TOUCH_END, touchEnd);
}
I think this code could work.
button1.addEventListener(TouchEvent.TOUCH_BEGIN, touchTap);
function touchTap(e:TouchEvent): void {
mcObj.visible = true;
button1.addEventListener(TouchEvent.TOUCH_END, touchEnd);
}
function touchEnd(e:TouchEvent): void {
mcObj.visible = false;
button1.removeEventListener(TouchEvent.TOUCH_END, touchEnd);
}
I changed
1: TouchEvent.TOUCH_TAP to TouchEvent.TOUCH_BEGIN
2: stage.addEventListener to button1.addEventListener
Before saying anything about your problem, let's take a look on the definitions of the TouchEvent.TOUCH_BEGIN, TouchEvent.TOUCH_END and TouchEvent.TOUCH_TAP events :
The TouchEvent.TOUCH_BEGIN is :
Dispatched when the user first contacts a touch-enabled device ...
The TouchEvent.TOUCH_END is :
Dispatched when the user removes contact with a touch-enabled device ...
The TouchEvent.TOUCH_TAP is :
Dispatched when the user lifts the point of contact over the same InteractiveObject instance on which the contact was initiated on a touch-enabled device ...
And with some tests, we can see that the TouchEvent.TOUCH_END event is, in almost cases, fired before the TouchEvent.TOUCH_TAP one (by 1 or 2 milliseconds), so we can understand the we are able to detect if the user has already removed contact with the device (TouchEvent.TOUCH_END is fired) then if that was on the same InteractiveObject object on which the contact was initiated (TouchEvent.TOUCH_TAP is fired).
And that's why your code is not working.
Now, let's see your problem : you want to show a MovieClip just when your user tap a button and hide it when he releases that button but only for a very short time (the time of a tap ~= 300 milliseconds).
In this case, I recommend you to use a TouchEvent.TOUCH_BEGIN event listener with a timeout to hide that object even if your user didn't release the button.
For that, take this example :
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
btn.addEventListener(TouchEvent.TOUCH_BEGIN, on_touchBegin);
function on_touchBegin(e:TouchEvent): void
{
obj.visible = true;
hide_obj();
}
function hide_obj(): void
{
// you can use a Timer object instead of setTimeout()
var timeout:int = setTimeout(function(){
clearTimeout(timeout);
obj.visible = false;
}, 300);
}
Hope that can help.

Missing Event type MouseUp

In the following scenario a Event from type MouseUp is missing.
The base to reproduce is this code (using rap 3.0)
#Override
protected void createContents(Composite parent) {
GridLayout gl = new GridLayout(1, false);
parent.setLayout(gl);
GridData gd = new GridData(SWT.FILL, SWT.TOP, true, false);
Composite above = new Composite(parent, SWT.BORDER);
above.setLayout(gl);
above.setLayoutData(gd);
Button buttonAbove = new Button(above, SWT.TOGGLE);
buttonAbove.setText("above");
Button button = new Button(parent, SWT.TOGGLE);
button.setText("start");
addListener(button);
Composite bottom = new Composite(parent, SWT.BORDER);
bottom.setLayout(gl);
bottom.setLayoutData(gd);
Button buttonBottom = new Button(bottom, SWT.TOGGLE);
buttonBottom.setText("bottom");
}
private void addListener(Button button) {
Listener listener = new Listener() {
#Override
public void handleEvent(Event event) {
switch (event.type) {
case SWT.MouseDown:
System.out.println("MouseDown");
break;
case SWT.MouseUp:
System.out.println("MouseUp");
break;
}
}
};
button.addListener(SWT.MouseDown, listener);
button.addListener(SWT.MouseUp, listener);
}
go with the cursor over the button start
press the mouse button and keep it pressed
drag the cursor to the right, over the button bottom or to the composite buttom and release the MouseButton --> the Event from type SWT.MouseUp is fired
go with the cursor over the button start again
press the mouse button and keep it pressed
drag the cursor over the button above or over the composite above and release the mouse button --> the Event is not fired
I found this problem in a more complex way while doing drag'n'drop of a Button and this seem to be the root of the problem.
In a SWT Application a MouseUp Event is always thrown.
Is this a bug in RAP?

Flash Senocular Transform Tool - controls are not showing on the tool

I am having trouble with the controls showing up for my transform tool. When I click my image I get the bounding box (to scale or rotate the image), but when I hover over the corner I do not get the cursor to transform it.
I am using these files:
TransformTool.as
TransformToolControl.as
TransformToolCursor.as
This is my code to call the transform tool:
var tool:TransformTool = new TransformTool();
addChild(tool);
And this later on to make the tool show up when the image is clicked and make the tool disappear when the stage is clicked:
tmpImage.addEventListener(MouseEvent.CLICK, select);
function select(e:MouseEvent):void {
tool.target = e.currentTarget as Sprite;
stage.addEventListener(MouseEvent.MOUSE_DOWN, deselect);
}
function deselect(e:MouseEvent):void {
tool.target = null;
tmpImage.addEventListener(MouseEvent.CLICK, select);
}
My image selection for the bounding box to appear and disappear work perfectly. All my code works as expected.... except the actual controls on the bounding box. Please help!
Edit
The concept is the user can click an image from a menu and drag a new instance of that image to the stage. Then the user can click the new instance and should be able to rotate or scale it. Then they can click off the image to make the bounding box disappear. (They can add as many images to the stage that they want).
Here is some code that shows the basic click, create new instance, and drag process I have implemented.
//sb1 is the menu area that contains a group of images
//hill is one of the images the user can add to the stage
sb1.hill.addEventListener(MouseEvent.MOUSE_DOWN, createCopy);
var i:int=0;
var tmpImage:Sprite; //to store which image is being dragged currently
function createCopy(e:MouseEvent):void {
tmpImage = new Hill_mc();
tmpImage.name = "hillChild"+(i++); //increment every copy
container.addChild(tmpImage);
tmpImage.x = mouseX-470;
tmpImage.y = mouseY-270;
tmpImage.startDrag();
tmpImage.addEventListener(MouseEvent.MOUSE_DOWN, onDown); //add the mouse down to this new object
stage.addEventListener(MouseEvent.MOUSE_UP, onUp); //since the mouse is currently down, we need to listen for mouse up to tell the current copy to stop dragging
}
//this will be called when click a copy
function onDown(e:MouseEvent):void {
tmpImage = Sprite(e.currentTarget); //get a reference to the one that was clicked, so we know which object to stop dragging on the global mouse up.
container.addEventListener(MouseEvent.MOUSE_UP, onUp); //listen for the mouse up
tmpImage.startDrag();
}
function onUp(e:MouseEvent):void {
container.removeEventListener(MouseEvent.MOUSE_UP,onUp);
if (tmpImage.hitTestObject(thesubmenu1)) {
container.removeChild(tmpImage);
}
else {
tmpImage.stopDrag();
}
tmpImage.addEventListener(MouseEvent.CLICK, select);
}
function select(e:MouseEvent):void {
tool.target = e.currentTarget as Sprite;
tmpImage.addEventListener(MouseEvent.MOUSE_DOWN, deselect);
}
function deselect(e:MouseEvent):void {
tool.target = null;
tmpImage.addEventListener(MouseEvent.CLICK, select);
}
EDIT
I found this code and placed it in my TransformTool.as. I feel like it's so close and that there must be something called incorrectly because I get an error for a null object reference:
public function select(event:Event):void {
// the selected object will either be the
// event target or current target. The current
// target is checked first followed by target.
// The parent of the target must match the
// parent of the tool to be selected this way.
if (event.currentTarget != this
&& event.currentTarget.parent == parent){
setTarget(event.currentTarget as DisplayObject, event);
}else if (event.target != this
&& event.target.parent == parent){
setTarget(event.target as DisplayObject, event);
}
}
/**
* Helper selection handler for deselecting target objects. Set this
* handler as the listener for an event that would cause the
* deselection of a target object.
* It is not required that you use this event handler. It is only a
* helper function that can optionally be used to help ease
* development.
*/
public function deselect(event:Event):void {
if (_target != null && event.eventPhase == EventPhase.AT_TARGET){
setTarget(null, null);
}
}
You give too little information to determine what exactly is wrong.
However, there is a very good sample code that does exactly what you want here :
http://www.senocular.com/demo/TransformToolAS3/TransformTool.html
(Click on the link at the bottom of the image.)
I am sure that you are going to make it with this.
EDIT :
Try to use the built-in handlers. I would do something like this :
Instead of this :
tmpImage.addEventListener(MouseEvent.CLICK, select);
function select(e:MouseEvent):void {
tool.target = e.currentTarget as Sprite;
stage.addEventListener(MouseEvent.MOUSE_DOWN, deselect);
}
function deselect(e:MouseEvent):void {
tool.target = null;
tmpImage.addEventListener(MouseEvent.CLICK, select);
}
Do this :
tmpImage.addEventListener(MouseEvent.MOUSE_DOWN, tool.select);
stage.addEventListener(MouseEvent.MOUSE_DOWN, tool.deselect);
EDIT :
If you do not have the handlers, I am not sure :) but I would recommand removing event listeners in each method as they might be interfering with each other.
tmpImage.addEventListener(MouseEvent.CLICK, select);
function select(e:MouseEvent):void {
tmpImage.removeEventListener(MouseEvent.CLICK, select);
tool.target = e.currentTarget as Sprite;
stage.addEventListener(MouseEvent.MOUSE_DOWN, deselect);
}
function deselect(e:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_DOWN, deselect);
tool.target = null;
tmpImage.addEventListener(MouseEvent.CLICK, select);
}

Actionscript 3: Listeners not working after child is removed, then added again

I have some code that adds a "back" button to the stage that has its own code, and clicking it removes the button and brings users back to a title screen. However, when the "back" button is reintroduced to the stage, none of its listeners work.
public class BACK extends SimpleButton {
public function BACK() {
// constructor code
trace('back button on stage');
addEventListener(Event.ADDED_TO_STAGE, startUp);
}
function startUp(ev:Event): void{
addEventListener(MouseEvent.CLICK, gotoTitle);
addEventListener(Event.REMOVED_FROM_STAGE, backBtnCleanUp);
}
function gotoTitle(ev:MouseEvent): void{
trace('gototitle called');
MovieClip(root).gotoTitle();
}
function backBtnCleanUp(ev:Event): void{
trace('back button cleanup called');
removeEventListener(Event.ADDED_TO_STAGE, startUp);
removeEventListener(MouseEvent.CLICK, gotoTitle);
removeEventListener(Event.REMOVED_FROM_STAGE, backBtnCleanUp);
}
}
the trace function executes when it is first added to the stage, but not when it is added again after being removed. This is the code (from Main) that both adds and removes it.
function gotoHelp(): void{ // transitions to the help screen
cleanTitle();
addChild(helpBG);
addChild(backBtn);
backBtn.x = 550;
backBtn.y = 200;
}
function gotoTitle(): void{ //goes to the title screen
trace('going to title');
removeChild(backBtn);
removeChild(helpBG);
titleStartUp();
}
You should create a new instance of your BACK button every time you need to show it, or remove this line from backBtnCleanUp function : ( not tested )
removeEventListener(Event.ADDED_TO_STAGE, startUp);

Click event outside MovieClip in AS3

Is there any way to detect if the user click outside a MovieClip?
For instance, I need to detect it to close a previously opened menu (like Menu bar style: File, Edition, Tools, Help, etc).
How can I detect this kind of event? Thanks!
Add a listener to stage and check if stage is the target of the event.
Example of code here:
http://wonderfl.net/c/eFao
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
public class FlashTest extends Sprite
{
private var _menu : Sprite;
public function FlashTest()
{
_menu = new Sprite();
_menu.x = 100;
_menu.y = 100;
_menu.alpha = 0.5;
with(_menu.graphics)
{
beginFill(0xFF0000, 1);
drawRect(0, 0, 300, 300);
endFill();
}
addChild(_menu);
_menu.addEventListener(MouseEvent.CLICK, onClickHandler);
stage.addEventListener(MouseEvent.CLICK, onClickHandler);
}
private function onClickHandler(event : MouseEvent) : void
{
switch(event.target)
{
case _menu:
_menu.alpha = 0.5;
break;
case stage:
_menu.alpha = 1;
break;
}
}
}
}
You can add a listener to the click event of the root element:
MovieClip(root).addEventListener(MouseEvent.CLICK, clickObject);
then in the function clickObject, you can check to see what you are clicking.
function clickObject(e:Event):void
{
var hoverArray:Array = MovieClip(root).getObjectsUnderPoint(new Point(stage.mouseX, stage.mouseY));
var hoverOverObject:* = hoverArray[hoverArray.length - 1];
}
hoverOverObject references the element that you are clicking on. Often this will be the shape within the movie clip, so you'll need to look at it's parent then compare it to your movie clip. If the click wasn't on the drop down movie clip, trigger the close.
var container:MovieClip = new MovieClip();
var mc:MovieClip = new MovieClip();
with(mc.graphics){
beginFill(0xff0000,1);
drawCircle(0,0,30);
endFill();
}
mc.name = "my_mc";
container.addChild(mc);
addChild(container);
stage.addEventListener(MouseEvent.CLICK, action);
function action (e:MouseEvent):void
{
if(e.target.name != "my_mc"){
if(container.numChildren != 0)
{
container.removeChild(container.getChildByName("my_mc"));
}
}
}
Use capture phase:
button.addEventListener(MouseEvent.CLICK, button_mouseClickHandler);
button.stage.addEventListener(MouseEvent.CLICK, stage_mouseClickHandler, true);
//...
private function button_mouseClickHandler(event:MouseEvent):void
{
trace("Button CLICK");
}
private function stage_mouseClickHandler(event:MouseEvent):void
{
if (event.target == button)
return;
trace("Button CLICK_OUTSIDE");
}
Note that using stopPropagation() is good for one object, but failed for several. This approach works good for me.
Use a stage and a sprite (menu) click listener with the sprite listener executing first and apply the stopPropagation() method to the click handler of the sprite. Like this:
menu.addEventListener(MouseEvent.CLICK, handleMenuClick);
stage.addEventListener(MouseEvent.CLICK, handleStageClick);
private function handleMenuClick(e:MouseEvent):void{
// stop the event from propagating up to the stage
// so handleStageClick is never executed.
e.stopPropagation();
// note that stopPropagation() still allows the event
// to propagate to all children so if there are children
// within the menu overlay that need to respond to click
// events that still works.
}
private function handleStageClick(e:MouseEvent):void{
// put hide or destroy code here
}
The idea is that a mouse click anywhere creates a single MouseEvent.CLICK event that bubbles from the stage, down through all children to the target, then back up through the parents of the target to the stage. Here we interrupt this cycle when the target is the menu overlay by not allowing the event to propagate back up to the parent stage, ensuring that the handleStageClick() method is never invoked. The nice thing about this approach is that it is completely general. The stage can have many children underneath the overlay and the overlay can have its own children that can respond to clicks and it all works.