scale9grid functioning on child movieclip - actionscript-3

I'm working on a UI project that requires that the automatic resizing buttons (based on label length) have a focus indicator graphic for keyboard or controller focus. This graphic must obviously scale with the parent as you would imagine.
This causes a problem; the parent clip is 9sliced, and that slicing doesn't fall through to the child Sprites/MovieClips of this clip. The focus indicator needs to be an accessible property because it has to be capable of being turned on or off.
Currently the only solution I can image is an extremely programmatical reimplementation of scale9Grid where I split the focus indicator into 9 and alter the 9 parts' properties any time the parent width/height/scaleX/scaleY is changed. This would also mean turning all 9 parts on and off when that button is focused
Is there any better way than that?

I recommend you create some wrapper class AppButton (or may be you already have one since you have some resizing by label functionality) with method setSkin(skin:MovieClip) (where skin is your MovieClip from the library) and overridden setters for width and height, so you can implement here skin resizing logic in method arrange() that called each time width or height are changed.
Skin can be complex - with other movie clips in children (focus border in your case), so don't use scale9Grid for the hole skin, but set sizes directly to the children with set scale9grid them as well, so your arrange method can be like that:
private function arrange():void
{
var child:DisplayObject;
for(var i:int = 0; i < numChildren; i++)
{
child = getChildAt(i);
child.width = width;
child.height = height;
}
}
It's also worth to make one skin format for button skins in project, so you can use one wrapper for all buttons.
Later you can add more features to this AppButton - switching view states on mouse events, setting text label, animating skins and so.
This approach work for me for many years, we have base ToggleButton and LabelButton extends ToggleButton classes, and extends them in every project with custom skin parsing and arranging.

Related

Handling Editable Objects

Here's the scenario.
A user selects an image, video, or other type of display object. It gets loaded inside a custom class known as EditableObject. The goal of EditableObject is re-sizing and re-positioning. EditableObject has 4 movieclips.
center_mc : Handles drag and drop and contains the display object.
rightside_mc : Handles re-sizing of width on mousedown
bottomside_mc : Handles re-sizing of height on mousedown
bottomright_mc : Handles scaling of object on mousedown
So far I can scale all parts of these objects. The bugs are what's causing trouble.
When I click down on the bottom or right side of the display object, the display object increases size from whichever side it's handling before I move the mouse. I get the amount to move based on the difference of the stageX and stageY positions of the mouse passed on MOUSE_DOWN and at the end of every MOUSE_MOVE. This isn't a problem, it just looks bad and currently solves the second bug..
When I handle bottomright_mc, I can only scale the object down. When trying to scale out, I have to position the mouse outside of EditableObject to get a difference greater than bottomright_mc's current position. This doesn't work because any attempts to exit the bounds of EditableObject trigger MOUSE_UP, even if I add the event listener using this.parent..
I want to be able to re-position and scale anything inside EditableObject using two sides and one corner of EditableObject when a mouse is held down and moved. Currently I can only move the object, scale the object less than its current size, and use the two sides to adjust the objects width and height but without having the mouse match the position of the side it's currently handling on initialization.
Here's an excerpt for the MOUSE_MOVE handler.
private function handleMouseMove(e:MouseEvent):void
{
switch(dragType)
{
case "right":
trace("Right triggered.");
this.width = e.stageX - this.x;
break;
case "bottom":
trace("Bottom triggered");
this.height = e.stageY - this.y;
break;
case "bottomright":
resizeMe(this, e.stageX - this.x, this.height);
break;
}
prevMouseX = e.stageX;
prevMouseY = e.stageY;
}
The full code for the class can be found here on pastebin.
Here's Editable Object in Adobe Flash CC
Here's EditableObject currently containing and handling an image inside the editor.
Based on this answer on stackoverflow provided by TOMATO in the comments, I found a great API that easily lets you handle DisplayObjects with just a few lines of code.
The one I have chosen is senocular's transform tool. A demonstration of his work can be found here. Broken down, this is how to use it.
//Constructor
var editTool:TransformTool = new TransformTool();
//Add to stage (This will not be visible until you give your TransformTool a target)
addChild(editTool);
desiredDisplayObject.addEventListener(MouseEvent.CLICK, handleMouseClick)
function handleMouseClick(e:MouseEvent):void
{
//Set the object clicked as the target for the TransformTool
editTool.target = e.target as Sprite;
//Swap the positioning in the display list so the TransformTool appears in front
editTool.parent.setChildIndex(editTool, editTool.parent.numChildren - 1);
}
You can do this a number of ways, but the basics of it is to simply add the transform tool to the stage and assign whatever display object you would like to the TransformTool.

