File: presentation.bs

package info (click to toggle)
storm-lang 0.7.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 52,028 kB
  • sloc: ansic: 261,471; cpp: 140,432; 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 (323 lines) | stat: -rw-r--r-- 8,045 bytes parent folder | download | duplicates (2)
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
use ui;
use core:geometry;
use graphics;

/**
 * A presentation.
 *
 * A presentation consists of a number of Slides, each of which contains a number of Elements to be
 * laid out in a certain way and displayed on the screen. Each slide may contain animations that
 * alter the state or layout of elements on the screen.
 *
 * In addition to the slides, the Presentation object contains global settings and resources for the
 * presentation in its entirety, such as background color, page numbering etc.
 */
class Presentation on Render {
	// Title of the presentation. Used in the title of the presentation viewer window.
	Str title;

	// Size of the coordinate system in the slides. Defaults to 1024x768, but may be modified
	// freely, for example by calling `makeWide` to make the presentation into a 16:9 aspect ratio.
	Size size;

	// Top and left border around slides.
	Size topLeftBorder;

	// Bottom and right border around slides.
	Size bottomRightBorder;

	// Set the entire border at the same time. Assign function, so it is possible to treat `border` as a variable.
	assign border(Size border) {
		topLeftBorder = bottomRightBorder = border;
	}

	// Default text style for headings.
	TextStyle headingStyle;

	// Default text style for the content of slides.
	TextStyle contentStyle;

	// Default heading alignment.
	Cardinal headingAlign;

	// Left margin of the content in the caption layout. This is in addition to the slide border.
	Float contentLeftMargin;

	// Right margin of the content in the caption layout. This is in addition to the slide border.
	Float contentRightMargin;

	// Default animation time.
	Duration animationTime;

	// All slides in the presentation.
	private Slide[] slides;

	// The background.
	private Slide myBackground;

	// Create.
	init(Str title) {
		Size size(640, 480);
		Size border(20, 20);

		layout:Border bgLayout;
		bgLayout.border = Size(0);
		bgLayout.add(component(SolidFill(white)));

		init() {
			title = title;
			size = size;
			topLeftBorder = border;
			bottomRightBorder = border;
			myBackground = Slide(bgLayout);
			headingStyle = defaultHeadingStyle;
			contentStyle = defaultContentStyle;
			headingAlign = west;
			animationTime = 200 ms;
		}

		myBackground.added(this);
	}

	// Make the presentation into 16:9 format.
	void makeWide() {
		size = Size(size.h * 16 / 9, size.h);
	}

	// Make the presentation into 4:3 format.
	void makeNarrow() {
		size = Size(size.h * 4 / 3, size.h);
	}

	// Perform any cleanup necessary.
	void cleanup() {
		for (slide in slides)
			slide.cleanup();
	}

	// Attach a repaint callback if any elements require the ability.
	void setupRepaint(Fn<void> callback) {
		for (slide in slides)
			slide.setupRepaint(callback);
	}


	/**
	 * A cursor to a position inside a presentation, excluding the timecode of any current
	 * animation.
	 *
	 * The entire state is stored in this class, so that a single application may have multiple
	 * cursors into the same presentation. It is then possible to render the presentation at the
	 * different stages at will.
	 *
	 * Do not modify this object directly, use the corresponding functions inside the Presentation
	 * class instead.
	 */
	public class Cursor {
		// Current slide.
		package Nat slide;

		// Current animation inside the slide.
		package Nat step;

		// Create a state representing the first slide in a presentation.
		init() {
			init() {
				slide = 0;
				step = 0;
			}
		}

		// Convenience constructor for use internally.
		package init(Nat slide, Nat step) {
			init() {
				slide = slide;
				step = step;
			}
		}

		// To string.
		void toS(StrBuf to) {
			to << "{ slide " << slide << ", step " << step << " }";
		}

		// Compare.
		Bool ==(Cursor other) {
			slide == other.slide & step == other.step;
		}
	}

	// The background slide.
	Slide background() { myBackground; }

	// Set the background slide. Allows treating `background` as a variable.
	assign background(Slide s) {
		myBackground = s;
		s.added(this);
	}

	// Add a slide.
	void add(Slide s) {
		slides << s;
		s.added(this);
	}

