[go: up one dir, main page]

File: dialbox.c

package info (click to toggle)
lincity 1.13.1-6
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 6,732 kB
  • ctags: 4,794
  • sloc: ansic: 32,736; sh: 8,578; makefile: 628; perl: 445; yacc: 316; sed: 16
file content (370 lines) | stat: -rw-r--r-- 9,641 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
/* ---------------------------------------------------------------------- *
 * dialbox.c
 * This file is part of lincity.
 * Lincity is copyright (c) I J Peters 1995-1997, (c) Greg Sharp 1997-2001.
 * Portions copyright (c) Corey Keasling, 2001.
 * ---------------------------------------------------------------------- */

#include "lcconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdarg.h> /* XXX: WCK: What does configure need to know? */
#include "lcstring.h"
#include "screen.h"
#include "geometry.h"
#include "dialbox.h"
#include "mouse.h"
#include "lclib.h"

static Dialog_Box db_entry[MAX_DBOX_ENTRIES];

static Rect dialog_window;   /* Describes position of window on screen */
static Rect text_window;     /* Describes position of text area on screen */

static Rect db_rect[MAX_DBOX_ENTRIES];    /* region of each line/button */
// static Rect button_rect[MAX_DBOX_ENTRIES];  /* click area for buttons, lines */
// static Rect line_rect[MAX_DBOX_ENTRIES];    /* offset from text_window */

static Mouse_Handle * main_handle;
static Mouse_Handle * text_handle;

static int dbn; /* number of dbox entries */
static int bn;  /* number of buttons */
static int ln;  /* number of lines */

static int db_longest_button; /* total width of all buttons, pixels */
static int db_longest_line;   /* pixel width of longest line */

static int bs; /* button spacing */
static int bse; /* extra spacing, to be added at beginning and end of line */

static int color;

static short db_up = 0;
static int db_return_value;

char * db_screen_buffer; /* hold the screen we overwrite */
char db_screen_fresh;    /* does the buffer hold information? */

/* Mouse handling routines: main_handler() and text_handler()
   main_handler handles the main dialog window: the text area and border.  
   Clicks in the border are useless and ignored; text_handler takes the
   interesting ones
*/
void 
main_handler(int x, int y, int button) 
{
    
}

void
text_handler(int x, int y, int button)
{
    int i;
    for (i = 0; i < dbn; i++) {
	if (mouse_in_rect(&db_rect[i], x, y) && db_entry[i].retval)
	    dialog_close(db_entry[i].retval);
    }


}

/* Keypress handler: dialog_key_handler()
   Iterate through possible hotkeys, returning if key matches.
*/

void
dialog_key_handler (int key) 
{
    int i;

    if (key == 0) 
	return;

    /* CR, LF, and space all activate default button, type 2 */

    if (key == 10 || key == 13 || key == 32) {
	for (i = 0; i < dbn; i++) 
	    if (db_entry[i].type == 2) {
		dialog_close(db_entry[i].retval);
		return;
	    }
    } else {
	for (i = 0; i < dbn;  i++) {
	    if (key == db_entry[i].retval) {
		dialog_close(db_entry[i].retval);
		return;
	    }
	}
    }
}
	    

