1 /***********************************************************************
2  Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 ***********************************************************************/
13 
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 
21 #include <X11/Intrinsic.h>
22 #include <X11/StringDefs.h>
23 #include <X11/Xaw/Form.h>
24 #include <X11/Xaw/Label.h>
25 #include <X11/Xaw/Command.h>
26 #include <X11/Xaw/List.h>
27 #include <X11/Xaw/MenuButton.h>
28 #include <X11/Xaw/SimpleMenu.h>
29 #include <X11/Xaw/SmeBSB.h>
30 #include <X11/Xaw/Toggle.h>
31 #include <X11/Xaw/Viewport.h>
32 
33 /* utility */
34 #include "fcintl.h"
35 #include "log.h"
36 #include "mem.h"
37 #include "shared.h"
38 #include "support.h"
39 
40 /* common */
41 #include "city.h"
42 #include "packets.h"
43 #include "unit.h"
44 
45 /* client */
46 #include "client_main.h"
47 #include "climisc.h"
48 
49 /* gui-xaw */
50 #include "chatline.h"
51 #include "citydlg.h"
52 #include "cityrepdata.h"
53 #include "gui_main.h"
54 #include "gui_stuff.h"
55 #include "mapview.h"
56 #include "optiondlg.h"
57 #include "options.h"
58 #include "repodlgs.h"
59 #include "text.h"
60 
61 #include "cityrep.h"
62 
63 /******************************************************************/
64 static void popup_chgall_dialog (Widget parent);
65 
66 /******************************************************************/
67 static Widget config_shell;
68 static Widget *config_toggle;
69 
70 void create_city_report_config_dialog(void);
71 void popup_city_report_config_dialog(void);
72 void config_ok_command_callback(Widget w, XtPointer client_data,
73 				XtPointer call_data);
74 
75 
76 /******************************************************************/
77 void create_city_report_dialog(bool make_modal);
78 void city_close_callback(Widget w, XtPointer client_data,
79 			 XtPointer call_data);
80 void city_center_callback(Widget w, XtPointer client_data,
81 			  XtPointer call_data);
82 void city_popup_callback(Widget w, XtPointer client_data,
83 			 XtPointer call_data);
84 void city_buy_callback(Widget w, XtPointer client_data,
85 		       XtPointer call_data);
86 void city_chgall_callback(Widget w, XtPointer client_data,
87 			  XtPointer call_data);
88 void city_refresh_callback(Widget w, XtPointer client_data,
89 		       XtPointer call_data);
90 void city_change_callback(Widget w, XtPointer client_data,
91 			  XtPointer call_data);
92 void city_list_callback(Widget w, XtPointer client_data,
93 			XtPointer call_data);
94 void city_config_callback(Widget w, XtPointer client_data,
95 			  XtPointer call_data);
96 
97 static Widget city_form;
98 static Widget city_dialog_shell;
99 static Widget city_label;
100 static Widget city_viewport;
101 static Widget city_list, city_list_label;
102 static Widget city_center_command, city_popup_command, city_buy_command,
103        city_chgall_command, city_refresh_command, city_config_command;
104 static Widget city_change_command, city_popupmenu;
105 
106 static int city_dialog_shell_is_modal;
107 static struct city **cities_in_list = NULL;
108 
109 static char *dummy_city_list[]={
110   "    "
111   " ",  " ",  " ",  " ",  " ",  " ",  " ",  " ",  " ",  " ",  " ",  " ",  " ",
112   " ",  " ",  " ",  0
113 };
114 
115 
116 /****************************************************************
117  Create the text for a line in the city report; n is size of buffer
118 *****************************************************************/
get_city_text(struct city * pcity,char * text,int n)119 static void get_city_text(struct city *pcity, char *text, int n)
120 {
121   struct city_report_spec *spec;
122   int i;
123 
124   text[0] = '\0';		/* init for strcat */
125   for(i=0, spec=city_report_specs; i<NUM_CREPORT_COLS; i++, spec++) {
126     if(!spec->show) continue;
127 
128     if(spec->space>0)
129       cat_snprintf(text, n, "%*s", spec->space, " ");
130 
131     cat_snprintf(text, n, "%*s", spec->width,
132 		 (spec->func)(pcity, spec->data));
133   }
134 }
135 
136 /****************************************************************
137  Return text line for the column headers for the city report
138 *****************************************************************/
get_city_table_header(void)139 static char *get_city_table_header(void)
140 {
141   static char text[400];
142   struct city_report_spec *spec;
143   int i, j;
144 
145   text[0] = '\0';		/* init for strcat */
146   for(j=0; j<=1; j++) {
147     for(i=0, spec=city_report_specs; i<NUM_CREPORT_COLS; i++, spec++) {
148       if(!spec->show) continue;
149 
150       if(spec->space>0)
151 	cat_snprintf(text, sizeof(text), "%*s", spec->space, " ");
152 
153       cat_snprintf(text, sizeof(text), "%*s", spec->width,
154 		   (j ? (spec->title2 ? spec->title2 : "")
155 		    : (spec->title1 ? spec->title1 : "")));
156     }
157     if (j==0) sz_strlcat(text, "\n");
158   }
159   return text;
160 }
161 
162 /****************************************************************
163 
164                       CITY REPORT DIALOG
165 
166 ****************************************************************/
167 
168 /****************************************************************
169 ...
170 ****************************************************************/
city_report_dialog_popup(bool make_modal)171 void city_report_dialog_popup(bool make_modal)
172 {
173   if(!city_dialog_shell) {
174       Position x, y;
175       Dimension width, height;
176 
177       city_dialog_shell_is_modal=make_modal;
178 
179       if(make_modal)
180 	XtSetSensitive(main_form, FALSE);
181 
182       create_city_report_dialog(make_modal);
183 
184       XtVaGetValues(toplevel, XtNwidth, &width, XtNheight, &height, NULL);
185 
186       XtTranslateCoords(toplevel, (Position) width/10, (Position) height/10,
187 			&x, &y);
188       XtVaSetValues(city_dialog_shell, XtNx, x, XtNy, y, NULL);
189 
190       XtPopup(city_dialog_shell, XtGrabNone);
191 
192       /* force refresh of viewport so the scrollbar is added.
193        * Buggy sun athena requires this */
194       XtVaSetValues(city_viewport, XtNforceBars, True, NULL);
195    }
196 }
197 
198 /****************************************************************
199   Closes the cityrep dialog.
200 ****************************************************************/
city_report_dialog_popdown(void)201 void city_report_dialog_popdown(void)
202 {
203   if (city_dialog_shell) {
204     if (city_dialog_shell_is_modal) {
205       XtSetSensitive(main_form, TRUE);
206     }
207     XtDestroyWidget(city_dialog_shell);
208     city_dialog_shell = 0;
209   }
210 }
211 
212 /****************************************************************
213 ...
214 *****************************************************************/
create_city_report_dialog(bool make_modal)215 void create_city_report_dialog(bool make_modal)
216 {
217   Widget close_command;
218   const char *report_title;
219 
220   city_dialog_shell =
221     I_T(XtVaCreatePopupShell("reportcitypopup",
222 			     (make_modal ? transientShellWidgetClass :
223 			      topLevelShellWidgetClass),
224 			     toplevel, NULL));
225 
226   city_form = XtVaCreateManagedWidget("reportcityform",
227 				      formWidgetClass,
228 				      city_dialog_shell,
229 				      NULL);
230 
231   report_title=get_centered_report_title(_("Cities"));
232   city_label = XtVaCreateManagedWidget("reportcitylabel",
233 				       labelWidgetClass,
234 				       city_form,
235 				       XtNlabel,
236 				       report_title,
237 				       NULL);
238   free((void *) report_title);
239   city_list_label = XtVaCreateManagedWidget("reportcitylistlabel",
240 				            labelWidgetClass,
241 				            city_form,
242 					    XtNlabel,
243 					    get_city_table_header(),
244 				            NULL);
245   city_viewport = XtVaCreateManagedWidget("reportcityviewport",
246 				          viewportWidgetClass,
247 				          city_form,
248 				          NULL);
249 
250   city_list = XtVaCreateManagedWidget("reportcitylist",
251 				      listWidgetClass,
252 				      city_viewport,
253                                       XtNlist,
254 				      (XtArgVal)dummy_city_list,
255 				      NULL);
256 
257   close_command =
258     I_L(XtVaCreateManagedWidget("reportcityclosecommand", commandWidgetClass,
259 				city_form, NULL));
260 
261   city_center_command =
262     I_L(XtVaCreateManagedWidget("reportcitycentercommand", commandWidgetClass,
263 				city_form, NULL));
264 
265   city_popup_command =
266     I_L(XtVaCreateManagedWidget("reportcitypopupcommand", commandWidgetClass,
267 				city_form, NULL));
268 
269   city_popupmenu = 0;
270 
271   city_buy_command =
272     I_L(XtVaCreateManagedWidget("reportcitybuycommand",  commandWidgetClass,
273 				city_form, NULL));
274 
275   city_change_command =
276     I_L(XtVaCreateManagedWidget("reportcitychangemenubutton",
277 				menuButtonWidgetClass,
278 				city_form, NULL));
279 
280   city_chgall_command =
281     I_L(XtVaCreateManagedWidget("reportcitychgallcommand",
282 				commandWidgetClass,
283 				city_form, NULL));
284 
285   city_refresh_command =
286     I_L(XtVaCreateManagedWidget("reportcityrefreshcommand",
287 				commandWidgetClass,
288 				city_form, NULL));
289 
290   city_config_command =
291     I_L(XtVaCreateManagedWidget("reportcityconfigcommand",
292 				commandWidgetClass,
293 				city_form, NULL));
294 
295   XtAddCallback(close_command, XtNcallback, city_close_callback, NULL);
296   XtAddCallback(city_center_command, XtNcallback, city_center_callback, NULL);
297   XtAddCallback(city_popup_command, XtNcallback, city_popup_callback, NULL);
298   XtAddCallback(city_buy_command, XtNcallback, city_buy_callback, NULL);
299   XtAddCallback(city_chgall_command, XtNcallback, city_chgall_callback, NULL);
300   XtAddCallback(city_refresh_command, XtNcallback, city_refresh_callback, NULL);
301   XtAddCallback(city_config_command, XtNcallback, city_config_callback, NULL);
302   XtAddCallback(city_list, XtNcallback, city_list_callback, NULL);
303 
304   XtRealizeWidget(city_dialog_shell);
305 
306   if (!make_modal) { /* ?? dwp */
307     XSetWMProtocols(display, XtWindow(city_dialog_shell),
308 		    &wm_delete_window, 1);
309     XtOverrideTranslations(city_dialog_shell,
310 	 XtParseTranslationTable("<Message>WM_PROTOCOLS: msg-close-city-report()"));
311   }
312 
313   real_city_report_dialog_update(NULL);
314 }
315 
316 /****************************************************************
317 ...
318 *****************************************************************/
city_list_callback(Widget w,XtPointer client_data,XtPointer call_data)319 void city_list_callback(Widget w, XtPointer client_data,
320 			 XtPointer call_data)
321 {
322   XawListReturnStruct *ret=XawListShowCurrent(city_list);
323   struct city *pcity;
324 
325   if(ret->list_index!=XAW_LIST_NONE &&
326      (pcity=cities_in_list[ret->list_index])) {
327     struct universal targets[MAX_NUM_PRODUCTION_TARGETS];
328     struct item items[MAX_NUM_PRODUCTION_TARGETS];
329     int targets_used = 0;
330     size_t i;
331 
332     XtSetSensitive(city_change_command, TRUE);
333     XtSetSensitive(city_center_command, TRUE);
334     XtSetSensitive(city_popup_command, TRUE);
335     XtSetSensitive(city_buy_command, city_can_buy(pcity));
336     if (city_popupmenu)
337       XtDestroyWidget(city_popupmenu);
338 
339     city_popupmenu=XtVaCreatePopupShell("menu",
340 				        simpleMenuWidgetClass,
341 				        city_change_command,
342 				        NULL);
343 
344     improvement_iterate(pimprove) {
345       if (can_city_build_improvement_now(pcity, pimprove)) {
346 	targets[targets_used].kind = VUT_IMPROVEMENT;
347 	targets[targets_used].value.building = pimprove;
348 	targets_used++;
349       }
350     } improvement_iterate_end;
351 
352     unit_type_iterate(punittype) {
353       if (can_city_build_unit_now(pcity, punittype)) {
354 	targets[targets_used].kind = VUT_UTYPE;
355 	targets[targets_used].value.utype = punittype;
356 	targets_used++;
357       }
358     } unit_type_iterate_end;
359 
360     name_and_sort_items(targets, targets_used, items, TRUE, NULL);
361 
362     for (i = 0; i < targets_used; i++) {
363       Widget entry =
364 	  XtVaCreateManagedWidget(items[i].descr, smeBSBObjectClass,
365 				  city_popupmenu, NULL);
366       XtAddCallback(entry, XtNcallback, city_change_callback,
367 		    INT_TO_XTPOINTER(cid_encode(items[i].item)));
368     }
369 
370     if (targets_used == 0)
371       XtSetSensitive(city_change_command, FALSE);
372   } else {
373     XtSetSensitive(city_change_command, FALSE);
374     XtSetSensitive(city_center_command, FALSE);
375     XtSetSensitive(city_popup_command, FALSE);
376     XtSetSensitive(city_buy_command, FALSE);
377   }
378 }
379 
380 /****************************************************************
381 ...
382 *****************************************************************/
city_change_callback(Widget w,XtPointer client_data,XtPointer call_data)383 void city_change_callback(Widget w, XtPointer client_data,
384                           XtPointer call_data)
385 {
386   XawListReturnStruct *ret = XawListShowCurrent(city_list);
387   struct city *pcity;
388   struct universal production;
389 
390   if (ret->list_index != XAW_LIST_NONE
391       && (pcity=cities_in_list[ret->list_index])) {
392     cid my_cid = (cid) XTPOINTER_TO_INT(client_data);
393 
394     production = cid_decode(my_cid);
395 
396     city_change_production(pcity, &production);
397   }
398 }
399 
400 /****************************************************************
401 ...
402 *****************************************************************/
city_buy_callback(Widget w,XtPointer client_data,XtPointer call_data)403 void city_buy_callback(Widget w, XtPointer client_data, XtPointer call_data)
404 {
405   XawListReturnStruct *ret = XawListShowCurrent(city_list);
406 
407   if (ret->list_index != XAW_LIST_NONE) {
408     struct city *pcity = cities_in_list[ret->list_index];
409     if (pcity) {
410       cityrep_buy(pcity);
411     }
412   }
413 }
414 
415 /****************************************************************
416 ...
417 *****************************************************************/
city_chgall_callback(Widget w,XtPointer client_data,XtPointer call_data)418 void city_chgall_callback(Widget w, XtPointer client_data,
419 			  XtPointer call_data)
420 {
421   popup_chgall_dialog (XtParent (w));
422 }
423 
424 /****************************************************************
425 ...
426 *****************************************************************/
city_refresh_callback(Widget w,XtPointer client_data,XtPointer call_data)427 void city_refresh_callback(Widget w, XtPointer client_data,
428 			   XtPointer call_data)
429 {
430   /* added by Syela - I find this very useful */
431   XawListReturnStruct *ret = XawListShowCurrent(city_list);
432 
433   if (ret->list_index != XAW_LIST_NONE) {
434     struct city *pcity = cities_in_list[ret->list_index];
435 
436     if (pcity) {
437       dsend_packet_city_refresh(&client.conn, pcity->id);
438     }
439   } else {
440     dsend_packet_city_refresh(&client.conn, 0);
441   }
442 }
443 
444 /****************************************************************
445 ...
446 *****************************************************************/
city_close_callback(Widget w,XtPointer client_data,XtPointer call_data)447 void city_close_callback(Widget w, XtPointer client_data,
448                          XtPointer call_data)
449 {
450   city_report_dialog_popdown();
451 }
452 
453 /****************************************************************
454 ...
455 *****************************************************************/
cityrep_msg_close(Widget w)456 void cityrep_msg_close(Widget w)
457 {
458   city_close_callback(w, NULL, NULL);
459 }
460 
461 /****************************************************************
462 ...
463 *****************************************************************/
city_center_callback(Widget w,XtPointer client_data,XtPointer call_data)464 void city_center_callback(Widget w, XtPointer client_data,
465 			  XtPointer call_data)
466 {
467   XawListReturnStruct *ret=XawListShowCurrent(city_list);
468 
469   if(ret->list_index!=XAW_LIST_NONE) {
470     struct city *pcity;
471     if((pcity=cities_in_list[ret->list_index]))
472       center_tile_mapcanvas(pcity->tile);
473   }
474 }
475 
476 /****************************************************************
477 ...
478 *****************************************************************/
city_popup_callback(Widget w,XtPointer client_data,XtPointer call_data)479 void city_popup_callback(Widget w, XtPointer client_data,
480 			 XtPointer call_data)
481 {
482   XawListReturnStruct *ret=XawListShowCurrent(city_list);
483 
484   if (ret->list_index!=XAW_LIST_NONE) {
485     struct city *pcity;
486 
487     if ((pcity = cities_in_list[ret->list_index])) {
488       if (gui_options.center_when_popup_city) {
489         center_tile_mapcanvas(pcity->tile);
490       }
491       popup_city_dialog(pcity);
492     }
493   }
494 }
495 
496 /****************************************************************
497 ...
498 *****************************************************************/
city_config_callback(Widget w,XtPointer client_data,XtPointer call_data)499 void city_config_callback(Widget w, XtPointer client_data,
500 			  XtPointer call_data)
501 {
502   popup_city_report_config_dialog();
503 }
504 
505 #define MAX_LEN_CITY_TEXT 200
506 /****************************************************************
507 ...
508 *****************************************************************/
real_city_report_dialog_update(void * unused)509 void real_city_report_dialog_update(void *unused)
510 {
511   if (!client_has_player()) {
512     return;
513   }
514 
515   if(city_dialog_shell) {
516     int i=0, n;
517     Dimension width;
518     static int n_alloc = 0;
519     static char **city_list_text = NULL;
520     const char *report_title;
521 
522     n = city_list_size(client.conn.playing->cities);
523     log_debug("%d cities in report", n);
524     if(n_alloc == 0 || n > n_alloc) {
525       int j, n_prev = n_alloc;
526 
527       n_alloc *= 2;
528       if (!n_alloc || n_alloc < n) n_alloc = n + 1;
529       log_debug("city report n_alloc increased to %d", n_alloc);
530       cities_in_list = fc_realloc(cities_in_list,
531 				  n_alloc*sizeof(*cities_in_list));
532       city_list_text = fc_realloc(city_list_text, n_alloc*sizeof(char*));
533       for(j=n_prev; j<n_alloc; j++) {
534 	city_list_text[j] = fc_malloc(MAX_LEN_CITY_TEXT);
535       }
536     }
537 
538     report_title=get_centered_report_title(_("Cities"));
539     xaw_set_label(city_label, report_title);
540     free((void *) report_title);
541 
542     xaw_set_label(city_list_label, get_city_table_header());
543 
544     if (city_popupmenu) {
545       XtDestroyWidget(city_popupmenu);
546       city_popupmenu = 0;
547     }
548 
549     /* Only sort once, in case any cities have duplicate/truncated names.
550      * Plus this should be much faster than sorting on ids which means
551      * having to find city corresponding to id for each comparison.
552      */
553     i=0;
554     city_list_iterate(client.conn.playing->cities, pcity) {
555       cities_in_list[i++] = pcity;
556     } city_list_iterate_end;
557     fc_assert(i==n);
558     qsort(cities_in_list, n, sizeof(struct city*), city_name_compare);
559     for(i=0; i<n; i++) {
560       get_city_text(cities_in_list[i], city_list_text[i], MAX_LEN_CITY_TEXT);
561     }
562     i = n;
563     if(!n) {
564       fc_strlcpy(city_list_text[0],
565 		"                                                             ",
566 		MAX_LEN_CITY_TEXT);
567       i=1;
568       cities_in_list[0]=NULL;
569     }
570 
571     XawFormDoLayout(city_form, False);
572     XawListChange(city_list, (CONST_FOR_XAW_LIST_CHANGE char **)city_list_text, i, 0, True);
573 
574     XtVaGetValues(city_list, XtNlongest, &i, NULL);
575     width=i+10;
576     /* I don't know the proper way to set the width of this viewport widget.
577        Someone who knows is more than welcome to fix this */
578     XtVaSetValues(city_viewport, XtNwidth, width+15, NULL);
579     XtVaSetValues(city_list_label, XtNwidth, width, NULL);
580     XtVaSetValues(city_label, XtNwidth, width+15, NULL);
581     XawFormDoLayout(city_form, True);
582 
583     XtSetSensitive(city_change_command, FALSE);
584     XtSetSensitive(city_center_command, FALSE);
585     XtSetSensitive(city_popup_command, FALSE);
586     XtSetSensitive(city_buy_command, FALSE);
587   }
588 }
589 
590 /****************************************************************
591   Update the text for a single city in the city report
592 *****************************************************************/
real_city_report_update_city(struct city * pcity)593 void real_city_report_update_city(struct city *pcity)
594 {
595   int i;
596 
597   if (!city_dialog_shell) {
598     return;
599   }
600 
601   for(i=0; cities_in_list[i]; i++)  {
602     if(cities_in_list[i]==pcity)  {
603       int n;
604       char **list;
605       Dimension w;
606       char new_city_line[MAX_LEN_CITY_TEXT];
607 
608       XtVaGetValues(city_list, XtNnumberStrings, &n, XtNlist, &list, NULL);
609       if (0 != strcmp(city_name_get(pcity), list[i])) {
610         break;
611       }
612       get_city_text(pcity, new_city_line, sizeof(new_city_line));
613 
614       if (strcmp(new_city_line, list[i]) == 0) {
615         return; /* no change */
616       }
617 
618       fc_strlcpy(list[i], new_city_line, MAX_LEN_CITY_TEXT);
619 
620       /* It seems really inefficient to regenerate the whole list just to
621          change one line.  It's also annoying to have to set the size
622 	 of each widget explicitly, since Xt is supposed to handle that. */
623       XawFormDoLayout(city_form, False);
624       XawListChange(city_list, (CONST_FOR_XAW_LIST_CHANGE char **)list, n, 0, False);
625       XtVaGetValues(city_list, XtNlongest, &n, NULL);
626       w=n+10;
627       XtVaSetValues(city_viewport, XtNwidth, w+15, NULL);
628       XtVaSetValues(city_list_label, XtNwidth, w, NULL);
629       XtVaSetValues(city_label, XtNwidth, w+15, NULL);
630       XawFormDoLayout(city_form, True);
631       return;
632     }
633   }
634   real_city_report_dialog_update(NULL);
635 }
636 
637 /****************************************************************
638  After a selection rectangle is defined, make the cities that
639  are hilited on the canvas exclusively hilited in the
640  City List window.
641 *****************************************************************/
hilite_cities_from_canvas(void)642 void hilite_cities_from_canvas(void)
643 {
644   /* PORTME */
645 }
646 
647 /****************************************************************
648  Toggle a city's hilited status.
649 *****************************************************************/
toggle_city_hilite(struct city * pcity,bool on_off)650 void toggle_city_hilite(struct city *pcity, bool on_off)
651 {
652   /* PORTME */
653 }
654 
655 /****************************************************************
656 
657                       CITY REPORT CONFIGURE DIALOG
658 
659 ****************************************************************/
660 
661 /****************************************************************
662 ...
663 *****************************************************************/
popup_city_report_config_dialog(void)664 void popup_city_report_config_dialog(void)
665 {
666   int i;
667 
668   if(config_shell)
669     return;
670 
671   create_city_report_config_dialog();
672 
673   for(i=1; i<NUM_CREPORT_COLS; i++) {
674     XtVaSetValues(config_toggle[i],
675 		  XtNstate, city_report_specs[i].show,
676 		  XtNlabel, city_report_specs[i].show?_("Yes"):_("No"), NULL);
677   }
678 
679   xaw_set_relative_position(city_dialog_shell, config_shell, 25, 25);
680   XtPopup(config_shell, XtGrabNone);
681   /* XtSetSensitive(main_form, FALSE); */
682 }
683 
684 /****************************************************************
685 ...
686 *****************************************************************/
create_city_report_config_dialog(void)687 void create_city_report_config_dialog(void)
688 {
689   Widget config_form, config_label, config_ok_command;
690   Widget config_optlabel=0, above;
691   struct city_report_spec *spec;
692   char buf[64];
693   int i;
694 
695   config_shell = I_T(XtCreatePopupShell("cityconfig",
696 					transientShellWidgetClass,
697 					toplevel, NULL, 0));
698 
699   config_form = XtVaCreateManagedWidget("cityconfigform",
700 				        formWidgetClass,
701 				        config_shell, NULL);
702 
703   config_label = I_L(XtVaCreateManagedWidget("cityconfiglabel",
704 					     labelWidgetClass,
705 					     config_form, NULL));
706 
707   config_toggle = fc_realloc(config_toggle,
708 			     NUM_CREPORT_COLS * sizeof(*config_toggle));
709   for(i=0, spec=city_report_specs+i; i<NUM_CREPORT_COLS; i++, spec++) {
710     fc_snprintf(buf, sizeof(buf), "%-32s", spec->explanation);
711     above = (i==1)?config_label:config_optlabel;
712 
713     config_optlabel = XtVaCreateManagedWidget("cityconfiglabel",
714 					      labelWidgetClass,
715 					      config_form,
716 					      XtNlabel, buf,
717 					      XtNfromVert, above,
718 					      NULL);
719 
720     config_toggle[i] = XtVaCreateManagedWidget("cityconfigtoggle",
721 					       toggleWidgetClass,
722 					       config_form,
723 					       XtNfromVert, above,
724 					       XtNfromHoriz, config_optlabel,
725 					       NULL);
726   }
727 
728   config_ok_command =
729     I_L(XtVaCreateManagedWidget("cityconfigokcommand",
730 				commandWidgetClass,
731 				config_form,
732 				XtNfromVert, config_optlabel,
733 				NULL));
734 
735   XtAddCallback(config_ok_command, XtNcallback,
736 		config_ok_command_callback, NULL);
737 
738   for(i=1; i<NUM_CREPORT_COLS; i++)
739     XtAddCallback(config_toggle[i], XtNcallback, toggle_callback, NULL);
740 
741   XtRealizeWidget(config_shell);
742 
743   xaw_horiz_center(config_label);
744 }
745 
746 /**************************************************************************
747 ...
748 **************************************************************************/
config_ok_command_callback(Widget w,XtPointer client_data,XtPointer call_data)749 void config_ok_command_callback(Widget w, XtPointer client_data,
750 				XtPointer call_data)
751 {
752   struct city_report_spec *spec;
753   int i;
754 
755   XtDestroyWidget(config_shell);
756 
757   for(i=0, spec=city_report_specs+i; i<NUM_CREPORT_COLS; i++, spec++) {
758     Boolean b;
759 
760     XtVaGetValues(config_toggle[i], XtNstate, &b, NULL);
761     spec->show = (bool) b;
762   }
763   config_shell=0;
764   real_city_report_dialog_update(NULL);
765 }
766 
767 /**************************************************************************
768 
769                           CHANGE ALL DIALOG
770 
771 **************************************************************************/
772 
773 struct chgall_data
774 {
775   struct
776   {
777     Widget shell;
778     Widget fr;
779     Widget to;
780     Widget change;
781     Widget refresh;
782     Widget cancel;
783   } w;
784 
785   int fr_count;
786   char *fr_list[U_LAST + B_LAST];
787   cid fr_cids[U_LAST + B_LAST];
788 
789   int to_count;
790   char *to_list[U_LAST + B_LAST];
791   cid to_cids[U_LAST + B_LAST];
792 
793   int fr_index;
794   int to_index;
795   int may_change;
796 };
797 
798 static struct chgall_data *chgall_state = NULL;
799 
800 static void chgall_accept_action (Widget w, XEvent *event,
801 				  String *params, Cardinal *num_params);
802 static void chgall_cancel_action (Widget w, XEvent *event,
803 				  String *params, Cardinal *num_params);
804 
805 static void chgall_shell_destroy (Widget w, XtPointer client_data,
806 				  XtPointer call_data);
807 static void chgall_fr_list_callback (Widget w, XtPointer client_data,
808 				     XtPointer call_data);
809 static void chgall_to_list_callback (Widget w, XtPointer client_data,
810 				     XtPointer call_data);
811 static void chgall_change_command_callback (Widget w, XtPointer client_data,
812 					    XtPointer call_data);
813 static void chgall_refresh_command_callback (Widget w, XtPointer client_data,
814 					     XtPointer call_data);
815 static void chgall_cancel_command_callback (Widget w, XtPointer client_data,
816 					    XtPointer call_data);
817 
818 static void chgall_update_widgets_state (struct chgall_data *state);
819 
820 /**************************************************************************
821 ...
822 **************************************************************************/
popup_chgall_dialog(Widget parent)823 static void popup_chgall_dialog(Widget parent)
824 {
825   struct chgall_data *state;
826   Widget shell;
827   Widget chgall_main;
828   Widget fr_viewport;
829   Widget to_viewport;
830   Position x, y;
831   Dimension width, height;
832   static int initialized = FALSE;
833 
834   if (!initialized)
835     {
836       static XtActionsRec actions[] =
837       {
838 	{ "key-dialog-chgall-accept", chgall_accept_action },
839 	{ "key-dialog-chgall-cancel", chgall_cancel_action }
840       };
841 
842       initialized = TRUE;
843 
844       XtAppAddActions (app_context, actions, XtNumber (actions));
845     }
846 
847   if (chgall_state)
848     {
849       XRaiseWindow (display, XtWindow (chgall_state->w.shell));
850       return;
851     }
852 
853   shell =
854     I_T(XtCreatePopupShell
855     (
856      "chgalldialog",
857      transientShellWidgetClass,
858      parent,
859      NULL, 0
860     ));
861 
862   state = chgall_state = fc_malloc (sizeof (struct chgall_data));
863   state->w.shell = shell;
864 
865   XtAddCallback (state->w.shell, XtNdestroyCallback,
866 		 chgall_shell_destroy, state);
867 
868   chgall_main =
869     XtVaCreateManagedWidget
870     (
871      "chgallform",
872      formWidgetClass,
873      state->w.shell,
874      NULL
875     );
876 
877   fr_viewport =
878     XtVaCreateManagedWidget
879     (
880      "chgallfrviewport",
881      viewportWidgetClass,
882      chgall_main,
883      NULL
884     );
885 
886   state->w.fr =
887     XtVaCreateManagedWidget
888     (
889      "chgallfrlist",
890      listWidgetClass,
891      fr_viewport,
892      NULL
893     );
894 
895   to_viewport =
896     XtVaCreateManagedWidget
897     (
898      "chgalltoviewport",
899      viewportWidgetClass,
900      chgall_main,
901      NULL
902     );
903 
904   state->w.to =
905     XtVaCreateManagedWidget
906     (
907      "chgalltolist",
908      listWidgetClass,
909      to_viewport,
910      NULL
911     );
912 
913   state->w.change =
914     I_L(XtVaCreateManagedWidget
915     (
916      "chgallchangecommand",
917      commandWidgetClass,
918      chgall_main,
919      NULL
920     ));
921 
922   state->w.refresh =
923     I_L(XtVaCreateManagedWidget
924     (
925      "chgallrefreshcommand",
926      commandWidgetClass,
927      chgall_main,
928      NULL
929     ));
930 
931   state->w.cancel =
932     I_L(XtVaCreateManagedWidget
933     (
934      "chgallcancelcommand",
935      commandWidgetClass,
936      chgall_main,
937      NULL
938     ));
939 
940   XtAddCallback (state->w.fr, XtNcallback,
941 		 chgall_fr_list_callback, state);
942   XtAddCallback (state->w.to, XtNcallback,
943 		 chgall_to_list_callback, state);
944   XtAddCallback (state->w.change, XtNcallback,
945 		 chgall_change_command_callback, state);
946   XtAddCallback (state->w.refresh, XtNcallback,
947 		 chgall_refresh_command_callback, state);
948   XtAddCallback (state->w.cancel, XtNcallback,
949 		 chgall_cancel_command_callback, state);
950 
951   chgall_refresh_command_callback (NULL, (XtPointer)state, NULL);
952 
953   XtRealizeWidget (state->w.shell);
954   XtVaGetValues (parent, XtNwidth, &width, XtNheight, &height, NULL);
955   XtTranslateCoords (parent,
956 		     (Position)(width / 20), (Position)(height / 20),
957 		     &x, &y);
958   XtVaSetValues (state->w.shell, XtNx, x, XtNy, y, NULL);
959 
960   XtPopup (state->w.shell, XtGrabNone);
961 
962   /* force refresh of viewports so the scrollbar is added.
963    * Buggy sun athena requires this */
964   XtVaSetValues (fr_viewport, XtNforceBars, True, NULL);
965   XtVaSetValues (to_viewport, XtNforceBars, True, NULL);
966 }
967 
968 /**************************************************************************
969 ...
970 **************************************************************************/
971 
chgall_accept_action(Widget w,XEvent * event,String * params,Cardinal * num_params)972 static void chgall_accept_action (Widget w, XEvent *event,
973 				  String *params, Cardinal *num_params)
974 {
975   Widget target = XtNameToWidget (w, "chgallchangecommand");
976 
977   if (target)
978     {
979       x_simulate_button_click (target);
980     }
981 }
982 
983 /**************************************************************************
984 ...
985 **************************************************************************/
986 
chgall_cancel_action(Widget w,XEvent * event,String * params,Cardinal * num_params)987 static void chgall_cancel_action (Widget w, XEvent *event,
988 				  String *params, Cardinal *num_params)
989 {
990   Widget target = XtNameToWidget (w, "chgallcancelcommand");
991 
992   if (target)
993     {
994       x_simulate_button_click (target);
995     }
996 }
997 
998 /**************************************************************************
999 ...
1000 **************************************************************************/
1001 
chgall_shell_destroy(Widget w,XtPointer client_data,XtPointer call_data)1002 static void chgall_shell_destroy(Widget w, XtPointer client_data,
1003 				 XtPointer call_data)
1004 {
1005   int i;
1006 
1007   for (i = 0; i < chgall_state->fr_count; i++) {
1008     free(chgall_state->fr_list[i]);
1009   }
1010   for (i = 0; i < chgall_state->to_count; i++) {
1011     free(chgall_state->to_list[i]);
1012   }
1013 
1014   chgall_state = NULL;
1015 
1016   free(client_data);
1017 }
1018 
1019 /**************************************************************************
1020 ...
1021 **************************************************************************/
1022 
chgall_fr_list_callback(Widget w,XtPointer client_data,XtPointer call_data)1023 static void chgall_fr_list_callback (Widget w, XtPointer client_data,
1024 				     XtPointer call_data)
1025 {
1026   chgall_update_widgets_state ((struct chgall_data *)client_data);
1027 }
1028 
1029 /**************************************************************************
1030 ...
1031 **************************************************************************/
1032 
chgall_to_list_callback(Widget w,XtPointer client_data,XtPointer call_data)1033 static void chgall_to_list_callback (Widget w, XtPointer client_data,
1034 				     XtPointer call_data)
1035 {
1036   chgall_update_widgets_state ((struct chgall_data *)client_data);
1037 }
1038 
1039 /**************************************************************************
1040 ...
1041 **************************************************************************/
chgall_change_command_callback(Widget w,XtPointer client_data,XtPointer call_data)1042 static void chgall_change_command_callback (Widget w, XtPointer client_data,
1043                                             XtPointer call_data)
1044 {
1045   struct chgall_data *state = (struct chgall_data *)client_data;
1046   struct universal fr;
1047   struct universal to;
1048 
1049   chgall_update_widgets_state (state);
1050 
1051   if (!(state->may_change)) {
1052     return;
1053   }
1054 
1055   fr = cid_decode(state->fr_cids[state->fr_index]);
1056   to = cid_decode(state->to_cids[state->to_index]);
1057 
1058   client_change_all(&fr, &to);
1059 
1060   XtDestroyWidget(state->w.shell);
1061 }
1062 
1063 /**************************************************************************
1064 ...
1065 **************************************************************************/
1066 
chgall_refresh_command_callback(Widget w,XtPointer client_data,XtPointer call_data)1067 static void chgall_refresh_command_callback(Widget w,
1068 					    XtPointer client_data,
1069 					    XtPointer call_data)
1070 {
1071   struct chgall_data *state = (struct chgall_data *) client_data;
1072   struct universal targets[MAX_NUM_PRODUCTION_TARGETS];
1073   struct item items[MAX_NUM_PRODUCTION_TARGETS];
1074   int i;
1075 
1076   state->fr_count = collect_currently_building_targets(targets);
1077   name_and_sort_items(targets, state->fr_count, items, false, NULL);
1078   for (i = 0; i < state->fr_count; i++) {
1079     state->fr_list[i] = fc_strdup(items[i].descr);
1080     state->fr_cids[i] = cid_encode(items[i].item);
1081   }
1082   XawListChange(state->w.fr, (CONST_FOR_XAW_LIST_CHANGE char **)state->fr_list,
1083                 state->fr_count, 0, FALSE);
1084 
1085   state->to_count = collect_buildable_targets(targets);
1086   name_and_sort_items(targets, state->to_count, items, TRUE, NULL);
1087   for (i = 0; i < state->to_count; i++) {
1088     state->to_list[i] = fc_strdup(items[i].descr);
1089     state->to_cids[i] = cid_encode(items[i].item);
1090   }
1091   XawListChange(state->w.to, (CONST_FOR_XAW_LIST_CHANGE char **)state->to_list,
1092                 state->to_count, 0, FALSE);
1093 
1094   chgall_update_widgets_state(state);
1095 }
1096 
1097 /**************************************************************************
1098 ...
1099 **************************************************************************/
1100 
chgall_cancel_command_callback(Widget w,XtPointer client_data,XtPointer call_data)1101 static void chgall_cancel_command_callback (Widget w, XtPointer client_data,
1102 					    XtPointer call_data)
1103 {
1104   struct chgall_data *state = (struct chgall_data *)client_data;
1105 
1106   XtDestroyWidget (state->w.shell);
1107 }
1108 
1109 /**************************************************************************
1110 ...
1111 **************************************************************************/
1112 
chgall_update_widgets_state(struct chgall_data * state)1113 static void chgall_update_widgets_state (struct chgall_data *state)
1114 {
1115   state->fr_index = (XawListShowCurrent (state->w.fr))->list_index;
1116   state->to_index = (XawListShowCurrent (state->w.to))->list_index;
1117 
1118   state->may_change =
1119       ((state->fr_index != XAW_LIST_NONE)
1120        && (state->to_index != XAW_LIST_NONE)
1121        && (state->fr_cids[state->fr_index] !=
1122 	   state->to_cids[state->to_index]));
1123 
1124   XtSetSensitive (state->w.change, state->may_change);
1125 }
1126