How to center text within a container box in actionscript - actionscript-3

I am stuck trying to center a text (RichEditableText) inside a container. My code so far looks like this
<?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:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<mx:Box id="myCustomBox" height="100%" width="100%" initialize="init();">
<fx:Script>
<![CDATA[
import mx.containers.Box;
import mx.containers.HBox;
import mx.containers.VBox;
import mx.controls.Button;
import mx.controls.Image;
import spark.components.RichEditableText;
import flashx.textLayout.elements.ParagraphElement;
import flashx.textLayout.elements.SpanElement;
import flashx.textLayout.elements.TextFlow;
import flashx.textLayout.formats.TextAlign;
[Embed("dialog_error.png")]
private var myImage:Class;
public function init():void {
var img:Image = new Image();
img.source = myImage;
this.addElement(buildPane("Something went wrong", img));
}
private function buildPane(message:String, image:Image):Box{
var exPane:HBox = new HBox();
exPane.percentHeight = 100;
exPane.percentWidth = 100;
exPane.setStyle("horizontalGap","0");
//Image hosting pane
var imPane:VBox = new VBox;
imPane.setStyle("backgroundColor","blue");
imPane.percentHeight = 100;
imPane.explicitWidth = 50;
image.minHeight = 16;
image.minWidth = 16;
imPane.setStyle("paddingLeft",10);
imPane.setStyle("paddingRight",10);
var invisBtn1:Button = new Button();
invisBtn1.percentHeight = 40;
invisBtn1.visible = false;
imPane.addChild(invisBtn1);
image.percentHeight = 20;
imPane.addChild(image);
var invisBtn2:Button = new Button();
invisBtn2.visible = false;
invisBtn2.percentHeight = 40;
imPane.addChild(invisBtn2);
exPane.addChild(imPane);
//Text hosting pane
var txtPane:Box = new Box();
txtPane.setStyle("backgroundColor","yellow");
txtPane.percentHeight = 100;
//txtPane.setStyle("paddingBottom",10);
txtPane.setStyle("paddingLeft",0);
//txtPane.setStyle("paddingTop",30);
txtPane.setStyle("paddingRight",5);
//Specify text alignment
var errMsgLabel:RichEditableText = new RichEditableText;
var textFlow:TextFlow = new TextFlow();
var pCenter:ParagraphElement = new ParagraphElement();
var spanCenter:SpanElement = new SpanElement();
spanCenter.text = message;
pCenter.addChild(spanCenter);
pCenter.textAlign = TextAlign.CENTER;
textFlow.addChild(pCenter);
errMsgLabel.textFlow = textFlow;
errMsgLabel.percentHeight = 100;
errMsgLabel.percentWidth = 100;
errMsgLabel.multiline = true;
txtPane.addChild(errMsgLabel);
exPane.addChild(txtPane);
return exPane;
}
]]>
</fx:Script>
</mx:Box>
</s:WindowedApplication>
I would like the text to be at the same level as the dialog_error icon (Usual X mark icon). So if the text is taller, the icon needs to center itself in the middle of the text. Any pointers would be helpful.
Thank you.

I can think of no good reason why you would be writing all of this in ActionScript instead of MXML. You're just making things harder for yourself.
The whole 100 lines of code in your question can be reduced to this:
<s:HGroup width="100%" gap="0">
<s:VGroup width="50" height="100%" paddingLeft="10" paddingRight="10"
verticalAlign="middle">
<s:Image id="msgIcon" source="#Embed('dialog_error.png')"/>
<s:Button visible="false" includeInLayout="false"/>
<s:Button visible="false" includeInLayout="false"/>
</s:VGroup>
<s:RichEditableText id="errMsgLabel" width="100%"/>
</s:HGroup>
This code also contains the necessary fixes to center the error icon horizontally with respect to the error message's text height.
removed the 100% height on the HGroup; this caused the Image to be centered in the middle of the entire container, not just the text height.
added verticalAlign="middle" to the VGroup containing Image and Buttons; this property will align the content of this container to its vertical center.
added includeInLayout="false" to the invisible Buttons; if you just make the Buttons invisible, they will still take up space in the layout, pushing the Image up a little; setting this property to false will tell the VGroup container to act as if the Buttons really weren't there to do its layout.
removed the 100% height on the RichEditableText so that it is only as high as its text content, otherwise the icon will still be centered to the middle of the entire container.
removed a bunch of redundant containers.
Note that I assumed you applied the background colors only for testing purposes, to see how the containers are laid out.
I understand you want to dynamically change the icon. You can easily achieve this by setting its source property programatically afterwards:
msgIcon.source = otherEmbeddedImage;
Or even better, through data binding:
<s:Image source="{msgIcon}"/>
msgIcon = otherEmbeddedImage;

Related

add vertical scrollbar to flex tooltip

