Flex container transform matrix problems - apache-flex

I have a Box container that has a label element inside it. When the box is transformed using a Matrix the label element is not visible anymore. How do I make the elements visible?
<mx:Script>
<![CDATA[
private function onBoxClick(event:MouseEvent):void
{
var transformMatrix:Matrix = this.box.transform.matrix;
transformMatrix.c = Math.PI * 2 * -15 / 360;;
this.box.transform.matrix = transformMatrix;
}
]]>
</mx:Script>
<mx:HBox id="box"
x="100" y="100"
width="100" height="100"
backgroundColor="0x000000"
click="onBoxClick(event)">
<mx:Label id="textLabel" text="This is a test" color="#FFFFFF" visible="true"/>
</mx:HBox>

I'm guessing the TextField inside the Label component doesn't have the font embedded. If you plan to use .rotation or .alpha on a dynamic text you must embed the font.
You can easily test this with a regular TextField:
var t:TextField = new TextField();
t.defaultTextFormat = new TextFormat('Verdana',12,0x000000);
t.embedFonts = true;
t.rotation = 10;
t.text = 'rotated';
addChild(t);
That is assuming you have the Verdana font embedded in this example. If you comment out the 3rd line you will see the text disappear.

Related

How to add an icon to an AdvancedDataGrid column header and keep word wrap feature for the text

As stated, I'm trying to obtain column headers consisting of an icon and wrappable text in a flex AdvancedDataGrid.
(EDIT: I forgot to mention an important part of the context: the columns are added dynamically, in actionscript. This apparently changes the behavior.)
I've tried using a custom mxml headerRenderer, like so:
<mx:headerRenderer>
<fx:Component>
<mx:HBox width="100%"
height="100%"
verticalAlign="middle">
<mx:Image source="<image_url>"
width="10%"
height="100%"/>
<mx:Text text="{data.headerText}"
width="90%"
height="100%"/>
</mx:HBox>
</fx:Component>
</mx:headerRenderer>
but for some reason, the text here is truncated instead of wrapped (it works outside of a renderer).
I've also tried creating a subclass of AdvancedDataGridHeaderRenderer and overriding createChildren to add the icon:
override protected function createChildren():void
{
var icon:Image = new Image();
icon.source = <image_url>;
icon.width = 16;
icon.height = 16;
addChild(icon);
super.createChildren();
}
but then, the icon and the text get superimposed.
I'm out of ideas on this. Anyone else?
It worked for me when I removed the height="100%" attribute from mx:Text in your headerRenderer.
UPDATE: it only works like this when I manually stretch the AdvancedDataGrid component. I'll look into how to make it work unconditionally.
When the height of the Text component was set to 100%, it was constrained to its parent HBox's height. Therefore when a word was wrapped and moved to the next line, it wasn't visible because the height of the Text component didn't allow for it to be visible.
If you remove this constraint, Text component's height will be determined dynamically based on its contents, as will headerRenderer's. Also add minHeight to your Text so that it is visible when it's loaded.
Here's the code (I also removed scrollbars because they were showing during resize):
<mx:headerRenderer>
<fx:Component>
<mx:HBox width="100%"
height="100%"
verticalAlign="middle"
horizontalScrollPolicy="off"
verticalScrollPolicy="off">
<mx:Image source="<image_url>"
width="10%"
height="100%"/>
<mx:Text text="{data.headerText}"
width="90%"
minHeight="20"/>
</mx:HBox>
</fx:Component>
</mx:headerRenderer>
In case anyone is interested in how to do this with dynamically created columns, a combination of Hunternif's code for the renderer and some added code on column creation worked for me:
The columns need to have fixed widths and need to be invalidated to inform the AdvancedDataGrid that it needs to rerender:
var cols:Array = [];
for each (...) {
var column:AdvancedDataGridColumn = new AdvancedDataGridColumn();
...
// Fix the width of created columns
column.width = 150;
cols.push(column);
}
grid.columns = cols;
// Invalidate columns so that sizes are recalculated
grid.mx_internal::columnsInvalid = true;
// Take changes into account
grid.validateNow();

Flex3: How to "Re-load" A Component

