How can I change a Spark WindowedApplication StatusBar skin programatically? - css

Currently I'm using the ideas in this post to skin my s:WindowedApplication, so in the declaration of my component I have skinClass="StatusBarSkin1". Also in my preinitialize function I have a method which puts the correct text onto the status bar using the label, which works fine.
The problem arises when I try and set the skinClass in my CSS, so I can change between StatusBarSkin1 and StatusBarSkin2. So I'm doing something like:
Style1.css
----------
.mainWindow
{
skinClass: ClassReference("StatusBarSkin1");
}
Style2.css
----------
.mainWindow
{
skinClass: ClassReference("StatusBarSkin2");
}
If I do this, the theme loads fine, but the text for the status bar won't display; and if I set the theme in the WindowedApplication itself, then I can't change the skin on the status bar when I change CSS files using a method.
Is there a better way to implement this than what I'm doing now?
EDIT:
The statusbar object is just an HGroup with some labels and stuff in it.
The statusbar skin is given by this code:
<s:Group id="statusBar"
width="100%"
minHeight="20">
<!-- status bar fill -->
<s:Rect left="0"
right="0"
top="0"
bottom="0">
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="0x575757" />
<s:GradientEntry color="0x373737" />
</s:LinearGradient>
</s:fill>
</s:Rect>
<!-- status bar highlight -->
<s:Rect left="1"
right="1"
top="1"
bottom="0">
<s:stroke>
<s:LinearGradientStroke rotation="90"
weight="1">
<s:GradientEntry color="0x575757" />
<s:GradientEntry color="0x373737" />
</s:LinearGradientStroke>
</s:stroke>
</s:Rect>
<!-- status text -->
<!--- #copy spark.components.WindowedApplication#statusText -->
<s:Label id="statusText" />
<s:Group id="statusBarSkin" />
</s:Group>
and then my preinit function is
private function InitStatusBar():void
{
statusGroup = new StatusBar();
(statusBar as Group).addElement(statusGroup);
}

Related

How to add a background gradient to an Application?

I'm a Flex newbie and am porting a pure Flash/AS3 application to Flex 4.5.
In my original Flash/AS3 application I had a Sprite acting as a background. I put it underneath all other DisplayObjects and fill it with a linear gradient of random color. It looked good and seemed to work well with Flash Components (Buttons, Checkboxes, TexFields), because they are transparent.
So in my new Flex program (with BasicLayout), I've tried creating a Rect too:
<s:Rect left="0" top="0" right="0" bottom="0">
<s:stroke>
<s:LinearGradientStroke id="_bgcolor" rotation="90" weight="1">
<s:GradientEntry color="0x33FFFF" alpha="0.55" />
<s:GradientEntry color="0x99FFFF" alpha="0.2475" />
</s:LinearGradientStroke>
</s:stroke>
</s:Rect>
But this doesn't work well, the Rect is obscured by the other Flex components:
Is there a quick way of adding a backround gradient to a Flex application (something as simple as backgroundColor="#CCCCCC") or do I have to study "skinning docs" (and will skinning of an Application help here, since the problem seems to be that the Flex components are opaque?)
Looks like the default white background overlays your custom Rect.
Try adding contentBackgroundAlpha="0" to hide the component background without messing with skins.
You used <stroke> instead of <fill>
<s:Rect left="0" top="0" right="0" bottom="0">
<s:fill>
<s:LinearGradient id="_bgcolor" rotation="90">
<s:GradientEntry color="0x33FFFF" alpha="0.55" />
<s:GradientEntry color="0x99FFFF" alpha="0.2475" />
</s:LinearGradient>
</s:fill>
</s:Rect>
You're missing content group
<s:Group id="chrome" left="0" right="0" top="0" bottom="0" visible.closedGroup="false">
<s:Rect left="0" top="0" right="0" bottom="0">
<s:fill>
<s:LinearGradient id="_bgcolor" rotation="90">
<s:GradientEntry color="0x33FFFF" alpha="0.55" />
<s:GradientEntry color="0x99FFFF" alpha="0.2475" />
</s:LinearGradient>
</s:fill>
</s:Rect>
<s:Group id="contentGroup" left="0" right="0" top="0" bottom="0" minWidth="0" minHeight="0">
<s:layout>
<s:BasicLayout/>
</s:layout>
</s:Group>
</s:Group>

