Main Page | Data Structures | Directories | File List | Data Fields | Globals

dialbox.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------- *
00002  * dialbox.c
00003  * This file is part of lincity.
00004  * Lincity is copyright (c) I J Peters 1995-1997, (c) Greg Sharp 1997-2001.
00005  * Portions copyright (c) Corey Keasling, 2001.
00006  * ---------------------------------------------------------------------- */
00007 
00008 #include "lcconfig.h"
00009 #include <stdio.h>
00010 #include <stdlib.h>
00011 #include <math.h>
00012 #include <stdarg.h> /* XXX: WCK: What does configure need to know? */
00013 #include "lcstring.h"
00014 #include "screen.h"
00015 #include "geometry.h"
00016 #include "dialbox.h"
00017 #include "mouse.h"
00018 #include "lclib.h"
00019 
00020 static Dialog_Box db_entry[MAX_DBOX_ENTRIES];
00021 static Dialog_Box * button[MAX_DBOX_ENTRIES];
00022 static Dialog_Box * line[MAX_DBOX_ENTRIES];
00023 
00024 static Rect dialog_window;   /* Describes position of window on screen */
00025 static Rect text_window;     /* Describes position of text area on screen */
00026 
00027 static Rect db_rect[MAX_DBOX_ENTRIES];    /* region of each line/button */
00028 // static Rect button_rect[MAX_DBOX_ENTRIES];  /* click area for buttons, lines */
00029 // static Rect line_rect[MAX_DBOX_ENTRIES];    /* offset from text_window */
00030 
00031 static Mouse_Handle * main_handle;
00032 static Mouse_Handle * text_handle;
00033 
00034 static int dbn; /* number of dbox entries */
00035 static int bn;  /* number of buttons */
00036 static int ln;  /* number of lines */
00037 
00038 static int db_longest_button; /* total width of all buttons, pixels */
00039 static int db_longest_line;   /* pixel width of longest line */
00040 
00041 static int bs; /* button spacing */
00042 static int bse; /* extra spacing, to be added at beginning and end of line */
00043 
00044 static int color;
00045 
00046 static short db_up = 0;
00047 static int db_return_value;
00048 
00049 char * db_screen_buffer; /* hold the screen we overwrite */
00050 char db_screen_fresh;    /* does the buffer hold information? */
00051 
00052 /* Mouse handling routines: main_handler() and text_handler()
00053    main_handler handles the main dialog window: the text area and border.  
00054    Clicks in the border are useless and ignored; text_handler takes the
00055    interesting ones
00056 */
00057 void 
00058 main_handler(int x, int y, int button) 
00059 {
00060     
00061 }
00062 
00063 void
00064 text_handler(int x, int y, int button)
00065 {
00066     int i;
00067     for (i = 0; i < dbn; i++) {
00068         if (mouse_in_rect(&db_rect[i], x, y) && db_entry[i].retval)
00069             dialog_close(db_entry[i].retval);
00070     }
00071 
00072 
00073 }
00074 
00075 /* Keypress handler: dialog_key_handler()
00076    Iterate through possible hotkeys, returning if key matches.
00077 */
00078 
00079 void
00080 dialog_key_handler (int key) 
00081 {
00082     int i;
00083 
00084     if (key == 0) 
00085         return;
00086 
00087     /* CR, LF, and space all activate default button, type 2 */
00088 
00089     if (key == 10 || key == 13 || key == 32) 
00090         for (i = 0; i < dbn; i++) 
00091             if (db_entry[i].type == 2) {
00092                 dialog_close(db_entry[i].retval);
00093                 return;
00094             }
00095     else
00096         for (i = 0; i < dbn;  i++) 
00097             if (key == db_entry[i].retval) {
00098                 dialog_close(db_entry[i].retval);
00099                 return;
00100             }
00101 }
00102             
00103 
00104 int
00105 dialog_box(int arg_color, int argc, ...)
00106 {
00107   va_list ap;
00108   int i;
00109   int db_last_button = -1;
00110   int key;
00111   char * working_str;
00112 
00113   /* Try the locks */
00114   if (db_up) {
00115       printf("Already have a dialog box on screen!\n");
00116       exit(-1);  /* GCS: I guess this must be a critical bug. */
00117   } else {
00118       db_up = 1; /* XXX: Need to reconcile these - don't need both flags */
00119       db_flag = 1;
00120   }
00121 
00122   bn = 0; ln = 0; dbn = 0;
00123   db_longest_button = 0; db_longest_line = 0;
00124   bs = 0; bse = 0;
00125   color = arg_color;
00126   db_screen_fresh = 0;
00127 
00128   va_start(ap, argc);
00129 
00130   /* For each argument pair, get the arguments, determine line or button,
00131      calculate width/length, adjust total size accordingly, increment type
00132      count. */
00133   
00134   for (i = 0; i < argc; i++) {
00135 
00136       if (dbn >= MAX_DBOX_ENTRIES) {
00137           fprintf(stderr,"Too many buttons in dialog_box!\n"
00138                   "Tweak MAX_DBOX_ENTRIES\n");
00139           exit(212);
00140       }  
00141 
00142     db_entry[dbn].type = (short) va_arg(ap, int);
00143     db_entry[dbn].retval = (short) va_arg(ap, int);
00144 
00145     if (db_entry[dbn].type == 0) { /* Text strings: Chop a paragraph into
00146                                     individual lines.*/
00147         char * newline;
00148         working_str = va_arg(ap, char *);
00149         do {
00150             newline = (char *)strchr(working_str,'\n');
00151             if (newline) {
00152                 int linelen = newline - working_str;
00153                 db_entry[dbn].text = (char *)lcalloc(1 + linelen);
00154                 strncpy(db_entry[dbn].text,working_str,linelen);
00155                 db_entry[dbn].text[linelen] = '\0';
00156                 working_str = (newline + 1) != '\0' ? newline + 1 : NULL;
00157             } else {
00158                 db_entry[dbn].text = (char *)lcalloc(1 + strlen(working_str));
00159                 strncpy(db_entry[dbn].text,working_str,strlen(working_str));
00160                 db_entry[dbn].text[strlen(working_str)] = '\0';
00161                 working_str = NULL;
00162             }
00163 
00164             db_entry[dbn].type = 0;
00165             db_entry[dbn].retval = 0;
00166 
00167             db_rect[dbn].w = (strlen(db_entry[dbn].text) * CHAR_WIDTH);
00168             db_rect[dbn].h = CHAR_HEIGHT;
00169             if (db_rect[dbn].w > db_longest_line) 
00170                 db_longest_line = db_rect[dbn].w;
00171 
00172             ln++;
00173             dbn++;
00174         } while ((working_str != NULL) && (strlen(working_str) >= 1));
00175     } else { 
00176         db_entry[dbn].text = va_arg(ap, char *);
00177         db_rect[dbn].w = ((strlen(db_entry[dbn].text) * CHAR_WIDTH)
00178                           + (BUTTON_BORDER * 2));
00179         db_rect[dbn].h = (CHAR_HEIGHT + (BUTTON_BORDER * 2));
00180         
00181         db_longest_button += db_rect[dbn].w;
00182         bn++;
00183         dbn++;
00184     }
00185   }
00186 
00187   va_end(ap);
00188 
00189   /* figure out how high and wide the box needs to be */
00190   text_window.h = 
00191       ((ln * (CHAR_HEIGHT + DB_V_SPACE)) + BUTTON_HEIGHT + DB_V_SPACE);
00192 
00193   if ((db_longest_button + (bn * BUTTON_MIN_SPACING)) > 
00194       (db_longest_line + LINE_MIN_SPACING)) {
00195       text_window.w = (db_longest_button + (bn * BUTTON_MIN_SPACING));
00196   } else {
00197       text_window.w = (db_longest_line + LINE_MIN_SPACING);
00198   }   
00199 
00200   /* Determine button spacing;
00201      add some extra in front and back */
00202 
00203   bs = (text_window.w - db_longest_button) / bn;
00204   bse = ((text_window.w - db_longest_line) % bn) / 2;  
00205 
00206   /* Position the buttons and lines */
00207 
00208   for (i = 0; i < dbn; i++)
00209   {
00210       if (db_entry[i].type) {                                  /* Buttons */
00211           if (db_last_button == -1)
00212               db_rect[i].x = ((bs + bse) / 2) - BUTTON_BORDER;
00213           else
00214               db_rect[i].x = ((db_rect[db_last_button].x  
00215                                + db_rect[db_last_button].w + bs)
00216                               - BUTTON_BORDER);
00217           
00218           db_rect[i].y = ((ln * (CHAR_HEIGHT + DB_V_SPACE) + DB_V_SPACE) 
00219                           - BUTTON_BORDER);
00220           
00221           db_last_button = i;
00222       } else {                                                   /* Lines */
00223         db_rect[i].x = ((text_window.w - db_rect[i].w) / 2);
00224         db_rect[i].y = (i * (CHAR_HEIGHT + DB_V_SPACE));
00225       }
00226   }
00227           
00228   /* Figure out window size */
00229 
00230   dialog_window.w = (text_window.w + BORDER_SIZE*2);
00231   dialog_window.h = (text_window.h + BORDER_SIZE*2);
00232   
00233   main_handle = mouse_register(&scr.client_win,&main_handler);
00234   text_handle = mouse_register(&text_window,&text_handler);
00235 
00236   dialog_refresh();
00237 
00238   db_return_value = 0;
00239 
00240   /* Wait for the user to click on it or press an appropriate key */
00241   /* Mouse clicks arrive from the mouse handler and set db_return_value */
00242 
00243   while (!db_return_value)  {
00244 #ifndef LC_X11
00245       lc_usleep (1000); /* call_wait_event does this for X11 */
00246 #endif
00247       
00248 #ifdef LC_X11
00249       call_wait_event ();
00250       key = x_key_value;
00251       x_key_value = 0;
00252 #elif defined (WIN32)
00253       HandleMouse ();
00254       key = GetKeystroke ();
00255 #else
00256       mouse_update ();
00257       key = vga_getkey ();
00258 #endif
00259       if (key == 0) continue;
00260 
00261       if (key == 10 || key == 13 || key == ' ') /* default button */
00262           for (i = 0; i <= dbn; i++) {
00263               if (db_entry[i].type == 2) {
00264                   dialog_close(db_entry[i].retval);
00265                   break;
00266               }
00267           }
00268       else
00269           for (i = 0; i <= dbn; i++) {
00270               if (key == db_entry[i].retval) {
00271                   dialog_close(key);
00272                   break;
00273               }
00274           }
00275   }
00276   return (db_return_value);
00277 }
00278 
00279 
00280 void 
00281 dialog_refresh(void)
00282 {
00283   int i;  /* Line, Button incrementors */
00284   if (!db_up) 
00285       return;
00286 
00287   /* Determine screen position */
00288   dialog_window.x = (scr.client_w / 2) - (dialog_window.w / 2);
00289   dialog_window.y = (scr.client_h / 2) - (dialog_window.h / 2);
00290 
00291   text_window.x = dialog_window.x + BORDER_SIZE;
00292   text_window.y = dialog_window.y + BORDER_SIZE;
00293 
00294   hide_mouse();
00295 
00296   if (screen_refreshing && db_screen_fresh) {
00297       free(db_screen_buffer);
00298       db_screen_fresh = 0;
00299   }
00300 
00301   if (!db_screen_fresh) {
00302       db_screen_buffer = (char *)lcalloc(dialog_window.w * dialog_window.h);
00303       Fgl_getrect(&dialog_window,db_screen_buffer);
00304       db_screen_fresh = 1;
00305   };
00306 
00307 
00308   /* Draw the border, and fill the background */
00309   draw_bezel(dialog_window,BORDER_SIZE,color);
00310 
00311   Fgl_fillbox(text_window.x,text_window.y,text_window.w,text_window.h,color);
00312 
00313 #ifdef USE_EXPANDED_FONT
00314     gl_setwritemode (WRITEMODE_MASKED | FONT_EXPANDED);
00315 #else
00316     Fgl_setfontcolors (color, TEXT_FG_COLOUR);
00317 #endif
00318 
00319     /* Loop calculating line position, and drawing the line */
00320     for (i = 0; i < dbn; i++)
00321     {
00322 
00323         if (db_entry[i].type) {
00324             Fgl_fillbox(db_rect[i].x + text_window.x,
00325                         db_rect[i].y + text_window.y,
00326                         db_rect[i].w,
00327                         db_rect[i].h,
00328                         white(0));
00329         }
00330         Fgl_write(db_rect[i].x + text_window.x + BUTTON_BORDER, 
00331                   db_rect[i].y + text_window.y + BUTTON_BORDER,
00332                   db_entry[i].text);
00333     }
00334 
00335 #ifdef USE_EXPANDED_FONT
00336     gl_setwritemode (WRITEMODE_OVERWRITE | FONT_EXPANDED);
00337 #else
00338     Fgl_setfontcolors (TEXT_BG_COLOUR, TEXT_FG_COLOUR);
00339 #endif
00340 
00341   redraw_mouse();
00342 
00343 }
00344 
00345 /* dialog_close: close the mouse handle and remember we closed it;
00346    save the results; put the old screen back up and remember that too. */
00347 
00348 void
00349 dialog_close(int return_value) 
00350 {
00351     int i;
00352     
00353     mouse_unregister(main_handle);
00354     mouse_unregister(text_handle);
00355     db_up = 0;
00356     db_return_value = return_value;
00357 
00358     for (i = 0; i < dbn; i++) 
00359         if (db_entry[i].type == DB_PARA) 
00360             free(db_entry[i].text);
00361     
00362     if (db_screen_fresh) {
00363         Fgl_putrect(&dialog_window,db_screen_buffer);
00364         free(db_screen_buffer);
00365         db_screen_fresh = 0;
00366     }
00367 
00368     db_flag = 0;
00369 }
00370 

Generated on Sun Dec 26 11:23:23 2004 for lincity by  doxygen 1.3.9.1