~ubuntu-branches/ubuntu/gutsy/inform/gutsy

« back to all changes in this revision

Viewing changes to include/menus.h

  • Committer: Bazaar Package Importer
  • Author(s): Mark Baker
  • Date: 2004-03-29 23:52:44 UTC
  • Revision ID: james.westby@ubuntu.com-20040329235244-fox1z1yv7d6vojoo
Tags: upstream-6.30
ImportĀ upstreamĀ versionĀ 6.30

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
! -------------------------------------------------------------------------
 
2
!   Menus.h           A library extension providing easier and better menus
 
3
!                                                      Graham Nelson 961113
 
4
!                                                       Kevin Bracey 011128
 
5
!
 
6
!   A menu is a tree of objects of class Option.  A Menu is an Option which
 
7
!   launches a fresh menu when chosen.  To choose option O, send the
 
8
!   message:
 
9
!
 
10
!       O.select();
 
11
!
 
12
!   So to start off a menu session, send this message to the top menu.
 
13
!
 
14
!   Here's a simple menu structure:
 
15
!
 
16
!       Menu "Instructions for playing Mordred";
 
17
!       Menu   -> "How to play adventure games";
 
18
!       Option -> -> "Looking around"
 
19
!                     with description "I am your eyes and ears ...";
 
20
!       Option -> -> "Taking and Dropping"
 
21
!                     with description "When you find items ...";
 
22
!       Option -> "About the author"
 
23
!                  with description "The author was born in ...";
 
24
!
 
25
!   Menus produced in this code are automatically divided into pages
 
26
!   so that they'll always fit on the screen, whatever size the screen is
 
27
!   and however many options there are.
 
28
!
 
29
!   Note that since objects can always be moved about in play, it's easy
 
30
!   to create new menu structures to fit the circumstances of the moment.
 
31
!   (For example, a hints menu which gives hints only on currently open
 
32
!   puzzles.)
 
33
!
 
34
!   You can instead write a routine to receive the "description" message.
 
35
!   Then the text printed when an option is chosen can also vary.
 
36
!
 
37
!   If you return 2 from such a routine, then the game does not prompt
 
38
!   the player to press a key before going back into the menu.
 
39
!   If you return 3, then the whole menu is closed up immediately.
 
40
!
 
41
!   Finally, you can always give your own "select" routine for an Option.
 
42
!   The rules for return values are the same; what's different is that
 
43
!   this way the screen will not be cleared and given a nice banner when
 
44
!   the option is chosen.  (Nothing visible will happen unless you do
 
45
!   it yourself.)  The SwitchOption class is an example of the kind of
 
46
!   gadget you might want this for:
 
47
!
 
48
!       Menu "Game settings";
 
49
!       SwitchOption -> FullRoomD   "full room descriptions" has on;
 
50
!       SwitchOption -> WordyP      "wordier prompts";
 
51
!       SwitchOption -> AllowSavedG "allow saved games" has on;
 
52
!
 
53
!   Choosing any of these switch-options flips them between on and off.
 
54
!   In your program, you can test
 
55
!
 
56
!       if (WordyP has on) ...
 
57
!
 
58
!   and so forth to check the current state.
 
59
! -------------------------------------------------------------------------
 
60
 
 
61
Ifndef PKEY__TX;
 
62
 
 
63
Constant LIB_PRE_63;
 
64
 
 
65
!   Then we are using library 6/1 or 6/2, which won't have defined these:
 
66
 
 
67
Constant NKEY__TX     = "  N = next option";
 
68
Constant PKEY__TX     = "P = previous";
 
69
Constant QKEY1__TX    = "  Q = resume game";
 
70
Constant QKEY2__TX    = "Q = previous menu";
 
71
Constant RKEY__TX     = "RETURN = select option";
 
72
 
 
73
Constant NKEY1__KY    = 'N';
 
74
Constant NKEY2__KY    = 'n';
 
75
Constant PKEY1__KY    = 'P';
 
76
Constant PKEY2__KY    = 'p';
 
