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