How do I, in effect, "reset" a component in order to have it look the the way it did when it first loaded. For example, I've got 3 buttons in an HBox. They start as red, visible, and have a label. I then programmatically make different changes to them-- change the color of some of them, change the visibility of some of them, etc.
I then need to "reload" this HBox, have it revert back to the way it looked at the start. Is there an easy way to do this? (I have a lot of components that need to be changed).
<mx:HBox>
<mx:Button id="button1"
label="button1"
fillColors="[red, red]"
toggle="true" click="myClickHandler"/>
<mx:Button id="button2"
label="button1"
fillColors="[red, red]"
toggle="true" click="myClickHandler"/>
<mx:Button id="button3"
label="button1"
fillColors="[red, red]"
toggle="true" click="myClickHandler"/>
</mx:HBox>
If you have a suggestion, please let me know. Thank you.
-Laxmidi
You are already problematically changing this code at runtime. Just write a method to change it back to it's default state. That is probably what I'd do.
Alternately, if this is an encapsulated component, you could always remove it with removeChild, create another instance, and put that new one in the same place.
Per comments, here is some psuedo code for looping over children of a component and changing properties:
for (var i : int =0; i<hBox.numChildren; i++){
var child : UIComponent = hBox.getChildAt(i);
child.setStyle('style','defaultValue');
child.property = 'default value'
}
<mx:Application>
<mx:Script>
private function onColorChange():void
{
can.removeAllChildren();
var loader:Loader = new Loader();
loader.load(new URLRequest('assets/images/logo/1.png'));
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onComplete);
/* image= new Image();
image.source = "assets/images/logo/1.jpg";
image.setStyle('horizontalCenter','0');
image.setStyle('verticalCenter','0'); */
//can.addChild(image);
txt= new Text();
txt.text = "Ankur sharma";
txt.styleName = "font";
txt.setStyle('fontFamily','Anime Ace');
txt.rotation = -10;
can.addChild(txt);
can.mask = txt;
//applyFilter(CC.uint2rgb(cp.selectedColor));
}
private function onComplete(event:Event):void
{
rect = new Rectangle();
rect = txt.getBounds(can);
can.graphics.clear();
can.graphics.beginBitmapFill(event.currentTarget.content.bitmapData);
can.graphics.drawRect(rect.x,rect.y,rect.width,rect.height);
can.graphics.endFill();
}
</mx:Script>
<mx:ColorPicker id="cp" change="onColorChange()"/>
<mx:Canvas id="can" height="100%" horizontalCenter="0" verticalCenter="0" borderStyle="solid" borderColor="#CCCCCC" borderThickness="5">
<mx:Image source="assets/images/logo/1.png" horizontalCenter="0" verticalCenter="0"/>
<mx:Text text="Ankur Sharma" styleName="font" rotation="-10"/>
</mx:Canvas>
<mx:Style source="style.css"/>
</mx:Application>
in this example, wht i m doin is i m removing all children in ma canvas(id=can) amd then then makeing n e changes, to exizting components and then adding thm back to the canvas,
this program is of masking n e ways, my canvas has two children, and i m putting ma text as a mask over the canvas, and i am filling the canva with bitmap image, thats it
i hop it hepls

In flex, how to get coordinates when using VBox for stacking up components?