AS3: Who should I layout first the parent or the children?

I am building large application in Starling and one of my main problems is who should I layout first: the parent or the children?
What is the default behavior in starling and also in flash:
By default Sprite will get his size based on his children after they have been added to stage.
What if I want to layout the children based on the parent? For example: What if I want to set one of the children to be at position of 20 pixels from the bottom, like bottom menu?
In this case I should:
Add the children
Determine their sizes. If you are building your application cross platform, you need to support many screens, and many times you come to have complicate logic for calculating the scale percentage of your components, which is their size.
Determine your size and layout yourself.
now the bottom menu could be layout at 20 pixels from the bottom. Also it doesn't matter if you place this logic inside the bottom menu or it's parent.
But this not always the case, sometimes you want to layout the parent based on his children. A common example if one of the children is the parent background. In this case you should:
Add the background.
Determinate background size and layout it.
Now you can layout the parent.
But what if I got both of the cases? If one of parent children is background and the other is bottom menu? What if the bottom menu got his own background and other children that need to be layouted base on the parent?
What solution can be used so I will not get lost inside all of this, and can Gazman SDK help here?
What you need is to create layout dependencies between all the components. Each Sprite should have an event that tells us when its layouting is complete.
Now if you have some layouting logic inside the parent that cannot start until its background child is complete layouting, you should create a dependency between the background and the parent. The parent should listen to LayoutComplete event from the background and then he can layout himself, and when he complete layouting he can dispatch LayoutComplete event, and now its child bottom menu can layout himself.
You can implement it yourself or use Gazman-SDK that do exactly that. If you choose Gazman-SDK your code will look like this:
public class ParentClass extends Group
{
private var background:Background = new Background();
private var bottomMenu:BottomMenu = new BottomMenu();
override protected function initialize():void
{
// check if not already added to stage
if(!background.parent){
addChild(background);
addChild(bottomMenu);
}
// Create dependency for background. If background have not
// been initialized yet the subscription will succeed
// And this.initialize() will be called again once
// background initialize is complete
if (subscribeForInitilize(background)){
return;
}
// do layouting logic here
}
}
public class BottomMenu extends Group
{
override protected function initialize():void
{
// Create dependency for parent. If parent have not
// been initialized yet the subscription will succeed
// And this.initialize() will be called again once
// parent initialize is complete
if (subscribeForInitilize(parent as Group)){
return;
}
// do layouting logic here
}
}

Can I create an overlay layer to disable all touches, even on menus?

