1  /*
     2   Copyright aswing.org, see the LICENCE.txt.
     3  */
     4  
     5  import org.aswing.ASColor;
     6  import org.aswing.ASFont;
     7  import org.aswing.ASTextExtent;
     8  import org.aswing.ASWingConstants;
     9  import org.aswing.ASWingUtils;
    10  import org.aswing.border.Border;
    11  import org.aswing.border.DecorateBorder;
    12  import org.aswing.Component;
    13  import org.aswing.geom.Rectangle;
    14  import org.aswing.graphices.Graphics;
    15  import org.aswing.graphices.Pen;
    16  import org.aswing.Insets;
    17  import org.aswing.utils.HashMap;
    18  
    19  /**
    20   * TitledBorder, a border with a line rectangle and a title text.
    21   * @author iiley
    22   */
    23  class org.aswing.border.TitledBorder extends DecorateBorder {
    24  		
    25  	public static function get DEFAULT_FONT():ASFont{
    26  		return ASFont.getASFont(null, null);
    27  	}
    28  	public static function get DEFAULT_COLOR():ASColor{
    29  		return ASColor.BLACK;
    30  	}
    31  	public static function get DEFAULT_LINE_COLOR():ASColor{
    32  		return ASColor.GRAY;
    33  	}
    34  	public static function get DEFAULT_LINE_LIGHT_COLOR():ASColor{
    35  		return ASColor.WHITE;
    36  	}
    37  	public static var DEFAULT_LINE_THICKNESS:Number = 1;
    38  		
    39  	public static var TOP:Number = ASWingConstants.TOP;
    40  	public static var BOTTOM:Number = ASWingConstants.BOTTOM;
    41  	
    42  	public static var CENTER:Number = ASWingConstants.CENTER;
    43  	public static var LEFT:Number = ASWingConstants.LEFT;
    44  	public static var RIGHT:Number = ASWingConstants.RIGHT;
    45  	
    46  
    47      // Space between the text and the line end
    48      public static var GAP:Number = 1;	
    49  	
    50  	private var title:String;
    51  	private var position:Number;
    52  	private var align:Number;
    53  	private var edge:Number;
    54  	private var round:Number;
    55  	private var font:ASFont;
    56  	private var color:ASColor;
    57  	private var lineColor:ASColor;
    58  	private var lineLightColor:ASColor;
    59  	private var lineThickness:Number;
    60  	private var beveled:Boolean;
    61  	private var textFields:HashMap;
    62  	var textFieldExtent:ASTextExtent;
    63  	
    64  	/**
    65  	 * TitledBorder(interior:Border, title:String, position:Number, align:Number, edge:Number, round:Number)<br>
    66  	 * TitledBorder(interior:Border, title:String, position:Number, align:Number, edge:Number)<br>
    67  	 * TitledBorder(interior:Border, title:String, position:Number, align:Number,)<br>
    68  	 * TitledBorder(interior:Border, title:String, position:Number)<br>
    69  	 * TitledBorder(interior:Border, title:String)<br>
    70  	 * @param title the title text string.
    71  	 * @param position the position of the title(TOP or BOTTOM), default is TOP
    72  	 * @param align the align of the title(CENTER or LEFT or RIGHT), default is CENTER
    73  	 * @param edge the edge space of title position, defaut is 0.
    74  	 * @param round round rect radius, default is 0 means normal rectangle, not rect.
    75  	 * @see org.aswing.border.SimpleTitledBorder
    76  	 * @see #setColor()
    77  	 * @see #setLineColor()
    78  	 * @see #setFont()
    79  	 * @see #setLineThickness()
    80  	 * @see #setBeveled()
    81  	 */
    82  	public function TitledBorder(interior:Border, title:String, position:Number, align:Number, edge:Number, round:Number){
    83  		super(interior);
    84  		this.title = title;
    85  		this.position = (position==undefined ? TOP : position);
    86  		this.align = (align==undefined ? CENTER : align);
    87  		this.edge = (edge==undefined ? 0 : edge);
    88  		this.round = (round==undefined ? 0 : round);
    89  		
    90  		font = DEFAULT_FONT;
    91  		color = DEFAULT_COLOR;
    92  		lineColor = DEFAULT_LINE_COLOR;
    93  		lineLightColor = DEFAULT_LINE_LIGHT_COLOR;
    94  		lineThickness = DEFAULT_LINE_THICKNESS;
    95  		beveled = true;
    96  		textFields = new HashMap();
    97  		textFieldExtent = font.getASTextFormat().getTextExtent(title);
    98  	}
    99  	
   100  	
   101  	public function paintBorderImp(c:Component, g:Graphics, bounds:Rectangle):Void{
   102      	var text_field:TextField = TextField(textFields.get(c.getID()));
   103      	if(text_field == null){
   104  	    	text_field = c.createTextField("titleBorder");
   105  	    	if(text_field != null){
   106      			textFields.put(c.getID(), text_field);
   107  	    	}
   108      	}
   109      	if(text_field == null){
   110      		return;
   111      	}
   112      	
   113      	var textHeight:Number = textFieldExtent.getTextFieldHeight();
   114      	var x1:Number = bounds.x + lineThickness*0.5;
   115      	var y1:Number = bounds.y + lineThickness*0.5;
   116      	if(position == TOP){
   117      		y1 += textHeight/2;
   118      	}
   119      	var w:Number = bounds.width - lineThickness;
   120      	var h:Number = bounds.height - lineThickness - textHeight/2;
   121      	if(beveled){
   122      		w -= lineThickness;
   123      		h -= lineThickness;
   124      	}
   125      	var x2:Number = x1 + w;
   126      	var y2:Number = y1 + h;
   127      	
   128      	var textR:Rectangle = new Rectangle();
   129      	var viewR:Rectangle = new Rectangle(bounds);
   130      	var text:String = title;
   131          var verticalAlignment:Number = position;
   132          var horizontalAlignment:Number = align;
   133      	
   134      	var pen:Pen = new Pen(lineColor, lineThickness);
   135      	if(round <= 0){
   136      		if(bounds.width <= edge*2){
   137      			g.drawRectangle(pen, x1, y1, w, h);
   138      			if(beveled){
   139      				pen.setASColor(lineLightColor);
   140      				g.beginDraw(pen);
   141      				g.moveTo(x1+lineThickness, y2-lineThickness);
   142      				g.lineTo(x1+lineThickness, y1+lineThickness);
   143      				g.lineTo(x2-lineThickness, y1+lineThickness);
   144      				g.moveTo(x2+lineThickness, y1);
   145      				g.lineTo(x2+lineThickness, y2+lineThickness);
   146      				g.lineTo(x1, y2+lineThickness);
   147      			}
   148      			text_field.text="";
   149      		}else{
   150      			viewR.x += edge;
   151      			viewR.width -= edge*2;
   152      			text = ASWingUtils.layoutText(font, text, verticalAlignment, horizontalAlignment, viewR, textR);
   153      			//draw dark rect
   154      			g.beginDraw(pen);
   155      			if(position == TOP){
   156  	    			g.moveTo(textR.x - GAP, y1);
   157  	    			g.lineTo(x1, y1);
   158  	    			g.lineTo(x1, y2);
   159  	    			g.lineTo(x2, y2);
   160  	    			g.lineTo(x2, y1);
   161  	    			g.lineTo(textR.x + textR.width+GAP, y1);
   162  	    				    			
   163      			}else{
   164  	    			g.moveTo(textR.x - GAP, y2);
   165  	    			g.lineTo(x1, y2);
   166  	    			g.lineTo(x1, y1);
   167  	    			g.lineTo(x2, y1);
   168  	    			g.lineTo(x2, y2);
   169  	    			g.lineTo(textR.x + textR.width+GAP, y2);
   170      			}
   171      			g.endDraw();
   172      			if(beveled){
   173  	    			//draw hightlight
   174  	    			pen.setASColor(lineLightColor);
   175  	    			g.beginDraw(pen);
   176  	    			if(position == TOP){
   177  		    			g.moveTo(textR.x - GAP, y1+lineThickness);
   178  		    			g.lineTo(x1+lineThickness, y1+lineThickness);
   179  		    			g.lineTo(x1+lineThickness, y2-lineThickness);
   180  		    			g.moveTo(x1, y2+lineThickness);
   181  		    			g.lineTo(x2+lineThickness, y2+lineThickness);
   182  		    			g.lineTo(x2+lineThickness, y1);
   183  		    			g.moveTo(x2-lineThickness, y1+lineThickness);
   184  		    			g.lineTo(textR.x + textR.width+GAP, y1+lineThickness);
   185  		    				    			
   186  	    			}else{
   187  		    			g.moveTo(textR.x - GAP, y2+lineThickness);
   188  		    			g.lineTo(x1, y2+lineThickness);
   189  		    			g.moveTo(x1+lineThickness, y2-lineThickness);
   190  		    			g.lineTo(x1+lineThickness, y1+lineThickness);
   191  		    			g.lineTo(x2-lineThickness, y1+lineThickness);
   192  		    			g.moveTo(x2+lineThickness, y1);
   193  		    			g.lineTo(x2+lineThickness, y2+lineThickness);
   194  		    			g.lineTo(textR.x + textR.width+GAP, y2+lineThickness);
   195  	    			}
   196  	    			g.endDraw();
   197      			}
   198      		}
   199      	}else{
   200      		if(bounds.width <= (edge*2 + round*2)){
   201      			if(beveled){
   202      				g.drawRoundRect(new Pen(lineLightColor, lineThickness), 
   203      							x1+lineThickness, y1+lineThickness, w, h, 
   204      							Math.min(round, Math.min(w/2, h/2)));
   205      			}
   206      			g.drawRoundRect(pen, x1, y1, w, h, 
   207      							Math.min(round, Math.min(w/2, h/2)));
   208      			text_field.text="";
   209      		}else{
   210      			viewR.x += (edge+round);
   211      			viewR.width -= (edge+round)*2;
   212      			text = ASWingUtils.layoutText(font, text, verticalAlignment, horizontalAlignment, viewR, textR);
   213  				var r:Number = round;
   214  
   215      			if(beveled){
   216      				pen.setASColor(lineLightColor);
   217  	    			g.beginDraw(pen);
   218  	    			var t:Number = lineThickness;
   219      				x1+=t;
   220      				x2+=t;
   221      				y1+=t;
   222      				y2+=t;
   223  	    			if(position == TOP){
   224  			    		g.moveTo(textR.x - GAP, y1);
   225  						//Top left
   226  						g.lineTo (x1+r, y1);
   227  						g.curveTo(x1, y1, x1, y1+r);
   228  						//Bottom left
   229  						g.lineTo (x1, y2-r );
   230  						g.curveTo(x1, y2, x1+r, y2);
   231  						//bottom right
   232  						g.lineTo(x2-r, y2);
   233  						g.curveTo(x2, y2, x2, y2-r);
   234  						//Top right
   235  						g.lineTo (x2, y1+r);
   236  						g.curveTo(x2, y1, x2-r, y1);
   237  						g.lineTo(textR.x + textR.width+GAP, y1);
   238  	    			}else{
   239  			    		g.moveTo(textR.x + textR.width+GAP, y2);
   240  						//bottom right
   241  						g.lineTo(x2-r, y2);
   242  						g.curveTo(x2, y2, x2, y2-r);
   243  						//Top right
   244  						g.lineTo (x2, y1+r);
   245  						g.curveTo(x2, y1, x2-r, y1);
   246  						//Top left
   247  						g.lineTo (x1+r, y1);
   248  						g.curveTo(x1, y1, x1, y1+r);
   249  						//Bottom left
   250  						g.lineTo (x1, y2-r );
   251  						g.curveTo(x1, y2, x1+r, y2);
   252  						g.lineTo(textR.x - GAP, y2);
   253  	    			}
   254  	    			g.endDraw();  
   255      				x1-=t;
   256      				x2-=t;
   257      				y1-=t;
   258      				y2-=t;  				
   259      			}		
   260      			pen.setASColor(lineColor);		
   261      			g.beginDraw(pen);
   262      			if(position == TOP){
   263  		    		g.moveTo(textR.x - GAP, y1);
   264  					//Top left
   265  					g.lineTo (x1+r, y1);
   266  					g.curveTo(x1, y1, x1, y1+r);
   267  					//Bottom left
   268  					g.lineTo (x1, y2-r );
   269  					g.curveTo(x1, y2, x1+r, y2);
   270  					//bottom right
   271  					g.lineTo(x2-r, y2);
   272  					g.curveTo(x2, y2, x2, y2-r);
   273  					//Top right
   274  					g.lineTo (x2, y1+r);
   275  					g.curveTo(x2, y1, x2-r, y1);
   276  					g.lineTo(textR.x + textR.width+GAP, y1);
   277      			}else{
   278  		    		g.moveTo(textR.x + textR.width+GAP, y2);
   279  					//bottom right
   280  					g.lineTo(x2-r, y2);
   281  					g.curveTo(x2, y2, x2, y2-r);
   282  					//Top right
   283  					g.lineTo (x2, y1+r);
   284  					g.curveTo(x2, y1, x2-r, y1);
   285  					//Top left
   286  					g.lineTo (x1+r, y1);
   287  					g.curveTo(x1, y1, x1, y1+r);
   288  					//Bottom left
   289  					g.lineTo (x1, y2-r );
   290  					g.curveTo(x1, y2, x1+r, y2);
   291  					g.lineTo(textR.x - GAP, y2);
   292      			}
   293      			g.endDraw();
   294      		}
   295      	}
   296      	text_field.text = text;
   297  		ASWingUtils.applyTextFontAndColor(text_field, font, color);
   298      	text_field._x = textR.x;
   299      	text_field._y = textR.y;
   300      }
   301      	   
   302      public function getBorderInsetsImp(c:Component, bounds:Rectangle):Insets{
   303      	var cornerW:Number = Math.ceil(lineThickness*2 + round - round*0.707106781186547);
   304      	var insets:Insets = new Insets(cornerW, cornerW, cornerW, cornerW);
   305      	if(position == BOTTOM){
   306      		insets.bottom += textFieldExtent.getTextFieldHeight();
   307      	}else{
   308      		insets.top += textFieldExtent.getTextFieldHeight();
   309      	}
   310      	return insets;
   311      }
   312      	
   313  	public function uninstallBorderImp(com:Component):Void{
   314  		var text_field:TextField = TextField(textFields.remove(com.getID()));
   315  		text_field.removeTextField();
   316  	}
   317  	
   318  	//-----------------------------------------------------------------
   319  
   320  	public function getFont():ASFont {
   321  		return font;
   322  	}
   323  
   324  	public function setFont(font:ASFont):Void {
   325  		if(this.font != font){
   326  			if(font == null) font = DEFAULT_FONT;
   327  			this.font = font;
   328  			textFieldExtent = font.getASTextFormat().getTextExtent(title);
   329  		}
   330  	}
   331  
   332  	public function getLineColor():ASColor {
   333  		return lineColor;
   334  	}
   335  
   336  	public function setLineColor(lineColor:ASColor):Void {
   337  		this.lineColor = lineColor;
   338  	}
   339  	
   340  	public function getLineLightColor():ASColor{
   341  		return lineLightColor;
   342  	}
   343  	
   344  	public function setLineLightColor(lineLightColor:ASColor):Void{
   345  		this.lineLightColor = lineLightColor;
   346  	}
   347  	
   348  	public function isBeveled():Boolean{
   349  		return beveled;
   350  	}
   351  	
   352  	public function setBeveled(b:Boolean):Void{
   353  		beveled = b;
   354  	}
   355  
   356  	public function getEdge():Number {
   357  		return edge;
   358  	}
   359  
   360  	public function setEdge(edge:Number):Void {
   361  		this.edge = edge;
   362  	}
   363  
   364  	public function getTitle():String {
   365  		return title;
   366  	}
   367  
   368  	public function setTitle(title:String):Void {
   369  		if(this.title != title){
   370  			this.title = title;
   371  			textFieldExtent = font.getASTextFormat().getTextExtent(title);
   372  		}
   373  	}
   374  
   375  	public function getRound():Number {
   376  		return round;
   377  	}
   378  
   379  	public function setRound(round:Number):Void {
   380  		this.round = round;
   381  	}
   382  
   383  	public function getColor():ASColor {
   384  		return color;
   385  	}
   386  
   387  	public function setColor(color:ASColor):Void {
   388  		this.color = color;
   389  	}
   390  
   391  	public function getAlign():Number {
   392  		return align;
   393  	}
   394  	
   395  	/**
   396  	 * Sets the align of title text.
   397  	 * @see #CENTER
   398  	 * @see #LEFT
   399  	 * @see #RIGHT
   400  	 */
   401  	public function setAlign(align:Number):Void {
   402  		this.align = align;
   403  	}
   404  
   405  	public function getPosition():Number {
   406  		return position;
   407  	}
   408  	
   409  	/**
   410  	 * Sets the position of title text.
   411  	 * @see #TOP
   412  	 * @see #BOTTOM
   413  	 */
   414  	public function setPosition(position:Number):Void {
   415  		this.position = position;
   416  	}	
   417  	
   418  	public function getLineThickness():Number {
   419  		return lineThickness;
   420  	}
   421  
   422  	public function setLineThickness(lineThickness:Number):Void {
   423  		this.lineThickness = lineThickness;
   424  	}	
   425  
   426  }
   427