Skip to content

Instantly share code, notes, and snippets.

@kheftel-old
Last active August 29, 2015 14:20
Show Gist options
  • Save kheftel-old/4c52f210f083f9503a45 to your computer and use it in GitHub Desktop.
Save kheftel-old/4c52f210f083f9503a45 to your computer and use it in GitHub Desktop.
Starling Auto-Size Button Labels with Feathers 1.3.1 - uses Starling TextField to allow button labels to automatically resize to fit
package {
import starling.display.Sprite;
public class app extends Sprite
{
function app()
{
var btn:Button = new Button();
btn.nameList.add('buttonAutoScale');
btn.label = 'Click Me!';
btn.width = 100;
btn.height = 100;
addChild(btn);
}
}
}
package feathers.controls.text
{
import flash.geom.Matrix;
import flash.geom.Point;
import flash.text.TextFieldAutoSize;
import feathers.core.FeathersControl;
import feathers.core.ITextRenderer;
import starling.core.RenderSupport;
import starling.events.Event;
import starling.text.TextField;
import starling.utils.HAlign;
import starling.utils.VAlign;
/**
* Renders text that autosizes to fill an area. Uses a Starling <code>starling.text.TextField</code>.
*
* Note: width and height must be explicitly set for this to work properly!
*
* @see http://wiki.starling-framework.org/feathers/text-renderers
* @see starling.text.TextField
*/
public class AutoSizeTextRenderer extends FeathersControl implements ITextRenderer
{
/**
* @private
*/
private static const HELPER_POINT:Point = new Point();
/**
* @private
*/
private static const HELPER_MATRIX:Matrix = new Matrix();
/**
* Constructor.
*/
public function AutoSizeTextRenderer()
{
this.isQuickHitAreaEnabled = true;
this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
}
/**
* The TextField instance used to render the text.
*/
protected var textField:TextField;
/**
* @private
*/
protected var _text:String = "";
public function get vAlign():String
{
return _vAlign;
}
public function set vAlign(value:String):void
{
_vAlign = value;
}
public function get hAlign():String
{
return _hAlign;
}
public function set hAlign(value:String):void
{
_hAlign = value;
}
public function get italic():Boolean
{
return _italic;
}
public function set italic(value:Boolean):void
{
_italic = value;
}
public function get fontSize():Number
{
return _fontSize;
}
public function set fontSize(value:Number):void
{
_fontSize = value;
}
public function get fontName():String
{
return _fontName;
}
public function set fontName(value:String):void
{
_fontName = value;
}
public function get color():uint
{
return _color;
}
public function set color(value:uint):void
{
_color = value;
}
public function get bold():Boolean
{
return _bold;
}
public function set bold(value:Boolean):void
{
_bold = value;
}
public function get autoScale():Boolean
{
return _autoScale;
}
/**
* @inheritDoc
*
* <p>In the following example, the text is changed:</p>
*
* <listing version="3.0">
* textRenderer.text = "Lorem ipsum";</listing>
*
* @default ""
*/
public function get text():String
{
return this._text;
}
/**
* @private
*/
public function set text(value:String):void
{
if(this._text == value)
{
return;
}
if(value === null)
{
//flash.text.TextField won't accept a null value - not sure about starling.text.TextField
value = "";
}
this._text = value;
this.invalidate(INVALIDATION_FLAG_DATA);
}
/**
* @inheritDoc
*/
public function get baseline():Number
{
return explicitHeight;
}
/**
* @private
*/
private var _border:Boolean = false;
/**
* Same as the TextField property with the same name.
*
* @default false
*
* @see starling.text.TextField#border
*/
public function get border():Boolean
{
return this._border;
}
/**
* @private
*/
public function set border(value:Boolean):void
{
if(this._border == value)
{
return;
}
this._border = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _nativeFilters:Array = null;
protected var _autoScale:Boolean = true;
protected var _bold:Boolean = false;
protected var _color:uint;
protected var _fontName:String;
protected var _fontSize:Number;
protected var _italic:Boolean = false;
protected var _hAlign:String = HAlign.CENTER;
protected var _vAlign:String = VAlign.CENTER;
/**
* Native filters to pass to the <code>flash.text.TextField</code>
* before creating the texture snapshot.
*
* <p>In the following example, the native filters are changed:</p>
*
* <listing version="3.0">
* renderer.nativeFilters = [ new GlowFilter() ];</listing>
*
* @default null
*/
public function get nativeFilters():Array
{
return this._nativeFilters;
}
/**
* @private
*/
public function set nativeFilters(value:Array):void
{
if(this._nativeFilters == value)
{
return;
}
this._nativeFilters = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @inheritDoc
*/
public function measureText(result:Point = null):Point
{
if(!result)
{
result = new Point();
}
if(!this.textField)
{
result.x = result.y = 0;
return result;
}
var needsWidth:Boolean = isNaN(this.explicitWidth);
var needsHeight:Boolean = isNaN(this.explicitHeight);
if(!needsWidth && !needsHeight)
{
result.x = this.explicitWidth;
result.y = this.explicitHeight;
return result;
}
else
throw new ArgumentError('you must set width/height explicitly to use AutoSizeTextRenderer');
}
/**
* @private
*/
override protected function initialize():void
{
if(!this.textField)
{
this.textField = new TextField(10, 10, "");
this.textField.touchable = false;
addChild(this.textField);
}
}
/**
* @private
*/
override protected function draw():void
{
var sizeInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_SIZE);
this.commit();
sizeInvalid = this.autoSizeIfNeeded() || sizeInvalid;
this.layout(sizeInvalid);
}
/**
* @private
*/
protected function commit():void
{
const stylesInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STYLES);
const dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA);
const stateInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STATE);
trace('styles: ' + stylesInvalid + ', data: ' + dataInvalid + ', state: ' + stateInvalid);
if(stylesInvalid)
{
this.textField.autoScale = this._autoScale;
this.textField.bold = this._bold;
this.textField.border = this._border;
this.textField.color = this._color;
this.textField.fontName = this._fontName;
this.textField.fontSize = this._fontSize;
this.textField.italic = this._italic;
this.textField.hAlign = this._hAlign;
this.textField.vAlign = this._vAlign;
this.textField.nativeFilters = this._nativeFilters;
}
if(dataInvalid || stylesInvalid || stateInvalid)
{
this.textField.text = this._text;
}
}
/**
* @private
*/
protected function layout(sizeInvalid:Boolean):void
{
var stylesInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STYLES);
var dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA);
if(sizeInvalid)
{
this.textField.width = this.actualWidth;
this.textField.height = this.actualHeight;
}
}
/**
* this component always requires dimensions to be set explicitly
*/
protected function autoSizeIfNeeded():Boolean
{
const needsWidth:Boolean = isNaN(this.explicitWidth);
const needsHeight:Boolean = isNaN(this.explicitHeight);
if(needsWidth || needsHeight)
throw new ArgumentError('width/height must be set explicitly to use AutoSizeTextRenderer');
return false;
}
/**
* @private
*/
protected function addedToStageHandler(event:Event):void
{
//we need to invalidate in order to get a fresh snapshot
this.invalidate(INVALIDATION_FLAG_SIZE);
}
/**
* @private
*/
protected function enterFrameHandler(event:Event):void
{
this.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
}
}
public class theme extends DisplayListwatcher
{
function theme()
{
setInitializerForClass(Button, buttonInitializer, 'buttonAutoScale');
}
private function initializeButton(b:Button):void
{
b.labelFactory = function():ITextRenderer {
var r:AutoSizeTextRenderer = new AutoSizeTextRenderer();
r.fontName = 'Verdana';
r.fontSize = 20;
r.width = b.width - b.paddingRight - b.paddingLeft;
r.height = b.height - b.paddingTop - b.paddingBottom;
r.color = 0xFFFFFF;
r.nativeFilters = [new DropShadowFilter(2, 45, 0x021725, .48, 2, 2)];
return r;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment