[I7, Glk] requesting help with figure display

Last year I came here requesting help with a module for displaying illustrations. The thread where I finally cracked it (with a great deal of help from many generous people, particularly zarf) is here, but to summarize briefly: a small thumbnail is displayed in the main gameplay window; when the player clicks on the thumbnail, a new window appears (completely covering the gameplay window), displaying the image; when the player clicks on the image OR presses any key, the image goes away and the player is returned to normal gameplay.

I am now trying to add two refinements to this module.

  1. Originally, when the illustration is cleared, I wanted the game to clear the screen and attempt a LOOK action, so that the player always returns to a description of the current location. This turned out to not always be ideal. What I would like to do instead is have the game return to displaying exactly what it was initially displaying before the player clicked on the thumbnail. In other words I just want to preserve the state of the gameplay window while the illustration window is active. For some reason I can’t get this to work, however; the gameplay window always ends up cleared of text, and I can’t figure out why.

  2. There is at least one situation where I want to set up a “wait for any key” event immediately after displaying an illustration. In other words: the player should see an illustration, then when the player clears the illustration some text is displayed, then when the player presses a key, play resumes as normal. I can’t get this to work, either.

The glk API has always been a weak spot for me; my understanding of this code even when it’s working is shaky at best. I would be really grateful for any insights or suggestions.

I’m posting the full source code for the example game I made to ilustrate these two problems. I’m also posting the graphics so that anyone up for the challenge can compile the game themselves.

[spoiler][code]“Test Case” by Michael Gentry.

The story headline is “An Interactive Sheep Punchin[’]”.

Include Unified Glulx Input by Andrew Plotkin.

[The overall concept is this: At various points throughout the game, small “thumbnail” graphics will appear in the main window. These are hyperlinked. If the player clicks a thumbnail:
1) The game opens up a graphical window that covers the main window entirely (it splits the main window, but takes up 100% of the window space) and displays a larger illustration.
2) The game also displays a caption for the picture in the status line.
3) If the player clicks on the larger illustration, OR presses any key, the graphical window closes and the player is returned to normal gameplay. Note, once a thumbnail is clicked, it does not reappear in subsequent gameplay. This is intentional.
]

Test Chamber is a room. “[Figure - Red Button]Not much to do here, [if Figure - Red Button has been displayed]now that you’ve pushed[otherwise]other than push[end if] that big, shiny red button in the corner.” The big shiny red button is scenery in the Test Chamber. Instead of doing something with the button, say “Just click it with your mouse.”

Chapter - The Illustrations

Figure - Title Page is the file “sheep_punch.png”.
Figure - Red Button is the file “red_button.png”.
Figure - Gorilla Shark is the file “gorilla_shark.png”.

Section - the table of illustrations

[In the full game, this table will match up all the full illustrations with their thumbnails and caption text.]

Table of Illustrations
link-number illustration-name thumb-name display-status caption
102 Figure - Gorilla Shark Figure - Red Button false “Totally Awesome!!”
999 Figure - Title Page – false “Press a key to continue.”

To decide if (F - a figure-name) has been displayed:
if the display-status corresponding to a thumb-name of F in the Table of Illustrations is false, no;
otherwise yes.

Chapter - The Illustration Displaying Machinery

Section - displaying thumbnails

To say (F - a figure-name):
if F has been displayed:
do nothing;
otherwise:
let N be the link-number corresponding to a thumb-name of F in the Table of Illustrations;
say “[hyperlink N]”;
display thumb F;
say “[/hyperlink][line break]”;

To display thumb (F - a figure-name):
(- glk_image_draw(gg_mainwin, ResourceIDsOfFigures–>{F}, imagealign_MarginLeft, 0); -);

Section - handling input

[We customize input in four ways. First, request hyperlink input (in normal mode) and char input (in window-open mode).]

Setting up input rule:
if the illustration window is not open:
now the story-window is hyperlink-input-request;
else:
now the input-request of the story-window is char-input.

[Second, a set of input-accepting rules. Note that there’s no specific rule for accepting character input. UGI knows that char input is acceptable whenever the input-request of the story-window is char-input.]

[Let mouse events pass through to become commands. (We have to do this explicitly because UGI is not yet aware of third-party windows.)]

Accepting input rule when handling mouse-event and the illustration window is open:
accept input event.

[Graphics-window-redraw events redraw the graphics window. But we reject the event so that the input loop keeps waiting.]

Accepting input rule when handling redraw-event and the illustration window is open:
let F be the illustration-name corresponding to a link-number of current illustration link-number in the Table of Illustrations;
redraw the full illustration of F;
reject input event.

[Same goes for window-rearrange events. This does the work of UGI’s “standard redraw status line on arrange rule” – it redraws the status line – but it also redraws the graphics window.]