77
Constant QKEY1__KY    = 'Q';
 
78
Constant QKEY2__KY    = 'q';
 
79
 
 
80
Endif;
 
81
 
 
82
Global screen_width;
 
83
Global screen_height;
 
84
Global char_width;
 
85
Global char_height;
 
86
 
 
87
Array ForUseByOptions -> 129;
 
88
 
 
89
#Iftrue #version_number==6;
 
90
[ Menus_Measure s;
 
91
    @output_stream 3 ForUseByOptions;
 
92
    print (string) s;
 
93
    @output_stream -3;
 
94
    return 0-->24;
 
95
];
 
96
#Endif;
 
97
 
 
98
Class Option
 
99
 with emblazon
 
100
      [ bar_height page pages temp;
 
101
 
 
102
          screen_width = 0->33;
 
103
 
 
104
          !   Clear screen:
 
105
 
 
106
          @erase_window -1;
 
107
          #Iftrue #version_number==6;
 
108
          @set_cursor -1;
 
109
          @mouse_window -1;
 
110
          temp = bar_height * char_height;
 
111
          @split_window temp;
 
112
          #Ifnot;
 
113
          @split_window bar_height;
 
114
          #Endif;
 
115
 
 
116
          !   Black out top line in reverse video:
 
117
          @set_window 1;
 
118
          @set_cursor 1 1;
 
119
          #Iftrue #version_number==6;
 
120
          @set_font 4 -> temp;
 
121
          #Endif;
 
122
          style reverse; spaces(screen_width);
 
123
          #Iftrue #version_number==6;
 
124
          @set_font 1 -> temp;
 
125
          #Endif;
 
126
 
 
127
          if (#version_number ~= 6 && standard_interpreter == 0)
 
128
              @set_cursor 1 1;
 
129
          else
 
130
          {   ForUseByOptions-->0 = 128;
 
131
              @output_stream 3 ForUseByOptions;
 
132
              print (name) self;
 
133
              if (pages ~= 1) print " [", page, "/", pages, "]";
 
134
              @output_stream -3;
 
135
              #Iftrue #version_number==6;
 
136
              temp = 1 + (screen_width*char_width - 0-->24)/2;
 
137
              #Ifnot;
 
138
              temp = (screen_width - ForUseByOptions-->0)/2;
 
139
              #Endif;
 
140
              @set_cursor 1 temp;
 
141
          }
 
142
 
 
143
          print (name) self;
 
144
          if (pages ~= 1) print " [", page, "/", pages, "]";
 
145
 
 
146
          return ForUseByOptions-->0;
 
147
      ],
 
148
      select
 
149
      [;  self.emblazon(1, 1, 1);
 
150
 
 
151
          style roman; @set_window 0; font on; new_line; new_line;
 
152
 
 
153
          if (self provides description)
 
154
              return self.description();
 
155
 
 
156
          "[No text written for this option.]^";
 
157
      ];    
 
158
 
 
159
Class Menu class Option
 
160
 with select
 
161
      [ count j obj pkey  line oldline top_line bottom_line
 
162
                            page pages options top_option y x;
 
163
 
 
164
          screen_width = 0->33;
 
165
          screen_height = 0->32;
 
166
          #Iftrue #version_number==6;
 
167
          @set_font 4 -> x;
 
168
          char_width = 0->39;
 
169
          char_height = 0->38;
 
170
          @set_font x -> x;
 
171
          #Ifnot;
 
172
          char_width = 0->38;
 
173
          char_height = 0->39;
 
174
          #Endif;
 
175
          if (screen_height == 0 or 255) screen_height = 18;
 
176
          screen_height = screen_height - 7;
 
177
 
 
178
          options = 0;
 
179
          objectloop (obj in self && obj ofclass Option) options++;
 
180
          if (options == 0) return 2;
 
181
 
 
182
          pages = options/screen_height;
 
183
          if (options%screen_height ~= 0) pages++;
 
184
 
 
185
          top_line = 6;
 
186
 
 
187
          page = 1;
 
188
 
 
189
          line = top_line;
 
190
 
 
191
          .ReDisplay;
 
192
 
 
193
          top_option = (page - 1) * screen_height;
 
194
 
 
195
          self.emblazon(5 + options, page, pages);
 
196
          
 
197
          #Iftrue #version_number==6;
 
198
          x = 1 + char_width; y = 1 + char_height; @set_cursor y 1;
 
199
          @set_font 4->j; spaces(screen_width); @set_font 1->j;
 
200
          @set_cursor y x; print (string) NKEY__TX;
 
201
          j = 1+screen_width*char_width - Menus_Measure(PKEY__TX) - char_width;
 
202
          @set_cursor y j; print (string) PKEY__TX;
 
203
          
 
204
          y = y + char_height; @set_cursor y 1;
 
205
          @set_font 4->j; spaces(screen_width); @set_font 1->j;
 
206
          @set_cursor y x; print (string) RKEY__TX;
 
207
          if (sender ofclass Option) j = QKEY2__TX; else j = QKEY1__TX;
 
208
          j = 1+screen_width*char_width - Menus_Measure(j) - char_width;
 
209
          @set_cursor y j;
 
210
          #Ifnot;
 
211
          @set_cursor 2 1; spaces(screen_width);
 
212
          @set_cursor 2 2; print (string) NKEY__TX;
 
213
          j = screen_width-12; @set_cursor 2 j; print (string) PKEY__TX;
 
214
 
 
215
          @set_cursor 3 1; spaces(screen_width);
 
216
          @set_cursor 3 2; print (string) RKEY__TX;
 
217
          j = screen_width-17; @set_cursor 3 j;
 
218
          #Endif;
 
219
 
 
220
          if (sender ofclass Option)
 
221
              print (string) QKEY2__TX;
 
222
          else
 
223
              print (string) QKEY1__TX;
 
224
          style roman;
 
225
 
 
226
          count = top_line; j = 0;
 
227
          objectloop (obj in self && obj ofclass Option)
 
228
          {   if (j >= top_option && j < (top_option + screen_height))
 
229
              {   
 
230
                  #Iftrue #version_number==6;
 
231
                  y = 1 + (count-1)*char_height;
 
232
                  x = 1 + 4*char_width;
 
233
                  @set_cursor y x;
 
234
                  print (char) ' ';
 
235
                  #Ifnot;
 
236
                  @set_cursor count 6;
 
237
                  #Endif;
 
238
                  print (name) obj;
 
239
                  count++;
 
240
              }
 
241
              j++;
 
242
          }
 
243
          bottom_line = count - 1;
 
244
          oldline = 0;
 
245
 
 
246
          for(::)
 
247
          {   !   Move or create the > cursor:
 
248
 
 
249
              if (line~=oldline)
 
250
              {   #Iftrue #version_number == 6;
 
251
                  x = 1 + 4*char_width;
 
252
                  count = top_line; j = 0;
 
253
                  objectloop (obj in self && obj ofclass Option)
 
254
                  {   if (j >= top_option && j < (top_option + screen_height))
 
255
                      {   if (j - top_option + top_line == oldline or line)
 
256
                          {   if (j - top_option + top_line == line)
 
257
                                  style reverse;
 
258
                              y = 1 + (count-1)*char_height;
 
259
                              @set_cursor y x;
 
260
                              print (char) ' ', (name) obj, (char) ' ';
 
261
                              style roman;
 
262
                          }
 
263
                          count++;
 
264
                      }
 
265
                      j++;
 
266
                  }
 
267
                  #Ifnot;
 
268
                  if (oldline~=0) { @set_cursor oldline 4; print " "; }
 
269
                  @set_cursor line 4; print ">";
 
270
                  #Endif;
 
271
              }
 
272
              oldline = line;
 
273
 
 
274
              @read_char 1 -> pkey;
 
275
              
 
276
              if (pkey == 253 or 254)
 
277
              {   !   Mouse click:
 
278
                  x = (0-->27-->1 - 1) / char_width + 1;
 
279
                  y = (0-->27-->2 - 1) / char_height + 1;
 
280
                  if (y >= top_line && y <= bottom_line)
 
281
                  {   line = y;
 
282
                      if (pkey == 253)
 
283
                         pkey = 13;
 
284
                      
 
285
                  }
 
286
                  else if (y == 2)
 
287
                  {   if (x <= screen_width / 2)
 
288
                          pkey = 130;
 
289
                      else
 
290
                          pkey = 129;
 
291
                  }
 
292
                  else if (y == 3)
 
293
                  {   if (x <= screen_width / 2)
 
294
                          pkey = 13;
 
295
                      else
 
296
                          pkey = 27;
 
297
                  }
 
298
                  else
 
299
                      @sound_effect 1;
 
300
              }
 
301
 
 
302
              if (pkey == NKEY1__KY or NKEY2__KY or 130)
 
303
              {   !   Cursor down:
 
304
                  line++;
 
305
                  if (line > bottom_line)
 
306
                  {   line = top_line;
 
307
                      if (pages > 1)
 
308
                      {   if (page == pages) page = 1; else page++;
 
309
                          jump ReDisplay;
 
310
                      }
 
311
                  }    
 
312
                  continue;
 
313
              }
 
314
 
 
315
              if (pkey == PKEY1__KY or PKEY2__KY or 129)
 
316
              {   !   Cursor up:
 
317
                  line--;
 
318
                  if (line < top_line)
 
319
                  {   line = bottom_line;
 
320
                      if (pages > 1)
 
321
                      {   if (page == 1)
 
322
                          {   page = pages;
 
323
                              line = top_line
 
324
                                     + (options % screen_height) - 1;
 
325
                          }
 
326
                          else
 
327
                          {   page--; line = top_line + screen_height - 1;
 
328
                          }
 
329
                          jump ReDisplay;
 
330
                      }
 
331
                  }    
 
332
                  continue;
 
333
              }
 
334
 
 
335
              if (pkey==QKEY1__KY or QKEY2__KY or 27 or 131) break;
 
336
 
 
337
              if (pkey==10 or 13 or 132)
 
338
              {   count = 0;
 
339
                  objectloop (obj in self && obj ofclass Option)
 
340
                  {   if (count == top_option + line - top_line) break;
 
341
                      count++;
 
342
                  }
 
343
 
 
344
                  switch(obj.select())
 
345
                  {   2: jump ReDisplay;
 
346
                      3: jump ExitMenu;
 
347
                  }
 
348
 
 
349
                  #ifdef LIB_PRE_63;
 
350
                  print "[Please press SPACE to continue.]^";
 
351
                  #ifnot;
 
352
                  L__M(##Miscellany, 53);
 
353
                  #endif;
 
354
                  @read_char 1 -> pkey;
 
355
                  jump ReDisplay;
 
356
              }
 
357
          }
 
358
 
 
359
          .ExitMenu;
 
360
 
 
361
          if (sender ofclass Option) return 2;
 
362
 
 
363
          #Iftrue #version_number==6;
 
364
          @set_font 1 -> x;
 
365
          #Ifnot;
 
366
          font on;
 
367
          #Endif;
 
368
          @set_cursor 1 1;
 
369
          @erase_window -1; @set_window 0;
 
370
          #Iftrue #version_number==6;
 
371
          @set_cursor -2;
 
372
          #Endif;
 
373
          new_line; new_line; new_line;
 
374
          if (deadflag==0) <<Look>>;
 
375
          return 2;
 
376
      ];
 
377
 
 
378
Class SwitchOption class Option
 
379
  with short_name
 
380
       [;  print (object) self, " ";
 
381
           if (self has on) print "(on)"; else print "(off)";
 
382
           rtrue;
 
383
       ],
 
384
       select
 
385
       [;  if (self has on) give self ~on; else give self on;
 
386
           return 2;
 
387
       ];
 
388
 
 
389
! ------------------------------------------------------------------------