-
Notifications
You must be signed in to change notification settings - Fork 1
/
OutputMessageBox.as
149 lines (123 loc) · 5.31 KB
/
OutputMessageBox.as
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Widget to show a series of game messages
// Author: [email protected]
// License: MIT
// Features:
// * Shows player icon
// * Shows player name in bold
// * Word wraps underneath player name, not under icon (icons serve as bullet points)
// * System messages look different from regular messages
// * Works with Unicode characters (including CJK)
// TODO: add hover over player icon
// TODO: add menu on player icon click
// TODO: add scrollback capability
package {
import amitp.*;
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.geom.Rectangle;
import flash.text.engine.*;
import com.gskinner.motion.GTween;
public class OutputMessageBox extends Sprite {
// The messages are represented as child Sprites. Each one
// contains a rendered TextBlock. We remember where we need to
// add the next sprite, and what the overall container size is:
private var nextYPosition:Number = 0.0;
private var maxWidth:Number;
private var maxHeight:Number;
// General configuration:
static public var MARGIN:Number = 2.0;
static public var LINE_SPACING:Number = 4.0;
static public var FONT:String = "Helvetica,Arial,_sans";
// Text formatting:
private var systemFormat:ElementFormat = new ElementFormat();
private var fromFormat:ElementFormat = new ElementFormat();
private var separatorFormat:ElementFormat = new ElementFormat();
private var textFormat:ElementFormat = new ElementFormat();
// Scrolling with a tween:
public var scrollPositionTween:GTween = new GTween(this, 0.1, {}, {});
public function get scrollPosition():Number { return scrollRect.y; }
public function set scrollPosition(position:Number):void {
// Flash note: Set .y instead of .top to preserve the rectangle
// height. Assign the rect back to scrollRect to trigger the
// setter method.
var rect:Rectangle = scrollRect;
rect.y = position;
scrollRect = rect;
}
// The constructor requires the expected size of this element so
// that we can set up a scroll box and clipping.
public function OutputMessageBox(w:Number, h:Number) {
var font1:FontDescription = new FontDescription(FONT, FontWeight.BOLD);
var font2:FontDescription = new FontDescription(FONT);
maxWidth = w;
maxHeight = h;
scrollRect = new Rectangle(0, 0, w, h);
systemFormat.fontSize = 14;
systemFormat.color = 0x0000ff;
systemFormat.fontDescription = font1;
fromFormat.fontSize = 12;
fromFormat.color = 0x009966;
fromFormat.fontDescription = font1;
separatorFormat.fontSize = 12;
separatorFormat.color = 0x999999;
separatorFormat.fontDescription = font2;
textFormat.fontSize = 12;
textFormat.fontDescription = font2;
}
// Add a text block with plain text from the game system
public function addSystemText(text:String):void {
var textBlock:TextBlock = new TextBlock();
textBlock.content = new TextElement(text, systemFormat);
addTextBlock(textBlock);
}
// Add a text block with chat text from a creature
public function addChat(icon:DisplayObject, from:String, systemText:String, userText:String):void {
var v:Vector.<ContentElement> = new Vector.<ContentElement>();
if (icon != null) v.push(new GraphicElement(icon, icon.width+2, icon.height-LINE_SPACING/2, fromFormat));
v.push(new TextElement(from, fromFormat),
new TextElement(systemText, separatorFormat),
new TextElement(userText, textFormat));
var groupElement:GroupElement = new GroupElement(v);
var textBlock:TextBlock = new TextBlock();
textBlock.content = groupElement;
addTextBlock(textBlock);
}
// Remove any children that are completely off screen.
private function removePastTextBlocks():void {
// This loop has two exit conditions: either there are
// no children left, or the first child is in the scroll
// rectangle.
while (true) {
if (numChildren == 0) break;
var rect:Rectangle = getChildAt(0).getBounds(this);
if (rect.bottom >= scrollRect.top) break;
removeChildAt(0);
}
}
// Add the text block to the sprite by creating a parent sprite
// and splitting the text block into individual text lines. Adjust
// the scroll position if necessary.
private function addTextBlock(textBlock:TextBlock):void {
removePastTextBlocks();
var block:Sprite = new Sprite();
var firstLineExtra:Number = 20;
var lineLength:Number = maxWidth - firstLineExtra - 2*MARGIN;
var xPosition:Number = MARGIN;
var textLine:TextLine = textBlock.createTextLine(null, lineLength + firstLineExtra);
while (textLine) {
block.addChild(textLine);
textLine.x = xPosition;
nextYPosition += textLine.height+LINE_SPACING;
textLine.y = nextYPosition;
xPosition = firstLineExtra + MARGIN;
textLine = textBlock.createTextLine(textLine, lineLength);
}
addChild(block);
// We want nextYPosition to be the bottom of the scroll
// rectangle, or above.
if (nextYPosition > scrollRect.bottom - LINE_SPACING) {
scrollPositionTween.setValue('scrollPosition', nextYPosition - maxHeight + LINE_SPACING);
}
}
}
}