	// Draw the presentation in its current state. Assumes 'g' has been set up to match the slide
	// size. 'time' is a number in the interval [0, 1] that indicates the position of the current
	// animation. 1.0 means complete, and 0.0 means it has just started. 'pos' is the state of the
	// current slide, and 'last' is the state of the previous state in the presentation. This is
	// used to provide good slide transitions.
	void draw(Graphics g, Cursor pos, Cursor? last, Float time) {
		Nat slide = pos.slide;
		if (slide >= slides.count) {
			return;
		}

		Slide curr = slides[slide];
		if (pos.step == 0 & time < 1.0) {
			if (intro = curr.intro) {
				Duration d = max(curr.duration(0), intro.duration);
				intro.draw(this, g, pos, last, d * time);
				return;
			}
		}

		drawSlide(g, pos, curr.duration(pos.step) * time);
	}

	// Draw a slide, complete with background and any overlays. Expected to be used from intro
	// animations.
	void drawSlide(Graphics g, Cursor cursor, Duration time) {
		var slide = cursor.slide;
		if (slide < slides.count) {
			background.draw(g, slide, background.duration(slide));
			slides[cursor.slide].draw(g, cursor.step, time);
		}
	}

	// Draw a slide that is not the current one.
	void drawSlide(Graphics g, Cursor cursor) {
		if (cursor.slide < slides.count) {
			Slide s = slides[cursor.slide];
			drawSlide(g, cursor, s.duration(cursor.step));
		}
	}

	// Get the animation state representing the beginning of the presentation. Expected to be used
	// from intro animations.
	Cursor begin() {
		Cursor(0, 0);
	}

	// Get the state representing the end of the presentation.
	Cursor end() {
		Cursor(slides.count, 0);
	}

	// Get the state for the n:th slide.
	Cursor at(Nat id) {
		Cursor(min(id, slides.count), 0);
	}

	// Get the next state.
	Cursor next(Cursor s) {
		if (s.slide >= slides.count)
			return s;

		Slide slide = slides[s.slide];
		if (s.step + 1 >= slide.stepCount)
			Cursor(s.slide + 1, 0);
		else
			Cursor(s.slide, s.step + 1);
	}

	// Get the state representing a jump to the next slide, skipping any animations in the current slide.
	Cursor nextSlide(Cursor s) {
		Cursor(min(s.slide + 1, slides.count), 0);
	}

	// Get the previous state.
	Cursor prev(Cursor s) {
		// TODO: Do we want to go back one step, or the entire slide?
		if (s.step > 0) {
			Cursor(s.slide, 0);
		} else if (s.slide > 0) {
			Cursor(s.slide - 1, 0);
		} else {
			Cursor(0, 0);
		}
	}

	// Get the slide that a cursor refers to.
	Slide? slide(Cursor c) {
		if (c.slide < slides.count)
			return slides[c.slide];
		else
			return null;
	}

	// Get the duration of a specific animation. Returns 0 ms if no animation is used for the
	// specified state.
	Duration duration(Cursor s) {
		if (s.slide >= slides.count)
			return Duration();

		Slide slide = slides[s.slide];
		Duration r = slide.duration(s.step);

		// Intro?
		if (s.step == 0)
			if (intro = slide.intro)
				r = max(r, intro.duration);

		r;
	}

	// Get an element from the current slide at a particular position. Does not examine the
	// background slide.
	Element? elementAt(Cursor pos, Point pt) {
		Nat slide = pos.slide;
		if (slide >= slides.count)
			return null;

		return slides[slide].elementAt(pt);
	}
}


/**
 * A description of text-styles. Used to specify defaults in a presentation so that one doesn't need
 * to specify the same style all over the place.
 */
class TextStyle on Render {
	// Font.
	Font font;

	// Brush used to fill the text.
	Brush fill;

	// Spacing.
	Float space;

	// Create.
	init(Font font, Brush fill, Float space) {
		init() {
			font = font;
			fill = fill;
			space = space;
		}
	}

	// Create.
	init(Font font, Color fill, Float space) {
		init() {
			font = font;
			fill = SolidBrush(fill);
			space = space;
		}
	}
}

// Default text styles.
TextStyle defaultHeadingStyle() on Render { TextStyle(Font("Arial", 32), black, 30); }
TextStyle defaultContentStyle() on Render { TextStyle(Font("Arial", 22), black, 10); }