I want to add scrollbar to the flex tootip. So i created custom tool tip. Below is the code snippet. Problem i am facing is that as soon as i move the mouse on the custom component tooltip, the custom component tooltip disppear. i have alse set the ToolTipManager.hideDelay = Infinity. I want to use the scrollbar of the cutom tool tip.
I do not want the custom tool top to hide till i move the mouse outside the custom tool tip component.Currently it hide itself once i move the mouse outside the label. How to control the destroy of tool tip.
<?xml version="1.0" encoding="utf-8"?>
<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"
width="100%"
height="100%"
implements="mx.core.IToolTip">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
private var _bodyText:String = "";
[Bindable]
public function get bodyText():String
{
return _bodyText;
}
public function set bodyText(value:String):void
{
_bodyText = value;
text = value;
}
private var _text:String;
public function get text():String
{
return _text;
}
public function set text(value:String):void
{
_text = value;
}
]]>
</fx:Script>
<s:Scroller width="100%" height="200">
<s:RichEditableText text="{bodyText}" width="100%" height="100%" color="red"/>
</s:Scroller>
</s:Group>
and i add this cutom tooltip on mx:label component on toolTipCreate event.
protected function label1_toolTipCreateHandler(event:ToolTipEvent):void
{
ScrollableToolTip ptt = new ScrollableToolTip();
ptt.bodyText = data.notes;
ptt.height = 300;
ptt.width = 100;
event.toolTip = ptt;
}
Any pointers..
Thanks
Raj
Instead of relying on the flex tooltip, you may want to add a popup on mouse roll over and deal with it that way, ofcoz you have to deal with the positioning of the popup later on, but I think this will give you a lot of flexibility later on.

How to make selected text in text area bold,italic etc and then add it on rich text?

I made selected text in text area bold,italic etc but i am not able to maintain bold ,italic properties when adding text on rich text.
Ok, look. Let's analyze our problem step by step:
Problem: we have text and we need to change selected text of initial text to bold;
Solution:
1) Take a selection text to separate string
2) Change style of separate string to bold(or other style)
3) Collect initial not-bold strings with bolded sting and show result :)
I think there are several ways to resolve this, but i propose the following:
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="Test">
<s:VGroup>
<s:RichEditableText id="ret" text="Test Text String for selection" />
<s:Button id="btnBold" label="Set Bold for Selection" click="btnBold_clickHandler(event)"/>
</s:VGroup>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import flashx.textLayout.conversion.TextConverter;
protected function btnBold_clickHandler(event:MouseEvent):void
{
setBoldForSelectionTex();
}
private function setBoldForSelectionTex():void
{
var startSelectionPos:int = 0;
var endSelectionPos:int = 0;
if(ret.selectionActivePosition > ret.selectionAnchorPosition)
{
endSelectionPos = ret.selectionActivePosition;
startSelectionPos = ret.selectionAnchorPosition;
}
else
{
endSelectionPos = ret.selectionAnchorPosition;
startSelectionPos = ret.selectionActivePosition;
}
var initialString:String = ret.text;
var startString:String = ret.text.toString().substr(0, startSelectionPos);
var middleString:String = ret.text.toString().substr(startSelectionPos, endSelectionPos - startSelectionPos);
var endString:String = ret.text.toString().substr(endSelectionPos, initialString.length - endSelectionPos);
var completeString:String = startString +"<b>" + middleString + "</b>" + endString;
ret.textFlow = TextConverter.importToFlow(completeString, TextConverter.TEXT_FIELD_HTML_FORMAT);
}
]]>
</fx:Script>
</s:View>
I hope this help you.

ItemRenderer Objects Changing Properties

Apologies for the vague title. I could not think of a better way to word it in so few words.
Basically, I am creating a custom ItemRenderer (IR). The IR has a label on the left side and an icon on the right side. The icon on the right side is dynamic (can be either an add or remove icon or nothing at all). This works beautifully and gives me the control I need over it.
Now, the problem is that when I scroll the list in my mobile application, the icons change.
How it should look:
How it looks after scrolling using a finger (or mouse in emulator) by dragging on Test3:
As you can see, the icons change but the labels do not. I have dragEnabled, dropEnabled, and dragMoveEnabled all set to false on my Spark List component. The only time the icon selection runs is on creationComplete, so there is no way it is choosing a different icon at some point. I can also verify that the data itself is what it should be after this change occurs.
Here is the MXML that creates the item:
<s:HGroup width="100%" verticalAlign="middle" left="{this.sideSpacing}" right="{this.sideSpacing}" top="{this.sideSpacing}" bottom="{this.sideSpacing}">
<s:Label id="text" width="100%"/>
<s:Image id="actionIcon" buttonMode="true" click="actionIconClick( event );">
<s:filters>
<s:DropShadowFilter alpha=".45" angle="90" distance="3" blurX="3" blurY="3" quality="3"/>
</s:filters>
</s:Image>
</s:HGroup>
<s:Rect width="100%" height="1" bottom="0" alpha=".1">
<s:fill>
<s:SolidColor color="#000000"/>
</s:fill>
</s:Rect>
And the possibly over-elaborate AS3 for selecting which icon should be displayed:
private function creationComplete( e:Event ):void {
if ( this.data.actionIcon != null ) {
this.actionIconType = this.data.actionIcon;
if ( this.data.actionIcon == ACTION_ICON_ADD ) {
this.actionIcon.source = this.addBitmapSource;
}
else if ( this.data.actionIcon == ACTION_ICON_REMOVE ) {
this.actionIcon.source = this.removeBitmapSource;
}
else {
this.actionIcon.source = null;
this.actionIcon.visible = false;
this.actionIcon.includeInLayout = false;
}
}
else {
this.actionIcon.source = null;
this.actionIcon.visible = false;
this.actionIcon.includeInLayout = false;
}
}
What could be causing this issue?
Basically, you need to update your renderer's label and icon when the dataChange event is fired. CreationComplete is only fired once. The list isn't really scrolled, just that the data in the itemRenderers change; causing it to look like things are scrolling. I call this renderer recycling.
Here is a component I created for a mobile app that does what you want. It displays a label and an icon (AKA the Decorator). When scrolling the label and icon are both updated. You can use a very similar approach.
<?xml version="1.0" encoding="utf-8"?>
<s:IconItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
dataChange="onDataChange(event)" alpha=".7" width="100%" cacheAsBitmap="true">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import com.dotcomit.magondaMaze.managers.BoardDataManager;
import com.dotcomit.magondaMaze.managers.StatManager;
import mx.events.FlexEvent;
[Embed(source="assets/images/chooseLevel/completed78x78.png")]
private var completedImage:Class;
public var statManager :StatManager = StatManager.instance;
protected function onDataChange(event:FlexEvent):void
{
var itemAsXML :XML = data as XML;
var results :String = itemAsXML.#id + '. ' + itemAsXML.#title;
label = results;
if( statManager.isBoardComplete(itemAsXML.#id)){
this.decorator = completedImage;
} else {
this.decorator = null;
}
}
]]>
</fx:Script>
</s:IconItemRenderer>
I'll also add that the IconItemRenderer component--which my code above extends--is designed to do exactly what you need. So, you may not have to re-write the wheel so to speak.

Flex Element wrongly keeps properties from previous parent - how do I reset it?

I want to put an element into another component (in this case a print template), print it, and then return it to its place. The problem is that when I return it, it has the properties of the print template! Here is a simplified example. When you click print, the label is removed and then returned but when returned it is affected by the padding of the print template! Why? How can I somehow refresh it to its proper properties? I tried all the invalidate... methods and parentChanged() but nothing worked.
<?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" width="400" height="200">
<fx:Script>
<![CDATA[
import spark.components.VGroup;
protected function button1_clickHandler(event:MouseEvent):void {
var printTemplate:VGroup = new VGroup();
printTemplate.paddingTop = 50;
printTemplate.paddingLeft = 30;
printTemplate.addElement(label);
addElement(printTemplate);
validateNow();
// print
removeElement(printTemplate);
addElement(label);
}
]]>
</fx:Script>
<s:Button label="Print" right="0" click="button1_clickHandler(event)"/>
<s:Label id="label" text="This is the label text, it should appear at the top-left."/>
</s:Application>
I would recommend you to have a separate print view-component which has a separate label which you only need to pass the right data.
OK I hacked up a solution. Put this in before adding the label back to its proper place:
var vg:VGroup = new VGroup();
vg.addElement(label);
addElement(vg);
validateNow();
removeElement(vg);
Then it gets the padding from "vg", which has no padding set. Yay. Another little hack to circumnavigate a Flex bug.

Place an 'addChild' button into grid space of TabNavigator

This question is similar to the post:
"Move Button into grid space of a TabNavigator’s tabs in Flex Builder."
Move Button into grid space of a TabNavigator's tabs in Flex Builder
but with a slight difference. I wish to have a button that adds a child (tab) to the TabNavigator in the grid space (simpler with TabBar, but see below), but will not block tabs as they extend towards the button. This functionality can be seen in every web browser that uses tabs.
In addition I would like to have a scroll button appear if too many tabs are opened, and the ability to close tabs. I have tried using Doug McCune's SuperTabNavigator, which offers most of these features, but it does not offer the addChild button that I am looking for.
Is there a way to add this 'addChild' button to the grid space, or to add the features from SuperTabNavigator to TabBar?
This class will do the trick except for scrolling when there are too many tabs.
<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="500" height="400">
<mx:HBox width="100%">
<mx:TabBar dataProvider="{viewstack}"/>
<mx:Button label="+" width="35" click="addTab()"/>
</mx:HBox>
<mx:ViewStack height="100%" width="100%" id="viewstack"/>
<mx:Script>
<![CDATA[
import mx.controls.Label;
import mx.containers.Panel;
//add a new container
private function addTab():void
{
var l:Label = new Label();
l.text = "Panel " + (viewstack.numChildren + 1);
var p:Panel = new Panel();
p.label = l.text;
p.addChild(l);
viewstack.addChild(p);
viewstack.selectedChild = p;
}
]]>
</mx:Script>
</mx:VBox>