Mouse events only on visible parts - actionscript-3

How can I make Flex dispatch mouse events only when I interact with visible parts of a component? In this case I want event to be dispatched only when hovering the line.
<s:Group mouseOver="trace('over')">
<s:Line xFrom="0" yFrom="0" xTo="100" yTo="100">
<s:stroke>
<s:SolidColorStroke color="0" weight="3"/>
</s:stroke>
</s:Line>
</s:Group>
I remember I had a problem some time ago in Flex 3, when I couldn't catch mouse events until I fill the canvas with transparent background. But now I have the opposite problem. Thanks for help.

You're on the right track.
As you've already done, you need to wrap the Line object in a Group, or some other container class, because the Spark graphics primitives (like Line) do not dispatch mouse events.
I assume your problem is that since your line is diagonal, the bounding box for the Group is a rectangle that is much larger than the line.
If you draw a horizontal or vertical line, the bounding box of the Group should then just be the dimensions of the Line. Then rotate the Group to get your diagonal line:
Note, I've just picked a random X value, and rotation ... The rotation has the effect of displacing the object's X/Y coordinates ... unless your using something other than the BasicLayout. So you'll have to adjust x/y/rotation (and/or the layout) to position your line at the right spot.
<s:Group mouseOver="trace('over')" rotation="45">
<s:Line x="100" yFrom="0" yTo="100">
<s:stroke>
<s:SolidColorStroke color="0" weight="3"/>
</s:stroke>
</s:Line>
</s:Group>

You can try below code: -
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
private function rollOver(event:MouseEvent):void
{
Alert.show('over');
}
private function drawLine():void
{
var g:Graphics = graphics;
graphComp.graphics.clear();
var strokeColor:Number = getStyle("strokeColor");
var shadowColor:Number = getStyle("shadowColor");
graphComp.graphics.beginFill(strokeColor);
graphComp.graphics.drawRect(0, 0, 100, 1);
graphComp.graphics.endFill();
graphComp.graphics.beginFill(shadowColor);
graphComp.graphics.drawRect(0, 1, 100, 1);
graphComp.graphics.endFill();
graphComp.rotation = 45;
}
]]>
</fx:Script>
<s:Group id="graphComp" x="100" y="100" creationComplete="drawLine()" rollOver="rollOver(event)"/>
</s:Application>

Related

Width of a group in mx:ViewStack

I have a simple application:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:local="*">
<mx:ViewStack width="100%" creationPolicy="all">
<s:NavigatorContent width="100%">
<local:TestGroup width="100%"/>
</s:NavigatorContent>
<s:NavigatorContent width="100%">
<local:TestGroup width="100%"/>
</s:NavigatorContent>
</mx:ViewStack>
</s:Application>
My TestGroup is a bare Spark group. It has creationComplete method, where the width of the group is traced:
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" creationComplete="group1_creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function group1_creationCompleteHandler(event:FlexEvent):void
{
trace("internal group width: " + this.width)
}
]]>
</fx:Script>
</s:Group>
When I run the application, the first TestGroup has width of 1600 (which is about right), but the second one regardless of creationPolicy="all" and width="100%" is 0 (zero).
It turs out that ms:ViewStack doesn't set width for components other than the selected one.
What is the logic behind this behavior?
How can I fix it so that my second group has a real width, and I can get it at the creation complete?
You can listen to change event, that will be fired each time the selected group is changing.
Only the current active group will give you her true width, so you can do someThing like this
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:local="*">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function onChange(event:Event):void
{
if(myViewStack.selectedChild){
myViewStack.selectedChild.initMyGroup();
}
}
]]>
</fx:Script>
<mx:ViewStack id="myViewStack" width="100%" creationPolicy="all" change="onChange()">
<s:NavigatorContent width="100%">
<local:TestGroup width="100%"/>
</s:NavigatorContent>
<s:NavigatorContent width="100%">
<local:TestGroup width="100%"/>
</s:NavigatorContent>
</mx:ViewStack>
</s:Application>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
public function initMyGroup():void
{
trace("internal group width: " + this.width)
}
]]>
</fx:Script>
</s:Group>
The ViewStack is a Multiple-view container. Even though having the creationComplete set to all which is by the way for Single-view containers only, Flex instantiates only the controls that are initially visible for the ViewStack. To achieve your goal, try using other containers aside from ViewStack.
More details can be found here:
http://livedocs.adobe.com/flex/3/html/help.html?content=layoutperformance_05.html
What is the logic behind this behavior?
Because there is no need to render a TestGroup element. If you set creationPlicy for all a flex container will create internal element, but it doesn't mean that the container will set size for the element.
How can I fix it so that my second group has a real width, and I can get it at the creation complete?
Use event updateComplete. Flex dispatches updateComplete events whenever the layout, position, size, or other visual characteristic of the component changes and the component is updated for display. So you will get it when second TestGroup will be selected first time.