In flex, I am using VBox & HBox to stack components. When I try to get x,y coordinate of a component, I always get 0. If I specify coordinate like mx:VBox x="120", then I get the value.
How can I get the coordinate without explicitly stating it.
You can translate the coordinates relatively to the stage. Check out the code below:
var box:VBox = new VBox;
var child:DisplayObject = new DisplayObject;
box.addChild(child);
child.addEventListener(FlexEvent.UPDATE_COMPLETE, updateCompleteHandler);
...
private function updateCompleteHandler(fe:FlexEvent):void{
// find global coordinates
var globalCoords:Point = child.localToGlobal(new Point(0,0));
// coordsInBox is what you are looking for
var coordsInBox:Point = box.globalToLocal(globalCoords);
}
The point is to use localToGlobal for the child components and then globalToLocal to translate the global coordinates so that they were expressed relatively to the box container.
Please notice, that the coordinates won't be processed until UPDATE_COMPLETE is called by the child object.
The X and Y values of a component are always relative to the component's parent. directionsHelp.x and directionsHelp.y will both return the position relative to the VBox containing them which, unless you explicitly set the values or insert other components around it, will be 0 by default.
The thing to remember about localToGlobal() is that you must call it from the child. If you have an Application and you just call localToGlobal( new Point(child.x, child.y) ), it will try to return the given point within the Application relative to the stage (because you haven't specified what "local" is), which will therefore conduct no transformations, and it will therefore stay equal to (0, 0).
If however you call child.localToGlobal( new Point(child.x, child.y) ), it will return the value of the child's position relative to the stage, transforming the given point by however much the child is offset on the stage.
Here's a quick app to demonstrate:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundColor="#FFFFFF">
<mx:Script>
<![CDATA[
private function updateCoords():void
{
var point:Point = new Point(directionsHelp.x, directionsHelp.y);
point = directionsHelp.localToGlobal(point);
directionsHelp.text = "My stage coordinates are ("+point.x+", "+point.y+")";
}
]]>
</mx:Script>
<mx:VBox>
<mx:Box height="100" width="100" borderStyle="solid" borderColor="#000000"
horizontalAlign="center" verticalAlign="middle">
<mx:Label text="100 x 100" />
</mx:Box>
<mx:VBox>
<mx:Text id="directionsHelp" color="#4FA4CD" fontSize="8" fontWeight="bold"
text="Click the button to display my position on the stage." />
<mx:Button label="Get Position" click="updateCoords()" />
</mx:VBox>
</mx:VBox>
</mx:Application>

Flex TextArea htmlText with stylesheet click bug

This bug is hard to describe, but easily reproduced with the bottom code. Just copy, paste, and compile+run in Flex 3 and you'll see the problem. Anyone know of a work around?
Edit: Here is a link to a running demo: http://shiinaringo.se/hosted/flex/textarea-bug/HtmlTextBug.html
In the demo, the default color of TextArea is set to red.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal" applicationComplete="applicationComplete(event);">
<mx:Script>
<![CDATA[
import mx.events.FlexEvent;
private function applicationComplete(event:Event):void {
var styles:String = "a:hover { color: #6666ff; text-decoration: underline; } a { color: #0000ff; }";
var ss:StyleSheet = new StyleSheet();
ss.parseCSS(styles);
textGreenStylesheet.styleSheet = ss;
}
private function enteredText(event:FlexEvent):void {
textDefault.htmlText = event.currentTarget.text;
textGreen.htmlText = event.currentTarget.text;
textGreenStylesheet.htmlText = event.currentTarget.text;
}
]]>
</mx:Script>
<mx:VBox height="100%" width="400" horizontalAlign="center">
<mx:Panel width="250" height="200" layout="absolute" title="TextArea A. Default colored text">
<mx:TextArea id="textDefault" condenseWhite="true" width="100%" height="100%" x="0" y="0">
<mx:htmlText>
<![CDATA[
This text has the default text color of the TextArea control.
]]>
</mx:htmlText>
</mx:TextArea>
</mx:Panel>
<mx:Panel width="250" height="200" layout="absolute" title="TextArea B. Green text">
<mx:TextArea id="textGreen" condenseWhite="true" width="100%" height="100%" x="0" y="0" color="green">
<mx:htmlText>
<![CDATA[
This text has the text color set to green
]]>
</mx:htmlText>
</mx:TextArea>
</mx:Panel>
<mx:Panel width="250" height="200" layout="absolute" title="TextArea C. Green text + stylesheet">
<mx:TextArea id="textGreenStylesheet" condenseWhite="true" width="100%" height="100%" x="0" y="0" color="green">
<mx:htmlText>
<![CDATA[
This text has the text color set to green, and also uses a stylesheet to make links blue and underlined when hovered.
]]>
</mx:htmlText>
</mx:TextArea>
</mx:Panel>
<mx:TextInput x="69" y="282" width="207" enter="enteredText(event);"/>
</mx:VBox>
<mx:VBox height="100%" width="200">
<mx:Text width="166" text="We have three TextArea controls. The top uses default text color, the middle one uses defined green text color, the bottom one also uses green color, but also uses a stylesheet to define some custom coloring of A tags." height="232"/>
<mx:Text width="166" text="To reproduce the problem, first try to just enter new text in the input field in the bottom, and press enter. The text in the three boxes will update. Notice that the colors and other styles don't change in any of the three boxes. But when you click once inside textarea C, then enter new text in the input field and hit enter, you'll notice that the color and font is lost in textarea C. Bug?" height="232"/>
</mx:VBox>
</mx:Application>
Basically, StyleSheet and TextFormat doesn't go together in a flash textfield.
Following is my guestimate of what might be happening:
The color="green" will become part of the defaultTextFormat of the internal TextField of the TextArea and will be applied to the text well before applicationComplete is fired. You can verify this by tracing trace(textGreenStylesheet.htmlText); in the application complete handler (before you set the stylesheet). Here is what I got:
<TEXTFORMAT LEADING="2"><P ALIGN="LEFT"><FONT FACE="Verdana" SIZE="10" COLOR="#008000" LETTERSPACING="0" KERNING="0">This text has the text color set to green, and also uses a stylesheet to make links blue and underlined when hovered. </FONT></P></TEXTFORMAT>
Now when you apply the stylesheet, the color remains unchanged (green) as the stylesheet do not specify any color for the whole text.
When you click on the TextArea, I believe flex recalculates properties of it (may be click triggers an invalidation - I am not sure what's happening underneath). While doing this, compiler finds that a stylesheet has been applied and ignores the color="green" attribute. Now, these new properties are applied only when the text/htmltext property is changed (later by hitting enter). So unless you click or somehow trigger an invalidation of textarea, it retains the default color specified before applying the stylesheet.
If you add .yellow{color:#ffff00;} to the stylesheet and enclose some text in the third text area with <span class="yellow">some text</span> tags, you can see that the enclosed text retains yellow color whether you click on it or not.
Here's what I'm doing to resolve this. It's a big hack, but it does work.
import flash.events.Event;
import flash.text.TextFormat;
import mx.controls.Text;
import flash.text.StyleSheet;
import mx.core.mx_internal;
import mx.events.FlexEvent;
public class SupText extends Text
{
use namespace mx_internal;
public var linkColor:String = "#355EBF";
private var format:TextFormat;
public function SupText()
{
super();
this.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:Event):void { setStyleSheet(); });
}
override public function set htmlText(value:String):void {
if (format != null) {
//glorious hack for style problem
textField.styleSheet = null;
textField.defaultTextFormat = format;
setStyleSheet();
}
super.htmlText = value;
if (textField.defaultTextFormat.font != "Times New Roman") {
format = textField.defaultTextFormat;
}
}
public function setStyleSheet():void {
var ss:StyleSheet = textField.styleSheet;
if(textField.styleSheet == null){
textField.styleSheet = new StyleSheet();
}
textField.styleSheet.setStyle("sup", { display: "inline", fontFamily: "ArialSup", fontWeight:"normal"});
textField.styleSheet.setStyle("a:link", { textDecoration: "none", color: linkColor });
textField.styleSheet.setStyle("a:hover", { textDecoration: "underline" });
textField.styleSheet.setStyle("a:active", { textDecoration: "underline" });
}
}
}
Can you assign the text directly to the .text property?
private function enteredText(event:FlexEvent):void
{
textDefault.text = event.currentTarget.text;
textGreen.text = event.currentTarget.text;
textGreenStylesheet.text = event.currentTarget.text;
}