Accepting input rule when handling arrange-event and the illustration window is open:
let F be the illustration-name corresponding to a link-number of current illustration link-number in the Table of Illustrations;
redraw the full illustration of F;
redraw the status line;
reject input event.

[Third, rules to convert hyperlink, mouse, and character input into custom actions.]

Handling input rule for a command input-context when handling hyperlink-event:
let N be current input event hyperlink number;
handle the current input event as the action of displaying illustration N;
rule succeeds.

Handling input rule for a command input-context when handling char-event and the illustration window is open:
say line break;
handle the current input event as the action of undisplaying illustration;
rule succeeds.

Handling input rule for a command input-context when handling mouse-event and the illustration window is open:
say line break;
handle the current input event as the action of undisplaying illustration;
rule succeeds.

[Fourth, we customize the prompt for window-open mode. This is only relevant when the display rules give the illustration window less than 100% of the screen.]

Prompt displaying rule when the illustration window is open:
instead say “[run paragraph on]”.

Section - status line rules

Rule for constructing the status line:
center “[the player’s surroundings]” at row 1;
rule succeeds.

Rule for constructing the status line when the illustration window is open:
let N be the current illustration link-number;
let C be the caption corresponding to a link-number of N in the Table of Illustrations;
center C at row 1;
rule succeeds.

Section - special actions

[We create actions for displaying and removing the full illustration. These actions cannot be typed by the player; they’re generated by the parser when a hyperlink, character, or mouse event arrives.]

The current illustration link-number is a number that varies.

Displaying illustration is an action out of world applying to one number.

Check displaying illustration when the illustration window is open:
say “Cannot display illustration [number understood], because illustration [current illustration link-number] is already visible.”;
stop the action.

Carry out displaying illustration:
let N be the number understood;
now the current illustration link-number is N;
let F be the illustration-name corresponding to a link-number of N in the Table of Illustrations;
reveal the full illustration of F;
now the display-status corresponding to a link-number of N in the Table of Illustrations is true.

Undisplaying illustration is an action out of world applying to nothing.

Check undisplaying illustration when the illustration window is not open:
say “Cannot undisplay illustration, because no illustration is visible.”;
stop the action.

[Here is where the game used to clear the screen and attempt a LOOK action after “undisplaying” the illustration. What I would like to do instead is have the game return to showing exactly whatever it was showing before the player clicked on the thumbnail. However, even when I comment out the “clear the screen” command below, the gameplay window is always blank when the illustration goes away. I can’t figure out why.]

Carry out undisplaying illustration:
close the illustration window;
[ clear the screen;
try looking.]

Section - opening the full illustration window

Include (-
Constant GG_ILLUSTRATION_ROCK 210;
Global gg_illustration_window = 0;
-) after “Global Variables” in “Output.i6t”.

To reveal the full illustration of (F - a figure-name):
(-
if (gg_illustration_window == 0) {
gg_illustration_window = glk_window_open(gg_mainwin, (winmethod_Above+winmethod_Proportional), 100, wintype_Graphics, GG_ILLUSTRATION_ROCK );
! Wait for a mouse-click event. (UGI does not yet handle any windows except the main window.)
glk_request_mouse_event(gg_illustration_window);
}
if (gg_illustration_window) { ! testing to see if the window exists
BlackBackground();
DisplayPicture(ResourceIDsOfFigures–>{F});
}
-).

To redraw the full illustration of (F - a figure-name):
(-
BlackBackground();
DisplayPicture(ResourceIDsOfFigures–>{F});
-).

To decide if the illustration window is open:
(- (gg_illustration_window) -).
To decide if the illustration window is not open:
(- (~~gg_illustration_window) -).

Section - blacking out the background

[This is adapted from Emily Short’s Simple Graphical Windows extension. ]

Include (-
[ BlackBackground color result graph_width graph_height;
if (gg_illustration_window) {
result = glk_window_get_size(gg_illustration_window, gg_arguments, gg_arguments+WORDSIZE);
graph_width = gg_arguments–>0;
graph_height = gg_arguments–>1;
glk_window_fill_rect(gg_illustration_window, 0, 0, 0, graph_width, graph_height);
}
];
-).

Section - basic screen effects

[These are copied from Emily Short’s Basic Screen Effects. That extension contains code which is not compatible with UGI, but the text-centering and screen-clearing routines are no problem.]

To center (quote - text):
(- CenterPrintComplex({quote}); -).

To center (quote - text) at the/-- row (depth - a number):
(- CenterPrint({quote}, {depth}); -).

Include (-

[ CenterPrint str depth i j len;
font off;
i = VM_ScreenWidth();
len = TEXT_TY_CharacterLength(str);
if (len > 63) len = 63;
j = (i-len)/2 - 1;
VM_MoveCursorInStatusLine(depth, j);
print (I7_string) str;
font on;
];

[ CenterPrintComplex str i j len;
font off;
print “^”;
i = VM_ScreenWidth();
len = TEXT_TY_CharacterLength(str);
if (len > 63) len = 63;
j = (i-len)/2 - 1;
spaces j;
print (I7_string) str;
font on;
];

-).