int
dialog_box(int arg_color, int argc, ...)
{
  va_list ap;
  int i;
  int db_last_button = -1;
  int key;
  char * working_str;

  /* Try the locks */
  if (db_up) {
      printf("Already have a dialog box on screen!\n");
      exit(-1);  /* GCS: I guess this must be a critical bug. */
  } else {
      db_up = 1; /* XXX: Need to reconcile these - don't need both flags */
      db_flag = 1;
  }

  bn = 0; ln = 0; dbn = 0;
  db_longest_button = 0; db_longest_line = 0;
  bs = 0; bse = 0;
  color = arg_color;
  db_screen_fresh = 0;

  va_start(ap, argc);

  /* For each argument pair, get the arguments, determine line or button,
     calculate width/length, adjust total size accordingly, increment type
     count. */
  
  for (i = 0; i < argc; i++) {

      if (dbn >= MAX_DBOX_ENTRIES) {
	  fprintf(stderr,"Too many buttons in dialog_box!\n"
		  "Tweak MAX_DBOX_ENTRIES\n");
	  exit(212);
      }  

    db_entry[dbn].type = (short) va_arg(ap, int);
    db_entry[dbn].retval = (short) va_arg(ap, int);

    if (db_entry[dbn].type == 0) { /* Text strings: Chop a paragraph into
				    individual lines.*/
	char * newline;
	working_str = va_arg(ap, char *);
	do {
	    newline = (char *)strchr(working_str,'\n');
	    if (newline) {
		int linelen = newline - working_str;
		db_entry[dbn].text = (char *)lcalloc(1 + linelen);
		strncpy(db_entry[dbn].text,working_str,linelen);
		db_entry[dbn].text[linelen] = '\0';
		working_str = (newline + 1) != '\0' ? newline + 1 : NULL;
	    } else {
		db_entry[dbn].text = (char *)lcalloc(1 + strlen(working_str));
		strncpy(db_entry[dbn].text,working_str,strlen(working_str));
		db_entry[dbn].text[strlen(working_str)] = '\0';
		working_str = NULL;
	    }

	    db_entry[dbn].type = 0;
	    db_entry[dbn].retval = 0;

	    db_rect[dbn].w = (strlen(db_entry[dbn].text) * CHAR_WIDTH);
	    db_rect[dbn].h = CHAR_HEIGHT;
	    if (db_rect[dbn].w > db_longest_line) 
		db_longest_line = db_rect[dbn].w;

	    ln++;
	    dbn++;
	} while ((working_str != NULL) && (strlen(working_str) >= 1));
    } else { 
	db_entry[dbn].text = va_arg(ap, char *);
	db_rect[dbn].w = ((strlen(db_entry[dbn].text) * CHAR_WIDTH)
			  + (BUTTON_BORDER * 2));
	db_rect[dbn].h = (CHAR_HEIGHT + (BUTTON_BORDER * 2));
	
	db_longest_button += db_rect[dbn].w;
	bn++;
	dbn++;
    }
  }

  va_end(ap);

  /* figure out how high and wide the box needs to be */
  text_window.h = 
      ((ln * (CHAR_HEIGHT + DB_V_SPACE)) + BUTTON_HEIGHT + DB_V_SPACE);

  if ((db_longest_button + (bn * BUTTON_MIN_SPACING)) > 
      (db_longest_line + LINE_MIN_SPACING)) {
      text_window.w = (db_longest_button + (bn * BUTTON_MIN_SPACING));
  } else {
      text_window.w = (db_longest_line + LINE_MIN_SPACING);
  }   

  /* Determine button spacing;
     add some extra in front and back */

  bs = (text_window.w - db_longest_button) / bn;
  bse = ((text_window.w - db_longest_line) % bn) / 2;  

  /* Position the buttons and lines */

  for (i = 0; i < dbn; i++)
  {
      if (db_entry[i].type) {                                  /* Buttons */
	  if (db_last_button == -1)
	      db_rect[i].x = ((bs + bse) / 2) - BUTTON_BORDER;
	  else
	      db_rect[i].x = ((db_rect[db_last_button].x  
			       + db_rect[db_last_button].w + bs)
			      - BUTTON_BORDER);
	  
	  db_rect[i].y = ((ln * (CHAR_HEIGHT + DB_V_SPACE) + DB_V_SPACE) 
			  - BUTTON_BORDER);
	  
	  db_last_button = i;
      } else {                                                   /* Lines */
	db_rect[i].x = ((text_window.w - db_rect[i].w) / 2);
	db_rect[i].y = (i * (CHAR_HEIGHT + DB_V_SPACE));
      }
  }
	  
  /* Figure out window size */

  dialog_window.w = (text_window.w + BORDER_SIZE*2);
  dialog_window.h = (text_window.h + BORDER_SIZE*2);
  
  main_handle = mouse_register(&scr.client_win,&main_handler);
  text_handle = mouse_register(&text_window,&text_handler);

  dialog_refresh();

  db_return_value = 0;

  /* Wait for the user to click on it or press an appropriate key */
  /* Mouse clicks arrive from the mouse handler and set db_return_value */

  while (!db_return_value)  {
#ifndef LC_X11
      lc_usleep (1000); /* call_wait_event does this for X11 */
#endif
      
#ifdef LC_X11
      call_wait_event ();
      key = x_key_value;
      x_key_value = 0;
#elif defined (WIN32)
      HandleMouse ();
      key = GetKeystroke ();
#else
      mouse_update ();
      key = vga_getkey ();
#endif
      if (key == 0) continue;

      if (key == 10 || key == 13 || key == ' ') /* default button */
	  for (i = 0; i <= dbn; i++) {
	      if (db_entry[i].type == 2) {
		  dialog_close(db_entry[i].retval);
		  break;
	      }
	  }
      else
	  for (i = 0; i <= dbn; i++) {
	      if (key == db_entry[i].retval) {
		  dialog_close(key);
		  break;
	      }
	  }
  }
  return (db_return_value);
}