I need to show a popup layer on a scene, creating a semi-transparent background layer that will also prevent touch events propagation. I am using the latest cocos2d-x v. 3.0-alpha-0.
What I want to achieve is a popup layer that fully handles touches (eg. buttons, menu items, scroll views, etc.), laying on a background layer (for design purposes), that covers the current scene. All items in the scene should not respond to touches any more.
Is this achievable using the new EventDispatcher class? I've been able to disable all touches to the main scene, but all instances of MenuItem that live in the scene are still touchable and active.
How can I achieve this? And, also, how can I create a touch listener that prevents all touches to the main scene but not to the popup?
You can disable menu items by setting setDisable property of menuitems to false.
Example
_menuItem->setEnabled(false);
For Layers use setTouchEnabled property
_backGroungLayer->setTouchEnabled(false);
Make sure that popup layer is not child of layer you want to disable.
To disable all items in menus do this
Suppose _menu contain various menuitems.
CCARRAY_FOREACH(_menu->getChildren(), item)
{
item.isEnabled=NO;
}
if you want to disable selected items just give them tags.There is no need to make any list.
I had the same problem and solved it with mm. It was dirty, but it worked:
Create a button using ccui.button.
Set the button size to your screen size.
Add this button as a background to your popup layer.
This will prevent any thing behind it being clicked.
By default, all CCMenu's have a set priority (kCCMenuHandlerPriority = -128) in cocos2d 2.1. So in a class (usually a CCNode descendant) that wants to swallow everything and preempt anything i do like in this dialog sequencer example below :
- (void)onEnter {
backdrop_.visible = self.isBackDropShown;
MPLOG(#"Adding self as a swallower touch delegate, above the rest of the planet.");
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:_dialogTouchPriority swallowsTouches:YES];
for (CCMenu *mn in _menus) {
mn.touchPriotity = _dialogTouchPriority -1 ;
}
[super onEnter];
}
where _dialogTouchPriority is kCCMenuHandlerPriority-1 by default. It will be served before everything 'below'. It is a bad hack (cocos2d internals could be changed and break this), i know , but bullet proof. Use carefully, make certain you only ever have one of these in your scene.

addChild(Button) in AS3

I am writing a class that extends mx.core.UIComponent. In the constructor of this class, I would like to add a Button (spark.components.Button). However, creating a new Button object (such as var b:Button = new Button();) and then doing this.addChild(b) doesn't work -- no button is appearing. Is there any reason why a Button object can't be added as a child?
Edit: Just to add, when I print out the children, it says that the Button object is a child, but the Button doesn't show up.
You need to add the button in the createChildren method not in the constructor.
protected var button:Button;
override protected function createChildren():void {
super.createChildren();
button = new Button();
addChild(button);
}
Depending on what you are trying to do you may also need to implement the measure and updateDisplayList methods.
Using UIComponent directly, you aren't getting the layout of the child handled for you; you would need to set the position and size of your child components manually (see docs).
Consider using a Group (or Canvas, if you're still on MX components) to handle child layout. You can still add rendering in updateDisplayList, just make sure you call super.updateDisplayList() as well.
You need to read up on the differences between ActionScript components and Flex components. When using a Flex component, you must use container.addElement( element ), not container.addChild( child ). As far as I am aware, the only classes with this functionality descend from Group (at least in the Spark framework, the one I am most familiar with). So extending UIComponent will not allow you to add a Button, although a UIComponent can be added to a Flex container (which I do not believe a normal Sprite can do)

Animating child elements in Flex 4

Anyone know how to animate the size/position of child elements of a layout in Flex 4 ?
Example:
I have a list component with a custom layout. I want when I change the positions of the child elements I want them to animate their move to the new positions.
There is currently no built in way, nor plans, to make animated layouts in Flex 4 :/.
What I've done to make this happen is to animate the setting of "setLayoutBoundsPosition" and "setLayoutBoundsSize" in the layout. So instead of creating a "Move" and "Resize" effect for each item in the layout, which would actually set the width and height explicitly, set the matrix. Then make sure the layout isn't invalidated again (which will happen if you set the width/height directly), or you might start getting an infinite loop. You might have to do some tricks to get this to work right (I haven't got it to work quite right with the Spark Effects, but it's really easy to do with Tweener/Tweenmax, since they have plugins and such to use "setActualSize" or "setLayoutBoundsSize", etc.).
I use TweenMax to animate layouts, and they have a few plugins to make this easy. TweenMax visibly looks like 3x faster (20 fps vs 7fps) than Spark Effects, too, so I'd go with that. It looks something like this, in the updateDisplayList method of your layout.
TweenMax.to(child, duration, {setLayoutBoundsPosition:{x:childX * i, y:childY * i}});
Just like you would normally...
public override function updateDisplayList(width:Number, height:Number) : void {
for (var i:uint = 0; i < target.numElements; i++)
{
var resizeElement:Resize = new Resize(target.getElementAt(i) as IVisualElement);
resizeElement.widthTo = 500;
resizeElement.play();
}
}