Apply effect on window in Flex, Air, AS3

I'm looking to animate a popup window using the effect.
The problem is that the effect is applied to the content of the popup window, not the popup window itself (including the title bar, minimize, maximize buttons etc)
Have a look at the result here..
My code is really simple and logically, should work if it is possible to animate a window.
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import comps.MyWin;
[Bindable]
private var _win:MyWin;
protected function openPopup():void
{
_win = new MyWin();
_win.width = 300;
_win.height = 300;
_win.open();
}
protected function animatepopup():void
{
MyEffect.play();
}
]]>
</fx:Script>
<fx:Declarations>
<s:Move id="MyEffect" xFrom="{_win.x}" xTo="{_win.x + 150}" target="{_win}"/>
</fx:Declarations>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:Button label="Open" click="openPopup()"/>
<s:Button label="Animate" click="animatepopup()"/>
</s:WindowedApplication>
I think you need to target the object's NativeWindow instance in order to move and resize the object.
Thus, replace _win.myProperty with _win.stage.nativeWindow.myProperty:
<s:Move id="MyEffect" xFrom="{_win.stage.nativeWindow.x}" xTo="{_win.stage.nativeWindow.x + 150}" target="{_win.stage.nativeWindow}"/>
Then, the animation will affect the NativeWindow and not the internals of the window.

Spark container not hiding contents outside of its body

This is what what my screen looks like:
It is composed like this :
First container <s:HGroup>(900 X 100)--top black area
Second container <s:Group> (900 X 475)--middle white area
Third container <s:HGroup>--(900 X 100)--bottom black area
If the project were done with Flex 3, the middle area would be an <mx:Canvas>.
Now suppose I have one BorderContainer(125 X 475) and name it middleContainerChild. It is located on the right side of the middle area. When I set its y postion to -middleContainerChild.height, it should be located at y = -475, outside of the container's body. And as you can see in the image above, it has been placed there.
But other than with <mx:Canvas>, the image still shows, even though it is no longer within the <s:Group>s body, and it is rendered "on top" of the <s:HGroup>.
See the image below for more clarification:
If I use <mx:Canvas>, it is hidden away properly, but if I use a Spark container (not only a group, but any Spark container), it remains visible.
Has anyone else had this problem?
Read a bit about clipAndEnableScrolling property of GroupBase class.
Regards.
As 2DH gave me the hint, i have prepared this sample,
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="900" minHeight="672">
<fx:Declarations>
<s:Move
id="moveUp"
yFrom="0"
yTo="-475"
target="{helpWindow}"/>
<s:Move
id="moveDown"
yFrom="-475"
yTo="0"
target="{helpWindow}"/>
</fx:Declarations>
<fx:Script>
<![CDATA[
private function buttonUp_clickHandler(event:MouseEvent):void
{
moveUp.play();
}
private function buttonDown_clickHandler(event:MouseEvent):void
{
moveDown.play();
}
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout gap="0"/>
</s:layout>
<s:BorderContainer
backgroundColor="#000000"
height="100"
width="100%"/>
<s:Group
height="475"
width="100%"
clipAndEnableScrolling="true">
<s:VGroup
left="0"
top="0">
<s:Button
label="Play Effect UP"
click="buttonUp_clickHandler(event)"/>
<s:Button
label="Play Effect DOWN"
click="buttonDown_clickHandler(event)"/>
</s:VGroup>
<s:BorderContainer
id="helpWindow"
backgroundColor="#CCCCCC"
y="{-helpWindow.height}"
right="0"
height="475"
width="125"
/>
</s:Group>
<s:BorderContainer
backgroundColor="#000000"
height="100"
width="100%"/>
</s:Application>
so now i have set my center container's clipAndEnableScrolling to true, and problem solved
Thanks to both the stack members:)

Adding a border to a group in run time in flex

i am trying to make a group of spark type in flex at runtime.i am making a couple of buttons as children of this group in runtime. i want to add border to all group. however when i use border container it hides all other children and the stuff in group container and only shows the border container screen. How can i add border to group.
Note that i am adding the border container as a child of group container in run time.
best regards
You can add a s:Rect child at particular index acting as a border.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.graphics.SolidColorStroke;
import spark.primitives.Rect;
protected function addNewBorderButtonClick(event:MouseEvent):void
{
var borderRect:Rect = new Rect();
var solidStroke:SolidColorStroke = new SolidColorStroke(0, 3);
borderRect.stroke = solidStroke;
borderRect.percentWidth = borderRect.percentHeight = 100;
targetGroup.addElementAt(borderRect, 0);
}
]]>
</fx:Script>
<fx:Declarations>
</fx:Declarations>
<s:Group id="targetGroup"
width="100" height="100"
horizontalCenter="0" verticalCenter="0">
<!-- some visual elements here -->
<s:Button id="addNewBorderButton"
label="Add Border"
horizontalCenter="0" verticalCenter="0"
click="addNewBorderButtonClick(event)" />
</s:Group>
</s:Application>
Hope this helps,
Blaze

