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