Update interpreters to latest Garglk codebase
[projects/chimara/chimara.git] / interpreters / nitfol / op_v6.c
1 /*  Nitfol - z-machine interpreter using Glk for output.
2     Copyright (C) 1999  Evin Robertson
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18     The author can be reached at nitfol@deja.com
19 */
20 #include "nitfol.h"
21
22
23 typedef enum { z6_text, z6_picture, z6_rectangle } z6_type;
24
25 struct graph_piece {
26   struct graph_piece *next;
27   struct graph_piece *prev;
28
29   int window;
30   zword x, y;
31   zword width, height;
32   z6_type type;
33
34   char *text;
35   zword picnum;
36   int color;   /* -1 means erase to background color */
37 };
38
39 static struct graph_piece *older_pieces;
40
41
42 static zwinid lower_win;
43
44 static zword window_props[8][16];
45 static int current_window;
46
47 typedef enum { w_y_coord,     w_x_coord,   w_y_size,     w_x_size,
48                w_y_cursor,    w_x_cursor,  w_l_margin,   w_r_margin,
49                w_nl_routine,  w_int_count, w_text_style, w_colour_data,
50                w_font_number, w_font_size, w_attributes, w_line_count
51 } win_prop_names;
52
53 typedef enum { wa_wrapping, wa_scrolling, wa_transcript, wa_buffered } win_attributes;
54
55
56 static int get_window_num(int arg)
57 {
58   if(numoperands <= arg || operand[arg] == neg(3))
59     return current_window;
60   if(operand[arg] > 7) {
61     n_show_error(E_OUTPUT, "illegal window number", operand[arg]);
62     return current_window;
63   }
64   return operand[arg];
65 }
66
67 static BOOL check_window_prop(int prop_num)
68 {
69   if(prop_num > 15) {
70     n_show_error(E_OUTPUT, "illegal wind_prop number", prop_num);
71     return FALSE;
72   }
73   return TRUE;
74 }
75
76
77 int is_in_bounds(glui32 x1, glui32 y1, glui32 width1, glui32 height1,
78                  glui32 x2, glui32 y2, glui32 width2, glui32 height2)
79 {
80   return (x1 >= x2 && y1 >= y2 &&
81           x1 + width1 <= x2 + width2 && y1 + height1 <= y2 + height2);
82 }
83
84
85 static void add_piece(struct graph_piece new_piece)
86 {
87   struct graph_piece *p, *q;
88
89   return;
90
91   if(new_piece.x + new_piece.width >
92      window_props[current_window][w_x_coord] +
93      window_props[current_window][w_x_size]) {
94     new_piece.width = window_props[current_window][w_x_coord] +
95                       window_props[current_window][w_x_size] -
96                       new_piece.x;
97   }
98
99   if(new_piece.y + new_piece.height >
100      window_props[current_window][w_y_coord] +
101      window_props[current_window][w_y_size]) {
102     new_piece.height = window_props[current_window][w_y_coord] +
103                        window_props[current_window][w_y_size] -
104                        new_piece.y;
105   }
106
107   q = NULL;
108   p = older_pieces;
109   while(p) {
110     if(is_in_bounds(p->x, p->y, p->width, p->height,
111                     new_piece.x, new_piece.y,
112                     new_piece.width, new_piece.height)) {
113       if(q) {
114         q->next = p->next;
115         n_free(p);
116         p = q->next;
117       } else {
118         LEremove(older_pieces);
119         p = older_pieces;
120       }
121     } else {
122       p = p-> next;
123     }
124     q = p;
125   }
126
127
128   LEadd(older_pieces, new_piece);
129
130
131
132 }
133
134
135 void v6_main_window_is(zwinid win)
136 {
137   lower_win = win;
138 }
139
140
141 void op_set_window6(void)
142 {
143   int win = get_window_num(0);
144   current_window = win;
145 }
146
147
148 void op_set_margins(void)
149 {
150   int win = get_window_num(2);
151
152 #ifdef DEBUG_IO
153   n_show_debug(E_OUTPUT, "set_margins w=", operand[2]);
154   n_show_debug(E_OUTPUT, "set_margins l=", operand[0]);
155   n_show_debug(E_OUTPUT, "set_margins r=", operand[1]);
156 #endif
157
158   window_props[win][w_l_margin] = operand[0];
159   window_props[win][w_r_margin] = operand[1];
160
161   /* FIXME: move cursor */
162 }
163
164
165 void op_move_window(void)
166 {
167   int win = get_window_num(0);
168
169 #ifdef DEBUG_IO
170   n_show_debug(E_OUTPUT, "move_window w=", operand[0]);
171   n_show_debug(E_OUTPUT, "move_window y=", operand[1]);
172   n_show_debug(E_OUTPUT, "move_window x=", operand[2]);
173 #endif
174
175   window_props[win][w_y_coord] = operand[1];
176   window_props[win][w_x_coord] = operand[2];
177 }
178
179
180 void op_window_size(void)
181 {
182   int win = get_window_num(0);
183
184 #ifdef DEBUG_IO
185   n_show_debug(E_OUTPUT, "window_size w=", operand[0]);
186   n_show_debug(E_OUTPUT, "window_size y=", operand[1]);
187   n_show_debug(E_OUTPUT, "window_size x=", operand[2]);
188 #endif
189
190   window_props[win][w_y_size] = operand[1];
191   window_props[win][w_x_size] = operand[2];
192 }
193
194
195 void op_window_style(void)
196 {
197   zword attr;
198   int win = get_window_num(0);
199
200   if(numoperands < 3)
201     operand[2] = 0;
202
203   attr = window_props[win][w_attributes];
204   switch(operand[2]) {
205   case 0: attr  = operand[1]; break;
206   case 1: attr |= operand[1]; break;
207   case 2: attr &= ~(operand[1]); break;
208   case 3: attr ^= operand[1]; break;
209   default: n_show_error(E_OUTPUT, "invalid flag operation", operand[2]);
210   }
211
212   window_props[win][w_attributes] = attr;
213 }
214
215
216 void op_get_wind_prop(void)
217 {
218   int win = get_window_num(0);
219
220   if(!check_window_prop(operand[1])) {
221     mop_store_result(0);
222     return;
223   }
224   mop_store_result(window_props[win][operand[1]]);
225 }
226
227
228 void op_put_wind_prop(void)
229 {
230   int win = get_window_num(0);
231
232   if(!check_window_prop(operand[1])) {
233     mop_store_result(0);
234     return;
235   }
236   window_props[win][operand[1]] = operand[2];
237 }
238
239
240 void op_scroll_window(void)
241 {
242   ;
243 }
244
245
246 void op_read_mouse(void)
247 {
248   ;
249 }
250
251
252 void op_mouse_window(void)
253 {
254   ;
255 }
256
257
258 void op_print_form(void)
259 {
260   ;
261 }
262
263
264 void op_make_menu(void)
265 {
266   mop_skip_branch();
267 }
268
269
270 void op_picture_table(void)
271 {
272   ; /* Glk contains no image prefetching facilities, so nothing to do here */
273 }
274
275
276 void op_draw_picture(void)
277 {
278   struct graph_piece new_piece;
279   glui32 width, height;
280
281   z_put_char(lower_win, 13); /* Work around a bug in xglk */
282   draw_intext_picture(lower_win, operand[0], imagealign_MarginLeft);
283
284
285   /*
286
287   new_piece.window = current_window;
288   new_piece.x = operand[2] + window_props[current_window][w_x_coord];
289   new_piece.y = operand[1] + window_props[current_window][w_y_coord];
290
291   wrap_glk_image_get_info(operand[0], &width, &height);
292
293   new_piece.width = width;
294   new_piece.height = height;
295
296   new_piece.type = z6_picture;
297   new_piece.picnum = operand[0];
298
299   add_piece(new_piece);
300
301   */
302 }
303
304
305 void op_picture_data(void)
306 {
307   if(glk_gestalt(gestalt_Graphics, 0)) {
308     glui32 width, height;
309     
310     if(operand[0] == 0) {
311       LOWORDwrite(operand[1], imagecount);
312       LOWORDwrite(operand[1], 42); /* FIXME: where do I get picture release? */
313     }
314     else if(wrap_glk_image_get_info(operand[0], &width, &height)) {
315       LOWORDwrite(operand[1], height);
316       LOWORDwrite(operand[1] + ZWORD_SIZE, width);
317       mop_take_branch();
318       return;
319     }
320   }
321   mop_skip_branch();
322 }
323
324
325 void op_erase_picture(void)
326 {
327   struct graph_piece new_piece;
328   glui32 width, height;
329
330   new_piece.window = current_window;
331   new_piece.x = operand[2] + window_props[current_window][w_x_coord];
332   new_piece.y = operand[1] + window_props[current_window][w_y_coord];
333
334   wrap_glk_image_get_info(operand[0], &width, &height);
335
336   new_piece.width = width;
337   new_piece.height = height;
338
339   new_piece.type = z6_rectangle;
340   new_piece.color = -1;
341
342   add_piece(new_piece);
343
344 }
345