Place spark TabBar on Bottom of ViewStacks (+ rounded corners pointing downwards)

<s:VGroup horizontalAlign="center" horizontalCenter="0" verticalCenter="0" gap="0">
<mx:ViewStack id="view" width="450" height="300" />
<!-- NavigatorContent dynamically gets added to view on appComplete-->
<s:TabBar dataProvider="{view}" skinClass="skins.CustomSparkTabBarSkin" />
</s:VGroup>
The Custom Skin:
<s:Skin
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
alpha.disabled="0.5"><fx:Metadata>
<![CDATA[
[HostComponent("spark.components.TabBar")]
]]>
</fx:Metadata>
<fx:Script fb:purpose="styling" >
<![CDATA[
import mx.core.UIComponent;
/** Push the cornerRadius style to the item renderers.*/
override protected function updateDisplayList(unscaledWidth:Number, unscaleHeight:Number):void {
const numElements:int = dataGroup.numElements;
const cornerRadius:int = hostComponent.getStyle("cornerRadius");
for (var i:int = 0; i < numElements; i++) {
var elt:UIComponent = dataGroup.getElementAt(i) as UIComponent;
if (elt)
elt.setStyle("cornerRadius", cornerRadius);
}
super.updateDisplayList(unscaledWidth, unscaledHeight);
}
]]>
</fx:Script>
<s:states>
<s:State name="normal" />
<s:State name="disabled" />
</s:states>
<!--- #copy spark.components.SkinnableDataContainer#dataGroup -->
<s:DataGroup id="dataGroup" width="100%" height="100%">
Comes out to something like so: http://yozef.com/files/tabExample.png
I would like to place that TabBar at the Bottom of the viewstack, rounded corners pointing outwardly.
Starting from scratch... While in Design mode...
Click the TabBar in the Outline view, in the properties view click the drop down next to Skin and choose Create Skin... Switch to source view and find the ButtonBarButton and add rotation="180" to it... (This is almost what you want but the text will be upside down) Go back to design view (on your TabBar custom skin) and click the ButtonBarButton in the Outline view and in the properties view click the drop down next to Skin and choose Create Skin... in the Outline view find the labelDisplay and add rotation="180"
this is the fastest way I can think of to achieve what you're looking for, you might find you want to tweak other values in the custom ButtonBarButton skin if the text isn't exactly where you'd like it...