Is this a PrintDataGrid bug or restriction or my lack of understanding?

I'm trying to implement PrintDataGrid in my application and I'm encountering a peculiar problem. The printout is skipping last several rows in the printout of each page.
I have narrowed down to what's causing this issue. My application-level custom skin provides Flex scrolling capability to the entire application. Presence of this scrollbar in the custom skin is causing PrintDataGrid to skip last rows. In fact, number of rows skipped depends on the height of the browser. If you reduce the browser height, you skip more rows!
Is this a bug PrintDataGrid or a restriction (cannot have PrintDataGrid within Scroller) or I'm missing something?
Please help as I'm struggling with this for several days!
Here is simple code to reproduce the issue:
Main Application:
Application custom skin class:ApplicationSkinCustom.mxml
============================================
#see spark.components.Application
#langversion 3.0
#playerversion Flash 10
#playerversion AIR 1.5
#productversion Flex 4
-->
<fx:Metadata>
<![CDATA[
/**
* A strongly typed property that references the component to which this skin is applied.
*/
[HostComponent("spark.components.Application")]
]]>
</fx:Metadata>
<fx:Script fb:purpose="styling">
<![CDATA[
/**
* #private
*/
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number) : void
{
bgRectFill.color = getStyle('backgroundColor');
super.updateDisplayList(unscaledWidth, unscaledHeight);
}
]]>
</fx:Script>
<s:states>
<s:State name="normal" />
<s:State name="disabled" />
<s:State name="normalWithControlBar" />
<s:State name="disabledWithControlBar" />
</s:states>
<!-- fill -->
<!---
A rectangle with a solid color fill that forms the background of the application.
The color of the fill is set to the Application's backgroundColor property.
-->
<s:Rect id="backgroundRect" left="0" right="0" top="0" bottom="0" >
<s:fill>
<s:SolidColor id="bgRectFill" color="#FFFFFF"/>
</s:fill>
</s:Rect>
<s:Scroller left="1" top="1" right="1" bottom="1" id="scroller">
<s:Group left="0" right="0" top="0" bottom="0">
<s:layout>
<s:VerticalLayout gap="0" horizontalAlign="justify" />
</s:layout>
<!---
#private
Application Control Bar
-->
<s:Group
id="topGroup"
minWidth="0"
minHeight="0"
includeIn="normalWithControlBar, disabledWithControlBar"
>
<!-- layer 0: control bar highlight -->
<s:Rect left="0" right="0" top="0" bottom="1" >
<s:stroke>
<s:LinearGradientStroke rotation="90" weight="1">
<s:GradientEntry color="0xFFFFFF" />
<s:GradientEntry color="0xD8D8D8" />
</s:LinearGradientStroke>
</s:stroke>
</s:Rect>
<!-- layer 1: control bar fill -->
<s:Rect left="1" right="1" top="1" bottom="2" >
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="0xEDEDED" />
<s:GradientEntry color="0xCDCDCD" />
</s:LinearGradient>
</s:fill>
</s:Rect>
<!-- layer 2: control bar divider line -->
<s:Rect left="0" right="0" bottom="0" height="1" alpha="0.55">
<s:fill>
<s:SolidColor color="0x000000" />
</s:fill>
</s:Rect>
<!-- layer 3: control bar -->
<!--- #copy spark.components.Application#controlBarGroup -->
<s:Group id="controlBarGroup" left="0" right="0" top="1" bottom="1" minWidth="0" minHeight="0">
<s:layout>
<s:HorizontalLayout paddingLeft="10" paddingRight="10" paddingTop="7" paddingBottom="7" gap="10" />
</s:layout>
</s:Group>
</s:Group>
<!--- #copy spark.components.SkinnableContainer#contentGroup -->
<!--<s:Group id="contentGroup" width="100%" height="100%" minWidth="0" minHeight="0" />-->
<s:Group id="contentGroup" left="0" right="0" top="0" bottom="0" />
</s:Group>
</s:Scroller>
This is apparently a known bug with the Flex printing library and Scroller controls. You can read about my discussions on this here:
http://forums.adobe.com/message/3626759
The first thing I would try is getting rid of the custom skin, processing your print job, and then re-applying the custom skin. This might do the trick. If that does work, but doesn't look the way you want, then you can work on creating a variant of your custom application skin that doesn't have a scroller. You would apply that before starting the print job, and then restore the original custom application skin after the print job completes.
The user may briefly see the "alternate" version of your app when they click the print button, but it should only be for a split second at most.
-Josh

