2
* This file is part of the dis-Emi-A HaXe Library. Copyright (c) edA-qa mort-ora-y
3
* For full copyright and license information please refer to doc/license.txt.
8
import flash.display.Sprite;
9
import flash.events.Event;
11
import flash.text.TextField;
12
import flash.text.TextFormat;
13
import flash.text.TextFormatAlign;
15
import mathx.MatPoint;
20
* This is to try and provide a better interface to static text fields in Flash.
21
* Flash doesn't allow creation of StaticText fields, the ones with which transformations
22
* can be done, and the TextField class sucks.
24
* For now this is a simple wrapper to the stupid TextField class.
29
* -clipping to target box
31
* -autosize to height of box (TODO: Add guaranteed fit mode)
32
* -rotation (though an imported font must be used in flash)
35
* -proper scaling (only font-size is supported, no arbitrary scaling)
36
* -cannot removed gutter( fixed at 2 in flash, stupid)
37
* -maximum size (flash seems to max out at format.size == 127)
38
* -minimum size (judging from appearance)
40
* NOTE: The text field will fill up the height of the given space based on the font
41
* height. For mot texts this may appear to be misaligned ascenders and descenders
42
* are not likely being used, if they were, everything would look more correct.
44
class StaticText extends Sprite, implements Widget
47
public var align(default, setTextAlign) : StaticTextAlign;
48
var clipMask : Sprite;
49
var suppressLayout : Bool;
50
var prefLineHeight : Float;
52
var prefNumRowsCols : MatPoint; //for multiline controls
55
var minNumRowsCols : MatPoint;
56
var maxNumRowsCols : MatPoint;
58
var scrollY : Scrollbar;
61
public var fillColor : Color;
62
public var constrainWidth : Bool;
64
function new( initText : String, ?align : StaticTextAlign, ?clip : Null<Bool> )
72
constrainWidth = true;
74
//in general I suspect the defaults for multilines are less than useful...
75
prefNumRowsCols = MatPoint.at( Math.floor(FontManager.cols / 2), Math.floor(FontManager.rows / 3) );
77
fillColor = null; //by default not background
79
//setup Flash native field
81
tf.selectable = false;
83
tf.textColor = Theme.current.textColor.asInt();
86
font = Theme.current.textFont;
87
tf.y = -font.getGutter(); //to remove wacky gutter
93
this.align = StaticTextAlign.Center;
96
*NOTE: Somethign about how this was done before caused Flash to always crash.
97
* I was creating a new object each time, but perhaps it was because I was removing
98
* the clipMaks without clearing it from the textField?
99
* I reduced the situation by not recreated clipping masks, but it is still there, using
100
* them causes the player to crash (during GC'ing it seems, based on timing with
103
//setup clipping (is this even needed?, text-test seems to work without)
108
clipMask = new Sprite();
109
addChild( clipMask );
113
addEventListener( Event.ADDED, onAdded );
114
tf.addEventListener( Event.SCROLL, onScrolled );
115
tf.addEventListener( Event.CHANGE, onChanged );
116
suppressLayout = false;
120
* Creates a single-line static text control.
122
* @param initText [in] the initial text to display
123
* @param align [in] the alignment of the text
124
* @param clip [in] to restrict text to the size of the control, if false text flows out of bounding box
125
* @param lineHeight [in] used in calculating preferred sizes to determine how large the text should be
126
* (NOTE: Use only for preferred size, actual size depends on final box size)
128
static public function singleLine( initText : String, ?align : StaticTextAlign, ?clip : Null<Bool>, ?lineHeight : Null<Float> ) : StaticText
130
var st = new StaticText( initText, align, clip );
131
if( lineHeight != null )
132
st.prefLineHeight = lineHeight;
133
st.noScrollY = true; //never have a scroll bar for single lines
138
* Creates a text field suitable for displaying large amounts of text,
139
* appropriate sizes and scrolling will be added as needed.
141
static public function scrollText( initText : String, ?align : StaticTextAlign, ?prefRowsCols : MatPoint ) : StaticText
143
var st = new StaticText( initText, align );
144
st.tf.multiline = true;
145
st.tf.wordWrap = true;
146
if( prefRowsCols != null )
147
st.prefNumRowsCols = prefRowsCols.clone();
152
//caller must update() since normally associated with some other change
153
public function setPrefRowsCols( prc : MatPoint )
155
prefNumRowsCols = prc.clone();
158
static public function autoSizing( initText : String, prefLineHeight : Float, minRowsCols : MatPoint, maxRowsCols : MatPoint, ?align : StaticTextAlign ) : StaticText
160
var st = new StaticText( initText, align );
161
st.tf.multiline = true;
162
st.tf.wordWrap = true;
163
st.minNumRowsCols = minRowsCols;
164
st.maxNumRowsCols = maxRowsCols;
165
st.prefLineHeight = prefLineHeight;
172
if( minNumRowsCols != null )
174
//this is very hard to precalculate, I'm just not sure how entirely
175
//thus we'll simply step through the allotted lines and take the one where the text first fits
176
for( numLines in minNumRowsCols.y...(maxNumRowsCols.y+1) )
178
var factor = (numLines - minNumRowsCols.y) / (maxNumRowsCols.y - minNumRowsCols.y);
179
var width = Math.round( factor * (maxNumRowsCols.x - minNumRowsCols.x) + minNumRowsCols.x );
181
autoSizeTo( width, numLines );
183
//if it fits, then we're almost done
184
if( tf.numLines <= numLines )
186
//resize to the number lines actually needed (with may have added a blank)
187
if( tf.numLines < numLines )
188
autoSizeTo( width, tf.numLines );
197
function autoSizeTo( width : Int, lines : Int )
199
prefNumRowsCols = MatPoint.at( width, lines );
200
//this may leave a small gap at the bottom since font sizes are somehow rounding to int
201
//but since it isn't the line height, this is very difficult to get exactly correct
202
resize( font.byXWidth( width, prefLineHeight ), lines * prefLineHeight );
206
* By default the text in a StaticText field cannot be selected, though
207
* in an Edit field it can be.
208
* This functions turns on the selection for static text fields
210
/*final*/ public function enableSelectable()
212
tf.selectable = true;
215
/*final*/ public function disableScrollY()
221
/*final*/ public function selectAll()
223
tf.setSelection( 0, tf.text.length );
226
/*final*/ public function getScrollYEnd()
231
return tf.maxScrollV;
234
/*final*/ public function setScrollY( at : Int )
239
/*final*/ function checkScroll( withUpdate: Bool )
241
//only multiline has a scrollbar (vertical only for now...)
245
var oldScrollY = scrollY != null;
246
var hasScrollY = tf.maxScrollV > 1 && !noScrollY; //flash starts at 1 for some reason
251
if( scrollY == null )
253
scrollY = Scrollbar.vertical();
255
scrollY.addEventListener( UIEvent.USER_CHANGE,
256
function( evt : Event ) { me.setScrollY( Math.floor(me.scrollY.at) ); } );
261
scrollY.setRange( 1, tf.maxScrollV, 1 );
262
scrollY.at = tf.scrollV;
264
else if( scrollY != null )
267
removeChild( scrollY );
271
if( changed && withUpdate )
276
/*protected*/ function onChanged( evt : Event )
281
/*final*/ function onScrolled( evt : Event )
283
if( scrollY != null )
284
scrollY.at = tf.scrollV;
287
/*final*/ function onAdded( evt : Event )
289
if( evt.target != this )
295
/*final*/ public function setTextAlign( a : StaticTextAlign ) : StaticTextAlign
302
public var text( getText, setText ) : String; //FAKE
303
public function setText( t : String ) : String
305
//do nothing if its the same (save some cycles)
315
public function getText( ) : String
321
public var htmlText( getHTMLText, setHTMLText ) : String;//FAKE
322
public function setHTMLText( t : String ) : String
324
if( tf.htmlText == t )
333
public function getHTMLText() : String
339
public var bold( getBold, setBold ) : Bool; //FAKE
341
public function setBold( b : Bool) : Bool
343
var fmt = new TextFormat();
345
tf.setTextFormat( fmt );
350
public function getBold( ) : Bool
352
return tf.getTextFormat().bold;
355
public var textColor( getTextColor, setTextColor ) : Color; //FAKE
357
public function setTextColor( c : Color ) : Color
359
tf.textColor = c.asInt();
363
public function getTextColor( ) : Color
365
return Color.int( tf.textColor );
368
public var font( getFont, setFont ) : FontManager;
370
public function getFont() : FontManager
375
public function setFont( font : FontManager ) : FontManager
379
var fmt = new TextFormat();
380
fmt.font = font.fontName;
381
tf.setTextFormat( fmt );
382
tf.embedFonts = font.isEmbedded;
388
function draw( w : Float, h : Float )
391
//graphics.lineStyle( 0, 0 );
392
if( fillColor != null )
393
graphics.beginFill( fillColor.asInt() );
394
graphics.drawRect( 0, 0, w, h );
398
* The core of the class which determines how the TextField should
399
* actually be formatted.
401
function _resize( w : Float, h : Float )
403
if( tf==null || suppressLayout )
407
if( scrollY != null )
409
scrollYX = font.xWidth * 1.5; //always 1.5 x wide
410
scrollY.move( w - scrollYX, 0 );
411
scrollY.resize( scrollYX, h );
414
tf.width = w - scrollYX;
415
tf.height = h + 2 *font.getGutter(); //accomodate gutters in height (top/bottom)
418
var fmt = new TextFormat();
420
fmt.size = font.fontSizeForHeight( h / prefNumRowsCols.y );
422
fmt.size = font.fontSizeForHeight( h );
424
//FLASH: max size for Flash, it will ignore higher sizes, but it messages up our calculations later
425
//TODO: is this perhaps only for device fonts?
429
//patchup for some fonts (TODO: with scrolling what happens?)
430
tf.y = fmt.size * font.padAscent;
432
/* START: Flash nonsense workaround */
436
fmt.align = TextFormatAlign.LEFT;
438
fmt.align = TextFormatAlign.RIGHT;
440
fmt.align = TextFormatAlign.CENTER;
444
//without this it doesn't work, *very* odd... (only if font.isEmbedded!)
445
//TODO: perhaps this is why <font> tags don't work though in htmlText
446
fmt.font = font.fontName;
448
tf.setTextFormat( fmt );
450
//constrain width to available space (NOTE: see Flash note below, this never works correctly!)
451
//var tw = tf.getLineMetrics(0).width + 2 * font.getGutter();
452
var tw = tf.textWidth + 2 * font.getGutter();
453
if( constrainWidth && tw > tf.width && !tf.multiline )
455
//NOTE: we are sometimes still 1 size too high :( ...
456
var oldSize : Float = fmt.size * 1.0;
457
fmt.size = Math.floor( oldSize / (tw / tf.width) - 0.5 ); //... thus - 0.5, seems to work
458
//trace( oldSize + " / ( " + tw + " / " + tf.width + ") = " + fmt.size );
459
tf.setTextFormat( fmt );
462
/* NOTE: This can't be used since Flash is junk when it comes to handling
463
dynamic text and scaling. There is no way to get the *REAL* width of
464
the text at this point, based on the new fmt. We are forced to rely on
465
the broken TextAlign mechanism, done above...
466
(width will be taken from initial rescale function)
467
//Crap, this is of the old font, before setTextFormat is called!!! (or something odd, the width is just wrong!)
468
//Though RIGHT Align doesn't work in Flash if width is greater than box... :(
469
var tw = tf.getLineMetrics(0).width + 2 * gutter;
471
//trace( tf.text + ":" + tw );
480
tf.x = (w/2) - (tw/2);
484
//clip text to our borders
485
if( clipMask != null )
487
clipMask.graphics.clear();
488
clipMask.graphics.beginFill( 0xFFFFFF );
489
clipMask.graphics.drawRect( 0, 0, w, h );
490
clipMask.graphics.endFill();
493
//we need to also check in the case of a resize, no just textual changes,
494
//the trick is however that until we size the TextField we won't know if we
495
//need a scrollbar, so thus this recusrion here -- ARGH!! Flash strikes again,
496
//somehow the scrolling parts of a text-field aren't set synchronously!!! This only
497
//seems to happen when the control is changing visibility...
498
//TODO:we're assuming it will never flip-flop, but that may be a false assumption
499
if( checkScroll( false ) )
503
public function getPrefWidth() : SizeType
506
return SizeType.XWidth( prefNumRowsCols.x );
507
return SizeType.XWidth(
508
font.xWidthOf( tf.text, prefLineHeight, getBold() )
509
+ 0.5 //to account for any gutters
513
public function getPrefHeight() : SizeType
516
return SizeType.Lines( prefNumRowsCols.y * prefLineHeight );
517
return SizeType.Lines( prefLineHeight );
520
define(`NoSizing',`')
521
include(`MixinWidget.ihx')