void 
dialog_refresh(void)
{
  int i;  /* Line, Button incrementors */
  if (!db_up) 
      return;

  /* Determine screen position */
  dialog_window.x = (scr.client_w / 2) - (dialog_window.w / 2);
  dialog_window.y = (scr.client_h / 2) - (dialog_window.h / 2);

  text_window.x = dialog_window.x + BORDER_SIZE;
  text_window.y = dialog_window.y + BORDER_SIZE;

  hide_mouse();

  if (screen_refreshing && db_screen_fresh) {
      free(db_screen_buffer);
      db_screen_fresh = 0;
  }

  if (!db_screen_fresh) {
      db_screen_buffer = (char *)lcalloc(dialog_window.w * dialog_window.h);
      Fgl_getrect(&dialog_window,db_screen_buffer);
      db_screen_fresh = 1;
  };


  /* Draw the border, and fill the background */
  draw_bezel(dialog_window,BORDER_SIZE,color);

  Fgl_fillbox(text_window.x,text_window.y,text_window.w,text_window.h,color);

#ifdef USE_EXPANDED_FONT
    gl_setwritemode (WRITEMODE_MASKED | FONT_EXPANDED);
#else
    Fgl_setfontcolors (color, TEXT_FG_COLOUR);
#endif

    /* Loop calculating line position, and drawing the line */
    for (i = 0; i < dbn; i++)
    {

	if (db_entry[i].type) {
	    Fgl_fillbox(db_rect[i].x + text_window.x,
			db_rect[i].y + text_window.y,
			db_rect[i].w,
			db_rect[i].h,
			white(0));
	}
	Fgl_write(db_rect[i].x + text_window.x + BUTTON_BORDER, 
		  db_rect[i].y + text_window.y + BUTTON_BORDER,
		  db_entry[i].text);
    }

#ifdef USE_EXPANDED_FONT
    gl_setwritemode (WRITEMODE_OVERWRITE | FONT_EXPANDED);
#else
    Fgl_setfontcolors (TEXT_BG_COLOUR, TEXT_FG_COLOUR);
#endif

  redraw_mouse();

}

/* dialog_close: close the mouse handle and remember we closed it;
   save the results; put the old screen back up and remember that too. */

void
dialog_close(int return_value) 
{
    int i;
    
    mouse_unregister(main_handle);
    mouse_unregister(text_handle);
    db_up = 0;
    db_return_value = return_value;

    for (i = 0; i < dbn; i++) 
	if (db_entry[i].type == DB_PARA) 
	    free(db_entry[i].text);
    
    if (db_screen_fresh) {
	Fgl_putrect(&dialog_window,db_screen_buffer);
	free(db_screen_buffer);
	db_screen_fresh = 0;
    }

    db_flag = 0;
}