Difficulty creating animated skin in Flex 4

I have been tasked with creating the equivalent Flex 4 implementation of graphical style of the buttons found on this page:
http://h.dwighthouse.com/temp/UDOP/2011-3-25_themeDevGlowing/
Namely, the animated glowing effect on the buttons. I've gotten what I think is the appropriate programmatic gradient-based skin basis, but I have two problems.
One, I can't get any mouse events to respond in the skin. I can't seem to find others with this problem. In the below code, startAnimation is never getting called when a mouse over occurs, but the event is apparently getting registered. To test this code, simply add skinClass="ButtonSkin" to a button declaration in your main application, the code below being the ButtonSkin.mxml file.
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
initialize="init()"
mouseEnabled="true">
<fx:Metadata>
[HostComponent("spark.components.Button")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import flash.events.Event;
[Bindable]
private var animatedAlpha:Number = 0.8;
private var animationDirection:Number = -1;
private function backAndForth(value:Number, max:Number, min:Number, increment:Number):Number {
value += (animationDirection * increment);
if (value < min || value > max)
{
animationDirection *= -1;
value += (animationDirection * increment * 2);
}
return value;
}
private function startAnimation(e:MouseEvent):void {
animatedAlpha = backAndForth(animatedAlpha, 0.8, 0.3, 0.1); // Or something
systemManager.addEventListener(MouseEvent.MOUSE_OUT, endAnimation);
}
private function endAnimation(e:MouseEvent):void {
animatedAlpha = backAndForth(animatedAlpha, 0.8, 0.3, 0.1); // Or something
systemManager.removeEventListener(MouseEvent.MOUSE_OUT, endAnimation);
}
private function init():void {
parent.mouseChildren = true; // Otherwise mouse events don't fire in the skin
clickableArea.addEventListener(MouseEvent.MOUSE_OVER, startAnimation);
}
]]>
</fx:Script>
<s:states>
<s:State name="up" />
<s:State name="over" />
<s:State name="down" />
<s:State name="disabled" />
</s:states>
<s:Group top="0" bottom="0" left="0" right="0" id="clickableArea">
<s:Rect top="0" bottom="0" left="0" right="0" radiusX="8" radiusY="8">
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="#000000" color.down="#bb0000" color.disabled="#3b3b3b" ratio="0" />
<s:GradientEntry color="#353535" color.down="#ff0000" color.disabled="#555555" ratio="1" />
</s:LinearGradient>
</s:fill>
</s:Rect>
<s:Rect top="0" bottom="0" left="0" right="0" radiusX="8" radiusY="8">
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color.over="#8f1b1b" alpha="0" ratio="0" />
<s:GradientEntry color.over="#8f1b1b" alpha="0" ratio="0.4" />
<s:GradientEntry color.over="#8f1b1b" alpha="{animatedAlpha}" alpha.down="0" ratio="1" />
</s:LinearGradient>
</s:fill>
</s:Rect>
<s:Rect top="0" bottom="0" left="0" right="0" radiusX="8" radiusY="8">
<s:stroke>
<s:SolidColorStroke color="#000000" color.disabled="#333333" weight="1" />
</s:stroke>
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="#ffffff" color.disabled="#9e9e9e" alpha="0.6" alpha.down="0.7" ratio="0" />
<s:GradientEntry color="#ffffff" color.disabled="#848484" alpha="0.2" alpha.down="0.4" ratio="0.45" />
<s:GradientEntry color="#ffffff" alpha="0" ratio="0.46" />
</s:LinearGradient>
</s:fill>
</s:Rect>
<s:Label id="labelDisplay" color="#ffffff" color.disabled="#aaaaaa" textAlign="center" baseline="center" paddingTop="7" paddingBottom="5" paddingLeft="10" paddingRight="10">
<s:filters>
<s:DropShadowFilter distance="0" angle="45" blurX="5" blurY="5" />
</s:filters>
</s:Label>
</s:Group>
EDIT I found out why mouse events weren't firing. The button apparently has mouseChildren false by default, which specifically prevents events from firing lower than itself. Using parent.mouseChildren = true; in the constructor fixes this issue. On to the next part of the question: continuous animation.
Other than that, I'd appreciate some help or point me in the right direction of calling a function every frame, and the ability to turn said incremental call on and off using mouse events. (If that's not how you animate in Flex, forgive me, I know nothing about Flash-based animation.) Thanks!
Answers to both questions have been found:
Buttons prevent their children (including Skins) from receiving mouse events. By setting parent.mouseChildren = true; in the skin's initializing function, mouse events are received normally.
Turns out you can animate in Flex (Actionscript) the same way you animate in Javascript: setInterval and clearInterval.

