Implement border/noborder window flags
[projects/chimara/chimara.git] / tests / splittest.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <libchimara/glk.h>
4
5 #define SPACE_FACTOR 1.8
6
7 void center_text(winid_t win, char *text)
8 {
9         glui32 width, height;
10         glk_window_get_size(win, &width, &height);
11         
12         glk_set_window(win);
13         glk_window_clear(win);
14         
15         if(glk_window_get_type(win) == wintype_TextGrid) {
16                 glk_window_move_cursor(win, width / 2 - strlen(text) / 2, height / 2);
17                 glk_put_string(text);
18         } else if(glk_window_get_type(win) == wintype_TextBuffer) {
19                 int count;
20                 for(count = 0; count < height / 2; count++)
21                         glk_put_char('\n');
22                 for(count = 0; 
23                         count < (int)(SPACE_FACTOR * (width / 2 - strlen(text) / 2)); 
24                         count++)
25                         glk_put_char(' ');
26                 glk_put_string(text);
27         }
28 }
29
30 void print_two_rows(winid_t win)
31 {
32         glui32 width, height;
33         glk_window_get_size(win, &width, &height);
34         
35         glk_set_window(win);
36         glk_window_clear(win);
37         
38         glui32 x = width / 2 - 3;
39         glui32 y = (height - 1) / 2;
40         if(x < 0) 
41                 x = 0;
42         if(y < 0)
43                 y = 0;
44         
45         glk_window_move_cursor(win, x, y);
46         glk_put_string("C: 2");
47         glk_window_move_cursor(win, x + 3, y + 1);
48         glk_put_string("rows");
49 }
50
51 void wait_for_key(winid_t win)
52 {
53     event_t ev;
54         glk_request_char_event(win);
55         do
56                 glk_select(&ev);
57     while(ev.type != evtype_CharInput);
58 }
59
60 void glk_main(void)
61 {
62     winid_t win_a = NULL, win_b = NULL, win_c = NULL, win_d = NULL;
63         
64         fprintf(stderr, "TEST CASES FROM GLK SPEC\n\n"
65                         "(Press a key in window A to continue each time)\n\n"
66                         "Say you do two splits, each a 50-50 percentage split. You start\n"
67                         "with the original window A, and split that into A and B; then\n"
68                         "you split B into B and C.\n\n");
69         
70         win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
71         win_b = glk_window_open(win_a, winmethod_Proportional | winmethod_Below,
72                                                         50, wintype_TextBuffer, 0);
73         win_c = glk_window_open(win_b, winmethod_Proportional | winmethod_Below,
74                                                         50, wintype_TextBuffer, 0);
75         if(!win_a || !win_b || !win_c)
76                 return;
77         center_text(win_a, "A");
78         center_text(win_b, "B");
79         center_text(win_c, "C");
80         
81         wait_for_key(win_a);
82         glk_window_close(glk_window_get_root(), NULL);
83         
84         fprintf(stderr, "Or, you could split A into A and B, and then split A\n"
85                         "again into A and C.\n\n");
86         
87         win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
88         win_b = glk_window_open(win_a, winmethod_Proportional | winmethod_Below,
89                                                         50, wintype_TextBuffer, 0);
90         win_c = glk_window_open(win_a, winmethod_Proportional | winmethod_Below,
91                                                         50, wintype_TextBuffer, 0);
92         if(!win_a || !win_b || !win_c)
93                 return;
94         center_text(win_a, "A");
95         center_text(win_b, "B");
96         center_text(win_c, "C");
97         
98         wait_for_key(win_a);
99         glk_window_close(glk_window_get_root(), NULL);
100         
101         fprintf(stderr, "Here are more ways to perform the first example; all of\n"
102                         "them have the same tree structure, but look different on the\n"
103                         "screen. Here, we turn the second split (B into B/C) upside down;\n"
104                         "we put the new window (C) above the old window (B).\n\n");
105         
106         win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
107         win_b = glk_window_open(win_a, winmethod_Proportional | winmethod_Below,
108                                                         50, wintype_TextBuffer, 0);
109         win_c = glk_window_open(win_b, winmethod_Proportional | winmethod_Above,
110                                                         50, wintype_TextBuffer, 0);
111         if(!win_a || !win_b || !win_c)
112                 return;
113         center_text(win_a, "A");
114         center_text(win_b, "B");
115         center_text(win_c, "C");
116         
117         wait_for_key(win_a);
118         glk_window_close(glk_window_get_root(), NULL);
119                         
120         fprintf(stderr, "Here, we mess with the percentages. The first split (A\n"
121                         "into A/B) is a 25-75 split, which makes B three times the size\n"
122                         "of A. The second (B into B/C) is a 33-66 split, which makes C\n"
123                         "twice the size of B. This looks rather like the second example,\n"
124                         "but has a different internal structure.\n\n");
125         
126         win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
127         win_b = glk_window_open(win_a, winmethod_Proportional | winmethod_Below,
128                                                         75, wintype_TextBuffer, 0);
129         win_c = glk_window_open(win_b, winmethod_Proportional | winmethod_Below,
130                                                         67, wintype_TextBuffer, 0);
131         if(!win_a || !win_b || !win_c)
132                 return;
133         center_text(win_a, "A");
134         center_text(win_b, "B");
135         center_text(win_c, "C");
136         
137         wait_for_key(win_a);
138         glk_window_close(glk_window_get_root(), NULL);
139         
140         fprintf(stderr, "Here, the second split (B into B/C) is vertical instead\n"
141                         "of horizontal, with the new window (C) on the left of the old\n"
142                         "one.\n\n");
143         
144         win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
145         win_b = glk_window_open(win_a, winmethod_Proportional | winmethod_Below,
146                                                         50, wintype_TextBuffer, 0);
147         win_c = glk_window_open(win_b, winmethod_Proportional | winmethod_Left,
148                                                         50, wintype_TextBuffer, 0);
149         if(!win_a || !win_b || !win_c)
150                 return;
151         center_text(win_a, "A");
152         center_text(win_b, "B");
153         center_text(win_c, "C");
154         
155         wait_for_key(win_a);
156         glk_window_close(glk_window_get_root(), NULL);
157         
158         fprintf(stderr, "In the following two-split process, you can see that\n"
159                         "when a window is split, it is replaced by a new pair window, and\n"
160                         "moves down to become one of its two children.\n\n");
161         
162         if(!(win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0)))
163                 return;
164         center_text(win_a, "A");
165         wait_for_key(win_a);
166         
167         if(!(win_b = glk_window_open(win_a, 
168                                                                  winmethod_Proportional | winmethod_Below,
169                                                                  50, wintype_TextBuffer, 0)))
170                 return;
171         center_text(win_a, "A");
172         center_text(win_b, "B");
173         wait_for_key(win_a);
174         
175         if(!(win_c = glk_window_open(win_b, winmethod_Proportional | winmethod_Left,
176                                                                  50, wintype_TextBuffer, 0)))
177                 return;
178         center_text(win_a, "A");
179         center_text(win_b, "B");
180         center_text(win_c, "C");
181         wait_for_key(win_a);
182         
183         glk_window_close(glk_window_get_root(), NULL);
184         
185         fprintf(stderr, "What happens when there is a conflict? The rules are\n"
186                         "simple. Size control always flows down the tree, and the player\n"
187                         "is at the top. Let's bring out an example: first we split A into\n"
188                         "A and B, with a 50%% proportional split. Then we split A into A\n"
189                         "and C, with C above, being a text grid window, and C gets a\n"
190                         "fixed size of two rows (as measured in its own font size). A\n"
191                         "gets whatever remains of the 50%% it had before.\n\n");
192         
193         win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
194         win_b = glk_window_open(win_a, winmethod_Proportional | winmethod_Below,
195                                                         50, wintype_TextBuffer, 0);
196         win_c = glk_window_open(win_a, winmethod_Fixed | winmethod_Above,
197                                                         2, wintype_TextGrid, 0);
198         if(!win_a || !win_b || !win_c)
199                 return;
200         center_text(win_a, "A");
201         center_text(win_b, "B: 50%");
202         print_two_rows(win_c);
203         wait_for_key(win_a);
204         
205         fprintf(stderr, "(Stage 1) Now the player stretches the window\n"
206                         "vertically.\n\n");
207         
208         wait_for_key(win_a);
209         
210         fprintf(stderr, "(Stage 2) Then the user maliciously starts squeezing the\n"
211                         "window down, in stages.\n\n");
212         
213         center_text(win_a, "A");
214         center_text(win_b, "B: 50%");
215         print_two_rows(win_c);
216         wait_for_key(win_a);
217         
218         fprintf(stderr, "(Stage 3) The logic remains the same. At stage 3,\n"
219                         "there's no room left for A, so it winds up with zero height.\n"
220                         "Nothing displayed in A will be visible.\n\n");
221         
222         center_text(win_a, "A");
223         center_text(win_b, "B");
224         center_text(win_c, "C");
225         wait_for_key(win_a);
226         
227         fprintf(stderr, "(Stage 4) At stage 4, there isn't even room in the upper\n"
228                         "50%% to give C its two rows; so it only gets one.\n\n");
229         
230         center_text(win_a, "A");
231         center_text(win_b, "B");
232         center_text(win_c, "C");
233         wait_for_key(win_a);
234         
235         fprintf(stderr, "(Stage 5) Finally, C is squashed out of existence as\n"
236                         "well.\n\n");
237         
238         center_text(win_a, "A");
239         center_text(win_b, "B");
240         wait_for_key(win_a);
241         
242         glk_window_close(glk_window_get_root(), NULL);
243         
244         fprintf(stderr, "What happens when you split a fixed-size window? The\n"
245                         "resulting pair window retains the same size constraint as the\n"
246                         "original window that was split. The key window for the original\n"
247                         "split is still the key window for that split, even though it's\n"
248                         "now a grandchild instead of a child.\n\n");
249         
250         if(!(win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0)))
251                 return;
252         center_text(win_a, "A");
253         wait_for_key(win_a);
254         
255         fprintf(stderr, "After the first split, the new pair window (O1, which\n"
256                         "covers the whole screen) knows that its first child (A) is above\n"
257                         "the second, and gets 50%% of its own area. (A is the key window\n"
258                         "for this split, but a proportional split doesn't care about key\n"
259                         "windows.)\n\n");
260         
261         if(!(win_b = glk_window_open(win_a, 
262                                                                  winmethod_Proportional | winmethod_Below,
263                                                                  50, wintype_TextBuffer, 0)))
264                 return;
265         center_text(win_a, "A: 50%");
266         center_text(win_b, "B");
267         wait_for_key(win_a);
268         
269         fprintf(stderr, "After the second split, all this remains true; O1 knows\n"
270                         "that its first child gets 50%% of its space, and A is O1's key\n"
271                         "window. But now O1's first child is O2 instead of A. The newer\n"
272                         "pair window (O2) knows that its first child (C) is above the\n"
273                         "second, and gets a fixed size of two rows. (As measured in C's\n"
274                         "font, because C is O2's key window.)\n\n");
275         
276         if(!(win_c = glk_window_open(win_a, winmethod_Fixed | winmethod_Above, 2,
277                                                                  wintype_TextGrid, 0)))
278                 return;
279         center_text(win_a, "A");
280         center_text(win_b, "B");
281         print_two_rows(win_c);
282         wait_for_key(win_a);
283         
284         fprintf(stderr, "If we split C, now, the resulting pair will still be two\n"
285                         "C-font rows high -- that is, tall enough for two lines of\n"
286                         "whatever font C displays. For the sake of example, we'll do this\n"
287                         "vertically.\n\n");
288         
289         if(!(win_d = glk_window_open(win_c, 
290                                                                  winmethod_Proportional | winmethod_Right,
291                                                                  50, wintype_TextBuffer, 0)))
292                 return;
293         center_text(win_a, "A");
294         center_text(win_b, "B");
295         center_text(win_c, "C");
296         center_text(win_d, "D");
297         wait_for_key(win_a);
298         
299         fprintf(stderr, "When you close a window (and it is not the root window),\n"
300                         "the other window in its pair takes over all the freed-up area.\n"
301                         "Let's close D, in the current example:\n\n");
302         
303         glk_window_close(win_d, NULL);
304         center_text(win_a, "A");
305         center_text(win_b, "B");
306         center_text(win_c, "C");
307         wait_for_key(win_a);
308         
309         fprintf(stderr, "But what if we had closed C instead of D? We would have\n"
310                         "gotten this:\n\n");
311         
312         glk_window_close(glk_window_get_root(), NULL);
313         win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
314         win_b = glk_window_open(win_a, winmethod_Proportional | winmethod_Below, 50,
315                                                         wintype_TextBuffer, 0);
316         win_c = glk_window_open(win_a, winmethod_Fixed | winmethod_Above, 2,
317                                                         wintype_TextGrid, 0);
318         win_d = glk_window_open(win_c, winmethod_Proportional | winmethod_Right, 50,
319                                                         wintype_TextBuffer, 0);
320         glk_window_close(win_c, NULL);
321         center_text(win_a, "A");
322         center_text(win_b, "B");
323         center_text(win_d, "D");
324         wait_for_key(win_a);
325         
326         fprintf(stderr, "Consider the example above, where D had collapsed to\n"
327                         "zero height. Say D was a text buffer window. You could make a\n"
328                         "more useful layout:\n\n");
329         winid_t o2 = glk_window_get_parent(win_d);
330         glk_window_set_arrangement(o2, winmethod_Above | winmethod_Fixed, 3, win_d);
331         center_text(win_a, "A");
332         center_text(win_b, "B");
333         center_text(win_d, "D");
334         wait_for_key(win_a);
335         
336         fprintf(stderr, "If you later wanted to expand D to five rows:\n\n");
337         glk_window_set_arrangement(o2, winmethod_Above | winmethod_Fixed, 5, NULL);
338         center_text(win_a, "A");
339         center_text(win_b, "B");
340         center_text(win_d, "D");
341         wait_for_key(win_a);
342         
343         fprintf(stderr, "This changes the constraint to be on the lower child of\n"
344                         "O2, which is A. The key window is still D; so A would then be\n"
345                         "three rows high as measured in D's font, and D would get the\n"
346                         "rest of O2's space. That may not be what you want.\n\n");
347         glk_window_set_arrangement(o2, winmethod_Below | winmethod_Fixed, 3, NULL);
348         center_text(win_a, "A");
349         center_text(win_b, "B");
350         center_text(win_d, "D");
351         wait_for_key(win_a);
352         
353         fprintf(stderr, "To set A to be three rows high as measured in A's font,\n"
354                         "you would do:\n\n");
355         glk_window_set_arrangement(o2, winmethod_Below | winmethod_Fixed, 3, win_a);
356         center_text(win_a, "A");
357         center_text(win_b, "B");
358         center_text(win_d, "D");
359         wait_for_key(win_a);
360         
361         fprintf(stderr, "Or you could change O2 to a proportional split:\n\n");
362         glk_window_set_arrangement(o2, winmethod_Below | winmethod_Proportional, 30,
363                                                            NULL);
364         center_text(win_a, "A");
365         center_text(win_b, "B");
366         center_text(win_d, "D");
367         wait_for_key(win_a);
368         
369         fprintf(stderr, "Or:\n\n");
370         glk_window_set_arrangement(o2, winmethod_Above | winmethod_Proportional, 70,
371                                                            NULL);
372         center_text(win_a, "A");
373         center_text(win_b, "B");
374         center_text(win_d, "D");
375         wait_for_key(win_a);
376         
377         glk_window_close(win_d, NULL);
378         glk_window_close(win_b, NULL);
379         glk_window_clear(win_a);
380         glk_set_window(win_a);
381         glk_put_string("That's all, folks...");
382 }