1 /* Closeups for the X11 interface to Xconq.
2    Copyright (C) 1995-1999 Massimo Campostrini and Stanley T. Shebs.
3 
4 Xconq is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.  See the file COPYING.  */
8 
9 /*  1) unit closeup                        */
10 /*  2) side closeup                        */
11 /*  3) unit list                           */
12 /*  4) list (summary) of unit closeups     */
13 
14 #include "conq.h"
15 #include "xtconq.h"
16 extern void create_orders_window(Side *side, Map *map);
17 
18 static void buffer_append(int nl);
19 static void add_to_closeup_summary(UnitCloseup *closeup, Side *side);
20 static void remove_from_closeup_summary(UnitCloseup *closeup,
21 						 Side *side);
22 static void summary_list_callback(Widget w, XtPointer dummy,
23 					   XawListReturnStruct *list);
24 static void unit_closeup_update(Widget w, XtPointer cldata,
25 					 XtPointer cadata);
26 static void unit_closeup_focus(Widget w, XtPointer cldata,
27 					XtPointer cadata);
28 static void unit_closeup_close(Widget w, XtPointer cldata,
29 					XtPointer cadata);
30 static void side_closeup_update(Widget w, XtPointer cldata,
31 					 XtPointer cadata);
32 static void side_closeup_close(Widget w, XtPointer cldata,
33 					XtPointer cadata);
34 static void side_closeup_close(Widget w, XtPointer cldata,
35 					XtPointer cadata);
36 static void side_closeup_type_callback(Widget w, XtPointer cldata,
37 						XtPointer cadata);
38 static void side_closeup_all_types_callback(Widget w,
39 						     XtPointer cldata,
40 						     XtPointer cadata);
41 static void build_unit_list(Widget w, XtPointer cldata,
42 				     XtPointer cadata);
43 static void unit_list_callback(Widget w, XtPointer dummy,
44 					XawListReturnStruct *list);
45 static void unit_list_close(Widget w, XtPointer cldata,
46 				     XtPointer cadata);
47 static UnitList *find_unit_list_via_button(Widget w, Side *side);
48 void destroy_unit_list(Side *side, UnitList *unit_list);
49 char *pad_string(char *str, int n, int min);
50 void one_line_unit_summary(char *buf, Unit *unit, Side *side,
51 				    int pos);
52 void hp_and_acp_desc(char *buf, Unit *unit, char *sep);
53 void list_unit_types(char *buff, int nums[]);
54 
55 Widget new_order_widgets(Side *side, OrderInterface *ordi, int num,
56 				  Widget up);
57 void sorder_cond_name(char *buffer, StandingOrder *sorder,
58 			       Side *side);
59 void update_order_widgets(Side *side, OrderInterface *ordi,
60 				   StandingOrder *sorder, char *types,
61 				   Task *task);
62 static void orders_help_call(Widget w, XtPointer cldata,
63 				      XtPointer cadata);
64 static void orders_done_help_call(Widget w, XtPointer cldata,
65 					   XtPointer cadata);
66 static void handle_done_orders_help(Widget w, XEvent *event,
67 					     String *params,
68 					     Cardinal *num_params);
69 static void handle_done_string_select(Widget w, XEvent *event,
70 					       String *params,
71 					       Cardinal *num_params);
72 static void orders_add_call(Widget w, XtPointer cldata,
73 				     XtPointer cadata);
74 static void orders_clone_call(Widget w, XtPointer cldata,
75 				       XtPointer cadata);
76 static void orders_add_named(Widget w, char *string);
77 static void orders_delete_call(Widget w, XtPointer cldata,
78 					XtPointer cadata);
79 static void orders_undo_call(Widget w, XtPointer cldata,
80 				      XtPointer cadata);
81 static void orders_save_call(Widget w, XtPointer cldata,
82 				      XtPointer cadata);
83 static void orders_restore_call(Widget w, XtPointer cldata,
84 					 XtPointer cadata);
85 static void orders_close_call(Widget w, XtPointer cldata,
86 				       XtPointer cadata);
87 static void order_toggle_call(Widget w, XtPointer cldata,
88 				       XtPointer cadata);
89 static void order_types_call(Widget w, XtPointer cldata,
90 				      XtPointer cadata);
91 static void order_etype_call(Widget w, XtPointer cldata,
92 				      XtPointer cadata);
93 static void order_eparms_call(Widget w, XtPointer cldata,
94 				       XtPointer cadata);
95 static void order_task_call(Widget w, XtPointer cldata,
96 				     XtPointer cadata);
97 static void order_tparms_call(Widget w, XtPointer cldata,
98 				       XtPointer cadata);
99 void set_cell_from_map(Side *side, Map *map, char *prompt,
100 				void *px, void *py, int size);
101 static void aux_set_cell(Side *side, Map *map, int cancel);
102 void set_unit_from_map(Side *side, Map *map, char *prompt,
103 				int *puid);
104 static void aux_set_unit(Side *side, Map *map, int cancel);
105 int find_side_and_ordi_via_widget(Widget w, Side **sidep,
106 					   OrderInterface **ordip);
107 void deactivate_orders(Side *side);
108 OrderInterface *active_ordi(Side *side);
109 int utype_select_popup(Side *side, Position x, Position y);
110 static void utype_select_call(Widget w, XtPointer cldata,
111 				       XtPointer cadata);
112 int dir_select_popup(Side *side, Position x, Position y);
113 static void dir_select_call(Widget w, XtPointer cldata,
114 				     XtPointer cadata);
115 int integer_select_popup(Side *side, Position x, Position y,
116 				  int init, char *prompt);
117 void string_select_popup(Side *side, Position x, Position y,
118 				  char *result, char *init, char *prompt);
119 int cond_select_popup(Side *side, Position x, Position y);
120 static void cond_select_call(Widget w, XtPointer cldata,
121 				      XtPointer cadata);
122 int task_select_popup(Side *side, Position x, Position y);
123 static void task_select_call(Widget w, XtPointer cldata,
124 				      XtPointer cadata);
125 int count_sorder(Side *side);
126 
127 static void orders_check(Side *side);
128 
129 static char buffer[200], *longbuffer = NULL;
130 /* initial lengths of arrays, they will grow when needed */
131 static int longbuffer_length = 1000, unitlist_size = 100, summary_size = 100;
132 
133 #define OTHERFILTERS 4  /* filters not based on unit typs */
134 #define LISTLINE 80
135 
136 /* Unit closeups. */
137 
138 UnitCloseup *
find_unit_closeup(Side * side,Unit * unit)139 find_unit_closeup(Side *side, Unit *unit)
140 {
141     UnitCloseup *unitcloseup;
142 
143     for_all_unit_closeups(unitcloseup, side) {
144 	if (unitcloseup->unit == unit && unitcloseup->shell)
145 	  return unitcloseup;
146     }
147     return NULL;
148 }
149 
150 UnitCloseup *
find_unit_closeup_via_button(Widget w,Side * side)151 find_unit_closeup_via_button(Widget w, Side *side)
152 {
153     UnitCloseup *unitcloseup;
154     Widget shell = XtParent(XtParent(w));
155 
156     for_all_unit_closeups(unitcloseup, side) {
157 	if (unitcloseup->shell == shell)
158 	  return unitcloseup;
159     }
160     return NULL;
161 }
162 
163 UnitCloseup *
create_unit_closeup(Side * side,Map * map,Unit * unit)164 create_unit_closeup(Side *side, Map *map, Unit *unit)
165 {
166     Widget cmd, up, left, form;
167     UnitCloseup *unitcloseup;
168     Side *side2;
169 
170     if (!active_display(side) || unit == NULL)
171       return NULL;
172     unitcloseup = (UnitCloseup *) xmalloc(sizeof(UnitCloseup));
173     side2 = unit->side;
174     if (side2 == NULL)
175       side2 = indepside;
176 
177     unitcloseup->unit = unit;
178     unitcloseup->map = map;
179 
180     /* create the popup */
181     strcpy(buffer, "Xconq closeup: ");
182     strcat(buffer, unit_handle(side, unit));
183     strcpy(spbuf, "Xconq: ");
184     strcat(spbuf, short_unit_handle(unit));
185     unitcloseup->shell =
186       XtVaCreatePopupShell("unitCloseup", topLevelShellWidgetClass,
187 			   side->ui->shell,
188 			   XtNtitle, buffer,
189 			   XtNiconName, spbuf,
190 			   NULL);
191     form =
192       XtVaCreateManagedWidget("form", formWidgetClass, unitcloseup->shell,
193 			      NULL);
194     left = up =
195       XtVaCreateManagedWidget("icon", labelWidgetClass, form,
196 			      XtNbitmap, get_unit_picture(unit->type, side),
197 			      XtNtop,    XawChainTop,
198 			      XtNbottom, XawChainTop,
199 			      XtNleft,   XawChainLeft,
200 			      XtNright,  XawChainLeft,
201 			      NULL);
202     left =
203       XtVaCreateManagedWidget("label", labelWidgetClass, form,
204 			      XtNfromHoriz, left,
205 			      XtNlabel,  unit_handle(side, unit),
206 			      XtNtop,    XawChainTop,
207 			      XtNbottom, XawChainTop,
208 			      XtNleft,   XawChainLeft,
209 			      XtNright,  XawChainLeft,
210 			      NULL);
211     left =
212       XtVaCreateManagedWidget("flag", labelWidgetClass, form,
213 			      XtNbitmap, get_side_picture(side, side2),
214 			      XtNlabel, "",
215 			      XtNfromHoriz, left,
216 			      XtNtop,    XawChainTop,
217 			      XtNbottom, XawChainTop,
218 			      XtNleft,   XawChainLeft,
219 			      XtNright,  XawChainLeft,
220 			      NULL);
221     left =
222       XtVaCreateManagedWidget("side", labelWidgetClass, form,
223 			      XtNfromHoriz, left,
224 			      XtNlabel,  side_adjective(side2),
225 			      XtNtop,    XawChainTop,
226 			      XtNbottom, XawChainTop,
227 			      XtNleft,   XawChainLeft,
228 			      XtNright,  XawChainLeft,
229 			      NULL);
230     up = unitcloseup->info =
231       XtVaCreateManagedWidget("info", asciiTextWidgetClass, form,
232 			      XtNfromVert, up,
233 			      XtNdisplayCaret, False,
234 			      XtNeditType, XawtextRead,
235 			      XtNscrollHorizontal, XawtextScrollWhenNeeded,
236 			      XtNscrollVertical, XawtextScrollWhenNeeded,
237 			      XtNtop,    XawChainTop,
238 			      XtNbottom, XawChainBottom,
239 			      XtNleft,   XawChainLeft,
240 			      XtNright,  XawChainRight,
241 			      NULL);
242     left = cmd =
243       XtVaCreateManagedWidget("update", commandWidgetClass, form,
244 			      XtNfromVert,  up,
245 			      XtNtop,    XawChainBottom,
246 			      XtNbottom, XawChainBottom,
247 			      XtNleft,   XawChainLeft,
248 			      XtNright,  XawChainLeft,
249 			      NULL);
250     XtAddCallback(cmd, XtNcallback, unit_closeup_update, NULL);
251     left = cmd =
252       XtVaCreateManagedWidget("focus", commandWidgetClass, form,
253 			      XtNfromHoriz, left,
254 			      XtNfromVert,  up,
255 			      XtNtop,    XawChainBottom,
256 			      XtNbottom, XawChainBottom,
257 			      XtNleft,   XawChainLeft,
258 			      XtNright,  XawChainLeft,
259 			      NULL);
260     XtAddCallback(cmd, XtNcallback, unit_closeup_focus, NULL);
261     cmd =
262       XtVaCreateManagedWidget("close", commandWidgetClass, form,
263 			      XtNfromHoriz, left,
264 			      XtNfromVert,  up,
265 			      XtNtop,    XawChainBottom,
266 			      XtNbottom, XawChainBottom,
267 			      XtNleft,   XawChainLeft,
268 			      XtNright,  XawChainLeft,
269 			      NULL);
270     XtAddCallback(cmd, XtNcallback, unit_closeup_close, NULL);
271 
272     /* insert in the side's unit closeup list */
273     unitcloseup->next = side->ui->unitcloseuplist;
274     side->ui->unitcloseuplist = unitcloseup;
275 
276     XtPopup(unitcloseup->shell, XtGrabNone);
277 
278     add_to_closeup_summary(unitcloseup, side);
279 
280     return unitcloseup;
281 }
282 
283 void
destroy_unit_closeup(Side * side,UnitCloseup * unitcloseup)284 destroy_unit_closeup(Side *side, UnitCloseup *unitcloseup)
285 {
286     UnitCloseup *uc;
287 
288     XtPopdown(unitcloseup->shell);
289     XtDestroyWidget(unitcloseup->shell);
290 
291     remove_from_closeup_summary(unitcloseup, side);
292 
293     /* remove from the side's unit closeup list */
294     if (side->ui->unitcloseuplist == unitcloseup) {
295 	side->ui->unitcloseuplist = unitcloseup->next;
296     } else {
297 	for_all_unit_closeups(uc,side) {
298 	    if (uc->next == unitcloseup) {
299 		uc->next = unitcloseup->next;
300 	    }
301 	}
302     }
303     free(unitcloseup);
304 }
305 
306 /* conveniency routine to append the contents of "buffer" */
307 /* into "longbuffer", growing it if needed */
308 /* append a newline if nl is not zero */
309 static void
buffer_append(int nl)310 buffer_append(int nl)
311 {
312     int len, longl;
313 
314     longl = strlen(longbuffer);
315     if (nl)
316       strcat(buffer, "\n");
317     len = strlen(buffer);
318 
319     if (len+longl > longbuffer_length-2) {
320 	longbuffer_length *= 2;
321 	longbuffer = (char *) realloc(longbuffer,
322 				      longbuffer_length*sizeof(char));
323     }
324     strcat(longbuffer, buffer);
325     buffer[0] = '\0';  /* clear buffer */
326 }
327 
328 void
draw_unit_closeup(Side * side,UnitCloseup * unitcloseup)329 draw_unit_closeup(Side *side, UnitCloseup *unitcloseup)
330 {
331     int m, u, i;
332     Unit *unit = unitcloseup->unit, *occupant;
333     char *featurename;
334 
335     if (!active_display(side))
336       return;
337     if (!in_play(unit)
338 	|| (!side_controls_unit(side, unit) && !endofgame)) {
339 	/* If the unit is no longer alive and ours, shut down the window. */
340 	destroy_unit_closeup(side, unitcloseup);
341 	return;
342     }
343 
344     if (longbuffer == NULL) {
345 	longbuffer = (char *) xmalloc(longbuffer_length*sizeof(char));
346     }
347     longbuffer[0] = '\0';
348 
349     /* Draw the unit's side and type. */
350     strcpy(buffer, unit_handle(side, unit));
351     pad_string(buffer, 40, 3);
352     buffer_append(0);
353 
354     /* Draw the unit's HP, CP and ACP */
355     hp_and_acp_desc(buffer, unit, "   ");
356     buffer_append(1);
357 
358     /* Draw the unit's location. */
359     if (unit->transport != NULL) {
360 	sprintf(buffer, "In %s (", short_unit_handle(unit->transport));
361     }
362     if (terrain_visible(side, unit->x, unit->y)) {
363 	sprintf(spbuf, "In %s", t_type_name(terrain_at(unit->x, unit->y)));
364 	linear_desc(spbuf, unit->x, unit->y);
365 	if (unit->transport != NULL) {
366 	    spbuf[0] = tolower(spbuf[0]);
367 	}
368 	strcat(buffer, spbuf);
369 	if (unit->transport == NULL) {
370 	    featurename = feature_name_at(unit->x, unit->y);
371 	    if (!empty_string(featurename))
372 	      tprintf(buffer, " (%s)", featurename);
373 	    if (temperatures_defined())
374 	      tprintf(buffer, " (T %d)", temperature_at(unit->x, unit->y));
375 	    if (elevations_defined())
376 	      tprintf(buffer, " (El %d)", elev_at(unit->x, unit->y));
377 	    /* (should list local weather also) */
378 	}
379 	strcat(buffer," ");
380     }
381     tprintf(buffer, "at %d,%d", unit->x, unit->y);
382     if (unit->transport != NULL) {
383 	strcat(buffer,")");
384     }
385     pad_string(buffer, 40, 3);
386     buffer_append(0);
387 
388     /* Draw the unit's supplies. */
389     i = 0;
390     for_all_material_types(m) {
391 	if (um_storage_x(unit->type, m) > 0) {
392 	    sprintf(buffer, "%s%s %d/%d", i ? ", " : "",
393 		    m_type_name(m), unit->supply[m],
394 		    um_storage_x(unit->type, m));
395 	    i = 1;
396 	    buffer_append(0);
397 	}
398     }
399     buffer_append(1);
400 
401     /* Draw the unit's toolup level (if any) */
402     if (unit->tooling != NULL) {
403 	i = 0;
404 	for_all_unit_types(u) {
405 	    i = i || unit->tooling[u];
406 	}
407 	if (i) {
408 	    buffer_append(1);
409 	    strcpy(buffer, "Toolup level: ");
410 	    for_all_unit_types(u) {
411 		if (unit->tooling[u]) {
412 		    if (unit->tooling[u]<uu_tp_max(unit->type, u)) {
413 			tprintf(buffer, "%d/%d%1s ",
414 				unit->tooling[u], uu_tp_max(unit->type, u),
415 				utype_name_n(u, 1));
416 		    } else {
417 			tprintf(buffer, "%d%1s ", unit->tooling[u],
418 				utype_name_n(u, 1));
419 		    }
420 		}
421 	    }
422 	    buffer_append(1);
423 	}
424     }
425 
426     /* Draw the unit's plan, if it has one. */
427     if (unit->plan) {
428 	Task *task;
429 	Plan *plan = unit->plan;
430 
431 	strcpy(buffer, "\nplan:  ");
432 	buffer_append(0);
433 
434 	plan_desc(buffer, unit);
435 
436     	if (plan->maingoal) {
437 	    strcat(buffer, "   ");
438 	    /* (should use a "goal_desc" routine) */
439 	    strcat(buffer, goal_desig(plan->maingoal));
440     	}
441     	if (plan->formation) {
442 	    strcat(buffer, "   ");
443 	    /* (should use a "goal_desc" routine) */
444 	    strcat(buffer, goal_desig(plan->formation));
445     	}
446 	buffer_append(1);
447 	if (plan->tasks) {
448 	    for (task = plan->tasks; task != NULL; task = task->next) {
449 		task_desc(buffer, unit->side, unit, task);
450 		buffer_append(1);
451 	    }
452 	}
453     }
454 
455     /* Draw the unit's occupants */
456     if (unit->occupant != NULL) {
457 	strcpy(buffer,"\n        Occupants:");
458 	buffer_append(1);
459 	for_all_occupants(unit,occupant) {
460 	    one_line_unit_summary(buffer, occupant, side, 0);
461 	    buffer_append(1);
462 	}
463     }
464 
465     XtVaSetValues(unitcloseup->info, XtNstring, longbuffer, NULL);
466 
467     raise_widget(unitcloseup->shell);
468 }
469 
470 /* Closeups for sides. */
471 
472 SideCloseup *
find_side_closeup(Side * side,Side * side2)473 find_side_closeup(Side *side, Side *side2)
474 {
475     SideCloseup *sidecloseup;
476 
477     if (side2 == NULL)
478       side2 = indepside;
479     for_all_side_closeups(sidecloseup, side) {
480 	if (sidecloseup->side == side2
481 	    && sidecloseup->shell)
482 	  return sidecloseup;
483     }
484     return NULL;
485 }
486 
487 SideCloseup *
find_side_closeup_via_button(Widget w,Side * side)488 find_side_closeup_via_button(Widget w, Side *side)
489 {
490     SideCloseup *sidecloseup;
491     Widget shell = XtParent(XtParent(w));
492 
493     for_all_side_closeups(sidecloseup, side) {
494 	if (sidecloseup->shell == shell)
495 	  return sidecloseup;
496     }
497     return NULL;
498 }
499 
500 SideCloseup *
create_side_closeup(Side * side,Map * map,Side * side2)501 create_side_closeup(Side *side, Map *map, Side *side2)
502 {
503     int u, fn;
504     Widget cmd, up, left, box, form, radio;
505     SideCloseup *sidecloseup;
506 
507     if (!active_display(side))
508       return NULL;
509     sidecloseup = (SideCloseup *) xmalloc(sizeof(SideCloseup));
510     sidecloseup->filter =
511       (Widget *) xmalloc((numutypes + OTHERFILTERS + 1) * sizeof(Widget));
512     /* It is possible to have a closeup of the "independent side". */
513     if (side2 == NULL)
514       side2 = indepside;
515     sidecloseup->side = side2;
516     sidecloseup->map = map;
517     /* Create the popup. */
518     strcpy(buffer, "Xconq side closeup: ");
519     strcat(buffer, short_side_title(side2));
520     strcpy(spbuf, "Xconq: ");
521     strcat(spbuf, short_side_title(side2));
522     sidecloseup->shell =
523       XtVaCreatePopupShell("sideCloseup", topLevelShellWidgetClass,
524 			   side->ui->shell,
525 			   XtNtitle, buffer,
526 			   XtNiconName, spbuf,
527 			   NULL);
528     form =
529       XtVaCreateManagedWidget("form", formWidgetClass, sidecloseup->shell,
530 			      NULL);
531     left = up =
532       XtVaCreateManagedWidget("flag", labelWidgetClass, form,
533 			      XtNbitmap, get_side_picture(side, side2),
534 			      XtNlabel, "",
535 			      XtNtop,    XawChainTop,
536 			      XtNbottom, XawChainTop,
537 			      XtNleft,   XawChainLeft,
538 			      XtNright,  XawChainLeft,
539 			      NULL);
540 
541     left =
542       XtVaCreateManagedWidget("side", labelWidgetClass, form,
543 			      XtNfromHoriz, left,
544 			      XtNlabel,  short_side_title(side2),
545 			      XtNtop,    XawChainTop,
546 			      XtNbottom, XawChainTop,
547 			      XtNleft,   XawChainLeft,
548 			      XtNright,  XawChainLeft,
549 			      NULL);
550 
551     up = sidecloseup->info =
552       XtVaCreateManagedWidget("info", asciiTextWidgetClass, form,
553 			      XtNfromVert, up,
554 			      XtNdisplayCaret, False,
555 			      XtNeditType, XawtextRead,
556 			      XtNscrollHorizontal, XawtextScrollWhenNeeded,
557 			      XtNscrollVertical, XawtextScrollWhenNeeded,
558 			      XtNtop,    XawChainTop,
559 			      XtNbottom, XawChainBottom,
560 			      XtNleft,   XawChainLeft,
561 			      XtNright,  XawChainRight,
562 			      NULL);
563 
564     up = box =
565       XtVaCreateManagedWidget("filter", boxWidgetClass, form,
566 			      XtNfromVert,  up,
567 			      XtNtop,    XawChainBottom,
568 			      XtNbottom, XawChainBottom,
569 			      XtNleft,   XawChainLeft,
570 			      XtNright,  XawChainLeft,
571 			      NULL);
572     XtVaCreateManagedWidget("label", labelWidgetClass, box,
573 			    NULL);
574 
575     fn = 0;
576     /* Unit type filters; managed by their callbacks. */
577     sidecloseup->filter[fn] =
578       XtVaCreateManagedWidget("allTypes", toggleWidgetClass, box,
579 			      XtNstate, True,
580 			      NULL);
581     XtAddCallback(sidecloseup->filter[fn++], XtNcallback,
582 		  side_closeup_all_types_callback, NULL);
583 
584     for_all_unit_types(u) {
585 	sidecloseup->filter[fn] =
586 	  XtVaCreateManagedWidget(utype_name_n(u, 8), toggleWidgetClass, box,
587 				  XtNbitmap, get_unit_picture(u, side),
588 				  XtNstate, False,
589 				  NULL);
590 	XtAddCallback(sidecloseup->filter[fn++], XtNcallback,
591 		      side_closeup_type_callback, NULL);
592     }
593     /* Other filters; managed as a radio group (at most one is set). */
594     radio = sidecloseup->filter[fn] =
595       XtVaCreateManagedWidget("completed", toggleWidgetClass, box,
596 			      XtNstate, True,
597 			    NULL);
598     XawToggleChangeRadioGroup(sidecloseup->filter[fn++], radio);
599     sidecloseup->filter[fn] =
600       XtVaCreateManagedWidget("waiting", toggleWidgetClass, box,
601 			      XtNstate, False,
602 			      NULL);
603     XawToggleChangeRadioGroup(sidecloseup->filter[fn++], radio);
604     sidecloseup->filter[fn] =
605       XtVaCreateManagedWidget("acpLeft", toggleWidgetClass, box,
606 			      XtNstate, False,
607 			      NULL);
608     XawToggleChangeRadioGroup(sidecloseup->filter[fn++], radio);
609 
610     left = cmd =
611       XtVaCreateManagedWidget("update", commandWidgetClass, form,
612 			      XtNfromVert,  up,
613 			      XtNtop,    XawChainBottom,
614 			      XtNbottom, XawChainBottom,
615 			      XtNleft,   XawChainLeft,
616 			      XtNright,  XawChainLeft,
617 			      NULL);
618     XtAddCallback(cmd, XtNcallback, side_closeup_update, NULL);
619 
620     left = cmd =
621       XtVaCreateManagedWidget("listUnits", commandWidgetClass, form,
622 			      XtNfromHoriz, left,
623 			      XtNfromVert,  up,
624 			      XtNtop,    XawChainBottom,
625 			      XtNbottom, XawChainBottom,
626 			      XtNleft,   XawChainLeft,
627 			      XtNright,  XawChainLeft,
628 			      NULL);
629     XtAddCallback(cmd, XtNcallback, build_unit_list, NULL);
630 
631     cmd =
632       XtVaCreateManagedWidget("close", commandWidgetClass, form,
633 			      XtNfromHoriz, left,
634 			      XtNfromVert,  up,
635 			      XtNtop,    XawChainBottom,
636 			      XtNbottom, XawChainBottom,
637 			      XtNleft,   XawChainLeft,
638 			      XtNright,  XawChainLeft,
639 			      NULL);
640     XtAddCallback(cmd, XtNcallback, side_closeup_close, NULL);
641 
642     /* Insert in the side's side closeup list, */
643     sidecloseup->next = side->ui->sidecloseuplist;
644     side->ui->sidecloseuplist = sidecloseup;
645     /* Make the window appear. */
646     XtPopup(sidecloseup->shell, XtGrabNone);
647     return sidecloseup;
648 }
649 
650 void
destroy_side_closeup(Side * side,SideCloseup * sidecloseup)651 destroy_side_closeup(Side *side, SideCloseup *sidecloseup)
652 {
653     SideCloseup *tmpcloseup;
654 
655     /* Make the window go away. */
656     XtPopdown(sidecloseup->shell);
657     XtDestroyWidget(sidecloseup->shell);
658     /* Unsplice from the side's side closeup list. */
659     if (side->ui->sidecloseuplist == sidecloseup) {
660 	side->ui->sidecloseuplist = sidecloseup->next;
661     } else {
662 	for_all_side_closeups(tmpcloseup, side) {
663 	    if (tmpcloseup->next == sidecloseup) {
664 		tmpcloseup->next = sidecloseup->next;
665 	    }
666 	}
667     }
668     /* Free up any allocated memory. */
669     free(sidecloseup);
670 }
671 
672 void
draw_side_closeup(Side * side,SideCloseup * sidecloseup)673 draw_side_closeup(Side *side, SideCloseup *sidecloseup)
674 {
675     int u, i;
676     int *numc;
677     int *numi;
678 
679     Side *side1 = sidecloseup->side, *side2;
680     Unit *unit;
681 
682     numc = (int *)xmalloc(sizeof (numc[0]) * numutypes);
683     numi = (int *)xmalloc(sizeof (numi[0]) * numutypes);
684 
685     if (!active_display(side))
686       return;
687 
688     if (longbuffer == NULL)
689       longbuffer = (char *) xmalloc(longbuffer_length * sizeof(char));
690     longbuffer[0] = '\0';
691 
692     /* draw side name and class */
693     strcpy(buffer, short_side_title(side1));
694     if (side1->sideclass) {
695 	tprintf(buffer, " (%s)", side1->sideclass);
696     }
697     buffer_append(1);
698     buffer_append(1);
699 
700     /* count and draw side's units (completed and incomplete) */
701     /* (should be generic code?) */
702     for_all_unit_types(u) {
703 	numc[u] = 0;
704 	numi[u] = 0;
705     }
706     for_all_side_units(side1,unit) {
707 	if (completed(unit)) {
708 	    numc[unit->type]++;
709 	} else {
710 	    numi[unit->type]++;
711 	}
712     }
713     strcpy(buffer, "Completed units: ");
714     list_unit_types(buffer, numc);
715     buffer_append(1);
716     strcpy(buffer, "Units under construction: ");
717     list_unit_types(buffer, numi);
718     buffer_append(1);
719 
720     /* list side's tech level (if any) */
721     /* (should be generic code) */
722     if (side1->tech != NULL) {
723 	i = 0;
724 	for_all_unit_types(u) {
725 	    i = i || side1->tech[u];
726 	}
727 	if (i) {
728 	    buffer_append(1);
729 	    strcpy(buffer, "Tech levels: ");
730 	    for_all_unit_types(u) {
731 		if (side1->tech[u]) {
732 		    if (side1->tech[u]<u_tech_max(u)) {
733 			tprintf(buffer, "%d/%d%1s ",
734 				side1->tech[u], u_tech_max(u),
735 				utype_name_n(u, 1));
736 		    } else {
737 			tprintf(buffer, "%d%1s ", side1->tech[u],
738 				utype_name_n(u, 1));
739 		    }
740 		}
741 	    }
742 	    buffer_append(1);
743 	}
744     }
745 
746     /* list trusted sides (if any) */
747     /* (should be generic code) */
748     i = 0;
749     for_all_sides(side2)
750       i = i || (trusted_side(side1, side2) && side1 != side2);
751 
752     if (i) {
753 	buffer_append(1);
754 	strcpy(buffer, "Trusted sides: ");
755 	for_all_sides(side2) {
756 	    if (trusted_side(side1, side2) && side1 != side2)
757 	      tprintf(buffer, "%s, ", side_name(side2));
758 	}
759 	/* chop last two characters */
760 	buffer[strlen(buffer)-2] = '\0';
761 	buffer_append(1);
762     }
763 
764     XtVaSetValues(sidecloseup->info, XtNstring, longbuffer, NULL);
765 
766     raise_widget(sidecloseup->shell);
767 
768     free (numc);
769     free (numi);
770 }
771 
772 /* manage a list (summary) of all unit closeups of a side */
773 
774 static void
add_to_closeup_summary(UnitCloseup * unitcloseup,Side * side)775 add_to_closeup_summary(UnitCloseup *unitcloseup, Side *side)
776 {
777     CloseupSummary *summary = side->ui->closeupsummary;
778     Widget form, port;
779     char *label;
780 
781     if (summary == NULL) {
782 	/* initialize and popup the summary */
783 	summary = side->ui->closeupsummary =
784 	  (CloseupSummary *) xmalloc(sizeof(CloseupSummary));
785 	summary->unitcloseups =
786 	  (UnitCloseup **) xmalloc(summary_size*sizeof(UnitCloseup *));
787 	summary->number = 0;
788 	summary->labels = (char **) xmalloc(summary_size*sizeof(char *));
789 
790 	summary->shell =
791 	  XtVaCreatePopupShell("closeupList", topLevelShellWidgetClass,
792 			       side->ui->shell,
793 			       NULL);
794 	form =
795 	  XtVaCreateManagedWidget("form", formWidgetClass, summary->shell,
796 				  NULL);
797 	summary->label =
798 	  XtVaCreateManagedWidget("label", labelWidgetClass, form,
799 				  /* reserve space for label */
800 				  XtNlabel,  "9999 unit closeups",
801 				  XtNtop,    XawChainTop,
802 				  XtNbottom, XawChainTop,
803 				  XtNleft,   XawChainLeft,
804 				  XtNright,  XawChainLeft,
805 				  NULL);
806 	port =
807 	  XtVaCreateManagedWidget("port", viewportWidgetClass, form,
808 				  XtNfromVert, summary->label,
809 				  XtNallowVert, True,
810 				  XtNtop,    XawChainTop,
811 				  XtNbottom, XawChainBottom,
812 				  XtNleft,   XawChainLeft,
813 				  XtNright,  XawChainRight,
814 				  NULL);
815 	summary->list =
816 	  XtVaCreateManagedWidget("list", listWidgetClass, port,
817 				  XtNlongest, 0,
818 				  NULL);
819 	XtAddCallback(summary->list, XtNcallback,
820 		      (XtCallbackProc) summary_list_callback,
821 		      (XtPointer) NULL);
822 
823 	XtPopup(summary->shell, XtGrabNone);
824     }
825 
826     summary->number++;
827     if (summary->number + 1 > summary_size) {
828 	/* grow arrays */
829 	summary_size *= 2;
830 	summary->unitcloseups =
831 	  (UnitCloseup **) realloc(summary->unitcloseups,
832 				   summary_size*sizeof(UnitCloseup *));
833 	summary->labels =
834 	  (char **) realloc(summary->labels,
835 			    summary_size*sizeof(char **));
836     }
837 
838     /* append new closeup */
839     summary->unitcloseups[summary->number - 1] = unitcloseup;
840     label = summary->labels[summary->number - 1] =
841       (char *)xmalloc((LISTLINE + 1) * sizeof(char));
842     one_line_unit_summary(buffer, unitcloseup->unit, side, 1);
843     strncpy(label, buffer, LISTLINE);
844     label[LISTLINE] = '\0';
845 
846     XawListChange(summary->list, summary->labels, summary->number, 0, True);
847 
848     sprintf(buffer, "%d unit closeup%s", summary->number,
849 	    (summary->number == 1) ? "" : "s");
850     XtVaSetValues(summary->label, XtNlabel, buffer, NULL);
851 
852     /* don't raise this window */
853 }
854 
855 static void
remove_from_closeup_summary(UnitCloseup * unitcloseup,Side * side)856 remove_from_closeup_summary(UnitCloseup *unitcloseup, Side *side)
857 {
858     CloseupSummary *summary = side->ui->closeupsummary;
859     int i, found;
860 
861     /* find and remove closeup */
862     found = 0;
863     for (i = 0; i < summary->number; i++) {
864 	if (summary->unitcloseups[i] == unitcloseup) {
865 	    found = 1;
866 	    free(summary->labels[i]);
867 	}
868 	if (found) {
869 	    summary->unitcloseups[i] = summary->unitcloseups[i+1];
870 	    summary->labels[i] = summary->labels[i+1];
871 	}
872     }
873     summary->number--;
874 
875     XawListChange(summary->list, summary->labels, summary->number, 0, True);
876 
877     sprintf(buffer, "%d unit closeup%s", summary->number,
878 	    (summary->number == 1) ? "" : "s");
879     XtVaSetValues(summary->label, XtNlabel, buffer, NULL);
880 
881     if (summary->number == 0) {
882 	/* destroy window and cleanup summary */
883 	XtPopdown(summary->shell);
884 	XtDestroyWidget(summary->shell);
885 	free(summary->unitcloseups);
886 	free(summary->labels);
887 	free(side->ui->closeupsummary);
888 	side->ui->closeupsummary = NULL;
889     }
890 }
891 
892 /* callback for closeup list */
893 
894 static void
summary_list_callback(Widget w,XtPointer dummy,XawListReturnStruct * list)895 summary_list_callback(Widget w, XtPointer dummy, XawListReturnStruct *list)
896 {
897     Side *side;
898 
899     if (!find_side_via_widget(w, &side))
900       return;
901 
902     draw_unit_closeup(side,
903 		      side->ui->closeupsummary->unitcloseups[list->list_index]);
904 }
905 
906 /* Redo the information in the unit's closeup. */
907 
908 static void
unit_closeup_update(Widget w,XtPointer client_data,XtPointer call_data)909 unit_closeup_update(Widget w, XtPointer client_data, XtPointer call_data)
910 {
911     Side *side;
912     UnitCloseup *unitcloseup;
913 
914     if (!find_side_via_widget(w, &side))
915       return;
916 
917     unitcloseup = find_unit_closeup_via_button(w, side);
918     draw_unit_closeup(side, unitcloseup);
919 }
920 
921 /* Raise the appropriate map and focus on the unit in the closeup. */
922 
923 static void
unit_closeup_focus(Widget w,XtPointer client_data,XtPointer call_data)924 unit_closeup_focus(Widget w, XtPointer client_data, XtPointer call_data)
925 {
926     Side *side;
927     Map *map;
928     UnitCloseup *unitcloseup;
929 
930     if (!find_side_via_widget(w, &side))
931       return;
932 
933     unitcloseup = find_unit_closeup_via_button(w, side);
934     draw_unit_closeup(side, unitcloseup);
935     for_all_maps(side, map) {
936 	if (map == unitcloseup->map) {
937 	    /* unitcloseup->map is up */
938 	    set_current_unit(side, map, unitcloseup->unit);
939 	    raise_widget(XtParent(map->mainwidget));
940 	    return;
941 	}
942     }
943     /* choose another map */
944     if (side->ui->maps == NULL)
945       return;
946 
947     set_current_unit(side, side->ui->maps, unitcloseup->unit);
948     raise_widget(XtParent(side->ui->maps->mainwidget));
949 }
950 
951 static void
unit_closeup_close(Widget w,XtPointer client_data,XtPointer call_data)952 unit_closeup_close(Widget w, XtPointer client_data, XtPointer call_data)
953 {
954     Side *side;
955     UnitCloseup *unitcloseup;
956 
957     if (!find_side_via_widget(w, &side))
958       return;
959 
960     unitcloseup = find_unit_closeup_via_button(w, side);
961     destroy_unit_closeup(side, unitcloseup);
962 }
963 
964 /* callbacks for side closeups */
965 
966 static void
side_closeup_close(Widget w,XtPointer client_data,XtPointer call_data)967 side_closeup_close(Widget w, XtPointer client_data, XtPointer call_data)
968 {
969     Side *side;
970     SideCloseup *sidecloseup;
971 
972     if (!find_side_via_widget(w, &side))
973       return;
974 
975     sidecloseup = find_side_closeup_via_button(w, side);
976     destroy_side_closeup(side, sidecloseup);
977 }
978 
979 static void
side_closeup_update(Widget w,XtPointer client_data,XtPointer call_data)980 side_closeup_update(Widget w, XtPointer client_data, XtPointer call_data)
981 {
982     Side *side;
983     SideCloseup *sidecloseup;
984 
985     if (!find_side_via_widget(w, &side))
986       return;
987 
988     sidecloseup = find_side_closeup_via_button(w, side);
989     draw_side_closeup(side, sidecloseup);
990 }
991 
992 /* if a unit type filter is toggled, clear the "all types" filter */
993 
994 static void
side_closeup_type_callback(Widget w,XtPointer client_data,XtPointer call_data)995 side_closeup_type_callback(Widget w, XtPointer client_data, XtPointer call_data)
996 {
997     Side *side;
998     SideCloseup *sidecloseup;
999 
1000     if (!find_side_via_widget(w, &side))
1001       return;
1002 
1003     sidecloseup = find_side_closeup_via_button(XtParent(w), side);
1004     if (!sidecloseup)
1005       return;
1006     XtVaSetValues(sidecloseup->filter[0], XtNstate, False, NULL);
1007 }
1008 
1009 /* if the "all types" filter is set, clear all unit type filters */
1010 /* if the "all types" filter is cleared, */
1011 /* clear all unit type filters but set the first one */
1012 
1013 static void
side_closeup_all_types_callback(Widget w,XtPointer client_data,XtPointer call_data)1014 side_closeup_all_types_callback(Widget w, XtPointer client_data, XtPointer call_data)
1015 {
1016     Side *side;
1017     SideCloseup *sidecloseup;
1018     int u;
1019     Boolean state;
1020 
1021     if (!find_side_via_widget(w, &side))
1022       return;
1023 
1024     sidecloseup = find_side_closeup_via_button(XtParent(w), side);
1025     if (sidecloseup == NULL)
1026       return;
1027     XtVaGetValues(sidecloseup->filter[0], XtNstate, &state, NULL);
1028 
1029     for_all_unit_types(u) {
1030 	XtVaSetValues(sidecloseup->filter[u+1], XtNstate,
1031 		      u==0 && !state, NULL);
1032     }
1033 }
1034 
1035 /* manage unit lists */
1036 
1037 static void
build_unit_list(Widget w,XtPointer client_data,XtPointer call_data)1038 build_unit_list(Widget w, XtPointer client_data, XtPointer call_data)
1039 {
1040     Widget form, left, up;
1041     Side *side, *side1;
1042     SideCloseup *sidecloseup;
1043     Unit *unit;
1044     UnitList *unit_list;
1045     int i, u, size;
1046     Boolean *filters;
1047 
1048     if (!find_side_via_widget(w, &side))
1049       return;
1050 
1051     filters = (Boolean*)xmalloc (sizeof (filters[0]) * (numutypes + OTHERFILTERS + 1));
1052     sidecloseup = find_side_closeup_via_button(w, side);
1053     for (i = 0; i < numutypes + OTHERFILTERS; ++i) {
1054 	XtVaGetValues(sidecloseup->filter[i], XtNstate, &filters[i], NULL);
1055     }
1056     side1 = sidecloseup->side;
1057     unit_list = (UnitList *) xmalloc(sizeof(UnitList));
1058     unit_list->map = sidecloseup->map;
1059     unit_list->units  = (Unit **) xmalloc(unitlist_size * sizeof(Unit **));
1060     unit_list->labels = (char **) xmalloc(unitlist_size * sizeof(char **));
1061 
1062     /* build the filtered unit list */
1063     size = 0;
1064     for_all_side_units(side1, unit) {
1065 	if (!alive(unit))
1066 	  continue;
1067 	/* right type? */
1068 	if (!filters[0] && !filters[unit->type+1])
1069 	  continue;
1070 	/* completed? */
1071 	if (filters[numutypes + 1] && !completed(unit))
1072 	  continue;
1073 	/* waiting for orders? */
1074 	if (filters[numutypes + 2] &&
1075 	    !(unit->plan &&
1076 	      !unit->plan->asleep &&
1077 	      !unit->plan->reserve &&
1078 	      !unit->plan->delayed &&
1079 	      unit->plan->waitingfortasks))
1080 	  continue;
1081 	/* acp left? */
1082 	if ((filters[numutypes+2] || filters[numutypes+3]) &&
1083 	    !has_acp_left(unit))
1084 	  continue;
1085 
1086 	/* unit is OK */
1087 
1088 	if (size + 1 > unitlist_size) {
1089 	    /* grow arrays */
1090 	    unitlist_size *= 2;
1091 	    unit_list->units =
1092 	      (Unit **) realloc(unit_list->units,
1093 				unitlist_size*sizeof(Unit **));
1094 	    unit_list->labels =
1095 	      (char **) realloc(unit_list->labels,
1096 				unitlist_size*sizeof(char **));
1097 	}
1098 
1099 	/* append unit to list */
1100 	unit_list->units[size] = unit;
1101 	unit_list->labels[size] = (char *)xmalloc((LISTLINE+1)*sizeof(char));
1102 	one_line_unit_summary(buffer, unit, side, 1);
1103 	strncpy(unit_list->labels[size], buffer, LISTLINE);
1104 	unit_list->labels[size][LISTLINE] = '\0';
1105 	size++;
1106     }
1107 
1108     unit_list->number = size;
1109 
1110     /* create the popup */
1111     strcpy(buffer, "Xconq unit list: ");
1112     strcat(buffer, side_adjective(side1));
1113     unit_list->shell =
1114       XtVaCreatePopupShell("unitList", topLevelShellWidgetClass,
1115 			   side->ui->shell,
1116 			   XtNtitle, buffer,
1117 			   XtNiconName, buffer,
1118 			   NULL);
1119 
1120     form =
1121       XtVaCreateManagedWidget("form", formWidgetClass, unit_list->shell,
1122 			      NULL);
1123     left = up =
1124       XtVaCreateManagedWidget("flag", labelWidgetClass, form,
1125 			      XtNbitmap, get_side_picture(side, side1),
1126 			      XtNlabel, "",
1127 			      XtNtop,    XawChainTop,
1128 			      XtNbottom, XawChainTop,
1129 			      XtNleft,   XawChainLeft,
1130 			      XtNright,  XawChainLeft,
1131 			      NULL);
1132     left =
1133       XtVaCreateManagedWidget("side", labelWidgetClass, form,
1134 			      XtNfromHoriz, left,
1135 			      XtNlabel,  side_adjective(side1),
1136 			      XtNtop,    XawChainTop,
1137 			      XtNbottom, XawChainTop,
1138 			      XtNleft,   XawChainLeft,
1139 			      XtNright,  XawChainLeft,
1140 			      NULL);
1141     sprintf(buffer,"%d unit%s", size, ((size == 1) ? "" : "s"));
1142     unit_list->label =
1143       XtVaCreateManagedWidget("label", labelWidgetClass, form,
1144 			      XtNlabel,  buffer,
1145 			      XtNfromHoriz, left,
1146 			      XtNtop,    XawChainTop,
1147 			      XtNbottom, XawChainTop,
1148 			      XtNleft,   XawChainLeft,
1149 			      XtNright,  XawChainLeft,
1150 			      NULL);
1151 
1152     /* show the filters used to produce the list */
1153     left = NULL;
1154     if (filters[0]) {
1155 	left =
1156 	  XtVaCreateManagedWidget("allTypes", labelWidgetClass, form,
1157 				  XtNfromVert, up,
1158 				  XtNtop,    XawChainTop,
1159 				  XtNbottom, XawChainTop,
1160 				  XtNleft,   XawChainLeft,
1161 				  XtNright,  XawChainLeft,
1162 				  NULL);
1163     } else {
1164 	for_all_unit_types(u) {
1165 	    if (filters[u+1]) {
1166 		left =
1167 		  XtVaCreateManagedWidget(utype_name_n(u,8),
1168 					  labelWidgetClass, form,
1169 					  XtNfromHoriz, left,
1170 					  XtNfromVert, up,
1171 					  XtNbitmap, get_unit_picture(u, side),
1172 					  XtNtop,    XawChainTop,
1173 					  XtNbottom, XawChainTop,
1174 					  XtNleft,   XawChainLeft,
1175 					  XtNright,  XawChainLeft,
1176 					  NULL);
1177 	    }
1178 	}
1179     }
1180     if (filters[numutypes+1]) {
1181 	left =
1182 	  XtVaCreateManagedWidget("completed", labelWidgetClass, form,
1183 				  XtNfromHoriz, left,
1184 				  XtNfromVert, up,
1185 				  XtNtop,    XawChainTop,
1186 				  XtNbottom, XawChainTop,
1187 				  XtNleft,   XawChainLeft,
1188 				  XtNright,  XawChainLeft,
1189 				  NULL);
1190     }
1191     if (filters[numutypes+2]) {
1192 	left =
1193 	  XtVaCreateManagedWidget("waiting", labelWidgetClass, form,
1194 				  XtNfromHoriz, left,
1195 				  XtNfromVert, up,
1196 				  XtNtop,    XawChainTop,
1197 				  XtNbottom, XawChainTop,
1198 				  XtNleft,   XawChainLeft,
1199 				  XtNright,  XawChainLeft,
1200 				  NULL);
1201     }
1202     if (filters[numutypes+3]) {
1203 	    left =
1204 	      XtVaCreateManagedWidget("acpLeft", labelWidgetClass, form,
1205 				      XtNfromHoriz, left,
1206 				      XtNfromVert, up,
1207 				      XtNtop,    XawChainTop,
1208 				      XtNbottom, XawChainTop,
1209 				      XtNleft,   XawChainLeft,
1210 				      XtNright,  XawChainLeft,
1211 				      NULL);
1212 	}
1213     if (left != NULL)
1214       up = left;
1215 
1216     if (size) {
1217 	/* we found some units, show them */
1218 	up =
1219 	  XtVaCreateManagedWidget("port", viewportWidgetClass, form,
1220 				  XtNfromVert, up,
1221 				  XtNallowVert, True,
1222 				  XtNtop,    XawChainTop,
1223 				  XtNbottom, XawChainBottom,
1224 				  XtNleft,   XawChainLeft,
1225 				  XtNright,  XawChainRight,
1226 				  NULL);
1227 	unit_list->list =
1228 	  XtVaCreateManagedWidget("list", listWidgetClass, up,
1229 				  XtNlongest, 0,
1230 				  NULL);
1231 	XawListChange(unit_list->list, unit_list->labels,
1232 		      size, 0, True);
1233 	XtAddCallback(unit_list->list, XtNcallback,
1234 		      (XtCallbackProc) unit_list_callback, (XtPointer) NULL);
1235     } else {
1236 	/* we found no units, show a warning */
1237 	unit_list->list = NULL;
1238 	up =
1239 	  XtVaCreateManagedWidget("failed", labelWidgetClass, form,
1240 				  XtNfromVert, up,
1241 				  XtNtop,    XawChainTop,
1242 				  XtNbottom, XawChainBottom,
1243 				  XtNleft,   XawChainLeft,
1244 				  XtNright,  XawChainLeft,
1245 				  NULL);
1246     }
1247     left = unit_list->close =
1248       XtVaCreateManagedWidget("close", commandWidgetClass, form,
1249 			      XtNfromVert,  up,
1250 			      XtNtop,    XawChainBottom,
1251 			      XtNbottom, XawChainBottom,
1252 			      XtNleft,   XawChainLeft,
1253 			      XtNright,  XawChainLeft,
1254 			      NULL);
1255     XtAddCallback(unit_list->close, XtNcallback, unit_list_close, NULL);
1256 
1257     XtPopup(unit_list->shell, XtGrabNone);
1258 
1259     /* append to list */
1260     unit_list->next = side->ui->unitlistlist;
1261     side->ui->unitlistlist = unit_list;
1262 
1263     free(filters);
1264 }
1265 
1266 static void
unit_list_callback(Widget w,XtPointer dummy,XawListReturnStruct * list)1267 unit_list_callback(Widget w, XtPointer dummy, XawListReturnStruct *list)
1268 {
1269     Side *side;
1270     UnitList *unitlist;
1271     UnitCloseup *unitcloseup;
1272     Unit *unit;
1273     Map *map;
1274     int i;
1275 
1276     if (!find_side_via_widget(w, &side))
1277       return;
1278     unitlist = find_unit_list_via_button(XtParent(w), side);
1279     if (unitlist == NULL)
1280       return;
1281 
1282     unit = unitlist->units[list->list_index];
1283     i = 0;
1284     for_all_maps(side, map) {
1285 	if (map == unitlist->map)
1286 	  i = 1;
1287     }
1288     if (i) {
1289 	map = unitlist->map;
1290     } else {
1291 	/* unitlist->map not found */
1292 	map = side->ui->maps;
1293     }
1294     if (map == NULL)
1295       return;
1296 
1297     unitcloseup = find_unit_closeup(side, unit);
1298     if (!unitcloseup)
1299       /* should never happen */
1300       unitcloseup = create_unit_closeup(side, map, unit);
1301     draw_unit_closeup(side, unitcloseup);
1302 }
1303 
1304 static void
unit_list_close(Widget w,XtPointer client_data,XtPointer call_data)1305 unit_list_close(Widget w, XtPointer client_data, XtPointer call_data)
1306 {
1307     Side *side;
1308     UnitList *unitlist;
1309 
1310     if (!find_side_via_widget(w, &side))
1311       return;
1312 
1313     unitlist = find_unit_list_via_button(w, side);
1314     destroy_unit_list(side, unitlist);
1315 }
1316 
1317 void
destroy_unit_list(Side * side,UnitList * unit_list)1318 destroy_unit_list(Side *side, UnitList *unit_list)
1319 {
1320     UnitList *unitlist;
1321     int i;
1322 
1323     XtPopdown(unit_list->shell);
1324     XtDestroyWidget(unit_list->shell);
1325 
1326     /* Unsplice from the side's list. */
1327     if (side->ui->unitlistlist == unit_list) {
1328 	side->ui->unitlistlist = unit_list->next;
1329     } else {
1330 	for_all_unit_lists(unitlist,side) {
1331 	    if (unitlist->next == unit_list) {
1332 		unitlist->next = unit_list->next;
1333 	    }
1334 	}
1335     }
1336     /* Release the memory used. */
1337     for (i = 0; i < unit_list->number; i++)
1338       free(unit_list->labels[i]);
1339     free(unit_list->units);
1340     free(unit_list->labels);
1341     free(unit_list);
1342 }
1343 
1344 static UnitList *
find_unit_list_via_button(Widget w,Side * side)1345 find_unit_list_via_button(Widget w, Side *side)
1346 {
1347     UnitList *unitlist;
1348     Widget shell = XtParent(XtParent(w));
1349 
1350     for_all_unit_lists(unitlist, side) {
1351 	if (unitlist->shell == shell)
1352 	  return unitlist;
1353     }
1354     return NULL;
1355 }
1356 
1357 /* miscellanea of utilities; to be moved in the appropriate files */
1358 
1359 /* pad str with blanks to reach a length n */
1360 /* if min is positive, add a minimum of min blanks */
1361 /* if min is negative, chop to n character, */
1362 /* including a minimum of |min| blanks */
1363 
1364 char *
pad_string(char * str,int n,int minim)1365 pad_string(char *str, int n, int minim)
1366 {
1367     int i;
1368     int len = strlen(str);
1369     int lim = ((minim >= 0) ? max(n, len + minim) : n);
1370 
1371     for (i = len; i < lim; i++) {
1372 	str[i] = ' ';
1373     }
1374     str[lim] = '\0';
1375     if (minim < 0) {
1376 	for (i = n + minim; i < n; i++) {
1377 	   str[i] = ' ';
1378        }
1379     }
1380     return str;
1381 }
1382 
1383 void
hp_and_acp_desc(char * buf,Unit * unit,char * sep)1384 hp_and_acp_desc(char *buf, Unit *unit, char *sep)
1385 {
1386     /* Draw the unit's hit points and CP. */
1387     hp_desc(spbuf, unit, TRUE);
1388     strcat(buf, spbuf);
1389 
1390     /* Draw the unit's current ACP, if applicable. */
1391     if (u_acp(unit->type) > 0) {
1392 	strcat(buf, sep);
1393 	acp_desc(spbuf, unit, TRUE);
1394 	strcat(buf, spbuf);
1395     }
1396 }
1397 
1398 /* a one-line description of unit and occupants */
1399 /* add position info if pos!=0 */
1400 
1401 void
one_line_unit_summary(char * buf,Unit * unit,Side * side,int pos)1402 one_line_unit_summary(char *buf, Unit *unit, Side *side, int pos)
1403 {
1404     Unit *occupant;
1405     int u;
1406 
1407     strcpy(buf, unit_handle(side, unit));
1408     if (pos) {
1409 	if (unit->transport != NULL) {
1410 	    tprintf(buf, " in %s", short_unit_handle(unit->transport));
1411 	} else {
1412 	    tprintf(buf, " in %s at %d,%d",
1413 		    t_type_name(terrain_at(unit->x, unit->y)),
1414 		    unit->x, unit->y);
1415 	}
1416     }
1417     pad_string(buf, pos ? 45 : 40, -2);
1418     hp_and_acp_desc(buf, unit, "  ");
1419     if (unit->occupant != NULL) {
1420 	/* Very briefly list the numbers and types of the occupants. */
1421 	strcat(buf, "  Occ ");
1422 	for_all_unit_types(u)
1423 	    tmp_u_array[u] = 0;
1424 	for_all_occupants(unit, occupant)
1425 	    tmp_u_array[occupant->type]++;
1426 	list_unit_types(buf, tmp_u_array);
1427     }
1428 }
1429 
1430 /* produce a list of the number of units for each type */
1431 /* from the given number array */
1432 
1433 void
list_unit_types(char * buff,int nums[])1434 list_unit_types(char *buff, int nums[])
1435 {
1436     int u, total = 0;
1437 
1438     for_all_unit_types(u) {
1439 	if (nums[u] > 0) {
1440 	    total += nums[u];
1441 	    tprintf(buffer, "%d%1s ", nums[u], utype_name_n(u, 1));
1442 	}
1443     }
1444     if (!total) {
1445 	strcat(buff, "none  ");
1446     }
1447 }
1448 
1449 /* cache and return a unit picture */
1450 
1451 Pixmap
get_unit_picture(int u,Side * side)1452 get_unit_picture(int u, Side *side)
1453 {
1454     Pixmap pic;
1455     Display *dpy = side->ui->dpy;
1456 
1457     if (side->ui->unitpics[4][u] == None) {
1458 	pic = XCreatePixmap(dpy, side->ui->rootwin,
1459 			    min_w_for_unit_image, min_h_for_unit_image,
1460 			    DefaultDepth(dpy, side->ui->screen));
1461 	XFillRectangle(dpy, pic, side->ui->gc,
1462 		       0, 0, min_w_for_unit_image, min_h_for_unit_image);
1463 	XSetForeground(dpy, side->ui->gc, side->ui->fgcolor);
1464 	draw_unit_image(uimages[u], side, pic, 0, 0,
1465 			min_w_for_unit_image, min_h_for_unit_image,
1466 			-1, -1, -1, 0);
1467 	side->ui->unitpics[4][u] = pic;
1468     }
1469     return side->ui->unitpics[4][u];
1470 }
1471 
1472 /* cache and return a side picture (flag) */
1473 /* should use mask somehow */
1474 
1475 Pixmap
get_side_picture(Side * side,Side * side1)1476 get_side_picture(Side *side, Side *side1)
1477 {
1478     int s = side_number(side1);
1479     Pixmap pic;
1480     Image *img;
1481     Display *dpy = side->ui->dpy;
1482 
1483     if (side->ui->emblempics[s] == None) {
1484 	img = best_image(side->ui->eimages[s],
1485 			 min_w_for_unit_image, min_h_for_unit_image);
1486 	if (img == NULL)
1487 	  return None;
1488 	pic = XCreatePixmap(dpy, side->ui->rootwin, img->w, img->h,
1489 			    DefaultDepth(dpy, side->ui->screen));
1490 	XSetForeground(dpy, side->ui->gc, side->ui->bgcolor);
1491 	XFillRectangle(dpy, pic, side->ui->gc,
1492 		       0, 0, img->w, img->h);
1493 	XSetForeground(dpy, side->ui->gc, side->ui->fgcolor);
1494 	draw_side_emblem(side, pic, 0, 0, img->w, img->h, s, 0);
1495 	side->ui->emblempics[s] = pic;
1496     }
1497     return side->ui->emblempics[s];
1498 }
1499 
1500 /* standing order support */
1501 
1502 #define ORDER_COND_NUM 4
1503 static char* order_cond[ORDER_COND_NUM] =
1504     { " none ", "  at  ", "  in  ", "within" };
1505 
1506 static XtActionsRec xorders_actions[] = {
1507   { "DoneOrdersHelp", handle_done_orders_help },
1508   { "DoneStringSelect", handle_done_string_select },
1509 };
1510 
1511 static char sorderfile[] = "standing.orders";
1512 
1513 static String helpText =
1514 "Only one order at a time can be active (i.e. it can be edited);\n\
1515 it is marked by an highlighted border.\n\
1516 Clicking on the leftmost button of an order will toggle its activity.\n\
1517 Deactivating an order will apply all changes.\n\
1518 \n\
1519 Clicking on an element of an active order will edit it.\n\
1520 Clicking on an element of an inactive order will visualize it:\n\
1521 if it is a cell address, the cell will be made current.\n\
1522 \n\
1523 The \"add\" button will add a new order.\n\
1524 The \"clone\" button will clone the active order.\n\
1525 The \"delete\" button will delete the active order.\n\
1526 The \"undo\" button will cancel all the changes to the active order.\n\
1527 The \"save\" button will save all the orders into a file.\n\
1528 The \"restore\" button will delete all orders, then restore\n\
1529     saved orders from a file.\n\
1530 The \"close\" button will popdown the orders window.";
1531 
1532 void
create_orders_window(Side * side,Map * map)1533 create_orders_window(Side *side, Map *map)
1534 {
1535     Widget form, up, left, port;
1536     StandingOrder *sorder;
1537     OrderInterface *ordi, **ordilist;
1538     int num, i;
1539 
1540     if (side->ui->sorder_edit == NULL)
1541       side->ui->sorder_edit = (StandingOrder *) xmalloc(sizeof(StandingOrder));
1542     if (side->ui->sorder_types_edit == NULL)
1543       side->ui->sorder_types_edit = (char *) xmalloc(numutypes*sizeof(char));
1544     if (side->ui->sorder_task_edit == NULL)
1545       side->ui->sorder_task_edit = (Task *) xmalloc(sizeof(Task));
1546 
1547     if (side->ui->orderlist == NULL) {
1548 	/* build the order list */
1549 	ordi = side->ui->orderlist;
1550 	for (sorder = side->orders; sorder != NULL; sorder = sorder->next) {
1551 	    if (side->ui->orderlist) {
1552 		ordi->next =
1553 		    (OrderInterface *) xmalloc(sizeof(OrderInterface));
1554 		ordi = ordi->next;
1555 	    } else {
1556 		side->ui->orderlist =
1557 		    (OrderInterface *) xmalloc(sizeof(OrderInterface));
1558 		ordi = side->ui->orderlist;
1559 	    }
1560 	    ordi->sorder = sorder;
1561 	}
1562     }
1563     orders_check(side);
1564 
1565     num = count_sorder(side);
1566 
1567     if (side->ui->orders_shell == NULL) {
1568         XtAppAddActions(thisapp, xorders_actions, XtNumber(xorders_actions));
1569 
1570 	/* initialize the window */
1571 	side->ui->orders_shell =
1572 	  XtVaCreatePopupShell("orders", topLevelShellWidgetClass,
1573 			       side->ui->shell,
1574 			       NULL);
1575 	form =
1576 	  XtVaCreateManagedWidget("form", formWidgetClass,
1577 				  side->ui->orders_shell,
1578 				  NULL);
1579 	side->ui->orders_label =
1580 	  XtVaCreateManagedWidget("label", labelWidgetClass, form,
1581 				  /* reserve space for label */
1582 				  XtNlabel,  "9999 standing orders",
1583 				  XtNtop,    XawChainTop,
1584 				  XtNbottom, XawChainTop,
1585 				  XtNleft,   XawChainLeft,
1586 				  XtNright,  XawChainLeft,
1587 				  NULL);
1588 	port =
1589 	  XtVaCreateManagedWidget("port", viewportWidgetClass, form,
1590 				  XtNfromVert, side->ui->orders_label,
1591 				  XtNallowVert, True,
1592 				  XtNtop,    XawChainTop,
1593 				  XtNbottom, XawChainBottom,
1594 				  XtNleft,   XawChainLeft,
1595 				  XtNright,  XawChainRight,
1596 				  NULL);
1597 	side->ui->orders_form =
1598 	  XtVaCreateManagedWidget("orders", formWidgetClass,
1599 				  port,
1600 				  NULL);
1601 
1602 	/* reverse list order */
1603 	if (num > 0) {
1604 	    ordilist = (OrderInterface **) xmalloc(num*sizeof(OrderInterface));
1605 	    for (ordi = side->ui->orderlist,  i = 0;
1606 		 ordi != NULL;
1607 		 ordi = ordi->next,  i++) {
1608 		ordilist[num-1-i] = ordi;
1609 	    }
1610 	    up = NULL;
1611 	    for (i = 0; i<num; i++) {
1612 		up = new_order_widgets(side, ordilist[i], i, up);
1613 	    }
1614 	    free(ordilist);
1615 	}
1616 
1617 	left =
1618 	  XtVaCreateManagedWidget("help", commandWidgetClass, form,
1619 				  XtNfromVert,  port,
1620 				  XtNtop,    XawChainBottom,
1621 				  XtNbottom, XawChainBottom,
1622 				  XtNleft,   XawChainLeft,
1623 				  XtNright,  XawChainLeft,
1624 				  NULL);
1625 	XtAddCallback(left, XtNcallback, orders_help_call, NULL);
1626 	left =
1627 	  XtVaCreateManagedWidget("add", commandWidgetClass, form,
1628 				  XtNfromVert,  port,
1629 				  XtNfromHoriz, left,
1630 				  XtNtop,    XawChainBottom,
1631 				  XtNbottom, XawChainBottom,
1632 				  XtNleft,   XawChainLeft,
1633 				  XtNright,  XawChainLeft,
1634 				  NULL);
1635 	XtAddCallback(left, XtNcallback, orders_add_call, NULL);
1636 	left =
1637 	  XtVaCreateManagedWidget("clone", commandWidgetClass, form,
1638 				  XtNfromVert,  port,
1639 				  XtNfromHoriz, left,
1640 				  XtNtop,    XawChainBottom,
1641 				  XtNbottom, XawChainBottom,
1642 				  XtNleft,   XawChainLeft,
1643 				  XtNright,  XawChainLeft,
1644 				  NULL);
1645 	XtAddCallback(left, XtNcallback, orders_clone_call, NULL);
1646 	left =
1647 	  XtVaCreateManagedWidget("delete", commandWidgetClass, form,
1648 				  XtNfromVert,  port,
1649 				  XtNfromHoriz, left,
1650 				  XtNtop,    XawChainBottom,
1651 				  XtNbottom, XawChainBottom,
1652 				  XtNleft,   XawChainLeft,
1653 				  XtNright,  XawChainLeft,
1654 				  NULL);
1655 	XtAddCallback(left, XtNcallback, orders_delete_call, NULL);
1656 	left =
1657 	  XtVaCreateManagedWidget("undo", commandWidgetClass, form,
1658 				  XtNfromVert,  port,
1659 				  XtNfromHoriz, left,
1660 				  XtNtop,    XawChainBottom,
1661 				  XtNbottom, XawChainBottom,
1662 				  XtNleft,   XawChainLeft,
1663 				  XtNright,  XawChainLeft,
1664 				  NULL);
1665 	XtAddCallback(left, XtNcallback, orders_undo_call, NULL);
1666 	left =
1667 	  XtVaCreateManagedWidget("save", commandWidgetClass, form,
1668 				  XtNfromVert,  port,
1669 				  XtNfromHoriz, left,
1670 				  XtNtop,    XawChainBottom,
1671 				  XtNbottom, XawChainBottom,
1672 				  XtNleft,   XawChainLeft,
1673 				  XtNright,  XawChainLeft,
1674 				  NULL);
1675 	XtAddCallback(left, XtNcallback, orders_save_call, NULL);
1676 	left =
1677 	  XtVaCreateManagedWidget("restore", commandWidgetClass, form,
1678 				  XtNfromVert,  port,
1679 				  XtNfromHoriz, left,
1680 				  XtNtop,    XawChainBottom,
1681 				  XtNbottom, XawChainBottom,
1682 				  XtNleft,   XawChainLeft,
1683 				  XtNright,  XawChainLeft,
1684 				  NULL);
1685 	XtAddCallback(left, XtNcallback, orders_restore_call, NULL);
1686 	left =
1687 	  XtVaCreateManagedWidget("close", commandWidgetClass, form,
1688 				  XtNfromVert,  port,
1689 				  XtNfromHoriz, left,
1690 				  XtNtop,    XawChainBottom,
1691 				  XtNbottom, XawChainBottom,
1692 				  XtNleft,   XawChainLeft,
1693 				  XtNright,  XawChainLeft,
1694 				  NULL);
1695 	XtAddCallback(left, XtNcallback, orders_close_call, NULL);
1696     }
1697 
1698     sprintf(buffer, "%d standing order%s", num, (num == 1) ? "" : "s");
1699     XtVaSetValues(side->ui->orders_label, XtNlabel, buffer, NULL);
1700 
1701     XtPopup(side->ui->orders_shell, XtGrabNone);
1702     raise_widget(side->ui->orders_shell);
1703 
1704     /* this is best done after the widgets has been realized
1705        and their widths have been fixed */
1706     for (ordi = side->ui->orderlist;  ordi != NULL;  ordi = ordi->next)
1707       update_order_widgets(side, ordi, ordi->sorder, ordi->sorder->types,
1708 			   ordi->sorder->task);
1709 
1710 }
1711 
1712 Widget
new_order_widgets(Side * side,OrderInterface * ordi,int num,Widget up)1713 new_order_widgets(Side *side, OrderInterface *ordi, int num, Widget up)
1714 {
1715     Widget left;
1716     XrmDatabase xrdb;
1717     char *stype;
1718     XrmValue val;
1719     XColor color, junk;
1720     Colormap cmap;
1721     int res_found = 0;
1722 
1723     sprintf(spbuf, "order_%d", num);
1724     ordi->form =
1725       XtVaCreateManagedWidget(spbuf, formWidgetClass,
1726 			      side->ui->orders_form,
1727 			      XtNfromVert, up,
1728 			      XtNtop,    XawChainTop,
1729 			      XtNbottom, XawChainTop,
1730 			      XtNleft,   XawChainLeft,
1731 			      XtNright,  XawChainLeft,
1732 			      NULL);
1733     XtVaGetValues(ordi->form, XtNbackground, &(ordi->form_bg), NULL);
1734 
1735     /* get foreground pixel */
1736     xrdb = XtDatabase(side->ui->dpy);
1737     if (XrmGetResource(xrdb, "xconq*orders*orders.Form.foreground",
1738 		       "Xconq*orders*orders.Form.Foreground",
1739 		       &stype, &val)) {
1740 	if (!strcmp(stype, "String")) {
1741 	    cmap = XDefaultColormap(side->ui->dpy, side->ui->screen);
1742 	    if (XAllocNamedColor(side->ui->dpy, cmap, val.addr,
1743 				 &color, &junk)) {
1744 		ordi->form_fg = color.pixel;
1745 		res_found = 1;
1746 	    }
1747 	}
1748     }
1749     if (!res_found) {
1750 	/* fallback = border pixel */
1751 	XtVaGetValues(ordi->form, XtNborderColor, &(ordi->form_fg), NULL);
1752     }
1753 
1754     left = ordi->toggle =
1755       XtVaCreateManagedWidget("toggle", toggleWidgetClass, ordi->form,
1756 			      XtNlabel,  "",
1757 			      XtNstate,  False,
1758 			      XtNleft,   XawChainLeft,
1759 			      XtNright,  XawChainLeft,
1760 			      NULL);
1761     XtAddCallback(left, XtNcallback, order_toggle_call, NULL);
1762     if (num == 0)
1763       side->ui->orders_radio = left;
1764     XawToggleChangeRadioGroup(left, side->ui->orders_radio);
1765 
1766     left = ordi->types =
1767       XtVaCreateManagedWidget("types", commandWidgetClass, ordi->form,
1768 			      XtNbitmap, get_unit_picture(0, side),
1769 			      XtNfromHoriz, left,
1770 			      XtNleft,   XawChainLeft,
1771 			      XtNright,  XawChainLeft,
1772 			      NULL);
1773     XtAddCallback(left, XtNcallback, order_types_call, NULL);
1774 
1775     left = ordi->etype =
1776       XtVaCreateManagedWidget("etype", commandWidgetClass, ordi->form,
1777 			      XtNlabel, "unknown",
1778 			      XtNfromHoriz, left,
1779 			      XtNleft,   XawChainLeft,
1780 			      XtNright,  XawChainLeft,
1781 			      NULL);
1782     XtAddCallback(left, XtNcallback, order_etype_call, NULL);
1783 
1784     left = ordi->eparms =
1785       XtVaCreateManagedWidget("eparms", commandWidgetClass, ordi->form,
1786 			      XtNlabel, "               ",
1787 			      XtNfromHoriz, left,
1788 			      XtNleft,   XawChainLeft,
1789 			      XtNright,  XawChainLeft,
1790 			      NULL);
1791     XtAddCallback(left, XtNcallback, order_eparms_call, NULL);
1792 
1793     left = ordi->task =
1794       XtVaCreateManagedWidget("task", commandWidgetClass, ordi->form,
1795 			      XtNlabel, "            ",
1796 			      XtNfromHoriz, left,
1797 			      XtNleft,   XawChainLeft,
1798 			      XtNright,  XawChainLeft,
1799 			      NULL);
1800     XtAddCallback(left, XtNcallback, order_task_call, NULL);
1801 
1802     left = ordi->tparms =
1803       XtVaCreateManagedWidget("tparms", commandWidgetClass, ordi->form,
1804 			      XtNlabel, "            ",
1805 			      XtNfromHoriz, left,
1806 			      XtNleft,   XawChainLeft,
1807 			      XtNright,  XawChainLeft,
1808 			      NULL);
1809     XtAddCallback(left, XtNcallback, order_tparms_call, NULL);
1810 #if 0
1811     if (ordi->sorder->condtype == 1) {
1812 	left =
1813 	  XtVaCreateManagedWidget("etype", labelWidgetClass, ordi->form,
1814 				  XtNlabel, "at",
1815 				  XtNfromHoriz, left,
1816 				  XtNleft,   XawChainLeft,
1817 				  XtNright,  XawChainLeft,
1818 				  NULL);
1819 
1820 	sprintf(buffer, "%3d,%3d", ordi->sorder->a1, ordi->sorder->a2);
1821 	left = ordi->eparms =
1822 	  XtVaCreateManagedWidget("eparms", commandWidgetClass, ordi->form,
1823 				  XtNlabel, buffer,
1824 				  XtNfromHoriz, left,
1825 				  XtNleft,   XawChainLeft,
1826 				  XtNright,  XawChainLeft,
1827 				  NULL);
1828 	XtAddCallback(left, XtNcallback, order_eparms_call, NULL);
1829     } else {
1830 	left =
1831 	  XtVaCreateManagedWidget("etype", labelWidgetClass, ordi->form,
1832 				  XtNlabel, "unknown",
1833 				  XtNfromHoriz, left,
1834 				  NULL);
1835     }
1836 
1837     if (ordi->sorder->task && ordi->sorder->task->type == TASK_MOVE_TO) {
1838 	left = ordi->task =
1839 	  XtVaCreateManagedWidget("task", labelWidgetClass, ordi->form,
1840 				  XtNlabel, "move-to",
1841 				  XtNfromHoriz, left,
1842 				  XtNleft,   XawChainLeft,
1843 				  XtNright,  XawChainLeft,
1844 				  NULL);
1845 
1846 	sprintf(buffer, "%3d,%3d",
1847 		ordi->sorder->task->args[0], ordi->sorder->task->args[1]);
1848 	left = ordi->tparms =
1849 	  XtVaCreateManagedWidget("tparms", commandWidgetClass, ordi->form,
1850 				  XtNlabel, buffer,
1851 				  XtNfromHoriz, left,
1852 				  XtNleft,   XawChainLeft,
1853 				  XtNright,  XawChainLeft,
1854 				  NULL);
1855 	XtAddCallback(left, XtNcallback, order_tparms_call, NULL);
1856     } else {
1857 	left = ordi->task =
1858 	  XtVaCreateManagedWidget("task", labelWidgetClass, ordi->form,
1859 				  XtNlabel, "unknown",
1860 				  XtNfromHoriz, left,
1861 				  XtNleft,   XawChainLeft,
1862 				  XtNright,  XawChainLeft,
1863 				  NULL);
1864 	left = ordi->tparms =
1865 	  XtVaCreateManagedWidget("tparms", commandWidgetClass, ordi->form,
1866 				  XtNlabel, "     ",
1867 				  XtNfromHoriz, left,
1868 				  XtNleft,   XawChainLeft,
1869 				  XtNright,  XawChainLeft,
1870 				  NULL);
1871 	XtAddCallback(left, XtNcallback, order_tparms_call, NULL);
1872     }
1873 #endif
1874 
1875     return ordi->form;
1876 }
1877 
1878 void
sorder_cond_name(char * buf,StandingOrder * sorder,Side * side)1879 sorder_cond_name(char *buf, StandingOrder *sorder, Side *side)
1880 {
1881     switch (sorder->condtype) {
1882     case 0:
1883 	strcpy(buf, "            ");
1884 	return;
1885     case 1:
1886 	sprintf(buf, "%3d,%3d      ", sorder->a1, sorder->a2);
1887 	return;
1888     /* let unit_handle and find_unit handle exceptions */
1889     case 2:
1890 	strcpy(buf, short_unit_handle(find_unit(sorder->a1)));
1891 	if (strlen(buf) < 12)
1892 	  strncat(buf, "            ", 12 - strlen(buf));
1893 	return;
1894     case 3:
1895 	sprintf(buf, "%2d of %3d,%3d", sorder->a3, sorder->a1, sorder->a2);
1896     }
1897 }
1898 
1899 void
update_order_widgets(Side * side,OrderInterface * ordi,StandingOrder * sorder,char * types,Task * task)1900 update_order_widgets(Side *side, OrderInterface *ordi, StandingOrder *sorder, char *types, Task *task)
1901 {
1902     int u;
1903     char *lab;
1904     Pixmap icon = None;
1905 
1906     for_all_unit_types(u) {
1907 	if (types[u]) {
1908 	    icon = get_unit_picture(u, side);
1909 	}
1910     }
1911     XtVaSetValues(ordi->types, XtNbitmap, icon, NULL);
1912 
1913     if (sorder->condtype >= 0 && sorder->condtype < ORDER_COND_NUM) {
1914 	lab = order_cond[(int) sorder->condtype];
1915     } else {
1916 	lab = "unknown";
1917     }
1918     XtVaSetValues(ordi->etype, XtNlabel, lab, NULL);
1919 
1920     sorder_cond_name(buffer, sorder, side);
1921     XtVaSetValues(ordi->eparms, XtNlabel, buffer, NULL);
1922 
1923     if (task) {
1924 	XtVaSetValues(ordi->task, XtNlabel, taskdefns[task->type].name, NULL);
1925 
1926 	/* get task description, chop task name and separator */
1927 	task_desc(buffer, side, NULL, task);
1928 	lab = buffer + strlen(taskdefns[task->type].name);
1929 	while (*lab == ' ' || *lab == ',')
1930 	    lab++;
1931 	XtVaSetValues(ordi->tparms, XtNlabel, lab, NULL);
1932     } else {
1933 	XtVaSetValues(ordi->task,   XtNlabel, "none        ", NULL);
1934 	XtVaSetValues(ordi->tparms, XtNlabel, "            ", NULL);
1935     }
1936 }
1937 
1938 /* callbacks for orders */
1939 
1940 static void
orders_help_call(Widget w,XtPointer client_data,XtPointer call_data)1941 orders_help_call(Widget w, XtPointer client_data, XtPointer call_data)
1942 {
1943     Side *side;
1944     Widget form, done, text;
1945 
1946     if (!find_side_via_widget(w, &side))
1947       return;
1948 
1949     if (!side->ui->orders_help_shell) {
1950 	side->ui->orders_help_shell =
1951 	  XtVaCreatePopupShell("ordersHelp", topLevelShellWidgetClass,
1952 			       side->ui->shell,
1953 			       NULL);
1954 	form =
1955 	  XtVaCreateManagedWidget("form", formWidgetClass,
1956 				  side->ui->orders_help_shell,
1957 				  NULL);
1958 	text =
1959 	  XtVaCreateManagedWidget("text", labelWidgetClass, form,
1960 				  XtNlabel, helpText,
1961 				  NULL);
1962 	done =
1963 	  XtVaCreateManagedWidget("done", commandWidgetClass, form,
1964 				  XtNfromVert, text,
1965 				  NULL);
1966 	XtAddCallback(done, XtNcallback, orders_done_help_call, NULL);
1967     }
1968 
1969     XtPopup(side->ui->orders_help_shell, XtGrabNone);
1970 }
1971 
1972 static void
orders_done_help_call(Widget w,XtPointer client_data,XtPointer call_data)1973 orders_done_help_call(Widget w, XtPointer client_data, XtPointer call_data)
1974 {
1975     Side *side;
1976 
1977     if (!find_side_via_widget(w, &side))
1978       return;
1979 
1980     if (side->ui->orders_help_shell)
1981       XtPopdown(side->ui->orders_help_shell);
1982 }
1983 
1984 static void
handle_done_orders_help(Widget w,XEvent * event,String * params,Cardinal * numparms)1985 handle_done_orders_help(Widget w, XEvent *event, String *params, Cardinal *numparms)
1986 {
1987     Side *side;
1988 
1989     if (!find_side_via_widget(w, &side))
1990       return;
1991 
1992     if (side->ui->orders_help_shell)
1993       XtPopdown(side->ui->orders_help_shell);
1994 }
1995 
1996 static void
orders_add_call(Widget w,XtPointer client_data,XtPointer call_data)1997 orders_add_call(Widget w, XtPointer client_data, XtPointer call_data)
1998 {
1999   /* generate a "blank" order */
2000   sprintf(spbuf, "%s at 0,0 move-to 0,0", u_type_name(0));
2001   orders_add_named(w, spbuf);
2002 }
2003 
2004 static void
orders_clone_call(Widget w,XtPointer client_data,XtPointer call_data)2005 orders_clone_call(Widget w, XtPointer client_data, XtPointer call_data)
2006 {
2007   Side *side;
2008   OrderInterface *ordi;
2009   char *name;
2010 
2011   if (!find_side_via_widget(w, &side))
2012     return;
2013 
2014   ordi = active_ordi(side);
2015   if (ordi == NULL)
2016     return;
2017 
2018   name = standing_order_desc(side->ui->sorder_edit, spbuf);
2019   orders_add_named(w, name);
2020 }
2021 
2022 static void
orders_add_named(Widget w,char * string)2023 orders_add_named(Widget w, char *string)
2024 {
2025     OrderInterface *ordi;
2026     Side *side;
2027     Widget up;
2028     int num;
2029 
2030     if (!find_side_via_widget(w, &side))
2031       return;
2032 
2033     deactivate_orders(side);
2034 
2035     if (parse_standing_order(side, string) != 0) {
2036 	/* parsing failed and no standing order was created */
2037 	return;
2038     }
2039     /* the standing order is now in side->orders */
2040 
2041     ordi = (OrderInterface *) xmalloc(sizeof(OrderInterface));
2042     if (side->ui->orderlist) {
2043 	up = side->ui->orderlist->form;
2044 	ordi->next = side->ui->orderlist;
2045     } else {
2046 	up = NULL;
2047 	ordi->next = NULL;
2048     }
2049     side->ui->orderlist = ordi;
2050     ordi->sorder = side->orders;
2051 
2052     orders_check(side);
2053 
2054     num = count_sorder(side);
2055     new_order_widgets(side, ordi, num-1, up);
2056     sprintf(buffer, "%d standing order%s", num, (num==1) ? "" : "s");
2057     XtVaSetValues(side->ui->orders_label, XtNlabel, buffer, NULL);
2058     update_order_widgets(side, ordi, ordi->sorder, ordi->sorder->types,
2059 			 ordi->sorder->task);
2060 
2061     /* activate new order */
2062     XtVaSetValues(ordi->toggle, XtNstate, True, NULL);
2063     order_toggle_call(ordi->toggle, NULL, NULL);
2064 }
2065 
2066 static void
orders_delete_call(Widget w,XtPointer client_data,XtPointer call_data)2067 orders_delete_call(Widget w, XtPointer client_data, XtPointer call_data)
2068 {
2069     Side *side;
2070     OrderInterface *ordi, *activeo;
2071     StandingOrder *sorder;
2072 
2073     if (!find_side_via_widget(w, &side))
2074       return;
2075 
2076     activeo = active_ordi(side);
2077     if (activeo == NULL)
2078       return;
2079 
2080     /* remove sorder and ordi */
2081     if (side->ui->orderlist == activeo) {
2082 	side->ui->orderlist = side->ui->orderlist->next;
2083 	side->orders = side->orders->next;
2084 	if (side->orders == NULL) {
2085 	    side->last_order = NULL;
2086 	}
2087     } else {
2088 	for (sorder = side->orders,  ordi = side->ui->orderlist;
2089 	     sorder != NULL && sorder->next != NULL;
2090 	     sorder = sorder->next,  ordi = ordi->next) {
2091 	    if (ordi->next == activeo) {
2092 		ordi->next = ordi->next->next;
2093 		if (sorder->next == side->last_order) {
2094 		    side->last_order = sorder;
2095 		}
2096 		sorder->next = sorder->next->next;
2097 		break;
2098 	    }
2099 	}
2100     }
2101 
2102     orders_check(side);
2103 
2104     /* re-create orders window */
2105     XtPopdown(side->ui->orders_shell);
2106     XtDestroyWidget(side->ui->orders_shell);
2107     side->ui->orders_shell = NULL;
2108     create_orders_window(side, side->ui->maps);
2109 }
2110 
2111 static void
orders_undo_call(Widget w,XtPointer client_data,XtPointer call_data)2112 orders_undo_call(Widget w, XtPointer client_data, XtPointer call_data)
2113 {
2114     Side *side;
2115     OrderInterface *ordi;
2116 
2117     if (!find_side_via_widget(w, &side))
2118       return;
2119 
2120     ordi = active_ordi(side);
2121     if (ordi == NULL)
2122       return;
2123 
2124     /* copy standing order */
2125     *(side->ui->sorder_edit) = *(ordi->sorder);
2126     memcpy(side->ui->sorder_types_edit, ordi->sorder->types,
2127 	   numutypes*sizeof(char));
2128     *(side->ui->sorder_task_edit) = *(ordi->sorder->task);
2129     update_order_widgets(side, ordi, ordi->sorder, ordi->sorder->types,
2130 			 ordi->sorder->task);
2131 }
2132 
2133 static void
orders_save_call(Widget w,XtPointer client_data,XtPointer call_data)2134 orders_save_call(Widget w, XtPointer client_data, XtPointer call_data)
2135 {
2136     Side *side;
2137     FILE *file;
2138     StandingOrder *sorder;
2139 
2140     if (!find_side_via_widget(w, &side))
2141       return;
2142 
2143     deactivate_orders(side);
2144 
2145     if (!(file = fopen(sorderfile, "w"))) {
2146 	run_warning("Cannot open file \"%s\", standing orders not saved!\n");
2147 	return;
2148     }
2149 
2150     for (sorder = side->orders; sorder != NULL; sorder = sorder->next) {
2151 	fprintf(file, "%s\n", standing_order_desc(sorder, buffer));
2152     }
2153     fclose(file);
2154     notify(side, "Standing orders saved in file \"%s\".", sorderfile);
2155 }
2156 
2157 static void
orders_restore_call(Widget w,XtPointer client_data,XtPointer call_data)2158 orders_restore_call(Widget w, XtPointer client_data, XtPointer call_data)
2159 {
2160     Side *side;
2161     FILE *file;
2162 
2163     if (!find_side_via_widget(w, &side))
2164       return;
2165 
2166     if (!(file = fopen(sorderfile, "r"))) {
2167 	run_warning("Cannot open file \"%s\", standing orders not restored!\n",
2168 		    sorderfile);
2169 	return;
2170     }
2171 
2172     /* clear all stading orders; quick & dirty, without free'ing
2173        malloc'd stuff (hopefully a negligible amount) */
2174     side->orders = side->last_order = NULL;
2175 
2176     while (!feof(file)) {
2177 	fgets(buffer, 160, file);
2178 	if (!feof(file) && strlen(buffer)>3) {
2179 	    parse_standing_order(side, buffer);
2180 	}
2181     }
2182     fclose(file);
2183     notify(side, "Standing orders restored from file \"%s\".", sorderfile);
2184 
2185    /* re-create orders window and list */
2186     XtPopdown(side->ui->orders_shell);
2187     XtDestroyWidget(side->ui->orders_shell);
2188     side->ui->orderlist = NULL;
2189     side->ui->orders_shell = NULL;
2190     create_orders_window(side, side->ui->maps);
2191 }
2192 
2193 static void
orders_close_call(Widget w,XtPointer client_data,XtPointer call_data)2194 orders_close_call(Widget w, XtPointer client_data, XtPointer call_data)
2195 {
2196     Side *side;
2197 
2198     if (!find_side_via_widget(w, &side))
2199       return;
2200 
2201     XtPopdown(side->ui->orders_shell);
2202 
2203     if (side->ui->orders_help_shell)
2204       XtPopdown(side->ui->orders_help_shell);
2205 }
2206 
2207 
2208 static void
order_toggle_call(Widget w,XtPointer client_data,XtPointer call_data)2209 order_toggle_call(Widget w, XtPointer client_data, XtPointer call_data)
2210 {
2211     Side *side;
2212     Boolean state;
2213     OrderInterface *ordi;
2214 
2215     if (!find_side_and_ordi_via_widget(w, &side, &ordi))
2216       return;
2217 
2218     XtVaGetValues(ordi->toggle, XtNstate, &state, NULL);
2219     if (state) {
2220 	XtVaSetValues(ordi->form, XtNbackground, ordi->form_fg, NULL);
2221 
2222 	/* copy standing order */
2223 	side->ui->ordi_edit = ordi;
2224 	*(side->ui->sorder_edit) = *(ordi->sorder);
2225 	memcpy(side->ui->sorder_types_edit, ordi->sorder->types,
2226 	       numutypes*sizeof(char));
2227 	*(side->ui->sorder_task_edit) = *(ordi->sorder->task);
2228     } else {
2229 	XtVaSetValues(ordi->form, XtNbackground, ordi->form_bg, NULL);
2230 
2231 	/* update standing order */
2232 	*(ordi->sorder) = *(side->ui->sorder_edit);
2233 	memcpy(ordi->sorder->types, side->ui->sorder_types_edit,
2234 	       numutypes*sizeof(char));
2235 	*(ordi->sorder->task) = *(side->ui->sorder_task_edit);
2236 	update_order_widgets(side, ordi, ordi->sorder, ordi->sorder->types,
2237 			     ordi->sorder->task);
2238     }
2239 }
2240 
2241 static void
order_etype_call(Widget w,XtPointer client_data,XtPointer call_data)2242 order_etype_call(Widget w, XtPointer client_data, XtPointer call_data)
2243 {
2244     Side *side;
2245     OrderInterface *ordi;
2246     Boolean state;
2247     Map *map;
2248     Position x, y;
2249     int i;
2250 
2251     if (!find_side_and_ordi_via_widget(w, &side, &ordi))
2252       return;
2253     map = side->ui->maps;
2254 
2255     XtVaGetValues(ordi->toggle, XtNstate, &state, NULL);
2256 
2257     if (!state)
2258       return;
2259 
2260     XtVaGetValues(side->ui->orders_shell, XtNx, &x, XtNy, &y, NULL);
2261     i = cond_select_popup(side, x + 32, y + 32);
2262     if (i >= 0 && i < ORDER_COND_NUM && i != side->ui->sorder_edit->condtype) {
2263 	XtVaSetValues(ordi->etype, XtNlabel, order_cond[i], NULL);
2264 	side->ui->sorder_edit->condtype = (enum sordercond)i;
2265 	side->ui->sorder_edit->a1 = 0;
2266 	side->ui->sorder_edit->a2 = 0;
2267 	side->ui->sorder_edit->a3 = 0;
2268 	sorder_cond_name(buffer, side->ui->sorder_edit, side);
2269 	XtVaSetValues(ordi->eparms, XtNlabel, buffer, NULL);
2270     }
2271 }
2272 
2273 static void
order_eparms_call(Widget w,XtPointer client_data,XtPointer call_data)2274 order_eparms_call(Widget w, XtPointer client_data, XtPointer call_data)
2275 {
2276     Side *side;
2277     OrderInterface *ordi;
2278     Boolean state;
2279     Map *map;
2280     Position x, y;
2281     Unit *unit;
2282 
2283     if (!find_side_and_ordi_via_widget(w, &side, &ordi))
2284       return;
2285     map = side->ui->maps;
2286 
2287     XtVaGetValues(ordi->toggle, XtNstate, &state, NULL);
2288 
2289     if (state) {
2290 	/* edit */
2291 	switch (side->ui->sorder_edit->condtype) {
2292 	case 1:
2293 	    set_cell_from_map(side, map,
2294 			      "select origin cell, then press space",
2295 			      (void *) &side->ui->sorder_edit->a1,
2296 			      (void *) &side->ui->sorder_edit->a2,
2297 			      sizeof(side->ui->sorder_edit->a1));
2298 	    break;
2299 	case 2:
2300 	    set_unit_from_map (side, map,
2301 			       "select origin unit, then press space",
2302 			       (int *) &side->ui->sorder_edit->a1);
2303 	    break;
2304 	case 3:
2305 	    XtVaGetValues(side->ui->orders_shell, XtNx, &x, XtNy, &y, NULL);
2306 	    side->ui->sorder_edit->a3 =
2307 	      integer_select_popup(side, x+32, y+32, side->ui->sorder_edit->a3,
2308 				   "enter origin radius");
2309 	    if (side->ui->sorder_edit->a3<0)
2310 	      side->ui->sorder_edit->a3 = 0;
2311 	    set_cell_from_map(side, map,
2312 			      "select origin center, then press space",
2313 			      (void *) &side->ui->sorder_edit->a1,
2314 			      (void *) &side->ui->sorder_edit->a2,
2315 			      sizeof(side->ui->sorder_edit->a1));
2316 	    break;
2317 	  default:
2318 	    break;
2319 	}
2320     } else {
2321 	/* display */
2322 	if (ordi->sorder->condtype == 1 || ordi->sorder->condtype == 3) {
2323 	    if (in_area(ordi->sorder->a1, ordi->sorder->a2)) {
2324 		map->curx = ordi->sorder->a1;
2325 		map->cury = ordi->sorder->a2;
2326 		map->curunit = NULL;
2327 		recenter(side, map, ordi->sorder->a1, ordi->sorder->a2);
2328 		side->ui->curmap = map;
2329 		do_flash(side);
2330 	    } else {
2331 		beep(side);
2332 	    }
2333 	} else if (ordi->sorder->condtype == 2) {
2334 	    if ((unit = find_unit(ordi->sorder->a1)) != NULL) {
2335 	        set_current_unit(side, map, unit);
2336 		map->curx = unit->x;  map->cury = unit->y;
2337 		recenter(side, map, unit->x, unit->y);
2338 		side->ui->curmap = map;
2339 		do_flash(side);
2340 	    } else {
2341 		beep(side);
2342 	    }
2343 	}
2344     }
2345 }
2346 
2347 static void
order_task_call(Widget w,XtPointer client_data,XtPointer call_data)2348 order_task_call(Widget w, XtPointer client_data, XtPointer call_data)
2349 {
2350     Side *side;
2351     OrderInterface *ordi;
2352     Boolean state;
2353     Map *map;
2354     Position x, y;
2355     int i, type;
2356 
2357     if (!find_side_and_ordi_via_widget(w, &side, &ordi))
2358       return;
2359     map = side->ui->maps;
2360 
2361     XtVaGetValues(ordi->toggle, XtNstate, &state, NULL);
2362 
2363     if (!state)
2364       return;
2365 
2366     XtVaGetValues(side->ui->orders_shell, XtNx, &x, XtNy, &y, NULL);
2367     type = task_select_popup(side, x+32, y+32);
2368     if (!is_task_type(type) || type==side->ui->sorder_task_edit->type)
2369       return;
2370 
2371     side->ui->sorder_task_edit->type = (TaskType)type;
2372     for (i=0; i<MAXTASKARGS; i++)
2373       side->ui->sorder_task_edit->args[i] = 0;
2374     side->ui->sorder_task_edit->execnum = 0;
2375     side->ui->sorder_task_edit->retrynum = 0;
2376 
2377     update_order_widgets(side, side->ui->ordi_edit, side->ui->sorder_edit,
2378 			 side->ui->sorder_types_edit,
2379 			 side->ui->sorder_task_edit);
2380 
2381 }
2382 
2383 static void
order_types_call(Widget w,XtPointer client_data,XtPointer call_data)2384 order_types_call(Widget w, XtPointer client_data, XtPointer call_data)
2385 {
2386     Side *side;
2387     OrderInterface *ordi;
2388     Boolean state;
2389     Pixmap icon;
2390     int i, oldu = 0, newu;
2391     Position x, y;
2392 
2393     if (!find_side_and_ordi_via_widget(w, &side, &ordi))
2394       return;
2395 
2396     XtVaGetValues(ordi->toggle, XtNstate, &state, NULL);
2397     if (!state)
2398       return;
2399 
2400     for_all_unit_types(i) {
2401 	if (side->ui->sorder_types_edit[i]) {
2402 	    oldu = i;
2403 	    break;
2404 	}
2405     }
2406 
2407     XtVaGetValues(side->ui->orders_shell, XtNx, &x, XtNy, &y, NULL);
2408     newu = utype_select_popup(side, x+32, y+32);
2409     if (newu != NONUTYPE) {
2410 	icon = get_unit_picture(newu, side);
2411 	XtVaSetValues(ordi->types, XtNbitmap, icon, NULL);
2412 	side->ui->sorder_types_edit[oldu] = 0;
2413 	side->ui->sorder_types_edit[newu] = 1;
2414     }
2415 }
2416 
2417 static int select_loop, select_cond, select_task, select_utype, select_dir;
2418 
2419 int
cond_select_popup(Side * side,Position x,Position y)2420 cond_select_popup(Side *side, Position x, Position y)
2421 {
2422     Widget box, shell, command;
2423     int i;
2424 
2425     select_cond = ORDER_COND_NUM;
2426 
2427     shell =
2428       XtVaCreatePopupShell("condSelect", transientShellWidgetClass,
2429 			   side->ui->shell,
2430 			   XtNx, x,
2431 			   XtNy, y,
2432 			   NULL);
2433     box = XtVaCreateManagedWidget("box", boxWidgetClass, shell,
2434 			   NULL);
2435 
2436     for (i=0; i<ORDER_COND_NUM; i++) {
2437 	command =
2438 	  XtVaCreateManagedWidget(order_cond[i], commandWidgetClass, box,
2439 				  NULL);
2440 	XtAddCallback(command, XtNcallback, cond_select_call,
2441 		      (XtPointer) i);
2442     }
2443     command =
2444       XtVaCreateManagedWidget("cancel", commandWidgetClass, box,
2445 			      NULL);
2446     XtAddCallback(command, XtNcallback, cond_select_call,
2447 		  (XtPointer) ORDER_COND_NUM);
2448 
2449     XtPopup(shell, XtGrabExclusive);
2450 
2451     XWarpPointer(side->ui->dpy, None, XtWindow(box), 0, 0, 0, 0, 32, 32);
2452 
2453     /* replacement for XtAppMainLoop(thisapp): */
2454     select_loop = 1;
2455     while (select_loop) {
2456 	XEvent event;
2457 
2458 	XtAppNextEvent(thisapp, &event);
2459 	XtDispatchEvent(&event);
2460     }
2461     XtPopdown(shell);
2462     XtDestroyWidget(shell);
2463 
2464     return select_cond;
2465 }
2466 
2467 static void
cond_select_call(Widget w,XtPointer client_data,XtPointer call_data)2468 cond_select_call(Widget w, XtPointer client_data, XtPointer call_data)
2469 {
2470     int i;
2471 
2472     for (i=0; i<ORDER_COND_NUM; i++) {
2473 	if (client_data == (XtPointer) i) {
2474 	    select_cond = i;
2475 	    select_loop = 0;
2476 	    return;
2477 	}
2478     }
2479     select_cond = ORDER_COND_NUM;
2480     select_loop = 0;
2481     return;
2482 }
2483 
2484 int
task_select_popup(Side * side,Position x,Position y)2485 task_select_popup(Side *side, Position x, Position y)
2486 {
2487     Widget box, shell, command;
2488     int i;
2489 
2490     select_task = -1;
2491 
2492     shell =
2493       XtVaCreatePopupShell("taskSelect", transientShellWidgetClass,
2494 			   side->ui->shell,
2495 			   XtNx, x,
2496 			   XtNy, y,
2497 			   NULL);
2498     box = XtVaCreateManagedWidget("box", boxWidgetClass, shell,
2499 			   NULL);
2500 
2501     for (i = 0; taskdefns[i].name != NULL; i++) {
2502         command =
2503 	  XtVaCreateManagedWidget(taskdefns[i].name, commandWidgetClass,
2504 				  box, NULL);
2505 	XtAddCallback(command, XtNcallback, task_select_call,
2506 		      (XtPointer) i);
2507     }
2508     command =
2509       XtVaCreateManagedWidget("cancel", commandWidgetClass, box,
2510 			      NULL);
2511     XtAddCallback(command, XtNcallback, task_select_call,
2512 		  (XtPointer) -1);
2513 
2514     XtPopup(shell, XtGrabExclusive);
2515 
2516     XWarpPointer(side->ui->dpy, None, XtWindow(box), 0, 0, 0, 0, 32, 32);
2517 
2518     /* replacement for XtAppMainLoop(thisapp): */
2519     select_loop = 1;
2520     while (select_loop) {
2521 	XEvent event;
2522 
2523 	XtAppNextEvent(thisapp, &event);
2524 	XtDispatchEvent(&event);
2525     }
2526     XtPopdown(shell);
2527     XtDestroyWidget(shell);
2528 
2529     return select_task;
2530 }
2531 
2532 static void
task_select_call(Widget w,XtPointer client_data,XtPointer call_data)2533 task_select_call(Widget w, XtPointer client_data, XtPointer call_data)
2534 {
2535     int i;
2536 
2537     for (i = 0; taskdefns[i].name != NULL; i++) {
2538 	if (client_data == (XtPointer) i) {
2539 	    select_task = i;
2540 	    select_loop = 0;
2541 	    return;
2542 	}
2543     }
2544     select_task = -1;
2545     select_loop = 0;
2546     return;
2547 }
2548 
2549 int
utype_select_popup(Side * side,Position x,Position y)2550 utype_select_popup(Side *side, Position x, Position y)
2551 {
2552     Widget box, shell, command;
2553     Pixmap icon;
2554     int u;
2555 
2556     select_utype = NONUTYPE;
2557 
2558     shell =
2559       XtVaCreatePopupShell("utypeSelect", transientShellWidgetClass,
2560 			   side->ui->shell,
2561 			   XtNx, x,
2562 			   XtNy, y,
2563 			   NULL);
2564     box = XtVaCreateManagedWidget("box", boxWidgetClass, shell,
2565 			   NULL);
2566 
2567     for_all_unit_types(u) {
2568 	icon = get_unit_picture(u, side);
2569 	build_name(buffer, "", u_type_name(u));
2570 	command =
2571 	   XtVaCreateManagedWidget(buffer, commandWidgetClass, box,
2572 				   XtNlabel, "",
2573 				   XtNbitmap, icon,
2574 				   NULL);
2575 	XtAddCallback(command, XtNcallback, utype_select_call,
2576 		      (XtPointer) u);
2577     }
2578     command =
2579       XtVaCreateManagedWidget("cancel", commandWidgetClass, box,
2580 			      NULL);
2581     XtAddCallback(command, XtNcallback, utype_select_call,
2582 		  (XtPointer) NONUTYPE);
2583 
2584     XtPopup(shell, XtGrabExclusive);
2585 
2586     XWarpPointer(side->ui->dpy, None, XtWindow(box), 0, 0, 0, 0, 32, 32);
2587 
2588     /* replacement for XtAppMainLoop(thisapp): */
2589     select_loop = 1;
2590     while (select_loop) {
2591 	XEvent event;
2592 
2593 	XtAppNextEvent(thisapp, &event);
2594 	XtDispatchEvent(&event);
2595     }
2596     XtPopdown(shell);
2597     XtDestroyWidget(shell);
2598 
2599     return select_utype;
2600 }
2601 
2602 static void
utype_select_call(Widget w,XtPointer client_data,XtPointer call_data)2603 utype_select_call(Widget w, XtPointer client_data, XtPointer call_data)
2604 {
2605     int u;
2606 
2607     for_all_unit_types(u) {
2608 	if (client_data == (XtPointer) u) {
2609 	    select_utype = u;
2610 	    select_loop = 0;
2611 	    return;
2612 	}
2613     }
2614     select_utype = NONUTYPE;
2615     select_loop = 0;
2616     return;
2617 }
2618 
2619 int
dir_select_popup(Side * side,Position x,Position y)2620 dir_select_popup(Side *side, Position x, Position y)
2621 {
2622     Widget box, shell, command;
2623     int dir;
2624 
2625     select_dir = -1;
2626 
2627     shell =
2628       XtVaCreatePopupShell("dirSelect", transientShellWidgetClass,
2629 			   side->ui->shell,
2630 			   XtNx, x,
2631 			   XtNy, y,
2632 			   NULL);
2633     box = XtVaCreateManagedWidget("box", boxWidgetClass, shell,
2634 			   NULL);
2635 
2636     for_all_directions(dir) {
2637 	command =
2638 	   XtVaCreateManagedWidget(dirnames[dir], commandWidgetClass, box,
2639 				   NULL);
2640 	XtAddCallback(command, XtNcallback, dir_select_call,
2641 		      (XtPointer) dir);
2642     }
2643 
2644     XtPopup(shell, XtGrabExclusive);
2645 
2646     XWarpPointer(side->ui->dpy, None, XtWindow(box), 0, 0, 0, 0, 32, 32);
2647 
2648     /* replacement for XtAppMainLoop(thisapp): */
2649     select_loop = 1;
2650     while (select_loop) {
2651 	XEvent event;
2652 
2653 	XtAppNextEvent(thisapp, &event);
2654 	XtDispatchEvent(&event);
2655     }
2656     XtPopdown(shell);
2657     XtDestroyWidget(shell);
2658 
2659     return select_dir;
2660 }
2661 
2662 static void
dir_select_call(Widget w,XtPointer client_data,XtPointer call_data)2663 dir_select_call(Widget w, XtPointer client_data, XtPointer call_data)
2664 {
2665     int dir;
2666 
2667     for_all_directions(dir) {
2668 	if (client_data == (XtPointer) dir) {
2669 	    select_dir = dir;
2670 	    select_loop = 0;
2671 	    return;
2672 	}
2673     }
2674     select_dir = -1;
2675     select_loop = 0;
2676     return;
2677 }
2678 
2679 int
integer_select_popup(Side * side,Position x,Position y,int value,char * prompt)2680 integer_select_popup(Side *side, Position x, Position y, int value, char *prompt)
2681 {
2682     int result;
2683 
2684     sprintf(tmpbuf, "%d", value);
2685     string_select_popup(side, x, y, buffer, tmpbuf, prompt);
2686     if (sscanf(buffer, "%d", &result) != 1)
2687       result = 0;
2688 
2689     return result;
2690 }
2691 
2692 void
string_select_popup(Side * side,Position x,Position y,char * result,char * value,char * prompt)2693 string_select_popup(Side *side, Position x, Position y, char *result, char *value, char *prompt)
2694 {
2695     Widget shell, dialog;
2696     char *string;
2697 
2698     select_task = -1;
2699 
2700     shell =
2701       XtVaCreatePopupShell("stringSelect", transientShellWidgetClass,
2702 			   side->ui->shell,
2703 			   XtNx, x,
2704 			   XtNy, y,
2705 			   NULL);
2706 
2707     dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, shell,
2708 					  XtNlabel, prompt,
2709 					  XtNvalue, value,
2710 					  NULL);
2711 
2712     XtPopup(shell, XtGrabExclusive);
2713     XWarpPointer(side->ui->dpy, None, XtWindow(dialog), 0, 0, 0, 0, 32, 32);
2714 
2715     /* replacement for XtAppMainLoop(thisapp): */
2716     select_loop = 1;
2717     while (select_loop) {
2718 	XEvent event;
2719 
2720 	XtAppNextEvent(thisapp, &event);
2721 	XtDispatchEvent(&event);
2722     }
2723 
2724     string = XawDialogGetValueString(dialog);
2725     /* safer to save the string, XtDestroyWidget may deallocate it */
2726     strcpy(result, string);
2727 
2728     XtPopdown(shell);
2729     XtDestroyWidget(shell);
2730 }
2731 
2732 static void
handle_done_string_select(Widget w,XEvent * event,String * params,Cardinal * numparms)2733 handle_done_string_select(Widget w, XEvent *event, String *params, Cardinal *numparms)
2734 {
2735     select_loop = 0;
2736 }
2737 
2738 
2739 static void
order_tparms_call(Widget w,XtPointer client_data,XtPointer call_data)2740 order_tparms_call(Widget w, XtPointer client_data, XtPointer call_data)
2741 {
2742     Side *side;
2743     OrderInterface *ordi;
2744     Boolean state;
2745     Map *map;
2746     char *lab;
2747     int utype, uid, i;
2748     Unit *unit;
2749     Position x, y;
2750     Task *task;
2751 
2752     if (!find_side_and_ordi_via_widget(w, &side, &ordi))
2753       return;
2754     map = side->ui->maps;
2755 
2756     XtVaGetValues(ordi->toggle, XtNstate, &state, NULL);
2757 
2758     XtVaGetValues(side->ui->orders_shell, XtNx, &x, XtNy, &y, NULL);
2759     x += 32;  y += 32;
2760 
2761     task = side->ui->sorder_task_edit;
2762 
2763     if (state) {
2764 	/* edit */
2765 
2766 	for (i = 0; i < MAXTASKARGS; ++i)
2767 	  side->ui->sorder_edit->task->args[i] = 0;
2768 
2769 	switch (task->type) {
2770 
2771 	case TASK_NONE:
2772 	case TASK_DISBAND:
2773 	    break;
2774 
2775 	case TASK_BUILD:
2776 	    utype = utype_select_popup(side, x, y);
2777 	    if (utype != NONUTYPE) {
2778 		task->args[0] = utype;
2779 		task->args[3] = 99;
2780 	    }
2781 	    break;
2782 
2783 	case TASK_CAPTURE:
2784 	case TASK_HIT_UNIT:
2785 	    set_unit_from_map (side, map,
2786 			       "select target unit, then press space",
2787 			       &uid);
2788 	    unit = find_unit(uid);
2789 	    task->args[0] = unit->x;
2790 	    task->args[1] = unit->y;
2791 	    if (task->type == TASK_HIT_UNIT) {
2792 		task->args[2] = NONUTYPE;
2793 		task->args[3] = -1;
2794 	    }
2795 	    break;
2796 
2797 	case TASK_MOVE_DIR:
2798 	    task->args[0] = dir_select_popup (side, x, y);
2799 	    task->args[1] = integer_select_popup(side, x, y, 99,
2800 						 "enter distance");
2801 	    break;
2802 
2803 	case TASK_MOVE_TO:
2804 	    task->args[2] = 0;  /* is this useful or just annoing?  Massimo */
2805 	    /* integer_select_popup(side, x, y, 0, "enter distance"); */
2806 
2807 	    set_cell_from_map (side, map,
2808 			       "select destination cell, then press space",
2809 			       (void *) &task->args[0],
2810 			       (void *) &task->args[1],
2811 			       sizeof(task->args[0]));
2812 	    break;
2813 
2814 	case TASK_HIT_POSITION:
2815 	    set_cell_from_map (side, map,
2816 			       "select target cell, then press space",
2817 			       (void *) &task->args[0],
2818 			       (void *) &task->args[1],
2819 			       sizeof(task->args[0]));
2820 	    break;
2821 
2822 	case TASK_OCCUPY:
2823 	case TASK_PICKUP:
2824 	    set_unit_from_map (side, map,
2825 			       "select target unit, then press space",
2826 			       (int *) &uid);
2827 	    break;
2828 
2829 	case TASK_SENTRY:
2830 	    task->args[0] = integer_select_popup(side, x, y, 99,
2831 						 "enter turn #");
2832 	    break;
2833 
2834 	default:
2835 	    beep(side);
2836 	}
2837 	/* get task description, chop task name and separator */
2838 	task_desc(buffer, side, NULL, task);
2839 	lab = buffer + strlen(taskdefns[task->type].name);
2840 	while (*lab == ' ' || *lab == ',')
2841 	  lab++;
2842 	XtVaSetValues(side->ui->ordi_edit->tparms, XtNlabel, lab, NULL);
2843 
2844     } else {
2845 	/* display */
2846 	if (ordi->sorder->task->type == TASK_MOVE_TO) {
2847 	    if (in_area(ordi->sorder->a1, ordi->sorder->a2)) {
2848 		map->curx = ordi->sorder->task->args[0];
2849 		map->cury = ordi->sorder->task->args[1];
2850 		map->curunit = NULL;
2851 		recenter(side, map, ordi->sorder->task->args[0],
2852 			            ordi->sorder->task->args[1]);
2853 		side->ui->curmap = map;
2854 		do_flash(side);
2855 	    } else {
2856 		beep(side);
2857 	    }
2858 	}
2859     }
2860 }
2861 
2862 void
set_cell_from_map(Side * side,Map * map,char * prompt,void * px,void * py,int size)2863 set_cell_from_map (Side *side, Map *map, char *prompt, void *px, void *py, int size)
2864 {
2865     save_cur(side, map);
2866     raise_widget(XtParent(map->mainwidget));
2867     map->curtool = looktool;
2868     set_tool_cursor(side, map);
2869     update_controls(side, map);
2870     side->ui->grok_p1 = (int *)px;
2871     side->ui->grok_p2 = (int *)py;
2872     side->ui->grok_size = size;
2873     ask_position(side, map, prompt, aux_set_cell);
2874 }
2875 
2876 static void
aux_set_cell(Side * side,Map * map,int cancel)2877 aux_set_cell(Side *side, Map *map, int cancel)
2878 {
2879     int x, y;
2880     Unit *unit;
2881     Boolean state;
2882 
2883     if (cancel)
2884       return;
2885     if (grok_position(side, map, &x, &y, &unit)) {
2886 /*	erase_current(side, map, x, y, NULL); */
2887 
2888 	XtVaGetValues(side->ui->ordi_edit->toggle, XtNstate, &state, NULL);
2889 	if (!state) {
2890 	    beep(side);
2891 	    return;
2892 	}
2893 	raise_widget(side->ui->orders_shell);
2894 	switch (side->ui->grok_size) {
2895 	case 1:
2896 	    *((char *)  side->ui->grok_p1) = x;
2897 	    *((char *)  side->ui->grok_p2) = y;
2898 	    break;
2899 	case 2:
2900 	    *((short *) side->ui->grok_p1) = x;
2901 	    *((short *) side->ui->grok_p2) = y;
2902 	    break;
2903 	case 4:
2904 	    *((int *)   side->ui->grok_p1) = x;
2905 	    *((int *)   side->ui->grok_p2) = y;
2906 	    break;
2907 	default:
2908 	    beep(side);
2909 	    return;
2910 	}
2911 	update_order_widgets(side, side->ui->ordi_edit, side->ui->sorder_edit,
2912 			     side->ui->sorder_types_edit,
2913 			     side->ui->sorder_task_edit);
2914     } else {
2915 	map->modalhandler = aux_set_cell;
2916     }
2917 }
2918 
2919 void
set_unit_from_map(Side * side,Map * map,char * prompt,int * puid)2920 set_unit_from_map (Side *side, Map *map, char *prompt, int *puid)
2921 {
2922     save_cur(side, map);
2923     raise_widget(XtParent(map->mainwidget));
2924     map->curtool = looktool;
2925     set_tool_cursor(side, map);
2926     update_controls(side, map);
2927     side->ui->grok_p1 = puid;
2928     ask_position(side, map, prompt, aux_set_unit);
2929 }
2930 
2931 static void
aux_set_unit(Side * side,Map * map,int cancel)2932 aux_set_unit(Side *side, Map *map, int cancel)
2933 {
2934     int x, y;
2935     Unit *unit;
2936     Boolean state;
2937 
2938     if (cancel)
2939       return;
2940     if (grok_position(side, map, &x, &y, &unit)) {
2941 /*	erase_current(side, map, x, y, NULL); */
2942 
2943 	XtVaGetValues(side->ui->ordi_edit->toggle, XtNstate, &state, NULL);
2944 	if (!state) {
2945 	    beep(side);
2946 	    return;
2947 	}
2948 	raise_widget(side->ui->orders_shell);
2949 
2950 	if (map->curunit == NULL)
2951 	  return;
2952 	*((int *) side->ui->grok_p1) = map->curunit->id;
2953 
2954 	update_order_widgets(side, side->ui->ordi_edit, side->ui->sorder_edit,
2955 			     side->ui->sorder_types_edit,
2956 			     side->ui->sorder_task_edit);
2957     } else {
2958 	map->modalhandler = aux_set_unit;
2959     }
2960 }
2961 
2962 int
find_side_and_ordi_via_widget(Widget w,Side ** sidep,OrderInterface ** ordip)2963 find_side_and_ordi_via_widget(Widget w, Side **sidep, OrderInterface **ordip)
2964 {
2965     OrderInterface *ordi;
2966     Widget form = XtParent(w);
2967 
2968     if (!find_side_via_widget(w, sidep))
2969       return 0;
2970 
2971     for (ordi = (*sidep)->ui->orderlist; ordi != NULL; ordi = ordi->next) {
2972 	if (ordi->form == form) {
2973 	    *ordip = ordi;
2974 	    return 1;
2975 	}
2976     }
2977 
2978     return 0;
2979 }
2980 
2981 void
deactivate_orders(Side * side)2982 deactivate_orders(Side *side)
2983 {
2984     OrderInterface *ordi;
2985 
2986     /* de-activate active order */
2987     ordi = active_ordi(side);
2988     if (ordi) {
2989 	XtVaSetValues(ordi->toggle, XtNstate, False, NULL);
2990 	order_toggle_call(ordi->toggle, NULL, NULL);
2991     }
2992 }
2993 
2994 OrderInterface *
active_ordi(Side * side)2995 active_ordi(Side *side)
2996 {
2997     OrderInterface *ordi;
2998     Boolean state;
2999 
3000     for (ordi = side->ui->orderlist; ordi != NULL; ordi = ordi->next) {
3001 	if (ordi->toggle) {
3002 	    XtVaGetValues(ordi->toggle, XtNstate, &state, NULL);
3003 	    if (state)  return ordi;
3004 	}
3005     }
3006     return NULL;
3007 }
3008 
3009 int
count_sorder(Side * side)3010 count_sorder(Side *side)
3011 {
3012     StandingOrder *sorder;
3013     int num;
3014 
3015     for (sorder = side->orders,  num = 0;
3016 	 sorder != NULL;
3017 	 sorder = sorder->next,  num++);
3018 
3019     return num;
3020 }
3021 
3022 int
num_tasks(void)3023 num_tasks(void)
3024 {
3025     int i;
3026 
3027     for (i = 0; taskdefns[i].name != NULL; i++) {}
3028     return i;
3029 }
3030 
3031 /* debugging stuff */
3032 
3033 static void
orders_check(Side * side)3034 orders_check (Side *side)
3035 {
3036     StandingOrder *sorder;
3037     OrderInterface *ordi;
3038     int i;
3039 
3040     if (side->orders == NULL) {
3041 	if (side->ui->orderlist) {
3042 	    run_error("check #1 failed in orders_check for %s",
3043 		      short_side_title(side));
3044 	} else {
3045 	    return;
3046 	}
3047     }
3048     for (sorder = side->orders,  ordi = side->ui->orderlist, i = 0;
3049 	 sorder != NULL && sorder->next != NULL;
3050 	 sorder = sorder->next, ordi = ordi->next, i++) {
3051 	if (ordi->sorder != sorder) {
3052 	    run_error("check #2 failed in orders_check for %s at i = %d",
3053 		      short_side_title(side), i);
3054 	}
3055     }
3056     if (sorder->next != NULL || sorder != side->last_order ||
3057 	ordi   == NULL || ordi->next   != NULL) {
3058 	run_error("check #3 failed in orders_check for %s",
3059 		  short_side_title(side));
3060     }
3061 
3062 }
3063