Change the background color of a Flex toggle button

What is the easiest way to change the background color of a toggle button when it is selected?
I've tried creating a custom skin for the button and applying it to the downSkin property, but I can't figure out how to change the background color from within the skin. Also I'd like to avoid using an image as a background if possible.
I hope I understand what you need.
In your skin file, the state upAndSelected is what you need to specify the color when the togglebutton is selected. You can copy the generated skin code from Flex to modify it or check the code below. Add it below the </s:Rect> tag under <!--layer 2: fill #private-->`
<s:Rect id="fill2" left="1" right="1" top="1" bottom="1" radiusX="2">
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="0xFFFFFF"
color.upAndSelected="#333333" // you can modify color here
alpha="0.85"
/>
<s:GradientEntry color="0xD8D8D8"
color.upAndSelected="red" // you can modify color here
alpha.downAndSelected="1" />
</s:LinearGradient>
</s:fill>
</s:Rect>
Paste the code above under
<!-- layer 2: fill -->
<!--- #private -->
<s:Rect id="fill" left="1" right="1" top="1" bottom="1" radiusX="2">
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="0xFFFFFF"
color.selectedUpStates="0xBBBDBD"
color.overStates="0xBBBDBD"
color.downStates="0xAAAAAA"
alpha="0.85"
alpha.overAndSelected="1" />
<s:GradientEntry color="0xD8D8D8"
color.selectedUpStates="0x9FA0A1"
color.over="0x9FA0A1"
color.overAndSelected="0x8E8F90"
color.downStates="0x929496"
alpha="0.85"
alpha.overAndSelected="1" />
</s:LinearGradient>
</s:fill>
</s:Rect>
Hope it helps.
No easy way. Your best bet is to open up Flash Professional and create a skin; then assign that skin to the button as a style using something like this:
MyButton.setStyle('skin', mySkin);
[This advice may not apply if you are referring to a Spark ToggleButton as opposed to a Halo ToggleButton[

Flex 4: How to skin a spark volumebar to make it work like a HSlider?

Can anyone point me in the direction of skinning a video player volumebar? I want a mute button on the left side and then an HSlider to the right that is always open (no popups).
I've managed to change the skin to use a custom track button and a custom thumb button and it mostly looks how I want.
I can't seem to figure out how to make the thumb slide horizontally across the track and how to hook it into the videoplayer. The thumb just wiggles a little up and down.
I realize I can make a separate HSlider and button and then attach them to the videoplayer controls, I was just hoping since the functionality is already built in that I could override a few skins and be done with it.
I had the same issue today and found that the solution was to reimplement VolumeBar extends VSlider so that HVolumeBar extends HSlider then alter updateSkinDisplayList() so the thumb position works correctly. I tried the rotation approach without success. I played with the skins a bit also.
override protected function updateSkinDisplayList():void
{
if (!thumb || !track)
return;
var thumbRange:Number = track.getLayoutBoundsWidth() - thumb.getLayoutBoundsWidth();
var range:Number = maximum - minimum;
// calculate new thumb position.
var thumbPosTrackX:Number;
// if muted, it's 0. otherwise, calculate it normally
// TODO (rfrishbe): should probably use setValue(0) and listen for CHANGE on the VideoPlayer
// instead of VALUE_COMMIT.
if (!muted)
thumbPosTrackX = (range > 0) ? (((pendingValue - minimum) / range) * thumbRange) : 0;
else
thumbPosTrackX = thumbRange;
// convert to parent's coordinates.
var thumbPos:Point = track.localToGlobal(new Point(thumbPosTrackX,0));
var thumbPosParentX:Number = thumb.parent.globalToLocal(thumbPos).x;
thumb.setLayoutBoundsPosition(Math.round(thumbPosParentX), thumb.getLayoutBoundsY() );
}
Edit: Horizontal Volume Bar Skin
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009" minWidth="11" alpha.disabled=".5">
<!-- host component -->
<fx:Metadata>
/**
* #copy spark.skins.spark.ApplicationSkin#hostComponent
*/
[HostComponent("grammit.media.HorizontalVolumeBar")]
</fx:Metadata>
<fx:Script fb:purpose="styling">
/* Define the skin elements that should not be colorized. */
static private const exclusions:Array = ["muteButton", "track", "thumb"];
/**
* #private
*/
override public function get colorizeExclusions():Array {return exclusions;}
/**
* #private
*/
override protected function initializationComplete():void
{
useChromeColor = true;
super.initializationComplete();
}
</fx:Script>
<s:states>
<s:State name="normal" />
<s:State name="open" />
<s:State name="disabled" />
</s:states>
<!--- The PopUpAnchor control that contains the drop-down slider control. -->
<s:PopUpAnchor id="popup" displayPopUp.normal="false" displayPopUp.open="true" includeIn="open"
left="0" right="0" top="0" bottom="0" popUpPosition="left" itemDestructionPolicy="auto">
<!--- #copy spark.components.mediaClasses.VolumeBar#dropDown -->
<s:Group id="dropDown" width="84" height="28" verticalCenter="0">
<!-- dropshadow for the dropdown -->
<s:Rect left="0" top="0" right="0" bottom="0">
<s:filters>
<s:DropShadowFilter knockout="true" blurX="20" blurY="20" alpha="0.32" distance="11" angle="90" />
</s:filters>
<s:fill>
<s:SolidColor color="0x000000" />
</s:fill>
</s:Rect>
<!-- background for the popup -->
<s:Rect left="0" right="0" top="0" bottom="0">
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="0xFFFFFF"/>
<s:GradientEntry color="0xDCDCDC"/>
</s:LinearGradient>
</s:fill>
<s:stroke>
<s:SolidColorStroke color="0x000000" />
</s:stroke>
</s:Rect>
<!--- The skin pat that defines the drop-down slider track. -->
<s:Button id="track" verticalCenter="0" left="6" right="7" minWidth="33" width="100"
skinClass="grammit.skins.HorizontalVolumeBarTrackSkin" />
<!--- The skin pat that defines the thumb in the drop-down slider track. -->
<s:Button id="thumb" verticalCenter="0" width="11" height="11"
skinClass="spark.skins.spark.mediaClasses.normal.VolumeBarThumbSkin" />
</s:Group>
</s:PopUpAnchor>
<!--- #copy spark.components.mediaClasses.VolumeBar#muteButton -->
<s:MuteButton id="muteButton" left="0" right="0" top="0" bottom="0" focusEnabled="false"
skinClass="spark.skins.spark.mediaClasses.normal.MuteButtonSkin" />
</s:SparkSkin>
I couldn't find a good solution to this either so I just used rotation=90 to volumebar and rotation=-90 to what ever needed to be rotated back inside the volumebarskin.

Resources