To clear the/-- screen:
(- VM_ClearScreen(0); -).

Section - scaling and displaying the picture

[Also from Emily Short’s Simple Graphical Windows extension.]

Include (-
[ DisplayPicture cur_pic result graph_width graph_height img_width img_height h_total w_total h_offset w_offset;
if (gg_illustration_window) {

	result = glk_window_get_size(gg_illustration_window, gg_arguments, gg_arguments+WORDSIZE);
		graph_width = gg_arguments-->0;
		graph_height = gg_arguments-->1;

	result = glk_image_get_info( cur_pic, gg_arguments, gg_arguments+WORDSIZE);
		img_width = gg_arguments-->0;
		img_height = gg_arguments-->1;

	w_total = img_width;
	h_total = img_height;

	if (graph_height - h_total < 0) {	! if the image won't fit, find the scaling factor
		w_total = (graph_height * w_total)/h_total;
		h_total = graph_height;
	}

	if (graph_width - w_total < 0) {
		h_total = (graph_width * h_total)/w_total;
		w_total = graph_width;
	}

	w_offset = (graph_width - w_total)/2; if (w_offset < 0) w_offset = 0;
	h_offset = (graph_height - h_total)/2; if (h_offset < 0) h_offset = 0;

	glk_image_draw_scaled(gg_illustration_window, cur_pic, w_offset, h_offset, w_total, h_total); 
}

];
-).

Section - removing the illustration

To close the illustration window:
(-
if (gg_illustration_window) {
glk_window_close(gg_illustration_window, 0);
gg_illustration_window = 0;
}
-).

Chapter - The Title Page

[Here is where I’m having problems creating a “wait for a key” event immediately after an illustraion. For the sake of this example, I want to have a textual intro page appear immediately after the initial illustration. The player should be able to click on the initial illustration, then see the intro page below, then press a key to begin the game proper.
What always happens instead, is that the initial illustration requires TWO clicks/keypresses to clear, and when it does clear, the game skips the intro page entirely.]

When play begins:
try displaying illustration 999;
center “”;
center “”;
center “”;
center “LET THE SHEEP PUNCHING BEGIN”;
center “(press a key)”;
wait for any key;
clear the screen.
[/code][/spoiler]
sheep_punch.png
gorilla_shark.png
red_button.png

I don’t have a full solution, but a few insights: it’s quite revealing to change the “100” in the “glk_window_open” call in the “To reveal the full illustration of (F - a figure-name)” section of I6 to “50”. That way, the illustration window only takes up half of the space that the main window had, so you can see what’s going on in the main window.

If you do that, it’s clear what’s going wrong with your second problem: the game displays the initial illustration, but then immediately prints the text that’s supposed to come after. The first key press clears this menu, causing the main bit of the game to run, and the second click clears the illustration.

The fundamental point here is that there’s nothing in your illustration code that actually waits for a key or mouse press when showing the illustration. “Carry out displaying illustration” shows the illustration, but then immediately carries on to the next thing. You’ve got event handling code such that when a mouse click occurs in the illustration it goes away, but nothing that pauses the game until that happens. At heart, what you need is for the initial sequence to be something like

When play begins: try displaying illustration 999; wait for the illustration to close; center ""; center ""; center ""; center "LET THE SHEEP PUNCHING BEGIN"; center "(press a key)"; wait for any key; clear the screen.However, precisely what the implementation of “wait for the illustration to close” might be I’m not yet sure. That will require more thought than I can manage tonight, and possibly a bit of Zarf magic.

For the first problem, I think that there isn’t anything actually clearing the main window, it’s just an artifact of what you’re doing. You reduce the main window size to 0, and then make it big again - at least in Windows Glulxe, you end up with the cursor near the top of the window, so it looks like the window has been cleared, but it’s not, it’s just scrolled off the top. Unfortunately I don’t see any way to guarantee what you want - the Glk specification makes no promises that if you shrink and then expand a text buffer window, you get back to seeing exactly what you had before. Sorry.

Thank you, that was actually VERY helpful. I was even able to figure out a “wait for the illustration to close” implemention:

When play begins:
	try displaying illustration 999.


Carry out undisplaying illustration (this is the splash page rule):
	if the current illustration link-number is 999:
		center "";
		center "";
		center "";
		center "LET THE SHEEP PUNCHING BEGIN";
		center "(press a key)";
		wait for any key;
		clear the screen;
		say "[line break][line break][line break][banner text][paragraph break]";
		try looking.

For the first problem, I see what you mean. I may end up having to figure out some sort of workaround for that, but at least I have a better idea now of what’s going on. Thanks!