Flex collision testing with hitTestObject

I'm trying to test clipping on two canvases. Both canvases are 100px wide. They're 20px apart. I've placed a label inside one and made it 200px wide. Scroll bars will show up on the canvas. When I don't have the label inside and use hitTestObject it returns false. When I place the label inside it returns true. Is there any way to alter the canvas with the label inside so that it doesn't expand to the width of the label?
<?xml version="1.0" encoding="utf-8"?>
private function init() : void {
var hitBox:Sprite = new Sprite;
hitBox.graphics.drawRect(box1.x, box1.y, 100, 100);
box1.hitArea = hitBox;
box1.mouseEnabled = false;
trace('box hit area: ' + box1.getBounds(box1));
trace('hitbox: ' + hitBox);
trace('box hit test: ' + box1.hitTestObject(box2));
}
]]>
</mx:Script>
<mx:Canvas id="box1" x="10" y="10" width="100" height="100" backgroundColor="#FFFFFF">
<mx:Label text="This is a test" width="200" />
</mx:Canvas>
<mx:Canvas id="box2" x="120" y="10" width="100" height="100" backgroundColor="#FFFFFF" />
Unfortunately, it doesn't look like you can accomplish what you want with hitTestObject. I played around with setting the clipContent and horizontalScrollPolicy properties on your canvases, to no use. What I think is happening is that hitTestObject considers your canvas to be as wide as the longest child component, regardless of any clip masks or scroll bars.
Are you forced to use hitTestObject? If not, I'd suggest writing your own collision detection function along the lines of:
public static function componentsCollide( obj1:DisplayObject, obj2:DisplayObject ):Boolean {
var bounds1:Rectangle = new Rectangle( obj1.x, obj1.y, obj1.width, obj1.height );
var bounds2:Rectangle = new Rectangle( obj2.x, obj2.y, obj2.width, obj2.height );
return bounds1.intersects( bounds2 );
}

Resources