1 /***********************************************************************
2  Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 ***********************************************************************/
13 /***********************************************************************
14                           wldlg.c  -  description
15                              -------------------
16     begin                : Wed Sep 18 2002
17     copyright            : (C) 2002 by Rafał Bursig
18     email                : Rafał Bursig <bursig@poczta.fm>
19 ***********************************************************************/
20 
21 #ifdef HAVE_CONFIG_H
22 #include <fc_config.h>
23 #endif
24 
25 #include <stdlib.h>
26 
27 /* SDL */
28 #include <SDL/SDL.h>
29 
30 /* utility */
31 #include "fcintl.h"
32 #include "log.h"
33 
34 /* common */
35 #include "game.h"
36 #include "movement.h"
37 #include "unit.h"
38 
39 /* client */
40 #include "client_main.h"
41 #include "climisc.h"
42 #include "global_worklist.h"
43 
44 /* gui-sdl */
45 #include "citydlg.h"
46 #include "colors.h"
47 #include "graphics.h"
48 #include "gui_iconv.h"
49 #include "gui_id.h"
50 #include "gui_main.h"
51 #include "gui_tilespec.h"
52 #include "helpdlg.h"
53 #include "mapview.h"
54 #include "sprite.h"
55 #include "themespec.h"
56 #include "widget.h"
57 
58 #include "wldlg.h"
59 
60 #define TARGETS_COL		4
61 #define TARGETS_ROW		4
62 
63 struct EDITOR {
64   struct widget *pBeginWidgetList;
65   struct widget *pEndWidgetList;/* window */
66 
67   struct ADVANCED_DLG *pTargets;
68   struct ADVANCED_DLG *pWork;
69   struct ADVANCED_DLG *pGlobal;
70 
71   struct city *pCity;
72   int global_worklist_id;
73   struct worklist worklist_copy;
74   char worklist_name[MAX_LEN_NAME];
75 
76   /* shortcuts  */
77   struct widget *pDock;
78   struct widget *pWorkList_Counter;
79 
80   struct widget *pProduction_Name;
81   struct widget *pProduction_Progres;
82 
83   int stock;
84   struct universal currently_building;
85 
86 } *pEditor = NULL;
87 
88 
89 static int worklist_editor_item_callback(struct widget *pWidget);
90 static SDL_Surface * get_progress_icon(int stock, int cost, int *progress);
91 static const char * get_production_name(struct city *pCity,
92 					struct universal prod, int *cost);
93 static void refresh_worklist_count_label(void);
94 static void refresh_production_label(int stock);
95 
96 /* =========================================================== */
97 
98 /* Worklist Editor Window Callback */
window_worklist_editor_callback(struct widget * pWidget)99 static int window_worklist_editor_callback(struct widget *pWidget)
100 {
101   return -1;
102 }
103 
104 /* Popdwon Worklist Editor */
popdown_worklist_editor_callback(struct widget * pWidget)105 static int popdown_worklist_editor_callback(struct widget *pWidget)
106 {
107   if (Main.event.button.button == SDL_BUTTON_LEFT) {
108     popdown_worklist_editor();
109   }
110   return -1;
111 }
112 
113 /*
114  * Commit changes to city/global worklist
115  * In City Mode Remove Double entry of Imprv/Woder Targets from list.
116  */
ok_worklist_editor_callback(struct widget * pWidget)117 static int ok_worklist_editor_callback(struct widget *pWidget)
118 {
119   if (Main.event.button.button == SDL_BUTTON_LEFT) {
120     int i, j;
121     struct city *pCity = pEditor->pCity;
122 
123     /* remove duplicate entry of impv./wonder target from worklist */
124     for (i = 0; i < worklist_length(&pEditor->worklist_copy); i++) {
125 
126       if (VUT_IMPROVEMENT == pEditor->worklist_copy.entries[i].kind) {
127         for (j = i + 1; j < worklist_length(&pEditor->worklist_copy); j++) {
128           if (VUT_IMPROVEMENT == pEditor->worklist_copy.entries[j].kind
129               && pEditor->worklist_copy.entries[i].value.building ==
130                  pEditor->worklist_copy.entries[j].value.building) {
131             worklist_remove(&pEditor->worklist_copy, j);
132           }
133         }
134       }
135     }
136 
137     if (pCity) {
138       /* remove duplicate entry of currently building impv./wonder from worklist */
139       if (VUT_IMPROVEMENT == pEditor->currently_building.kind) {
140         for (i = 0; i < worklist_length(&pEditor->worklist_copy); i++) {
141           if (VUT_IMPROVEMENT == pEditor->worklist_copy.entries[i].kind
142               && pEditor->worklist_copy.entries[i].value.building ==
143                  pEditor->currently_building.value.building) {
144             worklist_remove(&pEditor->worklist_copy, i);
145           }
146         }
147       }
148 
149       /* change production */
150       if (!are_universals_equal(&pCity->production, &pEditor->currently_building)) {
151         city_change_production(pCity, &pEditor->currently_building);
152       }
153 
154       /* commit new city worklist */
155       city_set_worklist(pCity, &pEditor->worklist_copy);
156     } else {
157       /* commit global worklist */
158       struct global_worklist *pGWL = global_worklist_by_id(pEditor->global_worklist_id);
159 
160       if (pGWL) {
161         global_worklist_set(pGWL, &pEditor->worklist_copy);
162         global_worklist_set_name(pGWL, pEditor->worklist_name);
163         update_worklist_report_dialog();
164       }
165     }
166 
167     /* popdown dialog */
168     popdown_worklist_editor();
169   }
170 
171   return -1;
172 }
173 
174 /*
175  * Rename Global Worklist
176  */
rename_worklist_editor_callback(struct widget * pWidget)177 static int rename_worklist_editor_callback(struct widget *pWidget)
178 {
179   if (Main.event.button.button == SDL_BUTTON_LEFT) {
180     if(pWidget->string16->text) {
181       char *pText = convert_to_chars(pWidget->string16->text);
182       fc_snprintf(pEditor->worklist_name, MAX_LEN_NAME, "%s", pText);
183       FC_FREE(pText);
184     } else {
185       /* empty input -> restore previous content */
186       copy_chars_to_string16(pWidget->string16, pEditor->worklist_name);
187       widget_redraw(pWidget);
188       widget_mark_dirty(pWidget);
189       flush_dirty();
190     }
191   }
192   return -1;
193 }
194 
195 /* ====================================================================== */
196 
197 /*
198  * Add target to worklist.
199  */
add_target_to_worklist(struct widget * pTarget)200 static void add_target_to_worklist(struct widget *pTarget)
201 {
202   struct widget *pBuf = NULL, *pDock = NULL;
203   SDL_String16 *pStr = NULL;
204   int i;
205   struct universal prod = cid_decode(MAX_ID - pTarget->ID);
206 
207   set_wstate(pTarget, FC_WS_SELLECTED);
208   widget_redraw(pTarget);
209   widget_flush(pTarget);
210 
211   /* Deny adding currently building Impr/Wonder Target */
212   if (pEditor->pCity
213       && VUT_IMPROVEMENT == prod.kind
214       && are_universals_equal(&prod, &pEditor->currently_building)) {
215     return;
216   }
217 
218   if (worklist_length(&pEditor->worklist_copy) >= MAX_LEN_WORKLIST - 1) {
219     return;
220   }
221 
222   for (i = 0; i < worklist_length(&pEditor->worklist_copy); i++) {
223     if (VUT_IMPROVEMENT == prod.kind
224         && are_universals_equal(&prod, &pEditor->worklist_copy.entries[i])) {
225       return;
226     }
227   }
228 
229   worklist_append(&pEditor->worklist_copy, &prod);
230 
231   /* create widget entry */
232   if (VUT_UTYPE == prod.kind) {
233     pStr = create_str16_from_char(utype_name_translation(prod.value.utype), adj_font(10));
234   } else {
235     pStr = create_str16_from_char(city_improvement_name_translation(pEditor->pCity, prod.value.building),
236                                   adj_font(10));
237   }
238 
239   pStr->style |= SF_CENTER;
240   pBuf = create_iconlabel(NULL, pTarget->dst, pStr,
241 				(WF_RESTORE_BACKGROUND|WF_FREE_DATA));
242 
243   set_wstate(pBuf, FC_WS_NORMAL);
244   pBuf->action = worklist_editor_item_callback;
245 
246   pBuf->data.ptr = fc_calloc(1, sizeof(int));
247   *((int *)pBuf->data.ptr) = worklist_length(&pEditor->worklist_copy) - 1;
248 
249   pBuf->ID = MAX_ID - cid_encode(prod);
250 
251   if(pEditor->pWork->pBeginActiveWidgetList) {
252     pDock = pEditor->pWork->pBeginActiveWidgetList;
253   } else {
254     pDock = pEditor->pDock;
255   }
256 
257 /* FIXME */
258 #if 0
259   if (worklist_length(&pEditor->worklist_copy) > pEditor->pWork->pScroll->active + 1) {
260 
261     setup_vertical_widgets_position(1,
262       pEditor->pEndWidgetList->area.x + adj_size(2),
263       get_widget_pointer_from_main_list(ID_WINDOW)->area.y + adj_size(152) +
264 	pEditor->pWork->pScroll->pUp_Left_Button->size.h + 1,
265 	adj_size(126), 0, pEditor->pWork->pBeginWidgetList,
266 		  pEditor->pWork->pEndWidgetList);
267 
268     setup_vertical_scrollbar_area(pEditor->pWork->pScroll,
269 	pEditor->pEndWidgetList->area.x + adj_size(2),
270         get_widget_pointer_from_main_list(ID_WINDOW)->area.y + adj_size(152),
271     	adj_size(225), FALSE);
272 
273     show_scrollbar(pEditor->pWork->pScroll);
274   }
275 #endif
276 
277   add_widget_to_vertical_scroll_widget_list(pEditor->pWork, pBuf,
278     pDock, FALSE,
279     pEditor->pEndWidgetList->area.x + adj_size(2),
280     pEditor->pEndWidgetList->area.y + adj_size(152));
281 
282   pBuf->size.w = adj_size(126);
283 
284   refresh_worklist_count_label();
285   redraw_group(pEditor->pWork->pBeginWidgetList,
286 			  pEditor->pWork->pEndWidgetList, TRUE);
287   flush_dirty();
288 }
289 
290 /**************************************************************************
291   Find if two targets are the same class (unit, imprv. , wonder).
292   This is needed by calculation of change production shields penalty.
293   [similar to are_universals_equal()]
294 **************************************************************************/
are_prods_same_class(const struct universal * one,const struct universal * two)295 static bool are_prods_same_class(const struct universal *one,
296                                  const struct universal *two)
297 {
298   if (one->kind != two->kind) {
299     return FALSE;
300   }
301 
302   if (VUT_IMPROVEMENT == one->kind) {
303     if (is_wonder(one->value.building)) {
304       return is_wonder(two->value.building);
305     } else {
306       return !is_wonder(two->value.building);
307     }
308   }
309 
310   return FALSE;
311 }
312 
313 /**************************************************************************
314   Change production in editor shell, calculate production shields penalty and
315   refresh production progress label
316 **************************************************************************/
change_production(struct universal * prod)317 static void change_production(struct universal *prod)
318 {
319   if (!are_prods_same_class(&pEditor->currently_building, prod)) {
320     if (pEditor->stock != pEditor->pCity->shield_stock) {
321       if (are_prods_same_class(&pEditor->pCity->production, prod)) {
322         pEditor->stock = pEditor->pCity->shield_stock;
323       }
324     } else {
325       pEditor->stock =
326         city_change_production_penalty(pEditor->pCity, prod);
327     }
328   }
329 
330   pEditor->currently_building = *prod;
331   refresh_production_label(pEditor->stock);
332 
333   return;
334 }
335 
336 /*
337  * Change production of city but only in Editor.
338  * You must commit this changes by exit editor via OK button (commit function).
339  *
340  * This function don't remove double imprv./wonder target entry from worklist
341  * and allow more entry of such target (In Production and worklist - this is
342  * fixed by commit function).
343  */
add_target_to_production(struct widget * pTarget)344 static void add_target_to_production(struct widget *pTarget)
345 {
346   int dummy;
347   struct universal prod;
348 
349   fc_assert_ret(pTarget != NULL);
350 
351   /* redraw Target Icon */
352   set_wstate(pTarget, FC_WS_SELLECTED);
353   widget_redraw(pTarget);
354   widget_flush(pTarget);
355 
356   prod = cid_decode(MAX_ID - pTarget->ID);
357 
358   /* check if we change to the same target */
359   if (are_universals_equal(&prod, &pEditor->currently_building)) {
360     /* comit changes and exit - double click detection */
361     ok_worklist_editor_callback(NULL);
362     return;
363   }
364 
365   change_production(&prod);
366 
367   /* change Production Text Label in Worklist Widget list */
368   copy_chars_to_string16(pEditor->pWork->pEndActiveWidgetList->string16,
369                          get_production_name(pEditor->pCity, prod, &dummy));
370 
371   pEditor->pWork->pEndActiveWidgetList->ID = MAX_ID - cid_encode(prod);
372 
373   widget_redraw(pEditor->pWork->pEndActiveWidgetList);
374   widget_mark_dirty(pEditor->pWork->pEndActiveWidgetList);
375 
376   flush_dirty();
377 }
378 
379 /* Get Help Info about target */
get_target_help_data(struct widget * pTarget)380 static void get_target_help_data(struct widget *pTarget)
381 {
382   struct universal prod;
383 
384   fc_assert_ret(pTarget != NULL);
385 
386   /* redraw Target Icon */
387   set_wstate(pTarget, FC_WS_SELLECTED);
388   widget_redraw(pTarget);
389   /*widget_flush(pTarget);*/
390 
391   prod = cid_decode(MAX_ID - pTarget->ID);
392 
393   if (VUT_UTYPE == prod.kind)
394   {
395     popup_unit_info(utype_number(prod.value.utype));
396   } else {
397     popup_impr_info(improvement_number(prod.value.building));
398   }
399 
400 }
401 
402 
403 /*
404  * Targets callback
405  * left mouse button -> In city mode change production to target.
406 			In global mode add target to worklist.
407  * middle mouse button -> get target "help"
408  * right mouse button -> add target to worklist.
409  */
worklist_editor_targets_callback(struct widget * pWidget)410 static int worklist_editor_targets_callback(struct widget *pWidget)
411 {
412   if (Main.event.type == SDL_MOUSEBUTTONDOWN) {
413     switch (Main.event.button.button) {
414     case SDL_BUTTON_LEFT:
415       if(pEditor->pCity) {
416         add_target_to_production(pWidget);
417       } else {
418 	add_target_to_worklist(pWidget);
419       }
420       break;
421     case SDL_BUTTON_MIDDLE:
422       get_target_help_data(pWidget);
423       break;
424     case SDL_BUTTON_RIGHT:
425       add_target_to_worklist(pWidget);
426       break;
427     default:
428       ;/* do nothing */
429       break;
430     }
431   }
432   return -1;
433 }
434 
435 /* ====================================================================== */
436 
437 /*
438  * Remove element from worklist or
439  * remove currently building imprv/unit and change production to first worklist
440  * element (or Capitalizations if worklist is empty)
441  */
remove_item_from_worklist(struct widget * pItem)442 static void remove_item_from_worklist(struct widget *pItem)
443 {
444   /* only one item (production) is left */
445   if (worklist_is_empty(&pEditor->worklist_copy))
446     return;
447 
448   if(pItem->data.ptr) {
449     /* correct "data" widget fiels */
450     struct widget *pBuf = pItem;
451     if(pBuf != pEditor->pWork->pBeginActiveWidgetList) {
452       do{
453 	pBuf = pBuf->prev;
454 	*((int *)pBuf->data.ptr) = *((int *)pBuf->data.ptr) - 1;
455       } while(pBuf != pEditor->pWork->pBeginActiveWidgetList);
456     }
457 
458     /* remove element from worklist */
459     worklist_remove(&pEditor->worklist_copy, *((int *)pItem->data.ptr));
460 
461     /* remove widget from widget list */
462     del_widget_from_vertical_scroll_widget_list(pEditor->pWork, pItem);
463   } else {
464     /* change productions to first worklist element */
465     struct widget *pBuf = pItem->prev;
466 
467     change_production(&pEditor->worklist_copy.entries[0]);
468     worklist_advance(&pEditor->worklist_copy);
469     del_widget_from_vertical_scroll_widget_list(pEditor->pWork, pItem);
470     FC_FREE(pBuf->data.ptr);
471     if (pBuf != pEditor->pWork->pBeginActiveWidgetList) {
472       do {
473         pBuf = pBuf->prev;
474         *((int *)pBuf->data.ptr) = *((int *)pBuf->data.ptr) - 1;
475       } while (pBuf != pEditor->pWork->pBeginActiveWidgetList);
476     }
477   }
478 
479 /* FIXME: fix scrollbar code */
480 #if 0
481   /* worklist_length(&pEditor->worklist_copy): without production */
482   if (worklist_length(&pEditor->worklist_copy) <= pEditor->pWork->pScroll->active + 1) {
483 
484     setup_vertical_widgets_position(1,
485       pEditor->pEndWidgetList->area.x + adj_size(2),
486       get_widget_pointer_from_main_list(ID_WINDOW)->area.y + adj_size(152),
487 	adj_size(126), 0, pEditor->pWork->pBeginWidgetList,
488 		  pEditor->pWork->pEndWidgetList);
489 #if 0
490     setup_vertical_scrollbar_area(pEditor->pWork->pScroll,
491 	pEditor->pEndWidgetList->area.x + adj_size(2),
492         get_widget_pointer_from_main_list(ID_WINDOW)->area.y + adj_size(152),
493     	adj_size(225), FALSE);*/
494 #endif
495     hide_scrollbar(pEditor->pWork->pScroll);
496   }
497 #endif
498 
499   refresh_worklist_count_label();
500   redraw_group(pEditor->pWork->pBeginWidgetList,
501 			  pEditor->pWork->pEndWidgetList, TRUE);
502   flush_dirty();
503 }
504 
505 /*
506  * Swap worklist entries DOWN.
507  * Fuction swap current element with next element of worklist.
508  *
509  * If pItem is last widget or there is only one widget on widgets list
510  * fuction remove this widget from widget list and target from worklist
511  *
512  * In City mode, when pItem is first worklist element, function make
513  * change production (currently building is moved to first element of worklist
514  * and first element of worklist is build).
515  */
swap_item_down_from_worklist(struct widget * pItem)516 static void swap_item_down_from_worklist(struct widget *pItem)
517 {
518   Uint16 *pText, ID;
519   bool changed = FALSE;
520   struct universal tmp;
521 
522   if(pItem == pEditor->pWork->pBeginActiveWidgetList) {
523     remove_item_from_worklist(pItem);
524     return;
525   }
526 
527   pText = pItem->string16->text;
528   ID = pItem->ID;
529 
530   /* second item or higher was clicked */
531   if(pItem->data.ptr) {
532     /* worklist operations -> swap down */
533     int row = *((int *)pItem->data.ptr);
534 
535     tmp = pEditor->worklist_copy.entries[row];
536     pEditor->worklist_copy.entries[row] = pEditor->worklist_copy.entries[row + 1];
537     pEditor->worklist_copy.entries[row + 1] = tmp;
538 
539     changed = TRUE;
540   } else {
541     /* first item was clicked -> change production */
542     change_production(&pEditor->worklist_copy.entries[0]);
543     pEditor->worklist_copy.entries[0] = cid_decode(MAX_ID - ID);
544       changed = TRUE;
545     }
546 
547   if(changed) {
548     pItem->string16->text = pItem->prev->string16->text;
549     pItem->ID = pItem->prev->ID;
550 
551     pItem->prev->string16->text = pText;
552     pItem->prev->ID = ID;
553 
554     redraw_group(pEditor->pWork->pBeginWidgetList,
555 			  pEditor->pWork->pEndWidgetList, TRUE);
556     flush_dirty();
557   }
558 
559 }
560 
561 /*
562  * Swap worklist entries UP.
563  * Fuction swap current element with prev. element of worklist.
564  *
565  * If pItem is first widget on widgets list fuction remove this widget
566  * from widget list and target from worklist (global mode)
567  * or from production (city mode)
568  *
569  * In City mode, when pItem is first worklist element, function make
570  * change production (currently building is moved to first element of worklist
571  * and first element of worklist is build).
572  */
swap_item_up_from_worklist(struct widget * pItem)573 static void swap_item_up_from_worklist(struct widget *pItem)
574 {
575   Uint16 *pText = pItem->string16->text;
576   Uint16 ID = pItem->ID;
577   bool changed = FALSE;
578   struct universal tmp;
579 
580   /* first item was clicked -> remove */
581   if(pItem == pEditor->pWork->pEndActiveWidgetList) {
582     remove_item_from_worklist(pItem);
583     return;
584   }
585 
586   /* third item or higher was clicked */
587   if(pItem->data.ptr && *((int *)pItem->data.ptr) > 0) {
588     /* worklist operations -> swap up*/
589     int row = *((int *)pItem->data.ptr);
590 
591     tmp = pEditor->worklist_copy.entries[row];
592     pEditor->worklist_copy.entries[row] = pEditor->worklist_copy.entries[row - 1];
593     pEditor->worklist_copy.entries[row - 1] = tmp;
594 
595     changed = TRUE;
596   } else {
597     /* second item was clicked -> change production ... */
598     tmp = pEditor->currently_building;
599     change_production(&pEditor->worklist_copy.entries[0]);
600     pEditor->worklist_copy.entries[0] = tmp;
601 
602     changed = TRUE;
603   }
604 
605   if(changed) {
606     pItem->string16->text = pItem->next->string16->text;
607     pItem->ID = pItem->next->ID;
608 
609     pItem->next->string16->text = pText;
610     pItem->next->ID = ID;
611 
612     redraw_group(pEditor->pWork->pBeginWidgetList,
613 			  pEditor->pWork->pEndWidgetList, TRUE);
614     flush_dirty();
615   }
616 }
617 
618 /*
619  * worklist callback
620  * left mouse button -> swap entries up.
621  * middle mouse button -> remove element from list
622  * right mouse button -> swap entries down.
623  */
worklist_editor_item_callback(struct widget * pWidget)624 static int worklist_editor_item_callback(struct widget *pWidget)
625 {
626   if (Main.event.type == SDL_MOUSEBUTTONDOWN) {
627     switch (Main.event.button.button) {
628     case SDL_BUTTON_LEFT:
629       swap_item_up_from_worklist(pWidget);
630       break;
631     case SDL_BUTTON_MIDDLE:
632       remove_item_from_worklist(pWidget);
633       break;
634     case SDL_BUTTON_RIGHT:
635       swap_item_down_from_worklist(pWidget);
636       break;
637     default:
638       ;/* do nothing */
639       break;
640     }
641   }
642   return -1;
643 }
644 /* ======================================================= */
645 
646 /*
647  * Add global worklist to city worklist starting from last free entry.
648  * Add only avilable targets in current game state.
649  * If global worklist have more targets that city worklist have free
650  * entries then we adding only first part of global worklist.
651  */
add_global_worklist(struct widget * pWidget)652 static void add_global_worklist(struct widget *pWidget)
653 {
654   struct global_worklist *pGWL = global_worklist_by_id(MAX_ID - pWidget->ID);
655   struct widget *pBuf = pEditor->pWork->pEndActiveWidgetList;
656   const struct worklist *pWorkList;
657   int count, firstfree;
658 
659   if (!pGWL
660       || !(pWorkList = global_worklist_get(pGWL))
661       || worklist_is_empty(pWorkList)) {
662     return;
663   }
664 
665   if (worklist_length(&pEditor->worklist_copy) >= MAX_LEN_WORKLIST - 1) {
666     /* worklist is full */
667     return;
668   }
669 
670   firstfree = worklist_length(&pEditor->worklist_copy);
671   /* copy global worklist to city worklist */
672   for (count = 0 ; count < worklist_length(pWorkList); count++) {
673 
674     /* global worklist can have targets unavilable in current state of game
675        then we must remove those targets from new city worklist */
676     if (!can_city_build_later(pEditor->pCity, &pWorkList->entries[count])) {
677       continue;
678     }
679 
680     worklist_append(&pEditor->worklist_copy, &pWorkList->entries[count]);
681 
682     /* create widget */
683     if(VUT_UTYPE == pWorkList->entries[count].kind) {
684       pBuf = create_iconlabel(NULL, pWidget->dst,
685               create_str16_from_char(
686                       utype_name_translation(pWorkList->entries[count].value.utype),
687                       adj_font(10)),
688               (WF_RESTORE_BACKGROUND|WF_FREE_DATA));
689       pBuf->ID = MAX_ID - cid_encode_unit(pWorkList->entries[count].value.utype);
690     } else {
691       pBuf = create_iconlabel(NULL, pWidget->dst,
692               create_str16_from_char(
693                       city_improvement_name_translation(pEditor->pCity,
694                               pWorkList->entries[count].value.building),
695                       adj_font(10)),
696               (WF_RESTORE_BACKGROUND|WF_FREE_DATA));
697       pBuf->ID = MAX_ID - cid_encode_building(pWorkList->entries[count].value.building);
698     }
699 
700     pBuf->string16->style |= SF_CENTER;
701     set_wstate(pBuf, FC_WS_NORMAL);
702     pBuf->action = worklist_editor_item_callback;
703     pBuf->size.w = adj_size(126);
704     pBuf->data.ptr = fc_calloc(1, sizeof(int));
705     *((int *)pBuf->data.ptr) = firstfree;
706 
707     add_widget_to_vertical_scroll_widget_list(pEditor->pWork,
708       pBuf, pEditor->pWork->pBeginActiveWidgetList, FALSE,
709       pEditor->pEndWidgetList->area.x + adj_size(2),
710       pEditor->pEndWidgetList->area.y + adj_size(152));
711 
712     firstfree++;
713     if(firstfree == MAX_LEN_WORKLIST - 1) {
714       break;
715     }
716   }
717 
718   refresh_worklist_count_label();
719   redraw_group(pEditor->pWork->pBeginWidgetList,
720                       pEditor->pWork->pEndWidgetList, TRUE);
721 
722   flush_dirty();
723 }
724 
725 /*
726  * Clear city worklist and copy here global worklist.
727  * Copy only avilable targets in current game state.
728  * If all targets are unavilable then leave city worklist untouched.
729  */
set_global_worklist(struct widget * pWidget)730 static void set_global_worklist(struct widget *pWidget)
731 {
732   struct global_worklist *pGWL = global_worklist_by_id(MAX_ID - pWidget->ID);
733   struct widget *pBuf = pEditor->pWork->pEndActiveWidgetList;
734   const struct worklist *pWorkList;
735   struct worklist wl;
736   int count, wl_count;
737   struct universal target;
738 
739   if (!pGWL
740       || !(pWorkList = global_worklist_get(pGWL))
741       || worklist_is_empty(pWorkList)) {
742     return;
743   }
744 
745   /* clear tmp worklist */
746   worklist_init(&wl);
747 
748   wl_count = 0;
749   /* copy global worklist to city worklist */
750   for (count = 0; count < worklist_length(pWorkList); count++) {
751 
752     /* global worklist can have targets unavilable in current state of game
753        then we must remove those targets from new city worklist */
754     if (!can_city_build_later(pEditor->pCity, &pWorkList->entries[count])) {
755       continue;
756     }
757 
758     wl.entries[wl_count] = pWorkList->entries[count];
759     wl_count++;
760   }
761   /* --------------------------------- */
762 
763   if (!worklist_is_empty(&wl)) {
764     /* free old widget list */
765     if (pBuf != pEditor->pWork->pBeginActiveWidgetList) {
766       pBuf = pBuf->prev;
767       if (pBuf != pEditor->pWork->pBeginActiveWidgetList) {
768         do {
769           pBuf = pBuf->prev;
770           del_widget_from_vertical_scroll_widget_list(pEditor->pWork, pBuf->next);
771         } while (pBuf != pEditor->pWork->pBeginActiveWidgetList);
772       }
773       del_widget_from_vertical_scroll_widget_list(pEditor->pWork, pBuf);
774     }
775     /* --------------------------------- */
776 
777     worklist_copy(&pEditor->worklist_copy, &wl);
778 
779     /* --------------------------------- */
780     /* create new widget list */
781     for(count = 0; count < MAX_LEN_WORKLIST; count++) {
782       /* end of list */
783       if(!worklist_peek_ith(&pEditor->worklist_copy, &target, count)) {
784         break;
785       }
786 
787       if(VUT_UTYPE == target.kind) {
788         pBuf = create_iconlabel(NULL, pWidget->dst,
789           create_str16_from_char(utype_name_translation(target.value.utype),
790                                  adj_font(10)),
791                                  (WF_RESTORE_BACKGROUND|WF_FREE_DATA));
792         pBuf->ID = MAX_ID - B_LAST - utype_number(target.value.utype);
793       } else {
794         pBuf = create_iconlabel(NULL, pWidget->dst,
795           create_str16_from_char(city_improvement_name_translation(pEditor->pCity, target.value.building),
796                                  adj_font(10)),
797                                  (WF_RESTORE_BACKGROUND|WF_FREE_DATA));
798         pBuf->ID = MAX_ID - improvement_number(target.value.building);
799       }
800       pBuf->string16->style |= SF_CENTER;
801       set_wstate(pBuf, FC_WS_NORMAL);
802       pBuf->action = worklist_editor_item_callback;
803       pBuf->size.w = adj_size(126);
804       pBuf->data.ptr = fc_calloc(1, sizeof(int));
805       *((int *)pBuf->data.ptr) = count;
806 
807       add_widget_to_vertical_scroll_widget_list(pEditor->pWork,
808         pBuf, pEditor->pWork->pBeginActiveWidgetList, FALSE,
809         pEditor->pEndWidgetList->area.x + adj_size(2),
810         pEditor->pEndWidgetList->area.y + adj_size(152));
811     }
812 
813     refresh_worklist_count_label();
814     redraw_group(pEditor->pWork->pBeginWidgetList,
815                       pEditor->pWork->pEndWidgetList, TRUE);
816 
817     flush_dirty();
818   }
819 }
820 
821 /*
822  * global worklist callback
823  * left mouse button -> add global worklist to current city list
824  * right mouse button -> clear city worklist and copy here global worklist.
825  *
826  * There are problems with imprv./wonder targets because those can't be doubled
827  * on worklist and adding/setting can give you situation that global worklist
828  * have imprv./wonder entry that exist on city worklist or in building state.
829  * I don't make such check here and allow this "functionality" because doubled
830  * imprv./wonder entry are removed from city worklist during "commit" phase.
831  */
global_worklist_callback(struct widget * pWidget)832 static int global_worklist_callback(struct widget *pWidget)
833 {
834   if (Main.event.type == SDL_MOUSEBUTTONDOWN) {
835     switch (Main.event.button.button) {
836     case SDL_BUTTON_LEFT:
837       add_global_worklist(pWidget);
838       break;
839     case SDL_BUTTON_MIDDLE:
840       /* nothing */
841       break;
842     case SDL_BUTTON_RIGHT:
843       set_global_worklist(pWidget);
844       break;
845     default:
846       ;/* do nothing */
847       break;
848     }
849   }
850   return -1;
851 }
852 
853 /* ======================================================= */
854 
855 /* return full unit/imprv. name and build cost in "cost" pointer */
get_production_name(struct city * pCity,struct universal prod,int * cost)856 static const char * get_production_name(struct city *pCity,
857 					struct universal prod, int *cost)
858 {
859   fc_assert_ret_val(cost != NULL, NULL);
860 
861   *cost = universal_build_shield_cost(&prod);
862   if(VUT_UTYPE == prod.kind) {
863     return utype_name_translation(prod.value.utype);
864   } else {
865     return city_improvement_name_translation(pCity, prod.value.building);
866   }
867 }
868 
869 /**************************************************************************
870   Return progress icon (bar) of current production state
871   stock - current shields stocks
872   cost - unit/imprv. cost
873   function return in "progress" pointer (0 - 100 %) progress in numbers
874 **************************************************************************/
get_progress_icon(int stock,int cost,int * progress)875 static SDL_Surface * get_progress_icon(int stock, int cost, int *progress)
876 {
877   SDL_Surface *pIcon = NULL;
878   int width;
879 
880   fc_assert_ret_val(progress != NULL, NULL);
881 
882   if (stock < cost) {
883     width = ((float)stock / cost) * adj_size(116.0);
884     *progress = ((float)stock / cost) * 100.0;
885     if(!width && stock) {
886       *progress = 1;
887       width = 1;
888     }
889   } else {
890     width = adj_size(116);
891     *progress = 100;
892   }
893 
894   pIcon = create_bcgnd_surf(current_theme->Edit, FC_WS_NORMAL, adj_size(120),
895                             adj_size(30));
896 
897   if (width) {
898     SDL_Rect dst = {2,1,0,0};
899     SDL_Surface *pBuf = create_bcgnd_surf(current_theme->Button, FC_WS_DISABLED,
900                                           width, adj_size(28));
901 
902     alphablit(pBuf, NULL, pIcon, &dst);
903     FREESURFACE(pBuf);
904   }
905 
906   return pIcon;
907 }
908 
909 /*
910  * update and redraw production name label in worklist editor
911  * stock - pCity->shields_stock or current stock after chnge production lost.
912  */
refresh_production_label(int stock)913 static void refresh_production_label(int stock)
914 {
915   int cost, turns;
916   char cBuf[64];
917   SDL_Rect area;
918   bool gold_prod = improvement_has_flag(pEditor->currently_building.value.building, IF_GOLD);
919   const char *name = get_production_name(pEditor->pCity,
920                                          pEditor->currently_building, &cost);
921 
922   if (VUT_IMPROVEMENT == pEditor->currently_building.kind && gold_prod) {
923     int gold = MAX(0, pEditor->pCity->surplus[O_SHIELD]);
924 
925     fc_snprintf(cBuf, sizeof(cBuf),
926                 PL_("%s\n%d gold per turn",
927                     "%s\n%d gold per turn", gold),
928                 name, gold);
929   } else {
930     if (stock < cost) {
931       turns = city_turns_to_build(pEditor->pCity,
932                                   &pEditor->currently_building, TRUE);
933       if (turns == 999) {
934         fc_snprintf(cBuf, sizeof(cBuf), _("%s\nblocked!"), name);
935       } else {
936         fc_snprintf(cBuf, sizeof(cBuf), _("%s\n%d %s"),
937                     name, turns, PL_("turn", "turns", turns));
938       }
939     } else {
940       fc_snprintf(cBuf, sizeof(cBuf), _("%s\nfinished!"), name);
941     }
942   }
943   copy_chars_to_string16(pEditor->pProduction_Name->string16, cBuf);
944 
945   widget_undraw(pEditor->pProduction_Name);
946   remake_label_size(pEditor->pProduction_Name);
947 
948   pEditor->pProduction_Name->size.x = pEditor->pEndWidgetList->area.x +
949     (adj_size(130) - pEditor->pProduction_Name->size.w) / 2;
950 
951   /* Can't just widget_mark_dirty(), as it may have reduced in size */
952   area.x = pEditor->pEndWidgetList->area.x;  /* left edge of client area */
953   area.y = pEditor->pProduction_Name->size.y;
954   area.w = adj_size(130);
955   area.h = pEditor->pProduction_Name->size.h;
956   layer_rect_to_screen_rect(pEditor->pEndWidgetList->dst, &area);
957 
958   if (get_wflags(pEditor->pProduction_Name) & WF_RESTORE_BACKGROUND) {
959     refresh_widget_background(pEditor->pProduction_Name);
960   }
961 
962   widget_redraw(pEditor->pProduction_Name);
963   sdl_dirty_rect(area);
964 
965   FREESURFACE(pEditor->pProduction_Progres->theme);
966   pEditor->pProduction_Progres->theme =
967     get_progress_icon(stock, cost, &cost);
968 
969   if (!gold_prod) {
970     fc_snprintf(cBuf, sizeof(cBuf), "%d%%" , cost);
971   } else {
972     fc_snprintf(cBuf, sizeof(cBuf), "-" );
973   }
974   copy_chars_to_string16(pEditor->pProduction_Progres->string16, cBuf);
975   widget_redraw(pEditor->pProduction_Progres);
976   widget_mark_dirty(pEditor->pProduction_Progres);
977 }
978 
979 /**************************************************************************
980   Update and redraw worklist length counter in worklist editor
981 **************************************************************************/
refresh_worklist_count_label(void)982 static void refresh_worklist_count_label(void)
983 {
984   char cBuf[64];
985   SDL_Rect area;
986   int len = worklist_length(&pEditor->worklist_copy);
987 
988   if (pEditor->pCity != NULL) {
989     len += 1;  /* External entry from current production */
990   }
991 
992   fc_snprintf(cBuf, sizeof(cBuf),
993               /* TRANS: length of worklist */
994               PL_("( %d entry )", "( %d entries )", len), len);
995   copy_chars_to_string16(pEditor->pWorkList_Counter->string16, cBuf);
996 
997   widget_undraw(pEditor->pWorkList_Counter);
998   remake_label_size(pEditor->pWorkList_Counter);
999 
1000   pEditor->pWorkList_Counter->size.x = pEditor->pEndWidgetList->area.x +
1001     (adj_size(130) - pEditor->pWorkList_Counter->size.w)/2;
1002 
1003   if (get_wflags(pEditor->pWorkList_Counter) & WF_RESTORE_BACKGROUND) {
1004     refresh_widget_background(pEditor->pWorkList_Counter);
1005   }
1006 
1007   widget_redraw(pEditor->pWorkList_Counter);
1008 
1009   /* Can't just widget_mark_dirty(), as it may have reduced in size */
1010   area.x = pEditor->pEndWidgetList->area.x;  /* left edge of client area */
1011   area.y = pEditor->pWorkList_Counter->size.y;
1012   area.w = adj_size(130);
1013   area.h = pEditor->pWorkList_Counter->size.h;
1014   layer_rect_to_screen_rect(pEditor->pEndWidgetList->dst, &area);
1015   sdl_dirty_rect(area);
1016 }
1017 
1018 
1019 /* ====================================================================== */
1020 
1021 
1022 /*
1023  * Global/City worklist editor.
1024  * if pCity == NULL then function takes pWorklist as global worklist.
1025  * pWorklist must be not NULL.
1026  */
popup_worklist_editor(struct city * pCity,struct global_worklist * gwl)1027 void popup_worklist_editor(struct city *pCity, struct global_worklist *gwl)
1028 {
1029   SDL_Color bg_color = {255,255,255,128};
1030   SDL_Color bg_color2 = {255,255,255,136};
1031 
1032   int count = 0, turns;
1033   int widget_w = 0, widget_h = 0;
1034   SDL_String16 *pStr = NULL;
1035   struct widget *pBuf = NULL, *pWindow, *pLast;
1036   SDL_Surface *pText = NULL, *pText_Name = NULL, *pZoom = NULL;
1037   SDL_Surface *pMain;
1038   SDL_Surface *pIcon;
1039   SDL_Rect dst;
1040   char cBuf[128];
1041   struct unit_type *punittype = NULL;
1042   char *state = NULL;
1043   bool advanced_tech;
1044   bool can_build, can_eventually_build;
1045   SDL_Rect area;
1046   int len;
1047 
1048   if (pEditor) {
1049     return;
1050   }
1051 
1052   pEditor = fc_calloc(1, sizeof(struct EDITOR));
1053 
1054   if (pCity) {
1055     pEditor->pCity = pCity;
1056     pEditor->global_worklist_id = -1;
1057     pEditor->currently_building = pCity->production;
1058     pEditor->stock = pCity->shield_stock;
1059     worklist_copy(&pEditor->worklist_copy, &pCity->worklist);
1060     fc_snprintf(pEditor->worklist_name, sizeof(pEditor->worklist_name),
1061                 "%s worklist", city_name_get(pCity));
1062   } else if (gwl != NULL) {
1063     pEditor->pCity = NULL;
1064     pEditor->global_worklist_id = global_worklist_id(gwl);
1065     worklist_copy(&pEditor->worklist_copy, global_worklist_get(gwl));
1066     sz_strlcpy(pEditor->worklist_name, global_worklist_name(gwl));
1067   } else {
1068     /* Not valid variant! */
1069     return;
1070   }
1071 
1072   len = worklist_length(&pEditor->worklist_copy);
1073   advanced_tech = (pCity == NULL);
1074 
1075   /* --------------- */
1076   /* create Target Background Icon */
1077   pMain = create_surf_alpha(adj_size(116), adj_size(116), SDL_SWSURFACE);
1078   SDL_FillRect(pMain, NULL, map_rgba(pMain->format, bg_color));
1079   putframe(pMain,
1080            0, 0, pMain->w - 1, pMain->h - 1,
1081            get_theme_color(COLOR_THEME_WLDLG_FRAME));
1082 
1083   /* ---------------- */
1084   /* Create Main Window */
1085   pWindow = create_window_skeleton(NULL, NULL, 0);
1086   pWindow->action = window_worklist_editor_callback;
1087   set_wstate(pWindow, FC_WS_NORMAL);
1088 
1089   add_to_gui_list(ID_WINDOW, pWindow);
1090   pEditor->pEndWidgetList = pWindow;
1091 
1092   area = pWindow->area;
1093 
1094   /* ---------------- */
1095   if (pCity) {
1096     fc_snprintf(cBuf, sizeof(cBuf), _("Worklist of\n%s"), city_name_get(pCity));
1097     len += 1;  /* External entry from current production */
1098   } else {
1099     fc_snprintf(cBuf, sizeof(cBuf), "%s", global_worklist_name(gwl));
1100   }
1101 
1102   pStr = create_str16_from_char(cBuf, adj_font(12));
1103   pStr->style |= (TTF_STYLE_BOLD|SF_CENTER);
1104 
1105   pBuf = create_iconlabel(NULL, pWindow->dst, pStr, WF_RESTORE_BACKGROUND);
1106 
1107   add_to_gui_list(ID_LABEL, pBuf);
1108   /* --------------------------- */
1109 
1110   fc_snprintf(cBuf, sizeof(cBuf),
1111               /* TRANS: length of worklist */
1112               PL_("( %d entry )", "( %d entries )", len), len);
1113   pStr = create_str16_from_char(cBuf, adj_font(10));
1114   pStr->bgcol = (SDL_Color) {0, 0, 0, 0};
1115   pBuf = create_iconlabel(NULL, pWindow->dst, pStr, WF_RESTORE_BACKGROUND);
1116   pEditor->pWorkList_Counter = pBuf;
1117   add_to_gui_list(ID_LABEL, pBuf);
1118   /* --------------------------- */
1119 
1120   /* create production proggres label or rename worklist edit */
1121   if(pCity) {
1122     /* count == cost */
1123     /* turns == progress */
1124     const char *name = city_production_name_translation(pCity);
1125     bool gold_prod = city_production_has_flag(pCity, IF_GOLD);
1126 
1127     count = city_production_build_shield_cost(pCity);
1128 
1129     if (gold_prod) {
1130       int gold = MAX(0, pCity->surplus[O_SHIELD]);
1131 
1132       fc_snprintf(cBuf, sizeof(cBuf),
1133                   PL_("%s\n%d gold per turn",
1134                       "%s\n%d gold per turn", gold),
1135                   name, gold);
1136     } else {
1137       if (pCity->shield_stock < count) {
1138         turns = city_production_turns_to_build(pCity, TRUE);
1139         if (turns == 999) {
1140           fc_snprintf(cBuf, sizeof(cBuf), _("%s\nblocked!"), name);
1141         } else {
1142           fc_snprintf(cBuf, sizeof(cBuf), _("%s\n%d %s"),
1143                       name, turns, PL_("turn", "turns", turns));
1144         }
1145       } else {
1146         fc_snprintf(cBuf, sizeof(cBuf), _("%s\nfinished!"), name);
1147       }
1148     }
1149     pStr = create_str16_from_char(cBuf, adj_font(10));
1150     pStr->style |= SF_CENTER;
1151     pBuf = create_iconlabel(NULL, pWindow->dst, pStr, WF_RESTORE_BACKGROUND);
1152 
1153     pEditor->pProduction_Name = pBuf;
1154     add_to_gui_list(ID_LABEL, pBuf);
1155 
1156     pIcon = get_progress_icon(pCity->shield_stock, count, &turns);
1157 
1158     if (!gold_prod) {
1159       fc_snprintf(cBuf, sizeof(cBuf), "%d%%" , turns);
1160     } else {
1161       fc_snprintf(cBuf, sizeof(cBuf), "-");
1162     }
1163     pStr = create_str16_from_char(cBuf, adj_font(12));
1164     pStr->style |= (TTF_STYLE_BOLD|SF_CENTER);
1165 
1166     pBuf = create_iconlabel(pIcon, pWindow->dst, pStr,
1167                             (WF_RESTORE_BACKGROUND|WF_ICON_CENTER|WF_FREE_THEME));
1168 
1169     pIcon = NULL;
1170     turns = 0;
1171     pEditor->pProduction_Progres = pBuf;
1172     add_to_gui_list(ID_LABEL, pBuf);
1173   } else {
1174     pBuf = create_edit_from_chars(NULL, pWindow->dst,
1175                                   global_worklist_name(gwl), adj_font(10),
1176                                   adj_size(120), WF_RESTORE_BACKGROUND);
1177     pBuf->action = rename_worklist_editor_callback;
1178     set_wstate(pBuf, FC_WS_NORMAL);
1179 
1180     add_to_gui_list(ID_EDIT, pBuf);
1181   }
1182 
1183   /* --------------------------- */
1184   /* Commit Widget */
1185   pBuf = create_themeicon(current_theme->OK_Icon, pWindow->dst, WF_RESTORE_BACKGROUND);
1186 
1187   pBuf->action = ok_worklist_editor_callback;
1188   set_wstate(pBuf, FC_WS_NORMAL);
1189   pBuf->key = SDLK_RETURN;
1190 
1191   add_to_gui_list(ID_BUTTON, pBuf);
1192   /* --------------------------- */
1193   /* Cancel Widget */
1194   pBuf = create_themeicon(current_theme->CANCEL_Icon, pWindow->dst,
1195                           WF_RESTORE_BACKGROUND);
1196 
1197   pBuf->action = popdown_worklist_editor_callback;
1198   set_wstate(pBuf, FC_WS_NORMAL);
1199   pBuf->key = SDLK_ESCAPE;
1200 
1201   add_to_gui_list(ID_BUTTON, pBuf);
1202   /* --------------------------- */
1203   /* work list */
1204 
1205   /*
1206      pWidget->data filed will contains position of target in worklist all
1207      action on worklist (swap/romove/add) must correct this fields
1208 
1209      Production Widget Label in worklist Widget list
1210      will have this field NULL
1211   */
1212 
1213   pEditor->pWork = fc_calloc(1, sizeof(struct ADVANCED_DLG));
1214 
1215   pEditor->pWork->pScroll = fc_calloc(1, sizeof(struct ScrollBar));
1216   pEditor->pWork->pScroll->count = 0;
1217   pEditor->pWork->pScroll->active = MAX_LEN_WORKLIST;
1218   pEditor->pWork->pScroll->step = 1;
1219 
1220 /* FIXME: this should replace the 4 lines above, but
1221  *        pEditor->pWork->pEndWidgetList is not set yet */
1222 #if 0
1223   create_vertical_scrollbar(pEditor->pWork, 1, MAX_LEN_WORKLIST, TRUE, TRUE);
1224 #endif
1225 
1226   if(pCity) {
1227    /* Production Widget Label */
1228     pStr = create_str16_from_char(city_production_name_translation(pCity), adj_font(10));
1229     turns = city_production_build_shield_cost(pCity);
1230     pStr->style |= SF_CENTER;
1231     pBuf = create_iconlabel(NULL, pWindow->dst, pStr, WF_RESTORE_BACKGROUND);
1232 
1233     set_wstate(pBuf, FC_WS_NORMAL);
1234     pBuf->action = worklist_editor_item_callback;
1235 
1236     add_to_gui_list(MAX_ID - cid_encode(pCity->production), pBuf);
1237 
1238     pEditor->pWork->pEndWidgetList = pBuf;
1239     pEditor->pWork->pBeginWidgetList = pBuf;
1240     pEditor->pWork->pEndActiveWidgetList = pEditor->pWork->pEndWidgetList;
1241     pEditor->pWork->pBeginActiveWidgetList = pEditor->pWork->pBeginWidgetList;
1242     pEditor->pWork->pScroll->count++;
1243   }
1244 
1245   pLast = pBuf;
1246   pEditor->pDock = pBuf;
1247 
1248   /* create Widget Labels of worklist entries */
1249 
1250   count = 0;
1251 
1252   worklist_iterate(&pEditor->worklist_copy, prod) {
1253 
1254     if(VUT_UTYPE == prod.kind) {
1255       pStr = create_str16_from_char(utype_name_translation(prod.value.utype),
1256                                     adj_font(10));
1257     } else {
1258       pStr = create_str16_from_char(city_improvement_name_translation(pCity,
1259                                                            prod.value.building),
1260                                     adj_font(10));
1261     }
1262     pStr->style |= SF_CENTER;
1263     pBuf = create_iconlabel(NULL, pWindow->dst, pStr,
1264 				(WF_RESTORE_BACKGROUND|WF_FREE_DATA));
1265 
1266     set_wstate(pBuf, FC_WS_NORMAL);
1267     pBuf->action = worklist_editor_item_callback;
1268 
1269     pBuf->data.ptr = fc_calloc(1, sizeof(int));
1270     *((int *)pBuf->data.ptr) = count;
1271 
1272     add_to_gui_list(MAX_ID - cid_encode(prod), pBuf);
1273 
1274     count++;
1275 
1276     if(count > pEditor->pWork->pScroll->active - 1) {
1277       set_wflag(pBuf, WF_HIDDEN);
1278   }
1279 
1280   } worklist_iterate_end;
1281 
1282   if(count) {
1283     if(!pCity) {
1284       pEditor->pWork->pEndWidgetList = pLast->prev;
1285       pEditor->pWork->pEndActiveWidgetList = pEditor->pWork->pEndWidgetList;
1286     }
1287     pEditor->pWork->pBeginWidgetList = pBuf;
1288     pEditor->pWork->pBeginActiveWidgetList = pEditor->pWork->pBeginWidgetList;
1289   } else {
1290     if(!pCity) {
1291       pEditor->pWork->pEndWidgetList = pLast;
1292     }
1293     pEditor->pWork->pBeginWidgetList = pLast;
1294   }
1295 
1296 /* FIXME */
1297 #if 0
1298   pEditor->pWork->pActiveWidgetList = pEditor->pWork->pEndActiveWidgetList;
1299   create_vertical_scrollbar(pEditor->pWork, 1,
1300                            pEditor->pWork->pScroll->active, FALSE, TRUE);
1301   pEditor->pWork->pScroll->pUp_Left_Button->size.w = adj_size(122);
1302   pEditor->pWork->pScroll->pDown_Right_Button->size.w = adj_size(122);
1303 
1304   /* count: without production */
1305   if(count <= pEditor->pWork->pScroll->active + 1) {
1306     if(count > 0) {
1307       struct widget *pTmp = pLast;
1308       do {
1309         pTmp = pTmp->prev;
1310         clear_wflag(pTmp, WF_HIDDEN);
1311       } while (pTmp != pBuf);
1312     }
1313     hide_scrollbar(pEditor->pWork->pScroll);
1314   }
1315 #endif
1316 
1317   pEditor->pWork->pScroll->count += count;
1318   pLast = pEditor->pWork->pBeginWidgetList;
1319 
1320   /* --------------------------- */
1321   /* global worklists */
1322   if (pCity) {
1323     count = 0;
1324 
1325     global_worklists_iterate(iter_gwl) {
1326       pBuf = create_iconlabel_from_chars(NULL, pWindow->dst,
1327                                          global_worklist_name(iter_gwl),
1328                                          adj_font(10),
1329                                          WF_RESTORE_BACKGROUND);
1330       set_wstate(pBuf, FC_WS_NORMAL);
1331       add_to_gui_list(MAX_ID - global_worklist_id(iter_gwl), pBuf);
1332       pBuf->string16->style |= SF_CENTER;
1333       pBuf->action = global_worklist_callback;
1334       pBuf->string16->fgcol = bg_color;
1335 
1336       count++;
1337 
1338       if (count > 4) {
1339         set_wflag(pBuf, WF_HIDDEN);
1340       }
1341     } global_worklists_iterate_end;
1342 
1343     if(count) {
1344       pEditor->pGlobal = fc_calloc(1, sizeof(struct ADVANCED_DLG));
1345       pEditor->pGlobal->pEndWidgetList = pLast->prev;
1346       pEditor->pGlobal->pEndActiveWidgetList = pEditor->pGlobal->pEndWidgetList;
1347       pEditor->pGlobal->pBeginWidgetList = pBuf;
1348       pEditor->pGlobal->pBeginActiveWidgetList = pEditor->pGlobal->pBeginWidgetList;
1349 
1350       if(count > 6) {
1351         pEditor->pGlobal->pActiveWidgetList = pEditor->pGlobal->pEndActiveWidgetList;
1352 
1353         create_vertical_scrollbar(pEditor->pGlobal, 1, 4, FALSE, TRUE);
1354 	pEditor->pGlobal->pScroll->pUp_Left_Button->size.w = adj_size(122);
1355 	pEditor->pGlobal->pScroll->pDown_Right_Button->size.w = adj_size(122);
1356       } else {
1357 	struct widget *pTmp = pLast;
1358 	do {
1359 	  pTmp = pTmp->prev;
1360 	  clear_wflag(pTmp, WF_HIDDEN);
1361 	} while (pTmp != pBuf);
1362       }
1363 
1364       pLast = pEditor->pGlobal->pBeginWidgetList;
1365     }
1366   }
1367   /* ----------------------------- */
1368   count = 0;
1369   /* Targets units and imprv. to build */
1370   pStr = create_string16(NULL, 0, adj_font(10));
1371   pStr->style |= (SF_CENTER|TTF_STYLE_BOLD);
1372   pStr->bgcol = (SDL_Color) {0, 0, 0, 0};
1373 
1374   improvement_iterate(pImprove) {
1375     can_build = can_player_build_improvement_now(client.conn.playing, pImprove);
1376     can_eventually_build =
1377 	can_player_build_improvement_later(client.conn.playing, pImprove);
1378 
1379     /* If there's a city, can the city build the improvement? */
1380     if (pCity) {
1381       can_build = can_build && can_city_build_improvement_now(pCity, pImprove);
1382       can_eventually_build = can_eventually_build &&
1383 	  can_city_build_improvement_later(pCity, pImprove);
1384     }
1385 
1386     if ((advanced_tech && can_eventually_build) ||
1387 	(!advanced_tech && can_build)) {
1388 
1389       pIcon = crop_rect_from_surface(pMain, NULL);
1390 
1391       fc_snprintf(cBuf, sizeof(cBuf), "%s", improvement_name_translation(pImprove));
1392       copy_chars_to_string16(pStr, cBuf);
1393       pStr->style |= TTF_STYLE_BOLD;
1394 
1395       pText_Name = create_text_surf_smaller_that_w(pStr, pIcon->w - 4);
1396 
1397       if (is_wonder(pImprove)) {
1398         if (improvement_obsolete(client.conn.playing, pImprove, pCity)) {
1399           state = _("Obsolete");
1400         } else if (is_great_wonder(pImprove)) {
1401           if (great_wonder_is_built(pImprove)) {
1402             state = _("Built");
1403           } else if (great_wonder_is_destroyed(pImprove)) {
1404             state = _("Destroyed");
1405           } else {
1406             state = _("Great Wonder");
1407           }
1408         } else if (is_small_wonder(pImprove)) {
1409           if (small_wonder_is_built(client.conn.playing, pImprove)) {
1410             state = _("Built");
1411           } else {
1412             state = _("Small Wonder");
1413           }
1414         }
1415       } else {
1416         state = NULL;
1417       }
1418 
1419       if (pCity) {
1420         if (!improvement_has_flag(pImprove, IF_GOLD)) {
1421           struct universal univ = cid_production(cid_encode_building(pImprove));
1422 
1423           turns = city_turns_to_build(pCity, &univ, TRUE);
1424 
1425           if (turns == FC_INFINITY) {
1426             if (state) {
1427               fc_snprintf(cBuf, sizeof(cBuf), _("(%s)\n%d/%d %s\n%s"),
1428                           state, pCity->shield_stock,
1429                           impr_build_shield_cost(pImprove),
1430                           PL_("shield", "shields",
1431                               impr_build_shield_cost(pImprove)),
1432                           _("never"));
1433             } else {
1434               fc_snprintf(cBuf, sizeof(cBuf), _("%d/%d %s\n%s"),
1435                           pCity->shield_stock, impr_build_shield_cost(pImprove),
1436                           PL_("shield", "shields",
1437                               impr_build_shield_cost(pImprove)), _("never"));
1438             }
1439           } else {
1440             if (state) {
1441               fc_snprintf(cBuf, sizeof(cBuf), _("(%s)\n%d/%d %s\n%d %s"),
1442                           state, pCity->shield_stock,
1443                           impr_build_shield_cost(pImprove),
1444                           PL_("shield", "shields",
1445                               impr_build_shield_cost(pImprove)),
1446                           turns, PL_("turn", "turns", turns));
1447             } else {
1448               fc_snprintf(cBuf, sizeof(cBuf), _("%d/%d %s\n%d %s"),
1449                           pCity->shield_stock, impr_build_shield_cost(pImprove),
1450                           PL_("shield", "shields",
1451                               impr_build_shield_cost(pImprove)),
1452                           turns, PL_("turn", "turns", turns));
1453             }
1454           }
1455         } else {
1456           /* capitalization */
1457           int gold = MAX(0, pCity->surplus[O_SHIELD]);
1458 
1459           fc_snprintf(cBuf, sizeof(cBuf), PL_("%d gold per turn",
1460                                               "%d gold per turn", gold),
1461                       gold);
1462         }
1463       } else {
1464         /* non city mode */
1465         if (!improvement_has_flag(pImprove, IF_GOLD)) {
1466           if (state) {
1467             fc_snprintf(cBuf, sizeof(cBuf), _("(%s)\n%d %s"),
1468 			state, impr_build_shield_cost(pImprove),
1469 			PL_("shield", "shields",
1470 			    impr_build_shield_cost(pImprove)));
1471           } else {
1472 	    fc_snprintf(cBuf, sizeof(cBuf), _("%d %s"),
1473 			impr_build_shield_cost(pImprove),
1474 			PL_("shield", "shields",
1475 			    impr_build_shield_cost(pImprove)));
1476           }
1477         } else {
1478           fc_snprintf(cBuf, sizeof(cBuf), _("shields into gold"));
1479         }
1480       }
1481 
1482       copy_chars_to_string16(pStr, cBuf);
1483       pStr->style &= ~TTF_STYLE_BOLD;
1484 
1485       pText = create_text_surf_from_str16(pStr);
1486 
1487       /*-----------------*/
1488 
1489       pZoom = get_building_surface(pImprove);
1490       pZoom = zoomSurface(pZoom, DEFAULT_ZOOM * ((float)54 / pZoom->w), DEFAULT_ZOOM * ((float)54 / pZoom->w), 1);
1491       dst.x = (pIcon->w - pZoom->w)/2;
1492       dst.y = (pIcon->h/2 - pZoom->h)/2;
1493       alphablit(pZoom, NULL, pIcon, &dst);
1494       dst.y += pZoom->h;
1495       FREESURFACE(pZoom);
1496 
1497       dst.x = (pIcon->w - pText_Name->w)/2;
1498       dst.y += ((pIcon->h - dst.y) - (pText_Name->h + pText->h))/2;
1499       alphablit(pText_Name, NULL, pIcon, &dst);
1500 
1501       dst.x = (pIcon->w - pText->w)/2;
1502       dst.y += pText_Name->h;
1503       alphablit(pText, NULL, pIcon, &dst);
1504 
1505       FREESURFACE(pText);
1506       FREESURFACE(pText_Name);
1507 
1508       pBuf = create_icon2(pIcon, pWindow->dst,
1509     				WF_RESTORE_BACKGROUND|WF_FREE_THEME);
1510       set_wstate(pBuf, FC_WS_NORMAL);
1511 
1512       widget_w = MAX(widget_w, pBuf->size.w);
1513       widget_h = MAX(widget_h, pBuf->size.h);
1514 
1515       pBuf->data.city = pCity;
1516       add_to_gui_list(MAX_ID - improvement_number(pImprove), pBuf);
1517       pBuf->action = worklist_editor_targets_callback;
1518 
1519       if(count > (TARGETS_ROW * TARGETS_COL - 1)) {
1520         set_wflag(pBuf, WF_HIDDEN);
1521       }
1522       count++;
1523     }
1524   } improvement_iterate_end;
1525 
1526   /* ------------------------------ */
1527 
1528   unit_type_iterate(un) {
1529     can_build = can_player_build_unit_now(client.conn.playing, un);
1530     can_eventually_build =
1531 	can_player_build_unit_later(client.conn.playing, un);
1532 
1533     /* If there's a city, can the city build the unit? */
1534     if (pCity) {
1535       can_build = can_build && can_city_build_unit_now(pCity, un);
1536       can_eventually_build = can_eventually_build &&
1537 	  		can_city_build_unit_later(pCity, un);
1538     }
1539 
1540     if ((advanced_tech && can_eventually_build)
1541         || (!advanced_tech && can_build)) {
1542 
1543       punittype = un;
1544 
1545       pIcon = crop_rect_from_surface(pMain, NULL);
1546 
1547       fc_snprintf(cBuf, sizeof(cBuf), "%s", utype_name_translation(un));
1548 
1549       copy_chars_to_string16(pStr, cBuf);
1550       pStr->style |= TTF_STYLE_BOLD;
1551       pText_Name = create_text_surf_smaller_that_w(pStr, pIcon->w - 4);
1552 
1553       if (pCity) {
1554         struct universal univ;
1555 
1556         univ = cid_production(cid_encode_unit(un));
1557         turns = city_turns_to_build(pCity, &univ, TRUE);
1558         if (turns == FC_INFINITY) {
1559           fc_snprintf(cBuf, sizeof(cBuf),
1560                       _("(%d/%d/%s)\n%d/%d %s\nnever"),
1561                       punittype->attack_strength,
1562                       punittype->defense_strength,
1563                       move_points_text(punittype->move_rate, TRUE),
1564                       pCity->shield_stock, utype_build_shield_cost(un),
1565                       PL_("shield", "shields", utype_build_shield_cost(un)));
1566         } else {
1567           fc_snprintf(cBuf, sizeof(cBuf),
1568                       _("(%d/%d/%s)\n%d/%d %s\n%d %s"),
1569                       punittype->attack_strength,
1570                       punittype->defense_strength,
1571                       move_points_text(punittype->move_rate, TRUE),
1572                       pCity->shield_stock, utype_build_shield_cost(un),
1573                       PL_("shield", "shields", utype_build_shield_cost(un)),
1574                       turns, PL_("turn", "turns", turns));
1575         }
1576       } else {
1577         fc_snprintf(cBuf, sizeof(cBuf),
1578                     _("(%d/%d/%s)\n%d %s"),
1579                     punittype->attack_strength,
1580                     punittype->defense_strength,
1581                     move_points_text(punittype->move_rate, TRUE),
1582                     utype_build_shield_cost(un),
1583                     PL_("shield", "shields", utype_build_shield_cost(un)));
1584       }
1585 
1586       copy_chars_to_string16(pStr, cBuf);
1587       pStr->style &= ~TTF_STYLE_BOLD;
1588 
1589       pText = create_text_surf_from_str16(pStr);
1590 
1591       pZoom = adj_surf(get_unittype_surface(un, direction8_invalid()));
1592       dst.x = (pIcon->w - pZoom->w)/2;
1593       dst.y = (pIcon->h/2 - pZoom->h)/2;
1594       alphablit(pZoom, NULL, pIcon, &dst);
1595       FREESURFACE(pZoom);
1596 
1597       dst.x = (pIcon->w - pText_Name->w)/2;
1598       dst.y = pIcon->h/2 + (pIcon->h/2 - (pText_Name->h + pText->h))/2;
1599       alphablit(pText_Name, NULL, pIcon, &dst);
1600 
1601       dst.x = (pIcon->w - pText->w)/2;
1602       dst.y += pText_Name->h;
1603       alphablit(pText, NULL, pIcon, &dst);
1604 
1605       FREESURFACE(pText);
1606       FREESURFACE(pText_Name);
1607 
1608       pBuf = create_icon2(pIcon, pWindow->dst,
1609     				WF_RESTORE_BACKGROUND|WF_FREE_THEME);
1610       set_wstate(pBuf, FC_WS_NORMAL);
1611 
1612       widget_w = MAX(widget_w, pBuf->size.w);
1613       widget_h = MAX(widget_h, pBuf->size.h);
1614 
1615       pBuf->data.city = pCity;
1616       add_to_gui_list(MAX_ID - cid_encode_unit(un), pBuf);
1617       pBuf->action = worklist_editor_targets_callback;
1618 
1619       if(count > (TARGETS_ROW * TARGETS_COL - 1)) {
1620         set_wflag(pBuf, WF_HIDDEN);
1621       }
1622       count++;
1623 
1624     }
1625   } unit_type_iterate_end;
1626 
1627   pEditor->pTargets = fc_calloc(1, sizeof(struct ADVANCED_DLG));
1628 
1629   pEditor->pTargets->pEndWidgetList = pLast->prev;
1630   pEditor->pTargets->pBeginWidgetList = pBuf;
1631   pEditor->pTargets->pEndActiveWidgetList = pEditor->pTargets->pEndWidgetList;
1632   pEditor->pTargets->pBeginActiveWidgetList = pEditor->pTargets->pBeginWidgetList;
1633   pEditor->pTargets->pActiveWidgetList = pEditor->pTargets->pEndActiveWidgetList;
1634 
1635   /* --------------- */
1636   if(count > (TARGETS_ROW * TARGETS_COL - 1)) {
1637     count = create_vertical_scrollbar(pEditor->pTargets,
1638 		    		TARGETS_COL, TARGETS_ROW, TRUE, TRUE);
1639   } else {
1640     count = 0;
1641   }
1642   /* --------------- */
1643 
1644   pEditor->pBeginWidgetList = pEditor->pTargets->pBeginWidgetList;
1645 
1646   /* Window */
1647   area.w = MAX(area.w, widget_w * TARGETS_COL + count + adj_size(130));
1648   area.h = MAX(area.h, widget_h * TARGETS_ROW);
1649 
1650   pIcon = theme_get_background(theme, BACKGROUND_WLDLG);
1651   if(resize_window(pWindow, pIcon, NULL,
1652                    (pWindow->size.w - pWindow->area.w) + area.w,
1653                    (pWindow->size.h - pWindow->area.h) + area.h)) {
1654     FREESURFACE(pIcon);
1655   }
1656 
1657   area = pWindow->area;
1658 
1659   /* Backgrounds */
1660   dst.x = area.x;
1661   dst.y = area.y;
1662   dst.w = adj_size(130);
1663   dst.h = adj_size(145);
1664 
1665   SDL_FillRect(pWindow->theme, &dst,
1666     map_rgba(pWindow->theme->format, *get_theme_color(COLOR_THEME_BACKGROUND)));
1667   putframe(pWindow->theme,
1668            dst.x, dst.y, dst.x + dst.w - 1, dst.y + dst.h - 1,
1669            get_theme_color(COLOR_THEME_WLDLG_FRAME));
1670   putframe(pWindow->theme,
1671            dst.x + 2, dst.y + 2, dst.x + dst.w - 3, dst.y + dst.h - 3,
1672            get_theme_color(COLOR_THEME_WLDLG_FRAME));
1673 
1674   dst.x = area.x;
1675   dst.y += dst.h + adj_size(2);
1676   dst.w = adj_size(130);
1677   dst.h = adj_size(228);
1678   SDL_FillRectAlpha(pWindow->theme, &dst, &bg_color2);
1679   putframe(pWindow->theme,
1680            dst.x, dst.y, dst.x + dst.w - 1, dst.y + dst.h - 1,
1681            get_theme_color(COLOR_THEME_WLDLG_FRAME));
1682 
1683   if(pEditor->pGlobal) {
1684     dst.x = area.x;
1685     dst.y += dst.h + adj_size(2);
1686     dst.w = adj_size(130);
1687     dst.h = pWindow->size.h - dst.y - adj_size(4);
1688 
1689     SDL_FillRect(pWindow->theme, &dst,
1690       map_rgba(pWindow->theme->format, *get_theme_color(COLOR_THEME_BACKGROUND)));
1691     putframe(pWindow->theme,
1692              dst.x, dst.y, dst.x + dst.w - 1, dst.y + dst.h - 1,
1693              get_theme_color(COLOR_THEME_WLDLG_FRAME));
1694     putframe(pWindow->theme,
1695              dst.x + adj_size(2), dst.y + adj_size(2),
1696              dst.x + dst.w - adj_size(3), dst.y + dst.h - adj_size(3),
1697              get_theme_color(COLOR_THEME_WLDLG_FRAME));
1698   }
1699 
1700   widget_set_position(pWindow,
1701                       (Main.screen->w - pWindow->size.w) / 2,
1702                       (Main.screen->h - pWindow->size.h) / 2);
1703 
1704   /* name */
1705   pBuf = pWindow->prev;
1706   pBuf->size.x = area.x + (adj_size(130) - pBuf->size.w)/2;
1707   pBuf->size.y = area.y + adj_size(4);
1708 
1709   /* size of worklist (without production) */
1710   pBuf = pBuf->prev;
1711   pBuf->size.x = area.x + (adj_size(130) - pBuf->size.w)/2;
1712   pBuf->size.y = pBuf->next->size.y + pBuf->next->size.h;
1713 
1714   if(pCity) {
1715     /* current build and proggrse bar */
1716     pBuf = pBuf->prev;
1717     pBuf->size.x = area.x + (adj_size(130) - pBuf->size.w)/2;
1718     pBuf->size.y = pBuf->next->size.y + pBuf->next->size.h + adj_size(5);
1719 
1720     pBuf = pBuf->prev;
1721     pBuf->size.x = area.x + (adj_size(130) - pBuf->size.w)/2;
1722     pBuf->size.y = pBuf->next->size.y + pBuf->next->size.h;
1723   } else {
1724     /* rename worklist */
1725     pBuf = pBuf->prev;
1726     pBuf->size.x = area.x + (adj_size(130) - pBuf->size.w)/2;
1727     pBuf->size.y = area.y + 1 + (adj_size(145) - pBuf->size.h)/2;
1728   }
1729 
1730   /* ok button */
1731   pBuf = pBuf->prev;
1732   pBuf->size.x = area.x + (adj_size(65) - pBuf->size.w)/2;
1733   pBuf->size.y = area.y + adj_size(135) - pBuf->size.h;
1734 
1735   /* exit button */
1736   pBuf = pBuf->prev;
1737   pBuf->size.x = area.x + adj_size(65) + (adj_size(65) - pBuf->size.w)/2;
1738   pBuf->size.y = area.y + adj_size(135) - pBuf->size.h;
1739 
1740   /* worklist */
1741   /* pEditor->pWork->pScroll->count: including production */
1742   if (len > 0) {
1743     /* FIXME */
1744     setup_vertical_widgets_position(1,
1745       area.x + adj_size(2), area.y + adj_size(152)/* +
1746 	((pEditor->pWork->pScroll->count > pEditor->pWork->pScroll->active + 2) ?
1747 	    pEditor->pWork->pScroll->pUp_Left_Button->size.h + 1 : 0)*/,
1748 	adj_size(126), 0, pEditor->pWork->pBeginWidgetList,
1749 		  pEditor->pWork->pEndWidgetList);
1750 
1751     setup_vertical_scrollbar_area(pEditor->pWork->pScroll,
1752 	area.x + adj_size(2),
1753     	area.y + adj_size(152),
1754     	adj_size(225), FALSE);
1755   }
1756 
1757   /* global worklists */
1758   if(pEditor->pGlobal) {
1759     setup_vertical_widgets_position(1,
1760       area.x + adj_size(4),
1761       area.y + adj_size(384) +
1762 	(pEditor->pGlobal->pScroll ?
1763 	    pEditor->pGlobal->pScroll->pUp_Left_Button->size.h + 1 : 0),
1764 		adj_size(122), 0, pEditor->pGlobal->pBeginWidgetList,
1765 		  	pEditor->pGlobal->pEndWidgetList);
1766 
1767     if(pEditor->pGlobal->pScroll) {
1768       setup_vertical_scrollbar_area(pEditor->pGlobal->pScroll,
1769 	area.x + adj_size(4),
1770     	area.y + adj_size(384),
1771     	adj_size(93), FALSE);
1772     }
1773 
1774   }
1775 
1776   /* Targets */
1777   setup_vertical_widgets_position(TARGETS_COL,
1778 	area.x + adj_size(130), area.y,
1779 	  0, 0, pEditor->pTargets->pBeginWidgetList,
1780 			  pEditor->pTargets->pEndWidgetList);
1781 
1782   if(pEditor->pTargets->pScroll) {
1783     setup_vertical_scrollbar_area(pEditor->pTargets->pScroll,
1784 	area.x + area.w,
1785     	area.y + 1,
1786     	area.h - 1, TRUE);
1787 
1788   }
1789 
1790   /* ----------------------------------- */
1791   FREESTRING16(pStr);
1792   FREESURFACE(pMain);
1793 
1794   redraw_group(pEditor->pBeginWidgetList, pWindow, 0);
1795   widget_flush(pWindow);
1796 }
1797 
popdown_worklist_editor(void)1798 void popdown_worklist_editor(void)
1799 {
1800   if (pEditor) {
1801     popdown_window_group_dialog(pEditor->pBeginWidgetList,
1802                                             pEditor->pEndWidgetList);
1803     FC_FREE(pEditor->pTargets->pScroll);
1804     FC_FREE(pEditor->pTargets);
1805 
1806     FC_FREE(pEditor->pWork->pScroll);
1807     FC_FREE(pEditor->pWork);
1808 
1809     if (pEditor->pGlobal) {
1810       FC_FREE(pEditor->pGlobal->pScroll);
1811       FC_FREE(pEditor->pGlobal);
1812     }
1813 
1814     if (city_dialog_is_open(pEditor->pCity)) {
1815       enable_city_dlg_widgets();
1816     }
1817 
1818     FC_FREE(pEditor);
1819 
1820     flush_dirty();
1821   }
1822 }
1823