File: coloredText.bs

package info (click to toggle)
storm-lang 0.7.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 52,004 kB
  • sloc: ansic: 261,462; cpp: 140,405; sh: 14,891; perl: 9,846; python: 2,525; lisp: 2,504; asm: 860; makefile: 678; pascal: 70; java: 52; xml: 37; awk: 12
file content (182 lines) | stat: -rw-r--r-- 3,161 bytes parent folder | download | duplicates (4)
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
use ui;
use core:io;
use core:geometry;
use graphics;

/**
 * An element that renders text colored as specified.
 *
 * Does not do automatic word wrapping.
 */
class ColoredText extends Element {
	// Font for the text.
	private Font font;

	// Default fill brush.
	private Brush defaultBrush;

	// Lines of text to draw.
	private Line[] lines;

	// Marked regions.
	private Marked[] marked;

	// Remember where labels start.
	private Str->Nat labels;

	// Create.
	init(TextStyle style) {
		init() {
			font = style.font;
			defaultBrush = style.fill;
		}

		// Start the first line.
		nextLine();
	}

	// Add a chunk of text with the default color.
	void text(Str t) {
		text(t, defaultBrush);
	}

	// Add a chunk of text with the specified brush.
	void text(Str t, Brush b) {
		lines.last.add(Chunk(Text(t, font), b));

		var w = lines.last.width;
		for (m in marked) {
			m.rect.p1.x = max(m.rect.p1.x, w);
		}
	}

	// Add a chunk of text with the specified color.
	void text(Str t, Color c) {
		text(t, SolidBrush(c));
	}

	// Skip to the next line.
	void nextLine() {
		lines << Line();
	}

	// Begin a marked text region.
	void begin(Str label) {
		Nat id = lines.count;
		if (id > 0) id--;
		labels.put(label, id);
	}

	// End a marked text region.
	void end(Str label, Color border, Color fill) {
		Nat from = labels.get(label);
		Nat to = lines.count;

		Rect pos;
		Float y = 0;
		for (i, line in lines) {
			pos.p1.x = max(pos.p1.x, line.width);
			if (i == from) {
				pos.p0.y = y;
			}
			if (i < to) {
				pos.p1.y = y;
			}

			y += line.height;
		}

		marked << Marked(pos, SolidBrush(border), SolidBrush(fill));
	}

	// Minimum size.
	Size minSize() : override {
		Size total;
		for (l in lines) {
			total.w = max(total.w, l.width);
			total.h += l.height;
		}
		total;
	}

	// Draw.
	void draw(Graphics g) : override {
		Point at = pos.p0;
		for (m in marked) {
			Rect r = m.rect + at;
			g.draw(r, m.border);
			if (fill = m.fill)
				g.fill(r, fill);
		}

		for (l in lines) {
			l.draw(g, at);
			at.y += l.height;
		}
	}

	// Representation of a single line.
	private class Line on Render {
		// Total height of the line.
		Float height;

		// Total width of the line.
		Float width;

		// Get the size.
		Size size() {
			Size(width, height);
		}

		// Individual text chunks in the line.
		Chunk[] chunks;

		// Add a chunk, keep the height updated.
		void add(Chunk chunk) {
			chunks << chunk;
			Size sz = chunk.text.size;
			height = max(height, sz.h);
			width += sz.w;
		}

		// Draw!
		void draw(Graphics g, Point at) {
			for (c in chunks) {
				Size sz = c.text.size;
				g.draw(c.text, c.fill, Point(at.x, at.y + height - sz.h));
				at.x += sz.w;
			}
		}
	}

	// A chunk of text.
	private value Chunk {
		// Text.
		Text text;

		// Color.
		Brush fill;

		// Create.
		init(Text t, Brush b) {
			init() { text = t; fill = b; }
		}
	}

	// A marked region of text.
	private class Marked {
		// Border color.
		Brush border;

		// Fill color.
		Brush? fill;

		// Rectangle to fill.
		Rect rect;

		// Create.
		init(Rect rect, Brush border, Brush? fill) {
			init() { border = border; fill = fill; rect = rect; }
		}
	}
}