From: fliep Date: Tue, 19 May 2009 20:47:32 +0000 (+0000) Subject: - Changed splittest.c to run through all the examples of window splitting in the X-Git-Tag: v0.9~410 X-Git-Url: https://git.stderr.nl/gitweb?p=projects%2Fchimara%2Fchimara.git;a=commitdiff_plain;h=02174ac95fb840d3155567507c4686af8c4789a8 - Changed splittest.c to run through all the examples of window splitting in the Glk spec - Took screenshots and added those to the documentation --- diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am index 4e05bb9..3af6caa 100644 --- a/docs/reference/Makefile.am +++ b/docs/reference/Makefile.am @@ -51,7 +51,27 @@ IGNORE_HFILES = chimara-glk-private.h \ callbacks.h error.h # Images to copy into HTML directory. -HTML_IMAGES = +HTML_IMAGES = \ + $(srcdir)/images/fig1.png \ + $(srcdir)/images/fig2.png \ + $(srcdir)/images/fig3a.png \ + $(srcdir)/images/fig3b.png \ + $(srcdir)/images/fig3c.png \ + $(srcdir)/images/fig4a.png \ + $(srcdir)/images/fig4b.png \ + $(srcdir)/images/fig4c.png \ + $(srcdir)/images/fig5-7a.png \ + $(srcdir)/images/fig6.png \ + $(srcdir)/images/fig7b.png \ + $(srcdir)/images/fig7c.png \ + $(srcdir)/images/fig7d.png \ + $(srcdir)/images/fig7e.png \ + $(srcdir)/images/fig8a.png \ + $(srcdir)/images/fig8b.png \ + $(srcdir)/images/fig8c.png \ + $(srcdir)/images/fig9.png \ + $(srcdir)/images/fig10.png \ + $(srcdir)/images/fig11.png # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). content_files = version.xml \ diff --git a/docs/reference/glk-window-arrangement.sgml b/docs/reference/glk-window-arrangement.sgml index 9926d81..fe9f667 100644 --- a/docs/reference/glk-window-arrangement.sgml +++ b/docs/reference/glk-window-arrangement.sgml @@ -37,11 +37,40 @@ It is important to remember that the order of splitting matters. If you split tw Example time. Say you do two splits, each a 50-50 percentage split. You start with the original window A, and split that into A and B; then you split B into B and C. -Screen shot 1 + + + + O + / \ + A O + / \ + B C + + Or, you could split A into A and B, and then split A again into A and C. -Screen shot 2 + + + + O + / \ + O B + / \ + A C + + I'm using the simplest possible splits in the examples above. Every split is 50-50, and the new window of the pair is always below the original one (the one that gets split.) You can get fancier than that. Here are three more ways to perform the first example; all of them have the same tree structure, but look different on the screen. -Screen shot 3 + + + + + + O + / \ + A O + / \ + B C + + On the left, we turn the second split (B into B/C) upside down; we put the new window (C) above the old window (B). @@ -55,7 +84,28 @@ The visible windows on the Glk screen are leaf nodes of the binar You don't create pair windows directly; they are created as a consequence of window splits. Whenever you create a new window, a new pair window is also created automatically. In the following two-split process, you can see that when a window is split, it is replaced by a new pair window, and moves down to become one of that O's two children. -Screen shot 4 + + + + A + + + + + O + / \ + A B + + + + + O + / \ + A O + / \ + B C + + You can't draw into a pair window. It's completely filled up with the two windows it contains. They're what you should be drawing into. diff --git a/docs/reference/images/fig1.png b/docs/reference/images/fig1.png new file mode 100644 index 0000000..3314081 Binary files /dev/null and b/docs/reference/images/fig1.png differ diff --git a/docs/reference/images/fig10.png b/docs/reference/images/fig10.png new file mode 100644 index 0000000..54c2989 Binary files /dev/null and b/docs/reference/images/fig10.png differ diff --git a/docs/reference/images/fig11.png b/docs/reference/images/fig11.png new file mode 100644 index 0000000..04baff6 Binary files /dev/null and b/docs/reference/images/fig11.png differ diff --git a/docs/reference/images/fig2.png b/docs/reference/images/fig2.png new file mode 100644 index 0000000..2865a2f Binary files /dev/null and b/docs/reference/images/fig2.png differ diff --git a/docs/reference/images/fig3a.png b/docs/reference/images/fig3a.png new file mode 100644 index 0000000..b178d7d Binary files /dev/null and b/docs/reference/images/fig3a.png differ diff --git a/docs/reference/images/fig3b.png b/docs/reference/images/fig3b.png new file mode 100644 index 0000000..112f4af Binary files /dev/null and b/docs/reference/images/fig3b.png differ diff --git a/docs/reference/images/fig3c.png b/docs/reference/images/fig3c.png new file mode 100644 index 0000000..6309db9 Binary files /dev/null and b/docs/reference/images/fig3c.png differ diff --git a/docs/reference/images/fig4a.png b/docs/reference/images/fig4a.png new file mode 100644 index 0000000..973e6de Binary files /dev/null and b/docs/reference/images/fig4a.png differ diff --git a/docs/reference/images/fig4b.png b/docs/reference/images/fig4b.png new file mode 100644 index 0000000..4410962 Binary files /dev/null and b/docs/reference/images/fig4b.png differ diff --git a/docs/reference/images/fig4c.png b/docs/reference/images/fig4c.png new file mode 100644 index 0000000..b5b60ca Binary files /dev/null and b/docs/reference/images/fig4c.png differ diff --git a/docs/reference/images/fig5-7a.png b/docs/reference/images/fig5-7a.png new file mode 100644 index 0000000..543c689 Binary files /dev/null and b/docs/reference/images/fig5-7a.png differ diff --git a/docs/reference/images/fig6.png b/docs/reference/images/fig6.png new file mode 100644 index 0000000..15f6331 Binary files /dev/null and b/docs/reference/images/fig6.png differ diff --git a/docs/reference/images/fig7b.png b/docs/reference/images/fig7b.png new file mode 100644 index 0000000..63fe6c7 Binary files /dev/null and b/docs/reference/images/fig7b.png differ diff --git a/docs/reference/images/fig7c.png b/docs/reference/images/fig7c.png new file mode 100644 index 0000000..839c945 Binary files /dev/null and b/docs/reference/images/fig7c.png differ diff --git a/docs/reference/images/fig7d.png b/docs/reference/images/fig7d.png new file mode 100644 index 0000000..9631819 Binary files /dev/null and b/docs/reference/images/fig7d.png differ diff --git a/docs/reference/images/fig7e.png b/docs/reference/images/fig7e.png new file mode 100644 index 0000000..a7c3cf5 Binary files /dev/null and b/docs/reference/images/fig7e.png differ diff --git a/docs/reference/images/fig8a.png b/docs/reference/images/fig8a.png new file mode 100644 index 0000000..7fa9ea7 Binary files /dev/null and b/docs/reference/images/fig8a.png differ diff --git a/docs/reference/images/fig8b.png b/docs/reference/images/fig8b.png new file mode 100644 index 0000000..2a4c05b Binary files /dev/null and b/docs/reference/images/fig8b.png differ diff --git a/docs/reference/images/fig8c.png b/docs/reference/images/fig8c.png new file mode 100644 index 0000000..d579b84 Binary files /dev/null and b/docs/reference/images/fig8c.png differ diff --git a/docs/reference/images/fig9.png b/docs/reference/images/fig9.png new file mode 100644 index 0000000..7386955 Binary files /dev/null and b/docs/reference/images/fig9.png differ diff --git a/src/main.c b/src/main.c index c34e4c5..496f1b2 100644 --- a/src/main.c +++ b/src/main.c @@ -118,7 +118,7 @@ main(int argc, char *argv[]) g_object_unref( G_OBJECT(builder) ); - if( !chimara_glk_run(CHIMARA_GLK(glk), ".libs/first.so", &error) ) { + if( !chimara_glk_run(CHIMARA_GLK(glk), ".libs/splittest.so", &error) ) { error_dialog(GTK_WINDOW(window), error, "Error starting Glk library: "); return 1; } diff --git a/src/splittest.c b/src/splittest.c index 58ed6f6..7448437 100644 --- a/src/splittest.c +++ b/src/splittest.c @@ -1,34 +1,331 @@ -#include "stdio.h" +#include +#include #include "glk.h" -void glk_main(void) +#define SPACE_FACTOR 1.8 + +void center_text(winid_t win, char *text) +{ + glui32 width, height; + glk_window_get_size(win, &width, &height); + + glk_set_window(win); + glk_window_clear(win); + + if(glk_window_get_type(win) == wintype_TextGrid) { + glk_window_move_cursor(win, width / 2 - strlen(text) / 2, height / 2); + glk_put_string(text); + } else if(glk_window_get_type(win) == wintype_TextBuffer) { + int count; + for(count = 0; count < height / 2; count++) + glk_put_char('\n'); + for(count = 0; + count < (int)(SPACE_FACTOR * (width / 2 - strlen(text) / 2)); + count++) + glk_put_char(' '); + glk_put_string(text); + } +} + +void print_two_rows(winid_t win) +{ + glui32 width, height; + glk_window_get_size(win, &width, &height); + + glk_set_window(win); + glk_window_clear(win); + + glui32 x = width / 2 - 3; + glui32 y = (height - 1) / 2; + if(x < 0) + x = 0; + if(y < 0) + y = 0; + + glk_window_move_cursor(win, x, y); + glk_put_string("C: 2"); + glk_window_move_cursor(win, x + 3, y + 1); + glk_put_string("rows"); +} + +void wait_for_key(winid_t win) { event_t ev; - winid_t mainwin = glk_window_open(0, 0, 0, wintype_TextBuffer, 0); - if(!mainwin) - return; - - winid_t subwin = glk_window_open(mainwin, winmethod_Right | winmethod_Proportional, 50, wintype_TextBuffer, 1); - printf("created new window\n"); - glk_set_window(mainwin); - glk_put_string("Philip en Marijn zijn vet goed.\n"); - glk_set_window(subwin); - glk_put_string("A veeeeeeeeeeeeeeeeeeeeeeeeeeeery looooooooooooooooooooooooong striiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiing.\n"); + glk_request_char_event(win); + do + glk_select(&ev); + while(ev.type != evtype_CharInput); +} - - guint32 width, height; - glk_window_get_size(mainwin, &width, &height); - printf("got window size\n"); - fprintf(stderr, "\nWidth: %d\nHeight: %d\n", width, height); - - glk_request_char_event(mainwin); - //while(1) { - glk_select(&ev); - if(ev.type == evtype_CharInput) { - glk_window_get_size(mainwin, &width, &height); - fprintf(stderr, "\nWidth: %d\nHeight: %d\n", width, height); - } - //} - glk_window_close(subwin, NULL); - printf("closed window\n"); +void glk_main(void) +{ + winid_t win_a = NULL, win_b = NULL, win_c = NULL, win_d = NULL; + + fprintf(stderr, "TEST CASES FROM GLK SPEC\n\n" + "(Press a key in window A to continue each time)\n\n" + "Say you do two splits, each a 50-50 percentage split. You start\n" + "with the original window A, and split that into A and B; then\n" + "you split B into B and C.\n\n"); + + win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0); + win_b = glk_window_open(win_a, winmethod_Proportional | winmethod_Below, + 50, wintype_TextBuffer, 0); + win_c = glk_window_open(win_b, winmethod_Proportional | winmethod_Below, + 50, wintype_TextBuffer, 0); + if(!win_a || !win_b || !win_c) + return; + center_text(win_a, "A"); + center_text(win_b, "B"); + center_text(win_c, "C"); + + wait_for_key(win_a); + glk_window_close(glk_window_get_root(), NULL); + + fprintf(stderr, "Or, you could split A into A and B, and then split A\n" + "again into A and C.\n\n"); + + win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0); + win_b = glk_window_open(win_a, winmethod_Proportional | winmethod_Below, + 50, wintype_TextBuffer, 0); + win_c = glk_window_open(win_a, winmethod_Proportional | winmethod_Below, + 50, wintype_TextBuffer, 0); + if(!win_a || !win_b || !win_c) + return; + center_text(win_a, "A"); + center_text(win_b, "B"); + center_text(win_c, "C"); + + wait_for_key(win_a); + glk_window_close(glk_window_get_root(), NULL); + + fprintf(stderr, "Here are more ways to perform the first example; all of\n" + "them have the same tree structure, but look different on the\n" + "screen. Here, we turn the second split (B into B/C) upside down;\n" + "we put the new window (C) above the old window (B).\n\n"); + + win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0); + win_b = glk_window_open(win_a, winmethod_Proportional | winmethod_Below, + 50, wintype_TextBuffer, 0); + win_c = glk_window_open(win_b, winmethod_Proportional | winmethod_Above, + 50, wintype_TextBuffer, 0); + if(!win_a || !win_b || !win_c) + return; + center_text(win_a, "A"); + center_text(win_b, "B"); + center_text(win_c, "C"); + + wait_for_key(win_a); + glk_window_close(glk_window_get_root(), NULL); + + fprintf(stderr, "Here, we mess with the percentages. The first split (A\n" + "into A/B) is a 25-75 split, which makes B three times the size\n" + "of A. The second (B into B/C) is a 33-66 split, which makes C\n" + "twice the size of B. This looks rather like the second example,\n" + "but has a different internal structure.\n\n"); + + win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0); + win_b = glk_window_open(win_a, winmethod_Proportional | winmethod_Below, + 75, wintype_TextBuffer, 0); + win_c = glk_window_open(win_b, winmethod_Proportional | winmethod_Below, + 67, wintype_TextBuffer, 0); + if(!win_a || !win_b || !win_c) + return; + center_text(win_a, "A"); + center_text(win_b, "B"); + center_text(win_c, "C"); + + wait_for_key(win_a); + glk_window_close(glk_window_get_root(), NULL); + + fprintf(stderr, "Here, the second split (B into B/C) is vertical instead\n" + "of horizontal, with the new window (C) on the left of the old\n" + "one.\n\n"); + + win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0); + win_b = glk_window_open(win_a, winmethod_Proportional | winmethod_Below, + 50, wintype_TextBuffer, 0); + win_c = glk_window_open(win_b, winmethod_Proportional | winmethod_Left, + 50, wintype_TextBuffer, 0); + if(!win_a || !win_b || !win_c) + return; + center_text(win_a, "A"); + center_text(win_b, "B"); + center_text(win_c, "C"); + + wait_for_key(win_a); + glk_window_close(glk_window_get_root(), NULL); + + fprintf(stderr, "In the following two-split process, you can see that\n" + "when a window is split, it is replaced by a new pair window, and\n" + "moves down to become one of its two children.\n\n"); + + if(!(win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0))) + return; + center_text(win_a, "A"); + wait_for_key(win_a); + + if(!(win_b = glk_window_open(win_a, + winmethod_Proportional | winmethod_Below, + 50, wintype_TextBuffer, 0))) + return; + center_text(win_a, "A"); + center_text(win_b, "B"); + wait_for_key(win_a); + + if(!(win_c = glk_window_open(win_b, winmethod_Proportional | winmethod_Left, + 50, wintype_TextBuffer, 0))) + return; + center_text(win_a, "A"); + center_text(win_b, "B"); + center_text(win_c, "C"); + wait_for_key(win_a); + + glk_window_close(glk_window_get_root(), NULL); + + fprintf(stderr, "What happens when there is a conflict? The rules are\n" + "simple. Size control always flows down the tree, and the player\n" + "is at the top. Let's bring out an example: first we split A into\n" + "A and B, with a 50%% proportional split. Then we split A into A\n" + "and C, with C above, being a text grid window, and C gets a\n" + "fixed size of two rows (as measured in its own font size). A\n" + "gets whatever remains of the 50%% it had before.\n\n"); + + win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0); + win_b = glk_window_open(win_a, winmethod_Proportional | winmethod_Below, + 50, wintype_TextBuffer, 0); + win_c = glk_window_open(win_a, winmethod_Fixed | winmethod_Above, + 2, wintype_TextGrid, 0); + if(!win_a || !win_b || !win_c) + return; + center_text(win_a, "A"); + center_text(win_b, "B: 50%"); + print_two_rows(win_c); + wait_for_key(win_a); + + fprintf(stderr, "(Stage 1) Now the player stretches the window\n" + "vertically.\n\n"); + + wait_for_key(win_a); + + fprintf(stderr, "(Stage 2) Then the user maliciously starts squeezing the\n" + "window down, in stages.\n\n"); + + center_text(win_a, "A"); + center_text(win_b, "B: 50%"); + print_two_rows(win_c); + wait_for_key(win_a); + + fprintf(stderr, "(Stage 3) The logic remains the same. At stage 3,\n" + "there's no room left for A, so it winds up with zero height.\n" + "Nothing displayed in A will be visible.\n\n"); + + center_text(win_a, "A"); + center_text(win_b, "B"); + center_text(win_c, "C"); + wait_for_key(win_a); + + fprintf(stderr, "(Stage 4) At stage 4, there isn't even room in the upper\n" + "50%% to give C its two rows; so it only gets one.\n\n"); + + center_text(win_a, "A"); + center_text(win_b, "B"); + center_text(win_c, "C"); + wait_for_key(win_a); + + fprintf(stderr, "(Stage 5) Finally, C is squashed out of existence as\n" + "well.\n\n"); + + center_text(win_a, "A"); + center_text(win_b, "B"); + wait_for_key(win_a); + + glk_window_close(glk_window_get_root(), NULL); + + fprintf(stderr, "What happens when you split a fixed-size window? The\n" + "resulting pair window retains the same size constraint as the\n" + "original window that was split. The key window for the original\n" + "split is still the key window for that split, even though it's\n" + "now a grandchild instead of a child.\n\n"); + + if(!(win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0))) + return; + center_text(win_a, "A"); + wait_for_key(win_a); + + fprintf(stderr, "After the first split, the new pair window (O1, which\n" + "covers the whole screen) knows that its first child (A) is above\n" + "the second, and gets 50%% of its own area. (A is the key window\n" + "for this split, but a proportional split doesn't care about key\n" + "windows.)\n\n"); + + if(!(win_b = glk_window_open(win_a, + winmethod_Proportional | winmethod_Below, + 50, wintype_TextBuffer, 0))) + return; + center_text(win_a, "A: 50%"); + center_text(win_b, "B"); + wait_for_key(win_a); + + fprintf(stderr, "After the second split, all this remains true; O1 knows\n" + "that its first child gets 50%% of its space, and A is O1's key\n" + "window. But now O1's first child is O2 instead of A. The newer\n" + "pair window (O2) knows that its first child (C) is above the\n" + "second, and gets a fixed size of two rows. (As measured in C's\n" + "font, because C is O2's key window.)\n\n"); + + if(!(win_c = glk_window_open(win_a, winmethod_Fixed | winmethod_Above, 2, + wintype_TextGrid, 0))) + return; + center_text(win_a, "A"); + center_text(win_b, "B"); + print_two_rows(win_c); + wait_for_key(win_a); + + fprintf(stderr, "If we split C, now, the resulting pair will still be two\n" + "C-font rows high -- that is, tall enough for two lines of\n" + "whatever font C displays. For the sake of example, we'll do this\n" + "vertically.\n\n"); + + if(!(win_d = glk_window_open(win_c, + winmethod_Proportional | winmethod_Right, + 50, wintype_TextBuffer, 0))) + return; + center_text(win_a, "A"); + center_text(win_b, "B"); + center_text(win_c, "C"); + center_text(win_d, "D"); + wait_for_key(win_a); + + fprintf(stderr, "When you close a window (and it is not the root window),\n" + "the other window in its pair takes over all the freed-up area.\n" + "Let's close D, in the current example:\n\n"); + + glk_window_close(win_d, NULL); + center_text(win_a, "A"); + center_text(win_b, "B"); + center_text(win_c, "C"); + wait_for_key(win_a); + + fprintf(stderr, "But what if we had closed C instead of D? We would have\n" + "gotten this:\n\n"); + + glk_window_close(glk_window_get_root(), NULL); + win_a = glk_window_open(0, 0, 0, wintype_TextBuffer, 0); + win_b = glk_window_open(win_a, winmethod_Proportional | winmethod_Below, 50, + wintype_TextBuffer, 0); + win_c = glk_window_open(win_a, winmethod_Fixed | winmethod_Above, 2, + wintype_TextGrid, 0); + win_d = glk_window_open(win_c, winmethod_Proportional | winmethod_Right, 50, + wintype_TextBuffer, 0); + glk_window_close(win_c, NULL); + center_text(win_a, "A"); + center_text(win_b, "B"); + center_text(win_d, "D"); + wait_for_key(win_a); + + glk_window_close(win_d, NULL); + glk_window_close(win_b, NULL); + glk_window_clear(win_a); + glk_set_window(win_a); + glk_put_string("That's all, folks..."); } diff --git a/src/window.c b/src/window.c index 876db66..2f3c602 100644 --- a/src/window.c +++ b/src/window.c @@ -237,8 +237,17 @@ glk_window_get_root() * What happens when there is a conflict? The rules are simple. Size control * always flows down the tree, and the player is at the top. Let's bring out an * example: - * Screen shot 5 - * + * + * + * + * + * O + * / \ + * O B + * / \ + * A C + * + * * * First we split A into A and B, with a 50% proportional split. Then we split * A into A and C, with C above, C being a text grid window, and C gets a fixed @@ -246,8 +255,8 @@ glk_window_get_root() * of the 50% it had before. * * Now the player stretches the window vertically. - * Screen shot 6 - * + * + * * * The library figures: the topmost split, the original A/B split, is 50-50. So * B gets half the screen space, and the pair window next to it (the lower @@ -255,8 +264,18 @@ glk_window_get_root() * O. C gets two rows; A gets the rest. All done. * * Then the user maliciously starts squeezing the window down, in stages: - * - * Screen shot 7 + * + * + * + * + * + * + * + * + * + * + * + * * * The logic remains the same. B always gets half the space. At stage 3, * there's no room left for A, so it winds up with zero height. Nothing @@ -290,8 +309,29 @@ glk_window_get_root() * is stored by a window's parent, not the window itself; and a constraint * consists of a pointer to a key window plus a size value. * - * Screen shot 8 - * + * + * + * + * + * A + * + * + * + * + * O1 + * / \ + * A B + * + * + * + * + * O1 + * / \ + * O2 B + * / \ + * A C + * + * * After the first split, the new pair window (O1, which covers the whole * screen) knows that its first child (A) is above the second, and gets 50% of * its own area. (A is the key window for this split, but a proportional split @@ -306,8 +346,19 @@ glk_window_get_root() * If we split C, now, the resulting pair will still be two C-font rows high * — that is, tall enough for two lines of whatever font C displays. For * the sake of example, we'll do this vertically. - * Screen shot 9 - * + * + * + * + * + * O1 + * / \ + * O2 B + * / \ + * A O3 + * / \ + * C D + * + * * * O3 now knows that its children have a 50-50 left-right split. O2 is still * committed to giving its upper child, O3, two C-font rows. Again, this is @@ -611,8 +662,17 @@ free_winids_below(winid_t win) * When you close a window (and it is not the root window), the other window * in its pair takes over all the freed-up area. Let's close D, in the current * example: - * Screen shot 10 - * + * + * + * + * + * O1 + * / \ + * O2 B + * / \ + * A C + * + * * * Notice what has happened. D is gone. O3 is gone, and its 50-50 left-right * split has gone with it. The other size constraints are unchanged; O2 is @@ -622,8 +682,17 @@ free_winids_below(winid_t win) * to the way it was before we created D. * * But what if we had closed C instead of D? We would have gotten this: - * Screen shot 11 - * + * + * + * + * + * O1 + * / \ + * O2 B + * / \ + * A D + * + * * * Again, O3 is gone. But D has collapsed to zero height. This is because its * height is controlled by O2, and O2's key window was C, and C is now gone. O2