Freeciv-3.1
Loading...
Searching...
No Matches
wldlg.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include <stdlib.h>
19#include <string.h>
20
21#include <gtk/gtk.h>
22#include <gdk/gdkkeysyms.h>
23
24/* utility */
25#include "fcintl.h"
26#include "log.h"
27#include "mem.h"
28#include "support.h"
29
30/* common */
31#include "city.h"
32#include "packets.h"
33#include "worklist.h"
34
35/* client */
36#include "citydlg_common.h"
37#include "client_main.h"
38#include "climisc.h"
39#include "global_worklist.h"
40#include "options.h"
41#include "text.h"
42#include "tilespec.h"
43
44/* client/gui-gtk-3.0 */
45#include "canvas.h"
46#include "citydlg.h"
47#include "graphics.h"
48#include "gui_main.h"
49#include "gui_stuff.h"
50#include "helpdlg.h"
51#include "inputdlg.h"
52
53#include "wldlg.h"
54
55static GtkWidget *worklists_shell;
56static GtkWidget *worklists_list;
57
58enum {
63};
64
65static GtkListStore *worklists_store;
66
67static int max_unit_height = -1, max_unit_width = -1;
68
69static void reset_global_worklist(GtkWidget *editor,
70 struct global_worklist *pgwl);
71static void popup_worklist(struct global_worklist *pgwl);
72static void popdown_worklist(struct global_worklist *pgwl);
73static void dst_row_callback(GtkTreeView *view, GtkTreePath *path,
74 GtkTreeViewColumn *col, gpointer data);
75
76/************************************************************************/
80{
81 max_unit_height = -1;
82 max_unit_width = -1;
83}
84
85/************************************************************************/
88static void update_max_unit_size(void)
89{
92
94 int x1, x2, y1, y2;
96 direction8_invalid());
97
98 sprite_get_bounding_box(sprite, &x1, &y1, &x2, &y2);
102}
103
104/************************************************************************/
107static void worklists_destroy_callback(GtkWidget *w, gpointer data)
108{
109 worklists_shell = NULL;
110}
111
112/************************************************************************/
116{
117 GtkTreeIter it;
118
119 gtk_list_store_clear(worklists_store);
121 gtk_list_store_append(worklists_store, &it);
122
123 gtk_list_store_set(worklists_store, &it,
124 0, global_worklist_name(pgwl),
125 1, global_worklist_id(pgwl),
126 -1);
128}
129
130/************************************************************************/
133static void worklists_response(GtkWidget *w, gint response)
134{
135 struct global_worklist *pgwl;
136 int id;
137 GtkTreeSelection *selection;
138 GtkTreeModel *model;
139 GtkTreeIter it;
140
141 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(worklists_list));
142
143 if (gtk_tree_selection_get_selected(selection, &model, &it)) {
144 gtk_tree_model_get(model, &it, 1, &id, -1);
145 pgwl = global_worklist_by_id(id);
146 } else {
147 pgwl = NULL;
148 id = -1;
149 }
150
151 switch (response) {
152 case WORKLISTS_NEW:
153 global_worklist_new(_("new"));
155 return;
156
157 case WORKLISTS_DELETE:
158 if (!pgwl) {
159 return;
160 }
161
162 popdown_worklist(pgwl);
165 return;
166
168 if (!pgwl) {
169 return;
170 }
171
172 popup_worklist(pgwl);
173 return;
174
175 default:
176 gtk_widget_destroy(worklists_shell);
177 return;
178 }
179}
180
181/************************************************************************/
184static void cell_edited(GtkCellRendererText *cell,
185 const gchar *spath,
186 const gchar *text, gpointer data)
187{
188 GtkTreePath *path;
189 GtkTreeIter it;
190 struct global_worklist *pgwl;
191 int id;
192
193 path = gtk_tree_path_new_from_string(spath);
194 gtk_tree_model_get_iter(GTK_TREE_MODEL(worklists_store), &it, path);
195 gtk_tree_path_free(path);
196
197 gtk_tree_model_get(GTK_TREE_MODEL(worklists_store), &it, 1, &id, -1);
198 pgwl = global_worklist_by_id(id);
199
200 if (!pgwl) {
201 gtk_list_store_remove(worklists_store, &it);
202 return;
203 }
204
205 global_worklist_set_name(pgwl, text);
206 gtk_list_store_set(worklists_store, &it, 0, text, -1);
207}
208
209/************************************************************************/
212static GtkWidget *create_worklists_report(void)
213{
214 GtkWidget *shell, *list;
215 GtkWidget *vbox, *label, *sw;
216 GtkCellRenderer *rend;
217
218 shell = gtk_dialog_new_with_buttons(_("Edit worklists"),
219 NULL,
220 0,
221 GTK_STOCK_NEW,
223 GTK_STOCK_DELETE,
225 GTK_STOCK_PROPERTIES,
227 GTK_STOCK_CLOSE,
229 NULL);
231 gtk_window_set_position(GTK_WINDOW(shell), GTK_WIN_POS_MOUSE);
232
233 g_signal_connect(shell, "response",
234 G_CALLBACK(worklists_response), NULL);
235 g_signal_connect(shell, "destroy",
236 G_CALLBACK(worklists_destroy_callback), NULL);
237
238 vbox = gtk_grid_new();
239 gtk_grid_set_row_spacing(GTK_GRID(vbox), 2);
240 gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
241 GTK_ORIENTATION_VERTICAL);
242 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(shell))), vbox);
243
244 worklists_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
245
246 list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(worklists_store));
247 gtk_widget_set_hexpand(list, TRUE);
248 gtk_widget_set_vexpand(list, TRUE);
249
250 g_object_unref(worklists_store);
251 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE);
252
254
255 rend = gtk_cell_renderer_text_new();
256 g_object_set(rend, "editable", TRUE, NULL);
257 g_signal_connect(rend, "edited",
258 G_CALLBACK(cell_edited), NULL);
259 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(list), -1, NULL,
260 rend, "text", 0, NULL);
261
262 sw = gtk_scrolled_window_new(NULL, NULL);
263 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(sw), 200);
264 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
265 GTK_SHADOW_ETCHED_IN);
266 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
267 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
268 gtk_container_add(GTK_CONTAINER(sw), list);
269
270 label = g_object_new(GTK_TYPE_LABEL,
271 "use-underline", TRUE,
272 "mnemonic-widget", list,
273 "label", _("_Worklists:"),
274 "xalign", 0.0, "yalign", 0.5, NULL);
275
276 gtk_container_add(GTK_CONTAINER(vbox), label);
277 gtk_container_add(GTK_CONTAINER(vbox), sw);
278 gtk_widget_show_all(vbox);
279
280 return shell;
281}
282
283/************************************************************************/
287{
288 if (!worklists_shell) {
290
292 }
293
294 gtk_window_present(GTK_WINDOW(worklists_shell));
295}
296
297
298
299/****************************************************************************
300 ...
301****************************************************************************/
304 struct city *pcity;
305
306 GtkWidget *editor;
307
308 GtkListStore *src, *dst;
309 GtkWidget *src_view, *dst_view;
310 GtkTreeSelection *src_selection, *dst_selection;
311
312 GtkTreeViewColumn *src_col, *dst_col;
313
316
317 bool future;
318};
319
320static GHashTable *hash;
321
322static void commit_worklist(struct worklist_data *ptr);
323
324
325enum {
328
329static GtkTargetEntry wl_dnd_targets[] = {
330 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, TARGET_GTK_TREE_MODEL_ROW },
331};
332
333
334/************************************************************************/
337void add_worklist_dnd_target(GtkWidget *w)
338{
339 gtk_drag_dest_set(w, GTK_DEST_DEFAULT_ALL,
340 wl_dnd_targets, G_N_ELEMENTS(wl_dnd_targets),
341 GDK_ACTION_COPY);
342}
343
344/************************************************************************/
347static GtkWidget *get_worklist(int global_worklist_id)
348{
349 if (hash) {
350 gpointer ret;
351
352 ret = g_hash_table_lookup(hash, GINT_TO_POINTER(global_worklist_id));
353 return ret;
354 } else {
355 return NULL;
356 }
357}
358
359/************************************************************************/
362static void insert_worklist(int global_worklist_id, GtkWidget *editor)
363{
364 if (!hash) {
365 hash = g_hash_table_new(g_direct_hash, g_direct_equal);
366 }
367 g_hash_table_insert(hash, GINT_TO_POINTER(global_worklist_id), editor);
368}
369
370/************************************************************************/
374{
375 if (hash) {
376 g_hash_table_remove(hash, GINT_TO_POINTER(global_worklist_id));
377 }
378}
379
380/************************************************************************/
383static void popup_worklist(struct global_worklist *pgwl)
384{
385 GtkWidget *shell;
386
387 if (!(shell = get_worklist(global_worklist_id(pgwl)))) {
388 GtkWidget *editor;
389
390 shell = gtk_dialog_new_with_buttons(global_worklist_name(pgwl),
391 GTK_WINDOW(worklists_shell),
392 GTK_DIALOG_DESTROY_WITH_PARENT,
393 GTK_STOCK_CLOSE,
394 GTK_RESPONSE_CLOSE,
395 NULL);
396 gtk_window_set_role(GTK_WINDOW(shell), "worklist");
397 gtk_window_set_position(GTK_WINDOW(shell), GTK_WIN_POS_MOUSE);
398 g_signal_connect(shell, "response", G_CALLBACK(gtk_widget_destroy), NULL);
399 gtk_window_set_default_size(GTK_WINDOW(shell), 500, 400);
400
404
405 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(shell))), editor);
406 gtk_widget_show(editor);
407
409 }
410
411 gtk_window_present(GTK_WINDOW(shell));
412}
413
414/************************************************************************/
417static void popdown_worklist(struct global_worklist *pgwl)
418{
419 GtkWidget *shell;
420
421 if ((shell = get_worklist(global_worklist_id(pgwl)))) {
422 GtkWidget *parent;
423
424 parent = gtk_widget_get_toplevel(shell);
425 gtk_widget_destroy(parent);
426 }
427}
428
429/************************************************************************/
432static void worklist_destroy(GtkWidget *editor, gpointer data)
433{
434 struct worklist_data *ptr;
435
436 ptr = data;
437
438 if (ptr->global_worklist_id != -1) {
440 }
441
442 free(ptr);
443}
444
445/************************************************************************/
448static void menu_item_callback(GtkMenuItem *item, struct worklist_data *ptr)
449{
450 struct global_worklist *pgwl;
451 const struct worklist *pwl;
452 size_t i;
453
454 if (NULL == client.conn.playing) {
455 return;
456 }
457
458 pgwl = global_worklist_by_id(GPOINTER_TO_INT
459 (g_object_get_data(G_OBJECT(item), "id")));
460 if (!pgwl) {
461 return;
462 }
463 pwl = global_worklist_get(pgwl);
464
465 for (i = 0; i < (size_t) worklist_length(pwl); i++) {
466 GtkTreeIter it;
467 cid id;
468 char buf[8192];
469
470 id = cid_encode(pwl->entries[i]);
471
472 gtk_list_store_append(ptr->dst, &it);
473 gtk_list_store_set(ptr->dst, &it, 0, (gint) id, -1);
474 gtk_list_store_set(ptr->dst, &it, 0, (gint)id,
475 1, production_help(&(pwl->entries[i]),
476 buf, sizeof(buf)), -1);
477 }
478
479 commit_worklist(ptr);
480}
481
482/************************************************************************/
485static void popup_add_menu(GtkMenuShell *menu, gpointer data)
486{
487 GtkWidget *item;
488
489 gtk_container_foreach(GTK_CONTAINER(menu),
490 (GtkCallback) gtk_widget_destroy, NULL);
491
493 item = gtk_menu_item_new_with_label(global_worklist_name(pgwl));
494 g_object_set_data(G_OBJECT(item), "id",
495 GINT_TO_POINTER(global_worklist_id(pgwl)));
496 gtk_widget_show(item);
497
498 gtk_container_add(GTK_CONTAINER(menu), item);
499 g_signal_connect(item, "activate",
500 G_CALLBACK(menu_item_callback), data);
502
503 item = gtk_separator_menu_item_new();
504 gtk_widget_show(item);
505
506 gtk_container_add(GTK_CONTAINER(menu), item);
507
508 item = gtk_menu_item_new_with_mnemonic(_("Edit Global _Worklists"));
509 gtk_widget_show(item);
510
511 gtk_container_add(GTK_CONTAINER(menu), item);
512 g_signal_connect(item, "activate",
513 G_CALLBACK(popup_worklists_report), NULL);
514}
515
516/************************************************************************/
519static void help_callback(GtkWidget *w, gpointer data)
520{
521 struct worklist_data *ptr;
522 GtkTreeSelection *selection;
523 GtkTreeModel *model;
524 GtkTreeIter it;
525
526 ptr = data;
527 selection = ptr->src_selection;
528
529 if (gtk_tree_selection_get_selected(selection, &model, &it)) {
530 gint id;
531 struct universal target;
532
533 gtk_tree_model_get(model, &it, 0, &id, -1);
534 target = cid_decode(id);
535
536 if (VUT_UTYPE == target.kind) {
538 HELP_UNIT);
539 } else if (is_great_wonder(target.value.building)) {
542 } else {
545 }
546 } else {
548 }
549}
550
551/************************************************************************/
554static void change_callback(GtkWidget *w, gpointer data)
555{
556 struct worklist_data *ptr;
557 GtkTreeSelection *selection;
558 GtkTreeModel *model;
559 GtkTreeIter it;
560
561 ptr = data;
562 selection = ptr->src_selection;
563
564 if (gtk_tree_selection_get_selected(selection, &model, &it)) {
565 gint id;
566 struct universal univ;
567
568 gtk_tree_model_get(model, &it, 0, &id, -1);
569 univ = cid_production(id);
570 city_change_production(ptr->pcity, &univ);
571 }
572}
573
574/************************************************************************/
577static void future_callback(GtkToggleButton *toggle, gpointer data)
578{
579 struct worklist_data *ptr;
580
581 ptr = data;
582 ptr->future = !ptr->future;
583
585}
586
587/************************************************************************/
590static void queue_bubble_up(struct worklist_data *ptr)
591{
592 GtkTreePath *path;
593 GtkTreeViewColumn *col;
594 GtkTreeModel *model;
595
596 if (!gtk_widget_is_sensitive(ptr->dst_view)) {
597 return;
598 }
599
600 model = GTK_TREE_MODEL(ptr->dst);
601 gtk_tree_view_get_cursor(GTK_TREE_VIEW(ptr->dst_view), &path, &col);
602 if (path) {
603 GtkTreeIter it, it_prev;
604
605 if (gtk_tree_path_prev(path)) {
606 gtk_tree_model_get_iter(model, &it_prev, path);
607 it = it_prev;
608 gtk_tree_model_iter_next(model, &it);
609
610 gtk_list_store_swap(GTK_LIST_STORE(model), &it, &it_prev);
611
612 gtk_tree_view_set_cursor(GTK_TREE_VIEW(ptr->dst_view), path, col, FALSE);
613 commit_worklist(ptr);
614 }
615 }
616 gtk_tree_path_free(path);
617}
618
619/************************************************************************/
622static void queue_remove(struct worklist_data *ptr)
623{
624 GtkTreePath *path;
625 GtkTreeViewColumn *col;
626
627 gtk_tree_view_get_cursor(GTK_TREE_VIEW(ptr->dst_view), &path, &col);
628 if (path) {
629 dst_row_callback(GTK_TREE_VIEW(ptr->dst_view), path, col, ptr);
630 gtk_tree_path_free(path);
631 }
632}
633
634/************************************************************************/
637static void queue_bubble_down(struct worklist_data *ptr)
638{
639 GtkTreePath *path;
640 GtkTreeViewColumn *col;
641 GtkTreeModel *model;
642
643 if (!gtk_widget_is_sensitive(ptr->dst_view)) {
644 return;
645 }
646
647 model = GTK_TREE_MODEL(ptr->dst);
648 gtk_tree_view_get_cursor(GTK_TREE_VIEW(ptr->dst_view), &path, &col);
649 if (path) {
650 GtkTreeIter it, it_next;
651
652 gtk_tree_model_get_iter(model, &it, path);
653 it_next = it;
654 if (gtk_tree_model_iter_next(model, &it_next)) {
655 gtk_list_store_swap(GTK_LIST_STORE(model), &it, &it_next);
656
657 gtk_tree_path_next(path);
658 gtk_tree_view_set_cursor(GTK_TREE_VIEW(ptr->dst_view), path, col, FALSE);
659 commit_worklist(ptr);
660 }
661 }
662 gtk_tree_path_free(path);
663}
664
665/************************************************************************/
668static void queue_insert(struct worklist_data *ptr, bool prepend)
669{
670 GtkTreeModel *model;
671 GtkTreeIter it;
672 GtkTreePath *path;
673
674 GtkTreeModel *src_model, *dst_model;
675 GtkTreeIter src_it, dst_it;
676 gint i, ncols;
677
678 if (!gtk_widget_is_sensitive(ptr->dst_view)) {
679 return;
680 }
681
682 if (!gtk_tree_selection_get_selected(ptr->src_selection, &model, &it)) {
683 return;
684 }
685
686 path = gtk_tree_model_get_path(model, &it);
687
688 src_model = GTK_TREE_MODEL(ptr->src);
689 dst_model = GTK_TREE_MODEL(ptr->dst);
690
691 gtk_tree_model_get_iter(src_model, &src_it, path);
692 if (prepend) {
693 gtk_list_store_prepend(GTK_LIST_STORE(dst_model), &dst_it);
694 } else {
695 gtk_list_store_append(GTK_LIST_STORE(dst_model), &dst_it);
696 }
697
698 ncols = gtk_tree_model_get_n_columns(src_model);
699
700 for (i = 0; i < ncols; i++) {
701 GValue value = { 0, };
702
703 gtk_tree_model_get_value(src_model, &src_it, i, &value);
704 gtk_list_store_set_value(GTK_LIST_STORE(dst_model), &dst_it, i, &value);
705 }
706 commit_worklist(ptr);
707
708 gtk_tree_path_free(path);
709}
710
711/************************************************************************/
714static void queue_prepend(struct worklist_data *ptr)
715{
716 queue_insert(ptr, TRUE);
717}
718
719/************************************************************************/
722static void queue_append(struct worklist_data *ptr)
723{
724 queue_insert(ptr, FALSE);
725}
726
727/************************************************************************/
730static void src_row_callback(GtkTreeView *view, GtkTreePath *path,
731 GtkTreeViewColumn *col, gpointer data)
732{
733 struct worklist_data *ptr;
734 GtkTreeModel *src_model, *dst_model;
735 GtkTreeIter src_it, dst_it;
736 gint i, ncols;
737
738 ptr = data;
739
740 if (!gtk_widget_is_sensitive(ptr->dst_view)) {
741 return;
742 }
743
744 src_model = GTK_TREE_MODEL(ptr->src);
745 dst_model = GTK_TREE_MODEL(ptr->dst);
746
747 gtk_tree_model_get_iter(src_model, &src_it, path);
748 gtk_list_store_append(GTK_LIST_STORE(dst_model), &dst_it);
749
750 ncols = gtk_tree_model_get_n_columns(src_model);
751
752 for (i = 0; i < ncols; i++) {
753 GValue value = { 0, };
754
755 gtk_tree_model_get_value(src_model, &src_it, i, &value);
756 gtk_list_store_set_value(GTK_LIST_STORE(dst_model), &dst_it, i, &value);
757 }
758 commit_worklist(ptr);
759}
760
761/************************************************************************/
764static void dst_row_callback(GtkTreeView *view, GtkTreePath *path,
765 GtkTreeViewColumn *col, gpointer data)
766{
767 struct worklist_data *ptr;
768 GtkTreeModel *dst_model;
769 GtkTreeIter it;
770
771 ptr = data;
772 dst_model = GTK_TREE_MODEL(ptr->dst);
773
774 gtk_tree_model_get_iter(dst_model, &it, path);
775
776 gtk_list_store_remove(GTK_LIST_STORE(dst_model), &it);
777 commit_worklist(ptr);
778}
779
780/************************************************************************/
783static gboolean src_key_press_callback(GtkWidget *w, GdkEventKey *ev,
784 gpointer data)
785{
786 struct worklist_data *ptr;
787
788 ptr = data;
789
790 if (!gtk_widget_is_sensitive(ptr->dst_view)) {
791 return FALSE;
792 }
793
794 if ((ev->state & GDK_SHIFT_MASK) && ev->keyval == GDK_KEY_Insert) {
795 queue_prepend(ptr);
796 return TRUE;
797 } else if (ev->keyval == GDK_KEY_Insert) {
798 queue_append(ptr);
799 return TRUE;
800 } else {
801 return FALSE;
802 }
803}
804
805/************************************************************************/
808static gboolean dst_key_press_callback(GtkWidget *w, GdkEventKey *ev,
809 gpointer data)
810{
811 GtkTreeModel *model;
812 struct worklist_data *ptr;
813
814 ptr = data;
815 model = GTK_TREE_MODEL(ptr->dst);
816
817 if (ev->keyval == GDK_KEY_Delete) {
818 GtkTreeIter it, it_next;
819 bool deleted = FALSE;
820
821 if (gtk_tree_model_get_iter_first(model, &it)) {
822 bool more;
823
824 do {
825 it_next = it;
826 more = gtk_tree_model_iter_next(model, &it_next);
827
828 if (gtk_tree_selection_iter_is_selected(ptr->dst_selection, &it)) {
829 gtk_list_store_remove(GTK_LIST_STORE(model), &it);
830 deleted = TRUE;
831 }
832 it = it_next;
833
834 } while (more);
835 }
836
837 if (deleted) {
838 commit_worklist(ptr);
839 }
840 return TRUE;
841
842 } else if ((ev->state & GDK_MOD1_MASK) && ev->keyval == GDK_KEY_Up) {
843 queue_bubble_up(ptr);
844 return TRUE;
845
846 } else if ((ev->state & GDK_MOD1_MASK) && ev->keyval == GDK_KEY_Down) {
848 return TRUE;
849
850 } else {
851 return FALSE;
852 }
853}
854
855/************************************************************************/
858static void src_selection_callback(GtkTreeSelection *selection, gpointer data)
859{
860 struct worklist_data *ptr;
861
862 ptr = data;
863
864 /* update widget sensitivity. */
865 if (gtk_tree_selection_get_selected(selection, NULL, NULL)) {
867 && (!ptr->pcity || city_owner(ptr->pcity) == client.conn.playing)) {
868 /* if ptr->pcity is NULL, this is a global worklist */
869 gtk_widget_set_sensitive(ptr->change_cmd, TRUE);
870 gtk_widget_set_sensitive(ptr->prepend_cmd, TRUE);
871 gtk_widget_set_sensitive(ptr->append_cmd, TRUE);
872 } else {
873 gtk_widget_set_sensitive(ptr->change_cmd, FALSE);
874 gtk_widget_set_sensitive(ptr->prepend_cmd, FALSE);
875 gtk_widget_set_sensitive(ptr->append_cmd, FALSE);
876 }
877 gtk_widget_set_sensitive(ptr->help_cmd, TRUE);
878 } else {
879 gtk_widget_set_sensitive(ptr->change_cmd, FALSE);
880 gtk_widget_set_sensitive(ptr->help_cmd, FALSE);
881 gtk_widget_set_sensitive(ptr->prepend_cmd, FALSE);
882 gtk_widget_set_sensitive(ptr->append_cmd, FALSE);
883 }
884}
885
886/************************************************************************/
889static void dst_selection_callback(GtkTreeSelection *selection, gpointer data)
890{
891 struct worklist_data *ptr;
892
893 ptr = data;
894
895 /* update widget sensitivity. */
896 if (gtk_tree_selection_count_selected_rows(selection) > 0) {
897 int num_rows = 0;
898 GtkTreeIter it;
899
900 gtk_widget_set_sensitive(ptr->up_cmd, TRUE);
901 gtk_widget_set_sensitive(ptr->down_cmd, TRUE);
902 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ptr->dst), &it)) {
903 do {
904 num_rows++;
905 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ptr->dst), &it));
906 }
907 if (num_rows > 1) {
908 gtk_widget_set_sensitive(ptr->remove_cmd, TRUE);
909 } else {
910 gtk_widget_set_sensitive(ptr->remove_cmd, FALSE);
911 }
912 } else {
913 gtk_widget_set_sensitive(ptr->up_cmd, FALSE);
914 gtk_widget_set_sensitive(ptr->down_cmd, FALSE);
915 gtk_widget_set_sensitive(ptr->remove_cmd, FALSE);
916 }
917}
918
919/************************************************************************/
922static gboolean dst_dnd_callback(GtkWidget *w, GdkDragContext *context,
923 struct worklist_data *ptr)
924{
925 commit_worklist(ptr);
926 return FALSE;
927}
928
929/************************************************************************/
932static void cell_render_func(GtkTreeViewColumn *col, GtkCellRenderer *rend,
933 GtkTreeModel *model, GtkTreeIter *it,
934 gpointer data)
935{
936 gint id;
937 struct universal target;
938
939 gtk_tree_model_get(model, it, 0, &id, -1);
940 target = cid_production(id);
941
942 if (GTK_IS_CELL_RENDERER_PIXBUF(rend)) {
943 GdkPixbuf *pix;
944 struct sprite *sprite;
945
946 if (VUT_UTYPE == target.kind) {
948 direction8_invalid()),
950
951 } else {
953
954 }
956 g_object_set(rend, "pixbuf", pix, NULL);
957 g_object_unref(G_OBJECT(pix));
958 if (VUT_UTYPE == target.kind) {
960 }
961 } else {
962 struct city **pcity = data;
963 gint column;
964 char *row[4];
965 char buf[4][64];
966 guint i;
967 gboolean useless;
968
969 for (i = 0; i < ARRAY_SIZE(row); i++) {
970 row[i] = buf[i];
971 }
972 column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(rend), "column"));
973
974 get_city_dialog_production_row(row, sizeof(buf[0]), &target, *pcity);
975 g_object_set(rend, "text", row[column], NULL);
976
977 if (NULL != *pcity && VUT_IMPROVEMENT == target.kind) {
978 useless = is_improvement_redundant(*pcity, target.value.building);
979 /* Mark building redundant if we are really certain that there is
980 * no use for it. */
981 g_object_set(rend, "strikethrough", useless, NULL);
982 } else {
983 g_object_set(rend, "strikethrough", FALSE, NULL);
984 }
985 }
986}
987
988/************************************************************************/
991static void populate_view(GtkTreeView *view, struct city **ppcity,
992 GtkTreeViewColumn **pcol)
993{
994 static const char *titles[] =
995 { N_("Type"), N_("Name"), N_("Info"), N_("Cost"), N_("Turns") };
996
997 static bool titles_done;
998 guint i;
999 GtkCellRenderer *rend;
1000 GtkTreeViewColumn *col;
1001
1002 intl_slist(ARRAY_SIZE(titles), titles, &titles_done);
1003
1004 /* Case i == 0 taken out of the loop to workaround gcc-4.2.1 bug
1005 * https://gcc.gnu.org/PR33381
1006 * Some values would 'stick' from i == 0 round. */
1007 i = 0;
1008
1009 rend = gtk_cell_renderer_pixbuf_new();
1010
1011 gtk_tree_view_insert_column_with_data_func(view,
1012 i, titles[i], rend, cell_render_func, ppcity, NULL);
1013 col = gtk_tree_view_get_column(view, i);
1014
1015 if (GUI_GTK_OPTION(show_task_icons)) {
1016 if (max_unit_width == -1 || max_unit_height == -1) {
1018 }
1019 } else {
1020 g_object_set(col, "visible", FALSE, NULL);
1021 }
1022 if (GUI_GTK_OPTION(show_task_icons)) {
1023 g_object_set(rend, "height", max_unit_height, NULL);
1024 }
1025
1026 for (i = 1; i < ARRAY_SIZE(titles); i++) {
1027
1028 gint pos = i-1;
1029
1030 rend = gtk_cell_renderer_text_new();
1031 g_object_set_data(G_OBJECT(rend), "column", GINT_TO_POINTER(pos));
1032
1033 gtk_tree_view_insert_column_with_data_func(view,
1034 i, titles[i], rend, cell_render_func, ppcity, NULL);
1035 col = gtk_tree_view_get_column(view, i);
1036
1037 if (pos >= 2) {
1038 g_object_set(G_OBJECT(rend), "xalign", 1.0, NULL);
1039 gtk_tree_view_column_set_alignment(col, 1.0);
1040 }
1041
1042 if (pos == 3) {
1043 *pcol = col;
1044 }
1045 if (GUI_GTK_OPTION(show_task_icons)) {
1046 g_object_set(rend, "height", max_unit_height, NULL);
1047 }
1048 }
1049}
1050
1051/************************************************************************/
1054GtkWidget *create_worklist(void)
1055{
1056 GtkWidget *editor, *table, *sw, *bbox;
1057 GtkWidget *src_view, *dst_view, *label, *button;
1058 GtkWidget *menubar, *item, *menu, *image;
1059 GtkWidget *table2, *arrow, *check;
1060 GtkSizeGroup *group;
1061 GtkListStore *src_store, *dst_store;
1062 struct worklist_data *ptr;
1063
1064 ptr = fc_malloc(sizeof(*ptr));
1065
1066 src_store = gtk_list_store_new(2, G_TYPE_INT, G_TYPE_STRING);
1067 dst_store = gtk_list_store_new(2, G_TYPE_INT, G_TYPE_STRING);
1068
1069 ptr->global_worklist_id = -1;
1070 ptr->pcity = NULL;
1071 ptr->src = src_store;
1072 ptr->dst = dst_store;
1073 ptr->future = FALSE;
1074
1075 /* create shell. */
1076 editor = gtk_grid_new();
1077 gtk_grid_set_row_spacing(GTK_GRID(editor), 6);
1078 gtk_orientable_set_orientation(GTK_ORIENTABLE(editor),
1079 GTK_ORIENTATION_VERTICAL);
1080 g_signal_connect(editor, "destroy", G_CALLBACK(worklist_destroy), ptr);
1081 g_object_set_data(G_OBJECT(editor), "data", ptr);
1082
1083 ptr->editor = editor;
1084
1085 /* add source and target lists. */
1086 table = gtk_grid_new();
1087 gtk_container_add(GTK_CONTAINER(editor), table);
1088
1089 group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1090
1091 sw = gtk_scrolled_window_new(NULL, NULL);
1092 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
1093 GTK_SHADOW_ETCHED_IN);
1094 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1095 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1096 gtk_grid_attach(GTK_GRID(table), sw, 3, 1, 2, 1);
1097
1098 src_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(src_store));
1099 gtk_widget_set_hexpand(src_view, TRUE);
1100 gtk_widget_set_vexpand(src_view, TRUE);
1101 g_object_unref(src_store);
1102 gtk_size_group_add_widget(group, src_view);
1103 gtk_widget_set_name(src_view, "small_font");
1104 gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(src_view), 1);
1105
1106 populate_view(GTK_TREE_VIEW(src_view), &ptr->pcity, &ptr->src_col);
1107 gtk_container_add(GTK_CONTAINER(sw), src_view);
1108
1109 label = g_object_new(GTK_TYPE_LABEL,
1110 "use-underline", TRUE,
1111 "mnemonic-widget", src_view,
1112 "label", _("Source _Tasks:"),
1113 "xalign", 0.0, "yalign", 0.5, NULL);
1114 gtk_grid_attach(GTK_GRID(table), label, 3, 0, 1, 1);
1115
1116 check = gtk_check_button_new_with_mnemonic(_("Show _Future Targets"));
1117 gtk_grid_attach(GTK_GRID(table), check, 4, 0, 1, 1);
1118 g_signal_connect(check, "toggled", G_CALLBACK(future_callback), ptr);
1119
1120 table2 = gtk_grid_new();
1121 gtk_grid_attach(GTK_GRID(table), table2, 2, 1, 1, 1);
1122
1123 button = gtk_button_new();
1124 gtk_widget_set_margin_top(button, 24);
1125 gtk_widget_set_margin_bottom(button, 24);
1126 ptr->prepend_cmd = button;
1127 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1128 gtk_grid_attach(GTK_GRID(table2), button, 0, 0, 1, 1);
1129
1130 arrow = gtk_arrow_new(GTK_ARROW_LEFT, GTK_SHADOW_NONE);
1131 gtk_container_add(GTK_CONTAINER(button), arrow);
1132 g_signal_connect_swapped(button, "clicked",
1133 G_CALLBACK(queue_prepend), ptr);
1134 gtk_widget_set_sensitive(ptr->prepend_cmd, FALSE);
1135
1136 button = gtk_button_new();
1137 ptr->up_cmd = button;
1138 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1139 gtk_grid_attach(GTK_GRID(table2), button, 0, 1, 1, 1);
1140
1141 arrow = gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_NONE);
1142 gtk_container_add(GTK_CONTAINER(button), arrow);
1143 g_signal_connect_swapped(button, "clicked",
1144 G_CALLBACK(queue_bubble_up), ptr);
1145 gtk_widget_set_sensitive(ptr->up_cmd, FALSE);
1146
1147 button = gtk_button_new();
1148 ptr->down_cmd = button;
1149 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1150 gtk_grid_attach(GTK_GRID(table2), button, 0, 2, 1, 1);
1151
1152 arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_IN);
1153 gtk_container_add(GTK_CONTAINER(button), arrow);
1154 g_signal_connect_swapped(button, "clicked",
1155 G_CALLBACK(queue_bubble_down), ptr);
1156 gtk_widget_set_sensitive(ptr->down_cmd, FALSE);
1157
1158 button = gtk_button_new();
1159 gtk_widget_set_margin_top(button, 24);
1160 gtk_widget_set_margin_bottom(button, 24);
1161 ptr->append_cmd = button;
1162 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1163 gtk_grid_attach(GTK_GRID(table2), button, 0, 3, 1, 1);
1164
1165 arrow = gtk_arrow_new(GTK_ARROW_LEFT, GTK_SHADOW_NONE);
1166 gtk_container_add(GTK_CONTAINER(button), arrow);
1167 g_signal_connect_swapped(button, "clicked",
1168 G_CALLBACK(queue_append), ptr);
1169 gtk_widget_set_sensitive(ptr->append_cmd, FALSE);
1170
1171 button = gtk_button_new();
1172 gtk_widget_set_margin_top(button, 24);
1173 gtk_widget_set_margin_bottom(button, 24);
1174 ptr->remove_cmd = button;
1175 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1176 gtk_grid_attach(GTK_GRID(table2), button, 0, 4, 1, 1);
1177
1178 arrow = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_IN);
1179 gtk_container_add(GTK_CONTAINER(button), arrow);
1180 g_signal_connect_swapped(button, "clicked",
1181 G_CALLBACK(queue_remove), ptr);
1182 gtk_widget_set_sensitive(ptr->remove_cmd, FALSE);
1183
1184 sw = gtk_scrolled_window_new(NULL, NULL);
1185 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
1186 GTK_SHADOW_ETCHED_IN);
1187 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1188 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1189 gtk_grid_attach(GTK_GRID(table), sw, 0, 1, 2, 1);
1190
1191 dst_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dst_store));
1192 gtk_widget_set_hexpand(dst_view, TRUE);
1193 gtk_widget_set_vexpand(dst_view, TRUE);
1194 g_object_unref(dst_store);
1195 gtk_size_group_add_widget(group, dst_view);
1196 gtk_widget_set_name(dst_view, "small_font");
1197 gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(dst_view), 1);
1198
1199 populate_view(GTK_TREE_VIEW(dst_view), &ptr->pcity, &ptr->dst_col);
1200 gtk_container_add(GTK_CONTAINER(sw), dst_view);
1201
1202 label = g_object_new(GTK_TYPE_LABEL,
1203 "use-underline", TRUE,
1204 "mnemonic-widget", dst_view,
1205 "label", _("Target _Worklist:"),
1206 "xalign", 0.0, "yalign", 0.5, NULL);
1207 gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1);
1208
1209 /* add bottom menu and buttons. */
1210 bbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
1211 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1212 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1213 gtk_container_add(GTK_CONTAINER(editor), bbox);
1214
1215 menubar = gtk_aux_menu_bar_new();
1216 gtk_container_add(GTK_CONTAINER(bbox), menubar);
1217 gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(bbox), menubar, TRUE);
1218
1219 menu = gtk_menu_new();
1220
1221 image = gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU);
1222 item = gtk_image_menu_item_new_with_mnemonic(_("_Add Global Worklist"));
1223 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
1224 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
1225 gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
1226 g_signal_connect(menu, "show",
1227 G_CALLBACK(popup_add_menu), ptr);
1228 ptr->add_cmd = item;
1229 gtk_widget_set_sensitive(ptr->add_cmd, FALSE);
1230
1231 button = gtk_button_new_from_stock(GTK_STOCK_HELP);
1232 gtk_container_add(GTK_CONTAINER(bbox), button);
1233 g_signal_connect(button, "clicked",
1234 G_CALLBACK(help_callback), ptr);
1235 ptr->help_cmd = button;
1236 gtk_widget_set_sensitive(ptr->help_cmd, FALSE);
1237
1238 button = gtk_button_new_with_mnemonic(_("Change Prod_uction"));
1239 gtk_container_add(GTK_CONTAINER(bbox), button);
1240 g_signal_connect(button, "clicked",
1241 G_CALLBACK(change_callback), ptr);
1242 ptr->change_cmd = button;
1243 gtk_widget_set_sensitive(ptr->change_cmd, FALSE);
1244
1245 ptr->src_view = src_view;
1246 ptr->dst_view = dst_view;
1247 ptr->src_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(src_view));
1248 ptr->dst_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dst_view));
1249 gtk_tree_selection_set_mode(ptr->dst_selection, GTK_SELECTION_MULTIPLE);
1250
1251 /* DND and other state changing callbacks. */
1252 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(dst_view), TRUE);
1253 g_signal_connect(dst_view, "drag_end",
1254 G_CALLBACK(dst_dnd_callback), ptr);
1255
1256 g_signal_connect(src_view, "row_activated",
1257 G_CALLBACK(src_row_callback), ptr);
1258 g_signal_connect(src_view, "key_press_event",
1259 G_CALLBACK(src_key_press_callback), ptr);
1260
1261 g_signal_connect(dst_view, "row_activated",
1262 G_CALLBACK(dst_row_callback), ptr);
1263 g_signal_connect(dst_view, "key_press_event",
1264 G_CALLBACK(dst_key_press_callback), ptr);
1265
1266 g_signal_connect(ptr->src_selection, "changed",
1267 G_CALLBACK(src_selection_callback), ptr);
1268 g_signal_connect(ptr->dst_selection, "changed",
1269 G_CALLBACK(dst_selection_callback), ptr);
1270
1271
1272 gtk_widget_show_all(table);
1273 gtk_widget_show_all(bbox);
1274
1275 return editor;
1276}
1277
1278/************************************************************************/
1281void reset_city_worklist(GtkWidget *editor, struct city *pcity)
1282{
1283 struct worklist_data *ptr;
1284
1285 ptr = g_object_get_data(G_OBJECT(editor), "data");
1286
1287 ptr->global_worklist_id = -1;
1288 ptr->pcity = pcity;
1289
1290 gtk_list_store_clear(ptr->src);
1291 gtk_list_store_clear(ptr->dst);
1292
1293 g_object_set(ptr->src_col, "visible", TRUE, NULL);
1294 g_object_set(ptr->dst_col, "visible", TRUE, NULL);
1295
1296 gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(ptr->src_view),
1297 GDK_BUTTON1_MASK,
1299 G_N_ELEMENTS(wl_dnd_targets),
1300 GDK_ACTION_COPY);
1301}
1302
1303/************************************************************************/
1306static void reset_global_worklist(GtkWidget *editor,
1307 struct global_worklist *pgwl)
1308{
1309 struct worklist_data *ptr;
1310
1311 ptr = g_object_get_data(G_OBJECT(editor), "data");
1312
1314 ptr->pcity = NULL;
1315
1316 gtk_list_store_clear(ptr->src);
1317 gtk_list_store_clear(ptr->dst);
1318
1319 gtk_widget_hide(ptr->change_cmd);
1320 g_object_set(ptr->src_col, "visible", FALSE, NULL);
1321 g_object_set(ptr->dst_col, "visible", FALSE, NULL);
1322
1323 gtk_tree_view_unset_rows_drag_source(GTK_TREE_VIEW(ptr->src_view));
1324}
1325
1326/************************************************************************/
1329void refresh_worklist(GtkWidget *editor)
1330{
1331 struct worklist_data *ptr;
1332 struct worklist queue;
1333 struct universal targets[MAX_NUM_PRODUCTION_TARGETS];
1334 int i, targets_used;
1335 struct item items[MAX_NUM_PRODUCTION_TARGETS];
1336 bool selected;
1337 gint id;
1338 GtkTreeIter it;
1339 GtkTreePath *path;
1340 GtkTreeModel *model;
1341 gboolean exists;
1342
1343 ptr = g_object_get_data(G_OBJECT(editor), "data");
1344
1345 /* refresh source tasks. */
1346 if (gtk_tree_selection_get_selected(ptr->src_selection, NULL, &it)) {
1347 gtk_tree_model_get(GTK_TREE_MODEL(ptr->src), &it, 0, &id, -1);
1348 selected = TRUE;
1349 } else {
1350 selected = FALSE;
1351 }
1352
1353 /* These behave just right if ptr->pcity is NULL -> in case of global
1354 * worklist. */
1355 targets_used = collect_eventually_buildable_targets(targets, ptr->pcity,
1356 ptr->future);
1357 name_and_sort_items(targets, targets_used, items, FALSE, ptr->pcity);
1358
1359 /* Re-purpose existing items in the list store -- this avoids the
1360 * UI jumping around (especially as the set of source tasks doesn't
1361 * actually change much in practice). */
1362 model = GTK_TREE_MODEL(ptr->src);
1363 exists = gtk_tree_model_get_iter_first(model, &it);
1364
1365 path = NULL;
1366 for (i = 0; i < targets_used; i++) {
1367 char buf[8192];
1368
1369 if (!exists) {
1370 gtk_list_store_append(ptr->src, &it);
1371 }
1372
1373 gtk_list_store_set(ptr->src, &it, 0, (gint)cid_encode(items[i].item),
1374 1, production_help(&(items[i].item),
1375 buf, sizeof(buf)), -1);
1376
1377 if (selected && cid_encode(items[i].item) == id) {
1378 path = gtk_tree_model_get_path(GTK_TREE_MODEL(ptr->src), &it);
1379 }
1380
1381 if (exists) {
1382 exists = gtk_tree_model_iter_next(model, &it);
1383 }
1384 }
1385
1386 /* If the list got shorter, delete any excess items. */
1387 if (exists) {
1388 GtkTreeIter it_next;
1389 bool more;
1390
1391 do {
1392 it_next = it;
1393 more = gtk_tree_model_iter_next(model, &it_next);
1394
1395 gtk_list_store_remove(ptr->src, &it);
1396 it = it_next;
1397 } while (more);
1398 }
1399
1400 /* Select the same item that was previously selected, if any. */
1401 if (path) {
1402 gtk_tree_view_set_cursor(GTK_TREE_VIEW(ptr->src_view), path, NULL, FALSE);
1403 gtk_tree_path_free(path);
1404 }
1405
1406 /* refresh target worklist. */
1407 model = GTK_TREE_MODEL(ptr->dst);
1408 exists = gtk_tree_model_get_iter_first(model, &it);
1409
1410 /* dance around worklist braindamage. */
1411 if (ptr->pcity != NULL) {
1412 city_get_queue(ptr->pcity, &queue);
1413 } else {
1414 const struct global_worklist *pgwl;
1415
1417
1418 fc_assert(NULL != pgwl);
1419
1420 worklist_copy(&queue, global_worklist_get(pgwl));
1421 }
1422
1423 for (i = 0; i < worklist_length(&queue); i++) {
1424 struct universal target = queue.entries[i];
1425 char buf[8192];
1426
1427 if (!exists) {
1428 gtk_list_store_append(ptr->dst, &it);
1429 }
1430
1431 gtk_list_store_set(ptr->dst, &it, 0, (gint)cid_encode(target),
1432 1, production_help(&target,
1433 buf, sizeof(buf)), -1);
1434
1435 if (exists) {
1436 exists = gtk_tree_model_iter_next(model, &it);
1437 }
1438 }
1439
1440 if (exists) {
1441 GtkTreeIter it_next;
1442 bool more;
1443
1444 do {
1445 it_next = it;
1446 more = gtk_tree_model_iter_next(model, &it_next);
1447
1448 gtk_list_store_remove(ptr->dst, &it);
1449 it = it_next;
1450 } while (more);
1451 }
1452
1453 /* update widget sensitivity. */
1454 if (ptr->pcity) {
1456 && city_owner(ptr->pcity) == client.conn.playing)) {
1457 gtk_widget_set_sensitive(ptr->add_cmd, TRUE);
1458 gtk_widget_set_sensitive(ptr->dst_view, TRUE);
1459 } else {
1460 gtk_widget_set_sensitive(ptr->add_cmd, FALSE);
1461 gtk_widget_set_sensitive(ptr->dst_view, FALSE);
1462 }
1463 } else {
1464 gtk_widget_set_sensitive(ptr->add_cmd, TRUE);
1465 gtk_widget_set_sensitive(ptr->dst_view, TRUE);
1466 }
1467}
1468
1469/************************************************************************/
1472static void commit_worklist(struct worklist_data *ptr)
1473{
1474 struct worklist queue;
1475 GtkTreeModel *model;
1476 GtkTreeIter it;
1477 size_t i;
1478
1479 model = GTK_TREE_MODEL(ptr->dst);
1480
1481 worklist_init(&queue);
1482
1483 i = 0;
1484 if (gtk_tree_model_get_iter_first(model, &it)) {
1485 do {
1486 gint id;
1487 struct universal univ;
1488
1489 /* oops, the player has a worklist longer than what we can store. */
1490 if (i >= MAX_LEN_WORKLIST) {
1491 break;
1492 }
1493
1494 gtk_tree_model_get(model, &it, 0, &id, -1);
1495 univ = cid_production(id);
1496 worklist_append(&queue, &univ);
1497
1498 i++;
1499 } while (gtk_tree_model_iter_next(model, &it));
1500 }
1501
1502 /* dance around worklist braindamage. */
1503 if (ptr->pcity) {
1504 if (!city_set_queue(ptr->pcity, &queue)) {
1505 /* Failed to change worklist. This means worklist visible
1506 * on screen is not true. */
1508 }
1509 } else {
1510 struct global_worklist *pgwl;
1511
1513 if (pgwl) {
1514 global_worklist_set(pgwl, &queue);
1515 }
1516 }
1517}
#define city_owner(_pcity_)
Definition city.h:543
void get_city_dialog_production_row(char *buf[], size_t column_size, struct universal *target, struct city *pcity)
bool city_set_queue(struct city *pcity, const struct worklist *pqueue)
int city_change_production(struct city *pcity, struct universal *target)
void city_get_queue(struct city *pcity, struct worklist *pqueue)
struct civclient client
bool can_client_issue_orders(void)
int collect_eventually_buildable_targets(struct universal *targets, struct city *pcity, bool advanced_tech)
Definition climisc.c:812
void name_and_sort_items(struct universal *targets, int num_targets, struct item *items, bool show_cost, struct city *pcity)
Definition climisc.c:643
cid cid_encode(struct universal target)
Definition climisc.c:476
struct universal cid_decode(cid id)
Definition climisc.c:519
#define MAX_NUM_PRODUCTION_TARGETS
Definition climisc.h:89
#define cid_production
Definition climisc.h:71
int cid
Definition climisc.h:31
static struct fc_sockaddr_list * list
Definition clinet.c:102
int int id
Definition editgui_g.h:28
static struct editor_state * editor
Definition editor.c:100
#define _(String)
Definition fcintl.h:67
#define N_(String)
Definition fcintl.h:69
struct global_worklist * global_worklist_by_id(int id)
bool global_worklist_set(struct global_worklist *pgwl, const struct worklist *pwl)
const char * global_worklist_name(const struct global_worklist *pgwl)
int global_worklist_id(const struct global_worklist *pgwl)
void global_worklist_destroy(struct global_worklist *pgwl)
const struct worklist * global_worklist_get(const struct global_worklist *pgwl)
struct global_worklist * global_worklist_new(const char *name)
void global_worklist_set_name(struct global_worklist *pgwl, const char *name)
#define global_worklists_iterate(pgwl)
#define global_worklists_iterate_end
static struct tile * pos
Definition finddlg.c:53
GtkWidget * toplevel
Definition gui_main.c:124
#define GUI_GTK_OPTION(optname)
Definition gui_main.h:25
GtkWidget * gtk_aux_menu_bar_new(void)
Definition gui_stuff.c:249
void setup_dialog(GtkWidget *shell, GtkWidget *parent)
Definition gui_stuff.c:281
void intl_slist(int n, const char **s, bool *done)
Definition gui_stuff.c:105
void popup_help_dialog_string(const char *item)
Definition helpdlg.c:211
void popup_help_dialog_typed(const char *item, enum help_page_type htype)
Definition helpdlg.c:195
static struct gui_dialog * shell
Definition messagedlg.c:39
void free_sprite(struct sprite *s)
Definition sprite.c:278
struct sprite * sprite_scale(struct sprite *src, int new_w, int new_h)
Definition sprite.c:291
GdkPixbuf * sprite_get_pixbuf(struct sprite *sprite)
Definition sprite.c:402
void sprite_get_bounding_box(struct sprite *sprite, int *start_x, int *start_y, int *end_x, int *end_y)
Definition sprite.c:321
static GHashTable * hash
Definition wldlg.c:320
static gboolean dst_dnd_callback(GtkWidget *w, GdkDragContext *context, struct worklist_data *ptr)
Definition wldlg.c:922
static void dst_selection_callback(GtkTreeSelection *selection, gpointer data)
Definition wldlg.c:889
@ TARGET_GTK_TREE_MODEL_ROW
Definition wldlg.c:326
static void worklists_response(GtkWidget *w, gint response)
Definition wldlg.c:133
void update_worklist_report_dialog(void)
Definition wldlg.c:115
static void queue_remove(struct worklist_data *ptr)
Definition wldlg.c:622
static GtkWidget * get_worklist(int global_worklist_id)
Definition wldlg.c:347
static void reset_global_worklist(GtkWidget *editor, struct global_worklist *pgwl)
Definition wldlg.c:1306
static void future_callback(GtkToggleButton *toggle, gpointer data)
Definition wldlg.c:577
void blank_max_unit_size(void)
Definition wldlg.c:79
static void src_selection_callback(GtkTreeSelection *selection, gpointer data)
Definition wldlg.c:858
static void help_callback(GtkWidget *w, gpointer data)
Definition wldlg.c:519
static GtkTargetEntry wl_dnd_targets[]
Definition wldlg.c:329
static void src_row_callback(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data)
Definition wldlg.c:730
static void dst_row_callback(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data)
Definition wldlg.c:764
static void delete_worklist(int global_worklist_id)
Definition wldlg.c:373
void refresh_worklist(GtkWidget *editor)
Definition wldlg.c:1329
void add_worklist_dnd_target(GtkWidget *w)
Definition wldlg.c:337
static gboolean src_key_press_callback(GtkWidget *w, GdkEventKey *ev, gpointer data)
Definition wldlg.c:783
static void popdown_worklist(struct global_worklist *pgwl)
Definition wldlg.c:417
static GtkWidget * worklists_shell
Definition wldlg.c:55
static void popup_worklist(struct global_worklist *pgwl)
Definition wldlg.c:383
static GtkWidget * worklists_list
Definition wldlg.c:56
static void queue_bubble_up(struct worklist_data *ptr)
Definition wldlg.c:590
static GtkWidget * create_worklists_report(void)
Definition wldlg.c:212
static void popup_add_menu(GtkMenuShell *menu, gpointer data)
Definition wldlg.c:485
static void cell_edited(GtkCellRendererText *cell, const gchar *spath, const gchar *text, gpointer data)
Definition wldlg.c:184
static void cell_render_func(GtkTreeViewColumn *col, GtkCellRenderer *rend, GtkTreeModel *model, GtkTreeIter *it, gpointer data)
Definition wldlg.c:932
static gboolean dst_key_press_callback(GtkWidget *w, GdkEventKey *ev, gpointer data)
Definition wldlg.c:808
static void worklist_destroy(GtkWidget *editor, gpointer data)
Definition wldlg.c:432
static void worklists_destroy_callback(GtkWidget *w, gpointer data)
Definition wldlg.c:107
static void change_callback(GtkWidget *w, gpointer data)
Definition wldlg.c:554
@ WORKLISTS_NEW
Definition wldlg.c:59
@ WORKLISTS_CLOSE
Definition wldlg.c:62
@ WORKLISTS_DELETE
Definition wldlg.c:60
@ WORKLISTS_PROPERTIES
Definition wldlg.c:61
void reset_city_worklist(GtkWidget *editor, struct city *pcity)
Definition wldlg.c:1281
static void queue_insert(struct worklist_data *ptr, bool prepend)
Definition wldlg.c:668
static void menu_item_callback(GtkMenuItem *item, struct worklist_data *ptr)
Definition wldlg.c:448
static void populate_view(GtkTreeView *view, struct city **ppcity, GtkTreeViewColumn **pcol)
Definition wldlg.c:991
static void insert_worklist(int global_worklist_id, GtkWidget *editor)
Definition wldlg.c:362
static void queue_append(struct worklist_data *ptr)
Definition wldlg.c:722
GtkWidget * create_worklist(void)
Definition wldlg.c:1054
static void commit_worklist(struct worklist_data *ptr)
Definition wldlg.c:1472
static void queue_bubble_down(struct worklist_data *ptr)
Definition wldlg.c:637
static int max_unit_width
Definition wldlg.c:67
static int max_unit_height
Definition wldlg.c:67
static void update_max_unit_size(void)
Definition wldlg.c:88
static void queue_prepend(struct worklist_data *ptr)
Definition wldlg.c:714
static GtkListStore * worklists_store
Definition wldlg.c:65
void popup_worklists_report(void)
Definition wldlg.c:286
#define HELP_WORKLIST_EDITOR_ITEM
@ HELP_IMPROVEMENT
Definition helpdlg_g.h:20
@ HELP_UNIT
Definition helpdlg_g.h:20
@ HELP_WONDER
Definition helpdlg_g.h:21
bool is_improvement_redundant(const struct city *pcity, const struct impr_type *pimprove)
bool is_great_wonder(const struct impr_type *pimprove)
const char * improvement_name_translation(const struct impr_type *pimprove)
#define fc_assert(condition)
Definition log.h:176
#define fc_malloc(sz)
Definition mem.h:34
#define ARRAY_SIZE(x)
Definition shared.h:85
#define MAX(x, y)
Definition shared.h:54
Definition city.h:309
struct connection conn
Definition client_main.h:96
struct player * playing
Definition connection.h:156
Definition climisc.h:82
enum universals_n kind
Definition fc_types.h:758
universals_u value
Definition fc_types.h:757
GtkWidget * prepend_cmd
Definition wldlg.c:315
GActionGroup * group
Definition wldlg.c:313
GtkWidget * dst_view
Definition wldlg.c:309
GtkTreeViewColumn * dst_col
Definition wldlg.c:312
GtkTreeSelection * dst_selection
Definition wldlg.c:310
GtkWidget * src_view
Definition wldlg.c:309
GtkWidget * up_cmd
Definition wldlg.c:315
bool future
Definition wldlg.c:317
GtkTreeSelection * src_selection
Definition wldlg.c:310
GtkListStore * src
Definition wldlg.c:308
GtkTreeViewColumn * src_col
Definition wldlg.c:312
GtkWidget * remove_cmd
Definition wldlg.c:315
GtkListStore * dst
Definition wldlg.c:308
GtkWidget * editor
Definition wldlg.c:306
int global_worklist_id
Definition wldlg.c:303
GMenu * menu
Definition wldlg.c:311
GtkWidget * append_cmd
Definition wldlg.c:315
GtkWidget * help_cmd
Definition wldlg.c:314
struct city * pcity
Definition wldlg.c:304
GtkWidget * down_cmd
Definition wldlg.c:315
GtkWidget * add_cmd
Definition wldlg.c:314
GtkWidget * change_cmd
Definition wldlg.c:314
struct universal entries[MAX_LEN_WORKLIST]
Definition worklist.h:30
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
const char * production_help(const struct universal *uni, char *buf, size_t bufsize)
Definition text.c:2120
struct sprite * get_building_sprite(const struct tileset *t, const struct impr_type *pimprove)
Definition tilespec.c:6494
struct sprite * get_unittype_sprite(const struct tileset *t, const struct unit_type *punittype, enum direction8 facing)
Definition tilespec.c:6516
const struct unit_type * utype
Definition fc_types.h:604
const struct impr_type * building
Definition fc_types.h:598
const char * utype_name_translation(const struct unit_type *punittype)
Definition unittype.c:1612
#define unit_type_iterate(_p)
Definition unittype.h:841
#define unit_type_iterate_end
Definition unittype.h:848
void worklist_copy(struct worklist *dst, const struct worklist *src)
Definition worklist.c:112
void worklist_init(struct worklist *pwl)
Definition worklist.c:38
bool worklist_append(struct worklist *pwl, const struct universal *prod)
Definition worklist.c:147
int worklist_length(const struct worklist *pwl)
Definition worklist.c:57
#define MAX_LEN_WORKLIST
Definition worklist.h:24