FTheme is an open-source Flex 4 look and feel customization library. It provides a special Flex theme that changes components appearance dynamically.
That's the way most looks are created. Here is a sample look JapaneseTatoo
, note that
fills reference bitmaps from ZIP archive:
So here are the simple look creation steps:
MyLook.txt
file and specify some fills or other stylesMyLook.zip
.
Note: do not apply compression to the archive, use STORE mode. We cannot
yet decompress archives but we can read uncompressed ones.lookLinks.xml
@author Maxim Kachurovskiy http://kachurovskiy.com @author Harish Sivaramakrishnan http://scalenine.com/ @license CC BY-NC 2.5 http://creativecommons.org/licenses/by-nc/2.5/ color: 0x000000 rollOverColor: 0xC0EBF5 selectionColor: 0xFEA500 errorColor: 0xCC0000 applicationFill: 0x1F1F1F panelFill: 0xF0F0F0 panelCornerRadius: 7 panelStroke: 0xFFFFFF alpha 0.8 progressBarFill: 0xF5DFBC 0xF9CE86 ratio 0.5 0xF8BF5B ratio 0.51 0xFEA500 progressBarStroke: 0xFFFFFF progressBarHeight: 20 buttonUpFill: 0xC0EBF5 0xA5E5F4 ratio 0.5 0x8ADEF1 ratio 0.51 0x67D7EF buttonOverFill: 0xC0EBF5 0xA5E5F4 ratio 0.5 0x8ADEF1 ratio 0.51 0x67D7EF buttonDownFill: 0xF5DFBC 0xF9CE86 ratio 0.5 0xF8BF5B ratio 0.51 0xFEA500 buttonSelectedFill: 0xF5DFBC 0xF9CE86 ratio 0.5 0xF8BF5B ratio 0.51 0xFEA500 buttonDisabledFill: 0xDDDDDD buttonStroke: 0xFFFFFF borderStroke: 0xFFFFFF buttonCornerRadius: 5 buttonMinWidth: 100 buttonMinHeight: 25 checkBoxSize: 18 headerFill: 0xC0EBF5 0xA5E5F4 ratio 0.5 0x8ADEF1 ratio 0.51 0x67D7EF headerColors: 0xC0EBF5 0x67D7EF radioButtonSize: 18 radioButtonDotSize: 8 inputFill: 0xE4E5E5 inputStroke: 0xE1E2E2 inputCornerRadius: 5 scrollBarButtonSize: 0 scrollBarSize: 17 hScrollBarThumbUpFill: 0xC0EBF5 0xA5E5F4 ratio 0.5 0x8ADEF1 ratio 0.51 0x67D7EF hScrollBarThumbOverFill: 0xC0EBF5 0xA5E5F4 ratio 0.5 0x8ADEF1 ratio 0.51 0x67D7EF hScrollBarThumbDownFill: 0xF5DFBC 0xF9CE86 ratio 0.5 0xF8BF5B ratio 0.51 0xFEA500 vScrollBarThumbUpFill: 0xC0EBF5 0xA5E5F4 ratio 0.5 0x8ADEF1 ratio 0.51 0x67D7EF rotation 0 vScrollBarThumbOverFill: 0xC0EBF5 0xA5E5F4 ratio 0.5 0x8ADEF1 ratio 0.51 0x67D7EF rotation 0 vScrollBarThumbDownFill: 0xF5DFBC 0xF9CE86 ratio 0.5 0xF8BF5B ratio 0.51 0xFEA500 rotation 0 hScrollBarTrackFill: 0xE4E5E5 vScrollBarTrackFill: 0xE4E5E5 scrollBarCornerRadius: 4 scrollBarStroke: 0xFFFFFF scrollBarThumbMinSize: 40 symbolColor: 0xFFFFFF symbolFill: 0xFFFFFF sliderTrackFill: 0xE4E5E5 sliderTrackSize: 9 sliderTrackStroke: 0xFFFFFF sliderThumbSize: 15 titlebarFill: 0xC0EBF5 0xA5E5F4 ratio 0.5 0x8ADEF1 ratio 0.51 0x67D7EF titlebarStroke: 0xFFFFFF toolbarFill: 0xAEE7F5 0xC5EDF7 ratio 0.4 0xB1E7F4 ratio 0.41 0xBFEAF4 toolbarStroke: 0xFFFFFF controlbarFill: 0xF5DFBC 0xF9CE86 ratio 0.5 0xF8BF5B ratio 0.51 0xFEA500 controlbarStroke: 0xFFFFFF contentFill: 0xFFFFFF contentStroke: 0xFFFFFF
FThemeController
constructor accepts one optional parameter options:FThemeOptions
.
It provides the following properties:
lookLinksXMLURL:String
default URL for the file with look links XML file.
Setting it e.g. to myLookLinks.xml
will cause manager to load and use that file.lookLinkNames:Array of String
array of look names. Look files are loaded from
LookName.txt
and LookName.zip
URLs.lookLinksURLBase:String
is used when lookLinkNames
are specified and is added
to look file URLs e.g. if lookLinkNames
is ["Plastic", "Sky"/code> and
lookLinksURLBase
is "/app/looks/"
then look files are loaded from
"/app/looks/Plastic.txt"
and "/app/looks/Sky.txt"
.
showDefaultLook
is true by default and allows user to select default look in
LookSelector
UI component.If options were not passed in controller constructor FlashVars are checked. The same options can be specified there:
<script type="text/javascript"> var flashvars = { lookLinksXMLURL: "/swf/lookLinks.xml", // lookLinkNames: "Plastic,Sky,Red", // lookLinksURLBase: "/some/dir/", // showDefaultLook: "false" }; swfobject.embedSWF("/swf/app.swf", "swfContainer", "100%", "450", "10.1", "/playerProductInstall.swf", flashvars); </script> <div id="swfContainer">
lookLinks.xml
If controller options were not specified and FlashVars are empty then FTheme tries to
load XML file lookLinks.xml
and expects to get this:
<lookLinks> <lookLink name="Plastic"/> <lookLink name="Yakuza"/> <lookLink name="Red"/> ... </lookLinks>
<lookLink>
node can also have the following attributes:
txtFileURL
- URL to look txt file. If not specified Name.txt
is usedzipFileURL
- URL to look zip file. If not specified Name.zip
is used
if look has bitmap fills.It works nearly the same way as default spark.swc
or wireframe.swc
via defining skin for each component like Button
, CheckBox
and so on.
The key difference is that FTheme does not define the actual pixels, they are
drawn by fills and strokes that are generated at runtime.
Compare ButtonSkin
in two themes:
Spark | FTheme |
---|---|
<!-- layer 1: shadow --> <!--- @private --> <s:Rect id="shadow" left="-1" right="-1" top="-1" bottom="-1" radiusX="2"> <s:fill> <s:LinearGradient rotation="90"> <s:GradientEntry color="0x000000" color.down="0xFFFFFF" alpha="0.01" alpha.down="0" /> <s:GradientEntry color="0x000000" color.down="0xFFFFFF" alpha="0.07" alpha.down="0.5" /> </s:LinearGradient> </s:fill> </s:Rect> <!-- 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.over="0xBBBDBD" color.down="0xAAAAAA" alpha="0.85" /> <s:GradientEntry color="0xD8D8D8" color.over="0x9FA0A1" color.down="0x929496" alpha="0.85" /> </s:LinearGradient> </s:fill> </s:Rect> <!-- layer 3: fill lowlight --> <!--- @private --> <s:Rect id="lowlight" left="1" right="1" top="1" bottom="1" radiusX="2"> <s:fill> <s:LinearGradient rotation="270"> <s:GradientEntry color="0x000000" ratio="0.0" alpha="0.0627" /> <s:GradientEntry color="0x000000" ratio="0.48" alpha="0.0099" /> <s:GradientEntry color="0x000000" ratio="0.48001" alpha="0" /> </s:LinearGradient> </s:fill> </s:Rect> <!-- layer 4: fill highlight --> <!--- @private --> <s:Rect id="highlight" left="1" right="1" top="1" bottom="1" radiusX="2"> <s:fill> <s:LinearGradient rotation="90"> <s:GradientEntry color="0xFFFFFF" ratio="0.0" alpha="0.33" alpha.over="0.22" alpha.down="0.12"/> <s:GradientEntry color="0xFFFFFF" ratio="0.48" alpha="0.33" alpha.over="0.22" alpha.down="0.12" /> <s:GradientEntry color="0xFFFFFF" ratio="0.48001" alpha="0" /> </s:LinearGradient> </s:fill> </s:Rect> <!-- layer 5: highlight stroke (all states except down) --> <!--- @private --> <s:Rect id="highlightStroke" left="1" right="1" top="1" bottom="1" radiusX="2" excludeFrom="down"> <s:stroke> <s:LinearGradientStroke rotation="90" weight="1"> <s:GradientEntry color="0xFFFFFF" alpha.over="0.22" /> <s:GradientEntry color="0xD8D8D8" alpha.over="0.22" /> </s:LinearGradientStroke> </s:stroke> </s:Rect> <!-- layer 6: highlight stroke (down state only) --> <!--- @private --> <s:Rect id="hldownstroke1" left="1" right="1" top="1" bottom="1" radiusX="2" includeIn="down"> <s:stroke> <s:LinearGradientStroke rotation="90" weight="1"> <s:GradientEntry color="0x000000" alpha="0.25" ratio="0.0" /> <s:GradientEntry color="0x000000" alpha="0.25" ratio="0.001" /> <s:GradientEntry color="0x000000" alpha="0.07" ratio="0.0011" /> <s:GradientEntry color="0x000000" alpha="0.07" ratio="0.965" /> <s:GradientEntry color="0x000000" alpha="0.00" ratio="0.9651" /> </s:LinearGradientStroke> </s:stroke> </s:Rect> <!--- @private --> <s:Rect id="hldownstroke2" left="2" right="2" top="2" bottom="2" radiusX="2" includeIn="down"> <s:stroke> <s:LinearGradientStroke rotation="90" weight="1"> <s:GradientEntry color="0x000000" alpha="0.09" ratio="0.0" /> <s:GradientEntry color="0x000000" alpha="0.00" ratio="0.0001" /> </s:LinearGradientStroke> </s:stroke> </s:Rect> <!-- layer 7: border - put on top of the fill so it doesn't disappear when scale is less than 1 --> <!--- @private --> <s:Rect id="border" left="0" right="0" top="0" bottom="0" width="69" height="20" radiusX="2"> <s:stroke> <s:LinearGradientStroke rotation="90" weight="1"> <s:GradientEntry color="0x000000" alpha="0.5625" alpha.down="0.6375" /> <s:GradientEntry color="0x000000" alpha="0.75" alpha.down="0.85" /> </s:LinearGradientStroke> </s:stroke> </s:Rect> <!-- layer 8: text --> <!--- @copy spark.components.supportClasses.ButtonBase#labelDisplay --> <s:Label id="labelDisplay" textAlign="center" verticalAlign="middle" maxDisplayedLines="1" horizontalCenter="0" verticalCenter="1" left="10" right="10" top="2" bottom="2"> </s:Label> |
<s:Rect left="1" right="1" top="1" bottom="1" fill.up="{getStyle('buttonUpFill')}" fill.over="{getStyle('buttonOverFill')}" fill.down="{getStyle('buttonDownFill')}" fill.disabled="{getStyle('buttonDisabledFill')}" radiusX="{getStyle('buttonCornerRadius')}"/> <s:Rect left="1" right="1" top="1" bottom="1" stroke="{getStyle('highlightStroke')}" radiusX="{Math.max(0, getStyle('buttonCornerRadius') - 1)}"/> <s:Rect left="0" right="0" top="0" bottom="0" stroke="{getStyle('buttonStroke')}" radiusX="{getStyle('buttonCornerRadius')}"/> <s:Label id="labelDisplay" textAlign="center" verticalAlign="middle" maxDisplayedLines="1" horizontalCenter="0" verticalCenter="1" left="10" right="10" top="2" bottom="2"/> |
As you see FTheme skin uses styles like buttonUpFill
that is
mx.graphics.IFill
instance and buttonStroke
that is
mx.graphics.IStroke
. That's what FTheme does - sets those styles
to .global
CSS style declatation inside Flex StyleManager
.
Here is the list of currently supported look properties:
Controlbar
is a component introduced by FTheme is much like mx:ControlBar
but it can be placed everywhere in the application. Background fill.mx:DateChooser
header fill.ToolbarButton
is a component introduced by FTheme. Button up background fill.Toolbar
is a component introduced by FTheme. Is usually placed right below the panel titlebar.buttonCornerRadius: 4
0xFFCC00
#FFCC00
0x333
#333
0xFFCC00 0xFF0000 0xCC5500
#333 #222
0x333
0xFFCC00
0xFFCC00 alpha 0.5
0xFFCC00 0xFF0000 rotation 45
0xFFCC00 alpha 0.5 ratio 0.2 0xFF0000 alpha 0.85 spreadMethod reflect scaleX 150
Valid values of spreadMethod
are pad
, reflect
and repeat
.
Default rotation
is 90
so that gradient draws vertically.
radial 0xFFCC00
radial 0xFFCC00 alpha 0.5
radial 0xFFCC00 0xFF0000 rotation 45 scaleX 100 scaleY 200 focalPointRatio -1
Valid values of spreadMethod
are pad
, reflect
and repeat
.
Default rotation
is 90
.
Valid values of focalPointRatio
are from -1.0
to 1.0
.
bitmap assetId
bitmap assetId fillMode clip horizontalAlign right verticalAlign bottom smooth true
bitmap assetId fillMode clip horizontalAlign right y -30
bitmap assetId fillMode scale maintainAspectRatio true
Before specifying bitmap fill ensure that you've got bitmaps with corresponding names in your ZIP archive:
alpha
and pixelHinting
are supported..
0xFFCC00
#333 alpha 0.5 pixelHinting true