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 #include <string.h>
21 
22 #include <X11/Intrinsic.h>
23 #include <X11/StringDefs.h>
24 #include <X11/Xaw/Form.h>
25 #include <X11/Xaw/Label.h>
26 #include <X11/Xaw/SimpleMenu.h>
27 #include <X11/Xaw/Command.h>
28 #include <X11/Xaw/List.h>
29 #include <X11/Xaw/Viewport.h>
30 #include <X11/Xaw/Toggle.h>
31 
32 /* utility */
33 #include "log.h"
34 #include "mem.h"
35 #include "support.h"
36 
37 /* common */
38 #include "game.h"
39 #include "map.h"
40 #include "packets.h"
41 #include "player.h"
42 #include "unit.h"
43 #include "unitlist.h"
44 
45 /* client */
46 #include "client_main.h"
47 #include "control.h"
48 #include "goto.h"
49 
50 /* gui-xaw */
51 #include "gui_main.h"
52 #include "gui_stuff.h"
53 #include "mapctrl.h"
54 #include "mapview.h"
55 
56 #include "gotodlg.h"
57 
58 static Widget goto_dialog_shell;
59 static Widget goto_form;
60 static Widget goto_label;
61 static Widget goto_viewport;
62 static Widget goto_list;
63 static Widget goto_center_command;
64 static Widget goto_airlift_command;
65 static Widget goto_all_toggle;
66 static Widget goto_cancel_command;
67 
68 void update_goto_dialog(Widget goto_list);
69 
70 void goto_cancel_command_callback(Widget w, XtPointer client_data,
71 				  XtPointer call_data);
72 void goto_goto_command_callback(Widget w, XtPointer client_data,
73 				  XtPointer call_data);
74 void goto_airlift_command_callback(Widget w, XtPointer client_data,
75 				  XtPointer call_data);
76 void goto_all_toggle_callback(Widget w, XtPointer client_data,
77 			      XtPointer call_data);
78 void goto_list_callback(Widget w, XtPointer client_data, XtPointer call_data);
79 
80 static void cleanup_goto_list(void);
81 
82 static CONST_FOR_XAW_LIST_CHANGE char *dummy_city_list[] = {
83   "                                ",
84   "                                ",
85   "                                ",
86   "                                ",
87   "                                ",
88   "                                ",
89   "                                ",
90   "                                ",
91   "                                ",
92   0
93 };
94 
95 static int ncities_total = 0;
96 static char **city_name_ptrs = NULL;
97 static struct tile *original_tile;
98 
99 
100 /****************************************************************
101 popup the dialog 10% inside the main-window
102 *****************************************************************/
popup_goto_dialog(void)103 void popup_goto_dialog(void)
104 {
105   Position x, y;
106   Dimension width, height;
107   Boolean no_player_cities;
108 
109   if (!can_client_issue_orders() || get_num_units_in_focus() == 0) {
110     return;
111   }
112 
113   no_player_cities = !(city_list_size(client.conn.playing->cities));
114 
115   original_tile = get_center_tile_mapcanvas();
116 
117   XtSetSensitive(main_form, FALSE);
118 
119   goto_dialog_shell =
120     I_T(XtCreatePopupShell("gotodialog", transientShellWidgetClass,
121 			   toplevel, NULL, 0));
122 
123   goto_form = XtVaCreateManagedWidget("gotoform",
124 				      formWidgetClass,
125 				      goto_dialog_shell, NULL);
126 
127   goto_label =
128     I_L(XtVaCreateManagedWidget("gotolabel", labelWidgetClass,
129 				goto_form, NULL));
130 
131   goto_viewport = XtVaCreateManagedWidget("gotoviewport",
132 				      viewportWidgetClass,
133 				      goto_form,
134 				      NULL);
135 
136   goto_list = XtVaCreateManagedWidget("gotolist",
137 				      listWidgetClass,
138 				      goto_viewport,
139 				      XtNlist,
140 				      (XtArgVal)dummy_city_list,
141 				      NULL);
142 
143   goto_center_command =
144     I_L(XtVaCreateManagedWidget("gotocentercommand", commandWidgetClass,
145 				goto_form, NULL));
146 
147   goto_airlift_command =
148     I_L(XtVaCreateManagedWidget("gotoairliftcommand", commandWidgetClass,
149 				goto_form, NULL));
150 
151   goto_all_toggle =
152     I_L(XtVaCreateManagedWidget("gotoalltoggle", toggleWidgetClass,
153 				goto_form,
154 				XtNstate, no_player_cities,
155 				XtNsensitive, !no_player_cities,
156 				NULL));
157 
158   goto_cancel_command =
159     I_L(XtVaCreateManagedWidget("gotocancelcommand", commandWidgetClass,
160 				goto_form, NULL));
161 
162   XtAddCallback(goto_list, XtNcallback, goto_list_callback, NULL);
163   XtAddCallback(goto_center_command, XtNcallback,
164 		goto_goto_command_callback, NULL);
165   XtAddCallback(goto_airlift_command, XtNcallback,
166 		goto_airlift_command_callback, NULL);
167   XtAddCallback(goto_all_toggle, XtNcallback,
168 		goto_all_toggle_callback, NULL);
169   XtAddCallback(goto_cancel_command, XtNcallback,
170 		goto_cancel_command_callback, NULL);
171 
172   XtRealizeWidget(goto_dialog_shell);
173 
174   update_goto_dialog(goto_list);
175 
176   XtVaGetValues(toplevel, XtNwidth, &width, XtNheight, &height, NULL);
177 
178   XtTranslateCoords(toplevel, (Position) width/10, (Position) height/10,
179 		    &x, &y);
180   XtVaSetValues(goto_dialog_shell, XtNx, x, XtNy, y, NULL);
181 
182   XtPopup(goto_dialog_shell, XtGrabNone);
183 
184   /* force refresh of viewport so the scrollbar is added.
185    * Buggy sun athena requires this */
186   XtVaSetValues(goto_viewport, XtNforceBars, True, NULL);
187 }
188 
get_selected_city(void)189 static struct city *get_selected_city(void)
190 {
191   XawListReturnStruct *ret;
192   int len;
193 
194   ret=XawListShowCurrent(goto_list);
195   if(ret->list_index==XAW_LIST_NONE)
196     return 0;
197 
198   len = strlen(ret->string);
199   if(len>3 && strcmp(ret->string+len-3, "(A)")==0) {
200     char name[MAX_LEN_NAME];
201     fc_strlcpy(name, ret->string, MIN(sizeof(name),len-2));
202     return game_city_by_name(name);
203   }
204   return game_city_by_name(ret->string);
205 }
206 
207 /**************************************************************************
208 ...
209 **************************************************************************/
update_goto_dialog(Widget goto_cities)210 void update_goto_dialog(Widget goto_cities)
211 {
212   int j = 0;
213   Boolean all_cities;
214 
215   if (!can_client_issue_orders()) {
216     return;
217   }
218 
219   XtVaGetValues(goto_all_toggle, XtNstate, &all_cities, NULL);
220 
221   cleanup_goto_list();
222 
223   if (all_cities) {
224     ncities_total = 0;
225     players_iterate(pplayer) {
226       ncities_total += city_list_size(pplayer->cities);
227     } players_iterate_end;
228   } else {
229     ncities_total = city_list_size(client.conn.playing->cities);
230   }
231 
232   city_name_ptrs = fc_malloc(ncities_total*sizeof(char*));
233 
234   players_iterate(pplayer) {
235     if (!all_cities && pplayer != client.conn.playing) {
236       continue;
237     }
238     city_list_iterate(pplayer->cities, pcity) {
239       char name[MAX_LEN_NAME+3];
240 
241       sz_strlcpy(name, city_name_get(pcity));
242       /* FIXME: should use unit_can_airlift_to(). */
243       if (pcity->airlift) {
244         sz_strlcat(name, "(A)");
245       }
246       city_name_ptrs[j++] = fc_strdup(name);
247     } city_list_iterate_end;
248   } players_iterate_end;
249 
250   if (ncities_total) {
251     qsort(city_name_ptrs, ncities_total, sizeof(char *), compare_strings_ptrs);
252     XawListChange(goto_cities, (CONST_FOR_XAW_LIST_CHANGE char **) city_name_ptrs,
253                   ncities_total, 0, True);
254   }
255 }
256 
257 /**************************************************************************
258 ...
259 **************************************************************************/
popdown_goto_dialog(void)260 static void popdown_goto_dialog(void)
261 {
262   cleanup_goto_list();
263 
264   XtDestroyWidget(goto_dialog_shell);
265   XtSetSensitive(main_form, TRUE);
266 }
267 
268 /**************************************************************************
269 ...
270 **************************************************************************/
goto_list_callback(Widget w,XtPointer client_data,XtPointer call_data)271 void goto_list_callback(Widget w, XtPointer client_data, XtPointer call_data)
272 {
273   XawListReturnStruct *ret;
274 
275   ret = XawListShowCurrent(goto_list);
276 
277   if (ret->list_index != XAW_LIST_NONE) {
278     struct city *pdestcity;
279 
280     if ((pdestcity = get_selected_city())) {
281       bool can_airlift = FALSE;
282 
283       unit_list_iterate(get_units_in_focus(), punit) {
284         if (unit_can_airlift_to(punit, pdestcity)) {
285 	  can_airlift = TRUE;
286 	  break;
287 	}
288       } unit_list_iterate_end;
289 
290       center_tile_mapcanvas(pdestcity->tile);
291       if (can_airlift) {
292 	XtSetSensitive(goto_airlift_command, True);
293 	return;
294       }
295     }
296   }
297   XtSetSensitive(goto_airlift_command, False);
298 }
299 
300 /**************************************************************************
301 ...
302 **************************************************************************/
goto_airlift_command_callback(Widget w,XtPointer client_data,XtPointer call_data)303 void goto_airlift_command_callback(Widget w, XtPointer client_data,
304 				  XtPointer call_data)
305 {
306   struct city *pdestcity=get_selected_city();
307   if (pdestcity) {
308     unit_list_iterate(get_units_in_focus(), punit) {
309       request_unit_airlift(punit, pdestcity);
310     } unit_list_iterate_end;
311   }
312   popdown_goto_dialog();
313 }
314 
315 /**************************************************************************
316 ...
317 **************************************************************************/
goto_all_toggle_callback(Widget w,XtPointer client_data,XtPointer call_data)318 void goto_all_toggle_callback(Widget w, XtPointer client_data,
319 			      XtPointer call_data)
320 {
321   update_goto_dialog(goto_list);
322 }
323 
324 /**************************************************************************
325 ...
326 **************************************************************************/
goto_goto_command_callback(Widget w,XtPointer client_data,XtPointer call_data)327 void goto_goto_command_callback(Widget w, XtPointer client_data,
328 				  XtPointer call_data)
329 {
330   struct city *pdestcity = get_selected_city();
331   if (pdestcity) {
332     unit_list_iterate(get_units_in_focus(), punit) {
333       send_goto_tile(punit, pdestcity->tile);
334     } unit_list_iterate_end;
335   }
336   popdown_goto_dialog();
337 }
338 
339 /**************************************************************************
340 ...
341 **************************************************************************/
goto_cancel_command_callback(Widget w,XtPointer client_data,XtPointer call_data)342 void goto_cancel_command_callback(Widget w, XtPointer client_data,
343 				  XtPointer call_data)
344 {
345   center_tile_mapcanvas(original_tile);
346   popdown_goto_dialog();
347 }
348 
349 /**************************************************************************
350 ...
351 **************************************************************************/
cleanup_goto_list(void)352 static void cleanup_goto_list(void)
353 {
354   int i;
355 
356   XawListChange(goto_list, dummy_city_list, 0, 0, FALSE);
357 
358   XtSetSensitive(goto_airlift_command, False);
359 
360   if(city_name_ptrs) {
361     for(i=0; i<ncities_total; i++) {
362       free(city_name_ptrs[i]);
363     }
364     free(city_name_ptrs);
365   }
366   ncities_total = 0;
367   city_name_ptrs = NULL;
368 }
369