Freeciv-3.3: /fast/freeciv/nightly/main/client/gui-gtk-3.22/wldlg.c Source File

Freeciv-3.3

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.22 */
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
55 static GtkWidget *worklists_shell;
56 static GtkWidget *worklists_list;
57
58enum {
59 WORKLISTS_NEW,
60 WORKLISTS_DELETE,
61 WORKLISTS_PROPERTIES,
62 WORKLISTS_CLOSE
63};
64
65 static GtkListStore *worklists_store;
66
67 static 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/************************************************************************/
79 void blank_max_unit_size(void)
80{
81 max_unit_height = -1;
82 max_unit_width = -1;
83}
84
85/************************************************************************/
88 static void update_max_unit_size(void)
89{
90 max_unit_height = 0;
91 max_unit_width = 0;
92
93 unit_type_iterate(i) {
94 int x1, x2, y1, y2;
95 struct sprite *sprite = get_unittype_sprite(tileset, i,
96 ACTIVITY_LAST,
97 direction8_invalid());
98
99 sprite_get_bounding_box(sprite, &x1, &y1, &x2, &y2);
100 max_unit_width = MAX(max_unit_width, x2 - x1);
101 max_unit_height = MAX(max_unit_height, y2 - y1);
102 } unit_type_iterate_end;
103}
104
105/************************************************************************/
108 static void worklists_destroy_callback(GtkWidget *w, gpointer data)
109{
110 worklists_shell = NULL;
111}
112
113/************************************************************************/
116 void update_worklist_report_dialog(void)
117{
118 GtkTreeIter it;
119
120 gtk_list_store_clear(worklists_store);
121 global_worklists_iterate(pgwl) {
122 gtk_list_store_append(worklists_store, &it);
123
124 gtk_list_store_set(worklists_store, &it,
125 0, global_worklist_name(pgwl),
126 1, global_worklist_id(pgwl),
127 -1);
128 } global_worklists_iterate_end;
129}
130
131/************************************************************************/
134 static void worklists_response(GtkWidget *w, gint response)
135{
136 struct global_worklist *pgwl;
137 int id;
138 GtkTreeSelection *selection;
139 GtkTreeModel *model;
140 GtkTreeIter it;
141
142 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(worklists_list));
143
144 if (gtk_tree_selection_get_selected(selection, &model, &it)) {
145 gtk_tree_model_get(model, &it, 1, &id, -1);
146 pgwl = global_worklist_by_id(id);
147 } else {
148 pgwl = NULL;
149 id = -1;
150 }
151
152 switch (response) {
153 case WORKLISTS_NEW:
154 global_worklist_new(_("new"));
155 update_worklist_report_dialog();
156 return;
157
158 case WORKLISTS_DELETE:
159 if (!pgwl) {
160 return;
161 }
162
163 popdown_worklist(pgwl);
164 global_worklist_destroy(pgwl);
165 update_worklist_report_dialog();
166 return;
167
168 case WORKLISTS_PROPERTIES:
169 if (!pgwl) {
170 return;
171 }
172
173 popup_worklist(pgwl);
174 return;
175
176 default:
177 gtk_widget_destroy(worklists_shell);
178 return;
179 }
180}
181
182/************************************************************************/
185 static void cell_edited(GtkCellRendererText *cell,
186 const gchar *spath,
187 const gchar *text, gpointer data)
188{
189 GtkTreePath *path;
190 GtkTreeIter it;
191 struct global_worklist *pgwl;
192 int id;
193
194 path = gtk_tree_path_new_from_string(spath);
195 gtk_tree_model_get_iter(GTK_TREE_MODEL(worklists_store), &it, path);
196 gtk_tree_path_free(path);
197
198 gtk_tree_model_get(GTK_TREE_MODEL(worklists_store), &it, 1, &id, -1);
199 pgwl = global_worklist_by_id(id);
200
201 if (!pgwl) {
202 gtk_list_store_remove(worklists_store, &it);
203 return;
204 }
205
206 global_worklist_set_name(pgwl, text);
207 gtk_list_store_set(worklists_store, &it, 0, text, -1);
208}
209
210/************************************************************************/
213 static GtkWidget *create_worklists_report(void)
214{
215 GtkWidget *shell, *list;
216 GtkWidget *vbox, *label, *sw;
217 GtkCellRenderer *rend;
218
219 shell = gtk_dialog_new_with_buttons(_("Edit worklists"),
220 NULL,
221 0,
222 _("_New"),
223 WORKLISTS_NEW,
224 _("_Delete"),
225 WORKLISTS_DELETE,
226 _("_Properties"),
227 WORKLISTS_PROPERTIES,
228 _("_Close"),
229 WORKLISTS_CLOSE,
230 NULL);
231 setup_dialog(shell, toplevel);
232 gtk_window_set_position(GTK_WINDOW(shell), GTK_WIN_POS_MOUSE);
233
234 g_signal_connect(shell, "response",
235 G_CALLBACK(worklists_response), NULL);
236 g_signal_connect(shell, "destroy",
237 G_CALLBACK(worklists_destroy_callback), NULL);
238
239 vbox = gtk_grid_new();
240 gtk_grid_set_row_spacing(GTK_GRID(vbox), 2);
241 gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
242 GTK_ORIENTATION_VERTICAL);
243 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(shell))), vbox);
244
245 worklists_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
246
247 list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(worklists_store));
248 gtk_widget_set_hexpand(list, TRUE);
249 gtk_widget_set_vexpand(list, TRUE);
250
251 g_object_unref(worklists_store);
252 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE);
253
254 worklists_list = list;
255
256 rend = gtk_cell_renderer_text_new();
257 g_object_set(rend, "editable", TRUE, NULL);
258 g_signal_connect(rend, "edited",
259 G_CALLBACK(cell_edited), NULL);
260 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(list), -1, NULL,
261 rend, "text", 0, NULL);
262
263 sw = gtk_scrolled_window_new(NULL, NULL);
264 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(sw), 200);
265 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
266 GTK_SHADOW_ETCHED_IN);
267 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
268 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
269 gtk_container_add(GTK_CONTAINER(sw), list);
270
271 label = g_object_new(GTK_TYPE_LABEL,
272 "use-underline", TRUE,
273 "mnemonic-widget", list,
274 "label", _("_Worklists:"),
275 "xalign", 0.0, "yalign", 0.5, NULL);
276
277 gtk_container_add(GTK_CONTAINER(vbox), label);
278 gtk_container_add(GTK_CONTAINER(vbox), sw);
279 gtk_widget_show_all(vbox);
280
281 return shell;
282}
283
284/************************************************************************/
287 void popup_worklists_report(void)
288{
289 if (!worklists_shell) {
290 worklists_shell = create_worklists_report();
291
292 update_worklist_report_dialog();
293 }
294
295 gtk_window_present(GTK_WINDOW(worklists_shell));
296}
297
298
299
300
301/****************************************************************
302...
303*****************************************************************/
304 struct worklist_data {
305 int global_worklist_id;
306 struct city *pcity;
307
308 GtkWidget *editor;
309
310 GtkListStore *src, *dst;
311 GtkWidget *src_view, *dst_view;
312 GtkTreeSelection *src_selection, *dst_selection;
313
314 GtkTreeViewColumn *src_col, *dst_col;
315
316 GtkWidget *add_cmd, *change_cmd, *help_cmd;
317 GtkWidget *up_cmd, *down_cmd, *prepend_cmd, *append_cmd, *remove_cmd;
318
319 bool future;
320};
321
322 static GHashTable *hash;
323
324static void commit_worklist(struct worklist_data *ptr);
325
326
327enum {
328 TARGET_GTK_TREE_MODEL_ROW
329};
330
331 static GtkTargetEntry wl_dnd_targets[] = {
332 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, TARGET_GTK_TREE_MODEL_ROW },
333};
334
335
336/************************************************************************/
339 void add_worklist_dnd_target(GtkWidget *w)
340{
341 gtk_drag_dest_set(w, GTK_DEST_DEFAULT_ALL,
342 wl_dnd_targets, G_N_ELEMENTS(wl_dnd_targets),
343 GDK_ACTION_COPY);
344}
345
346/************************************************************************/
349 static GtkWidget *get_worklist(int global_worklist_id)
350{
351 if (hash) {
352 gpointer ret;
353
354 ret = g_hash_table_lookup(hash, GINT_TO_POINTER(global_worklist_id));
355 return ret;
356 } else {
357 return NULL;
358 }
359}
360
361/************************************************************************/
364 static void insert_worklist(int global_worklist_id, GtkWidget *editor)
365{
366 if (!hash) {
367 hash = g_hash_table_new(g_direct_hash, g_direct_equal);
368 }
369 g_hash_table_insert(hash, GINT_TO_POINTER(global_worklist_id), editor);
370}
371
372/************************************************************************/
375 static void delete_worklist(int global_worklist_id)
376{
377 if (hash) {
378 g_hash_table_remove(hash, GINT_TO_POINTER(global_worklist_id));
379 }
380}
381
382/************************************************************************/
385 static void popup_worklist(struct global_worklist *pgwl)
386{
387 GtkWidget *shell;
388
389 if (!(shell = get_worklist(global_worklist_id(pgwl)))) {
390 GtkWidget *editor;
391
392 shell = gtk_dialog_new_with_buttons(global_worklist_name(pgwl),
393 GTK_WINDOW(worklists_shell),
394 GTK_DIALOG_DESTROY_WITH_PARENT,
395 _("_Close"),
396 GTK_RESPONSE_CLOSE,
397 NULL);
398 gtk_window_set_role(GTK_WINDOW(shell), "worklist");
399 gtk_window_set_position(GTK_WINDOW(shell), GTK_WIN_POS_MOUSE);
400 g_signal_connect(shell, "response", G_CALLBACK(gtk_widget_destroy), NULL);
401 gtk_window_set_default_size(GTK_WINDOW(shell), 500, 400);
402
403 editor = create_worklist();
404 reset_global_worklist(editor, pgwl);
405 insert_worklist(global_worklist_id(pgwl), editor);
406
407 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(shell))),
408 editor);
409 gtk_widget_show(editor);
410
411 refresh_worklist(editor);
412 }
413
414 gtk_window_present(GTK_WINDOW(shell));
415}
416
417/************************************************************************/
420 static void popdown_worklist(struct global_worklist *pgwl)
421{
422 GtkWidget *shell;
423
424 if ((shell = get_worklist(global_worklist_id(pgwl)))) {
425 GtkWidget *parent;
426
427 parent = gtk_widget_get_toplevel(shell);
428 gtk_widget_destroy(parent);
429 }
430}
431
432/************************************************************************/
435 static void worklist_destroy(GtkWidget *editor, gpointer data)
436{
437 struct worklist_data *ptr;
438
439 ptr = data;
440
441 if (ptr->global_worklist_id != -1) {
442 delete_worklist(ptr->global_worklist_id);
443 }
444
445 free(ptr);
446}
447
448/************************************************************************/
451 static void menu_item_callback(GtkMenuItem *item, struct worklist_data *ptr)
452{
453 struct global_worklist *pgwl;
454 const struct worklist *pwl;
455 size_t i;
456
457 if (NULL == client.conn.playing) {
458 return;
459 }
460
461 pgwl = global_worklist_by_id(GPOINTER_TO_INT
462 (g_object_get_data(G_OBJECT(item), "id")));
463 if (!pgwl) {
464 return;
465 }
466 pwl = global_worklist_get(pgwl);
467
468 for (i = 0; i < (size_t) worklist_length(pwl); i++) {
469 GtkTreeIter it;
470 cid id;
471 char buf[8192];
472
473 id = cid_encode(pwl->entries[i]);
474
475 gtk_list_store_append(ptr->dst, &it);
476 gtk_list_store_set(ptr->dst, &it, 0, (gint)id,
477 1, production_help(&(pwl->entries[i]),
478 buf, sizeof(buf)), -1);
479 }
480
481 commit_worklist(ptr);
482}
483
484/************************************************************************/
487 static void popup_add_menu(GtkMenuShell *menu, gpointer data)
488{
489 GtkWidget *item;
490
491 gtk_container_foreach(GTK_CONTAINER(menu),
492 (GtkCallback) gtk_widget_destroy, NULL);
493
494 global_worklists_iterate(pgwl) {
495 item = gtk_menu_item_new_with_label(global_worklist_name(pgwl));
496 g_object_set_data(G_OBJECT(item), "id",
497 GINT_TO_POINTER(global_worklist_id(pgwl)));
498 gtk_widget_show(item);
499
500 gtk_container_add(GTK_CONTAINER(menu), item);
501 g_signal_connect(item, "activate",
502 G_CALLBACK(menu_item_callback), data);
503 } global_worklists_iterate_end;
504
505 item = gtk_separator_menu_item_new();
506 gtk_widget_show(item);
507
508 gtk_container_add(GTK_CONTAINER(menu), item);
509
510 item = gtk_menu_item_new_with_mnemonic(_("Edit Global _Worklists"));
511 gtk_widget_show(item);
512
513 gtk_container_add(GTK_CONTAINER(menu), item);
514 g_signal_connect(item, "activate",
515 G_CALLBACK(popup_worklists_report), NULL);
516}
517
518/************************************************************************/
521 static void help_callback(GtkWidget *w, gpointer data)
522{
523 struct worklist_data *ptr;
524 GtkTreeSelection *selection;
525 GtkTreeModel *model;
526 GtkTreeIter it;
527
528 ptr = data;
529 selection = ptr->src_selection;
530
531 if (gtk_tree_selection_get_selected(selection, &model, &it)) {
532 gint id;
533 struct universal target;
534
535 gtk_tree_model_get(model, &it, 0, &id, -1);
536 target = cid_decode(id);
537
538 if (VUT_UTYPE == target.kind) {
539 popup_help_dialog_typed(utype_name_translation(target.value.utype),
540 HELP_UNIT);
541 } else if (is_great_wonder(target.value.building)) {
542 popup_help_dialog_typed(improvement_name_translation(target.value.building),
543 HELP_WONDER);
544 } else {
545 popup_help_dialog_typed(improvement_name_translation(target.value.building),
546 HELP_IMPROVEMENT);
547 }
548 } else {
549 popup_help_dialog_string(HELP_WORKLIST_EDITOR_ITEM);
550 }
551}
552
553/************************************************************************/
556 static void change_callback(GtkWidget *w, gpointer data)
557{
558 struct worklist_data *ptr;
559 GtkTreeSelection *selection;
560 GtkTreeModel *model;
561 GtkTreeIter it;
562
563 ptr = data;
564 selection = ptr->src_selection;
565
566 if (gtk_tree_selection_get_selected(selection, &model, &it)) {
567 gint id;
568 struct universal univ;
569
570 gtk_tree_model_get(model, &it, 0, &id, -1);
571 univ = cid_production(id);
572 city_change_production(ptr->pcity, &univ);
573 }
574}
575
576/************************************************************************/
579 static void future_callback(GtkToggleButton *toggle, gpointer data)
580{
581 struct worklist_data *ptr;
582
583 ptr = data;
584 ptr->future = !ptr->future;
585
586 refresh_worklist(ptr->editor);
587}
588
589/************************************************************************/
592 static void queue_bubble_up(struct worklist_data *ptr)
593{
594 GtkTreePath *path;
595 GtkTreeViewColumn *col;
596 GtkTreeModel *model;
597
598 if (!gtk_widget_is_sensitive(ptr->dst_view)) {
599 return;
600 }
601
602 model = GTK_TREE_MODEL(ptr->dst);
603 gtk_tree_view_get_cursor(GTK_TREE_VIEW(ptr->dst_view), &path, &col);
604 if (path) {
605 GtkTreeIter it, it_prev;
606
607 if (gtk_tree_path_prev(path)) {
608 gtk_tree_model_get_iter(model, &it_prev, path);
609 it = it_prev;
610 gtk_tree_model_iter_next(model, &it);
611
612 gtk_list_store_swap(GTK_LIST_STORE(model), &it, &it_prev);
613
614 gtk_tree_view_set_cursor(GTK_TREE_VIEW(ptr->dst_view), path, col, FALSE);
615 commit_worklist(ptr);
616 }
617 }
618 gtk_tree_path_free(path);
619}
620
621/************************************************************************/
624 static void queue_remove(struct worklist_data *ptr)
625{
626 GtkTreePath *path;
627 GtkTreeViewColumn *col;
628
629 gtk_tree_view_get_cursor(GTK_TREE_VIEW(ptr->dst_view), &path, &col);
630 if (path) {
631 dst_row_callback(GTK_TREE_VIEW(ptr->dst_view), path, col, ptr);
632 gtk_tree_path_free(path);
633 }
634}
635
636/************************************************************************/
639 static void queue_bubble_down(struct worklist_data *ptr)
640{
641 GtkTreePath *path;
642 GtkTreeViewColumn *col;
643 GtkTreeModel *model;
644
645 if (!gtk_widget_is_sensitive(ptr->dst_view)) {
646 return;
647 }
648
649 model = GTK_TREE_MODEL(ptr->dst);
650 gtk_tree_view_get_cursor(GTK_TREE_VIEW(ptr->dst_view), &path, &col);
651 if (path) {
652 GtkTreeIter it, it_next;
653
654 gtk_tree_model_get_iter(model, &it, path);
655 it_next = it;
656 if (gtk_tree_model_iter_next(model, &it_next)) {
657 gtk_list_store_swap(GTK_LIST_STORE(model), &it, &it_next);
658
659 gtk_tree_path_next(path);
660 gtk_tree_view_set_cursor(GTK_TREE_VIEW(ptr->dst_view), path, col, FALSE);
661 commit_worklist(ptr);
662 }
663 }
664 gtk_tree_path_free(path);
665}
666
667/************************************************************************/
670 static void queue_insert(struct worklist_data *ptr, bool prepend)
671{
672 GtkTreeModel *model;
673 GtkTreeIter it;
674 GtkTreePath *path;
675
676 GtkTreeModel *src_model, *dst_model;
677 GtkTreeIter src_it, dst_it;
678 gint i, ncols;
679
680 if (!gtk_widget_is_sensitive(ptr->dst_view)) {
681 return;
682 }
683
684 if (!gtk_tree_selection_get_selected(ptr->src_selection, &model, &it)) {
685 return;
686 }
687
688 path = gtk_tree_model_get_path(model, &it);
689
690 src_model = GTK_TREE_MODEL(ptr->src);
691 dst_model = GTK_TREE_MODEL(ptr->dst);
692
693 gtk_tree_model_get_iter(src_model, &src_it, path);
694 if (prepend) {
695 gtk_list_store_prepend(GTK_LIST_STORE(dst_model), &dst_it);
696 } else {
697 gtk_list_store_append(GTK_LIST_STORE(dst_model), &dst_it);
698 }
699
700 ncols = gtk_tree_model_get_n_columns(src_model);
701
702 for (i = 0; i < ncols; i++) {
703 GValue value = { 0, };
704
705 gtk_tree_model_get_value(src_model, &src_it, i, &value);
706 gtk_list_store_set_value(GTK_LIST_STORE(dst_model), &dst_it, i, &value);
707 }
708 commit_worklist(ptr);
709
710 gtk_tree_path_free(path);
711}
712
713/************************************************************************/
716 static void queue_prepend(struct worklist_data *ptr)
717{
718 queue_insert(ptr, TRUE);
719}
720
721/************************************************************************/
724 static void queue_append(struct worklist_data *ptr)
725{
726 queue_insert(ptr, FALSE);
727}
728
729/************************************************************************/
732 static void src_row_callback(GtkTreeView *view, GtkTreePath *path,
733 GtkTreeViewColumn *col, gpointer data)
734{
735 struct worklist_data *ptr;
736 GtkTreeModel *src_model, *dst_model;
737 GtkTreeIter src_it, dst_it;
738 gint i, ncols;
739
740 ptr = data;
741
742 if (!gtk_widget_is_sensitive(ptr->dst_view)) {
743 return;
744 }
745
746 src_model = GTK_TREE_MODEL(ptr->src);
747 dst_model = GTK_TREE_MODEL(ptr->dst);
748
749 gtk_tree_model_get_iter(src_model, &src_it, path);
750 gtk_list_store_append(GTK_LIST_STORE(dst_model), &dst_it);
751
752 ncols = gtk_tree_model_get_n_columns(src_model);
753
754 for (i = 0; i < ncols; i++) {
755 GValue value = { 0, };
756
757 gtk_tree_model_get_value(src_model, &src_it, i, &value);
758 gtk_list_store_set_value(GTK_LIST_STORE(dst_model), &dst_it, i, &value);
759 }
760 commit_worklist(ptr);
761}
762
763/************************************************************************/
766 static void dst_row_callback(GtkTreeView *view, GtkTreePath *path,
767 GtkTreeViewColumn *col, gpointer data)
768{
769 struct worklist_data *ptr;
770 GtkTreeModel *dst_model;
771 GtkTreeIter it;
772
773 ptr = data;
774 dst_model = GTK_TREE_MODEL(ptr->dst);
775
776 gtk_tree_model_get_iter(dst_model, &it, path);
777
778 gtk_list_store_remove(GTK_LIST_STORE(dst_model), &it);
779 commit_worklist(ptr);
780}
781
782/************************************************************************/
785 static gboolean src_key_press_callback(GtkWidget *w, GdkEventKey *ev,
786 gpointer data)
787{
788 struct worklist_data *ptr;
789
790 ptr = data;
791
792 if (!gtk_widget_is_sensitive(ptr->dst_view)) {
793 return FALSE;
794 }
795
796 if ((ev->state & GDK_SHIFT_MASK) && ev->keyval == GDK_KEY_Insert) {
797 queue_prepend(ptr);
798 return TRUE;
799 } else if (ev->keyval == GDK_KEY_Insert) {
800 queue_append(ptr);
801 return TRUE;
802 } else {
803 return FALSE;
804 }
805}
806
807/************************************************************************/
810 static gboolean dst_key_press_callback(GtkWidget *w, GdkEventKey *ev,
811 gpointer data)
812{
813 GtkTreeModel *model;
814 struct worklist_data *ptr;
815
816 ptr = data;
817 model = GTK_TREE_MODEL(ptr->dst);
818
819 if (ev->keyval == GDK_KEY_Delete) {
820 GtkTreeIter it, it_next;
821 bool deleted = FALSE;
822
823 if (gtk_tree_model_get_iter_first(model, &it)) {
824 bool more;
825
826 do {
827 it_next = it;
828 more = gtk_tree_model_iter_next(model, &it_next);
829
830 if (gtk_tree_selection_iter_is_selected(ptr->dst_selection, &it)) {
831 gtk_list_store_remove(GTK_LIST_STORE(model), &it);
832 deleted = TRUE;
833 }
834 it = it_next;
835
836 } while (more);
837 }
838
839 if (deleted) {
840 commit_worklist(ptr);
841 }
842 return TRUE;
843
844 } else if ((ev->state & GDK_MOD1_MASK) && ev->keyval == GDK_KEY_Up) {
845 queue_bubble_up(ptr);
846 return TRUE;
847
848 } else if ((ev->state & GDK_MOD1_MASK) && ev->keyval == GDK_KEY_Down) {
849 queue_bubble_down(ptr);
850 return TRUE;
851
852 } else {
853 return FALSE;
854 }
855}
856
857/************************************************************************/
860 static void src_selection_callback(GtkTreeSelection *selection, gpointer data)
861{
862 struct worklist_data *ptr;
863
864 ptr = data;
865
866 /* update widget sensitivity. */
867 if (gtk_tree_selection_get_selected(selection, NULL, NULL)) {
868 if (can_client_issue_orders()
869 && (!ptr->pcity || city_owner(ptr->pcity) == client.conn.playing)) {
870 /* if ptr->pcity is NULL, this is a global worklist */
871 gtk_widget_set_sensitive(ptr->change_cmd, TRUE);
872 gtk_widget_set_sensitive(ptr->prepend_cmd, TRUE);
873 gtk_widget_set_sensitive(ptr->append_cmd, TRUE);
874 } else {
875 gtk_widget_set_sensitive(ptr->change_cmd, FALSE);
876 gtk_widget_set_sensitive(ptr->prepend_cmd, FALSE);
877 gtk_widget_set_sensitive(ptr->append_cmd, FALSE);
878 }
879 gtk_widget_set_sensitive(ptr->help_cmd, TRUE);
880 } else {
881 gtk_widget_set_sensitive(ptr->change_cmd, FALSE);
882 gtk_widget_set_sensitive(ptr->help_cmd, FALSE);
883 gtk_widget_set_sensitive(ptr->prepend_cmd, FALSE);
884 gtk_widget_set_sensitive(ptr->append_cmd, FALSE);
885 }
886}
887
888/************************************************************************/
891 static void dst_selection_callback(GtkTreeSelection *selection, gpointer data)
892{
893 struct worklist_data *ptr;
894
895 ptr = data;
896
897 /* update widget sensitivity. */
898 if (gtk_tree_selection_count_selected_rows(selection) > 0) {
899 int num_rows = 0;
900 GtkTreeIter it;
901
902 gtk_widget_set_sensitive(ptr->up_cmd, TRUE);
903 gtk_widget_set_sensitive(ptr->down_cmd, TRUE);
904 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ptr->dst), &it)) {
905 do {
906 num_rows++;
907 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ptr->dst), &it));
908 }
909 if (num_rows > 1) {
910 gtk_widget_set_sensitive(ptr->remove_cmd, TRUE);
911 } else {
912 gtk_widget_set_sensitive(ptr->remove_cmd, FALSE);
913 }
914 } else {
915 gtk_widget_set_sensitive(ptr->up_cmd, FALSE);
916 gtk_widget_set_sensitive(ptr->down_cmd, FALSE);
917 gtk_widget_set_sensitive(ptr->remove_cmd, FALSE);
918 }
919}
920
921/************************************************************************/
924 static gboolean dst_dnd_callback(GtkWidget *w, GdkDragContext *context,
925 struct worklist_data *ptr)
926{
927 commit_worklist(ptr);
928 return FALSE;
929}
930
931/************************************************************************/
934 static void cell_render_func(GtkTreeViewColumn *col, GtkCellRenderer *rend,
935 GtkTreeModel *model, GtkTreeIter *it,
936 gpointer data)
937{
938 gint id;
939 struct universal target;
940
941 gtk_tree_model_get(model, it, 0, &id, -1);
942 target = cid_production(id);
943
944 if (GTK_IS_CELL_RENDERER_PIXBUF(rend)) {
945 GdkPixbuf *pix;
946 struct sprite *sprite;
947
948 if (VUT_UTYPE == target.kind) {
949 sprite = sprite_scale(get_unittype_sprite(tileset, target.value.utype,
950 ACTIVITY_LAST,
951 direction8_invalid()),
952 max_unit_width, max_unit_height);
953 } else {
954 sprite = get_building_sprite(tileset, target.value.building);
955 }
956 pix = sprite_get_pixbuf(sprite);
957 g_object_set(rend, "pixbuf", pix, NULL);
958 g_object_unref(G_OBJECT(pix));
959 if (VUT_UTYPE == target.kind) {
960 free_sprite(sprite);
961 }
962 } else {
963 struct city **pcity = data;
964 gint column;
965 char *row[4];
966 char buf[4][64];
967 guint i;
968 gboolean useless;
969
970 for (i = 0; i < ARRAY_SIZE(row); i++) {
971 row[i] = buf[i];
972 }
973 column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(rend), "column"));
974
975 get_city_dialog_production_row(row, sizeof(buf[0]), &target, *pcity);
976 g_object_set(rend, "text", row[column], NULL);
977
978 if (NULL != *pcity && VUT_IMPROVEMENT == target.kind) {
979 useless = is_improvement_redundant(*pcity, target.value.building);
980 /* Mark building redundant if we are really certain that there is
981 * no use for it. */
982 g_object_set(rend, "strikethrough", useless, NULL);
983 } else {
984 g_object_set(rend, "strikethrough", FALSE, NULL);
985 }
986 }
987}
988
989/************************************************************************/
992 static void populate_view(GtkTreeView *view, struct city **ppcity,
993 GtkTreeViewColumn **pcol)
994{
995 static const char *titles[] =
996 { N_("Type"), N_("Name"), N_("Info"), N_("Cost"), N_("Turns") };
997
998 static bool titles_done;
999 guint i;
1000 GtkCellRenderer *rend;
1001 GtkTreeViewColumn *col;
1002
1003 intl_slist(ARRAY_SIZE(titles), titles, &titles_done);
1004
1005 /* Case i == 0 taken out of the loop to workaround gcc-4.2.1 bug
1006 * https://gcc.gnu.org/PR33381
1007 * Some values would 'stick' from i == 0 round. */
1008 i = 0;
1009
1010 rend = gtk_cell_renderer_pixbuf_new();
1011
1012 gtk_tree_view_insert_column_with_data_func(view,
1013 i, titles[i], rend, cell_render_func, ppcity, NULL);
1014 col = gtk_tree_view_get_column(view, i);
1015
1016 if (GUI_GTK_OPTION(show_task_icons)) {
1017 if (max_unit_width == -1 || max_unit_height == -1) {
1018 update_max_unit_size();
1019 }
1020 } else {
1021 g_object_set(col, "visible", FALSE, NULL);
1022 }
1023 if (GUI_GTK_OPTION(show_task_icons)) {
1024 g_object_set(rend, "height", max_unit_height, NULL);
1025 }
1026
1027 for (i = 1; i < ARRAY_SIZE(titles); i++) {
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/************************************************************************/
1054 GtkWidget *create_worklist(void)
1055{
1056 GtkWidget *editor, *table, *sw, *bbox;
1057 GtkWidget *src_view, *dst_view, *label, *button;
1058 GtkWidget *menubar, *item, *menu;
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_image_new_from_icon_name("pan-start-symbolic", GTK_ICON_SIZE_MENU);
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_image_new_from_icon_name("pan-up-symbolic", GTK_ICON_SIZE_MENU);
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_image_new_from_icon_name("pan-down-symbolic", GTK_ICON_SIZE_MENU);
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_image_new_from_icon_name("pan-start-symbolic", GTK_ICON_SIZE_MENU);
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_image_new_from_icon_name("pan-end-symbolic", GTK_ICON_SIZE_MENU);
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 item = gtk_menu_item_new_with_mnemonic(_("_Add Global Worklist"));
1222 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
1223 gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
1224 g_signal_connect(menu, "show",
1225 G_CALLBACK(popup_add_menu), ptr);
1226 ptr->add_cmd = item;
1227 gtk_widget_set_sensitive(ptr->add_cmd, FALSE);
1228
1229 button = icon_label_button_new("help-browser", _("Help"));
1230 gtk_container_add(GTK_CONTAINER(bbox), button);
1231 g_signal_connect(button, "clicked",
1232 G_CALLBACK(help_callback), ptr);
1233 ptr->help_cmd = button;
1234 gtk_widget_set_sensitive(ptr->help_cmd, FALSE);
1235
1236 button = gtk_button_new_with_mnemonic(_("Change Prod_uction"));
1237 gtk_container_add(GTK_CONTAINER(bbox), button);
1238 g_signal_connect(button, "clicked",
1239 G_CALLBACK(change_callback), ptr);
1240 ptr->change_cmd = button;
1241 gtk_widget_set_sensitive(ptr->change_cmd, FALSE);
1242
1243 ptr->src_view = src_view;
1244 ptr->dst_view = dst_view;
1245 ptr->src_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(src_view));
1246 ptr->dst_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dst_view));
1247 gtk_tree_selection_set_mode(ptr->dst_selection, GTK_SELECTION_MULTIPLE);
1248
1249 /* DND and other state changing callbacks. */
1250 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(dst_view), TRUE);
1251 g_signal_connect(dst_view, "drag_end",
1252 G_CALLBACK(dst_dnd_callback), ptr);
1253
1254 g_signal_connect(src_view, "row_activated",
1255 G_CALLBACK(src_row_callback), ptr);
1256 g_signal_connect(src_view, "key_press_event",
1257 G_CALLBACK(src_key_press_callback), ptr);
1258
1259 g_signal_connect(dst_view, "row_activated",
1260 G_CALLBACK(dst_row_callback), ptr);
1261 g_signal_connect(dst_view, "key_press_event",
1262 G_CALLBACK(dst_key_press_callback), ptr);
1263
1264 g_signal_connect(ptr->src_selection, "changed",
1265 G_CALLBACK(src_selection_callback), ptr);
1266 g_signal_connect(ptr->dst_selection, "changed",
1267 G_CALLBACK(dst_selection_callback), ptr);
1268
1269
1270 gtk_widget_show_all(table);
1271 gtk_widget_show_all(bbox);
1272
1273 return editor;
1274}
1275
1276/************************************************************************/
1279 void reset_city_worklist(GtkWidget *editor, struct city *pcity)
1280{
1281 struct worklist_data *ptr;
1282
1283 ptr = g_object_get_data(G_OBJECT(editor), "data");
1284
1285 ptr->global_worklist_id = -1;
1286 ptr->pcity = pcity;
1287
1288 gtk_list_store_clear(ptr->src);
1289 gtk_list_store_clear(ptr->dst);
1290
1291 g_object_set(ptr->src_col, "visible", TRUE, NULL);
1292 g_object_set(ptr->dst_col, "visible", TRUE, NULL);
1293
1294 gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(ptr->src_view),
1295 GDK_BUTTON1_MASK,
1296 wl_dnd_targets,
1297 G_N_ELEMENTS(wl_dnd_targets),
1298 GDK_ACTION_COPY);
1299}
1300
1301/************************************************************************/
1304 static void reset_global_worklist(GtkWidget *editor,
1305 struct global_worklist *pgwl)
1306{
1307 struct worklist_data *ptr;
1308
1309 ptr = g_object_get_data(G_OBJECT(editor), "data");
1310
1311 ptr->global_worklist_id = global_worklist_id(pgwl);
1312 ptr->pcity = NULL;
1313
1314 gtk_list_store_clear(ptr->src);
1315 gtk_list_store_clear(ptr->dst);
1316
1317 gtk_widget_hide(ptr->change_cmd);
1318 g_object_set(ptr->src_col, "visible", FALSE, NULL);
1319 g_object_set(ptr->dst_col, "visible", FALSE, NULL);
1320
1321 gtk_tree_view_unset_rows_drag_source(GTK_TREE_VIEW(ptr->src_view));
1322}
1323
1324/************************************************************************/
1327 void refresh_worklist(GtkWidget *editor)
1328{
1329 struct worklist_data *ptr;
1330 struct worklist queue;
1331 struct universal targets[MAX_NUM_PRODUCTION_TARGETS];
1332 int i, targets_used;
1333 struct item items[MAX_NUM_PRODUCTION_TARGETS];
1334 bool selected;
1335 gint id;
1336 GtkTreeIter it;
1337 GtkTreePath *path;
1338 GtkTreeModel *model;
1339 gboolean exists;
1340
1341 ptr = g_object_get_data(G_OBJECT(editor), "data");
1342
1343 /* refresh source tasks. */
1344 if (gtk_tree_selection_get_selected(ptr->src_selection, NULL, &it)) {
1345 gtk_tree_model_get(GTK_TREE_MODEL(ptr->src), &it, 0, &id, -1);
1346 selected = TRUE;
1347 } else {
1348 selected = FALSE;
1349 }
1350
1351 /* These behave just right if ptr->pcity is NULL -> in case of global
1352 * worklist. */
1353 targets_used = collect_eventually_buildable_targets(targets, ptr->pcity,
1354 ptr->future);
1355 name_and_sort_items(targets, targets_used, items, FALSE, ptr->pcity);
1356
1357 /* Re-purpose existing items in the list store -- this avoids the
1358 * UI jumping around (especially as the set of source tasks doesn't
1359 * actually change much in practice). */
1360 model = GTK_TREE_MODEL(ptr->src);
1361 exists = gtk_tree_model_get_iter_first(model, &it);
1362
1363 path = NULL;
1364 for (i = 0; i < targets_used; i++) {
1365 char buf[8192];
1366
1367 if (!exists) {
1368 gtk_list_store_append(ptr->src, &it);
1369 }
1370
1371 gtk_list_store_set(ptr->src, &it, 0, (gint)cid_encode(items[i].item),
1372 1, production_help(&(items[i].item),
1373 buf, sizeof(buf)), -1);
1374
1375 if (selected && cid_encode(items[i].item) == id) {
1376 path = gtk_tree_model_get_path(GTK_TREE_MODEL(ptr->src), &it);
1377 }
1378
1379 if (exists) {
1380 exists = gtk_tree_model_iter_next(model, &it);
1381 }
1382 }
1383
1384 /* If the list got shorter, delete any excess items. */
1385 if (exists) {
1386 GtkTreeIter it_next;
1387 bool more;
1388
1389 do {
1390 it_next = it;
1391 more = gtk_tree_model_iter_next(model, &it_next);
1392
1393 gtk_list_store_remove(ptr->src, &it);
1394 it = it_next;
1395 } while (more);
1396 }
1397
1398 /* Select the same item that was previously selected, if any. */
1399 if (path) {
1400 gtk_tree_view_set_cursor(GTK_TREE_VIEW(ptr->src_view), path, NULL, FALSE);
1401 gtk_tree_path_free(path);
1402 }
1403
1404 /* refresh target worklist. */
1405 model = GTK_TREE_MODEL(ptr->dst);
1406 exists = gtk_tree_model_get_iter_first(model, &it);
1407
1408 /* dance around worklist braindamage. */
1409 if (ptr->pcity != NULL) {
1410 city_get_queue(ptr->pcity, &queue);
1411 } else {
1412 const struct global_worklist *pgwl;
1413
1414 pgwl = global_worklist_by_id(ptr->global_worklist_id);
1415
1416 fc_assert(NULL != pgwl);
1417
1418 worklist_copy(&queue, global_worklist_get(pgwl));
1419 }
1420
1421 for (i = 0; i < worklist_length(&queue); i++) {
1422 struct universal target = queue.entries[i];
1423 char buf[8192];
1424
1425 if (!exists) {
1426 gtk_list_store_append(ptr->dst, &it);
1427 }
1428
1429 gtk_list_store_set(ptr->dst, &it, 0, (gint)cid_encode(target),
1430 1, production_help(&target,
1431 buf, sizeof(buf)), -1);
1432
1433 if (exists) {
1434 exists = gtk_tree_model_iter_next(model, &it);
1435 }
1436 }
1437
1438 if (exists) {
1439 GtkTreeIter it_next;
1440 bool more;
1441
1442 do {
1443 it_next = it;
1444 more = gtk_tree_model_iter_next(model, &it_next);
1445
1446 gtk_list_store_remove(ptr->dst, &it);
1447 it = it_next;
1448 } while (more);
1449 }
1450
1451 /* update widget sensitivity. */
1452 if (ptr->pcity) {
1453 if ((can_client_issue_orders()
1454 && city_owner(ptr->pcity) == client.conn.playing)) {
1455 gtk_widget_set_sensitive(ptr->add_cmd, TRUE);
1456 gtk_widget_set_sensitive(ptr->dst_view, TRUE);
1457 } else {
1458 gtk_widget_set_sensitive(ptr->add_cmd, FALSE);
1459 gtk_widget_set_sensitive(ptr->dst_view, FALSE);
1460 }
1461 } else {
1462 gtk_widget_set_sensitive(ptr->add_cmd, TRUE);
1463 gtk_widget_set_sensitive(ptr->dst_view, TRUE);
1464 }
1465}
1466
1467/************************************************************************/
1470 static void commit_worklist(struct worklist_data *ptr)
1471{
1472 struct worklist queue;
1473 GtkTreeModel *model;
1474 GtkTreeIter it;
1475 size_t i;
1476
1477 model = GTK_TREE_MODEL(ptr->dst);
1478
1479 worklist_init(&queue);
1480
1481 i = 0;
1482 if (gtk_tree_model_get_iter_first(model, &it)) {
1483 do {
1484 gint id;
1485 struct universal univ;
1486
1487 /* oops, the player has a worklist longer than what we can store. */
1488 if (i >= MAX_LEN_WORKLIST) {
1489 break;
1490 }
1491
1492 gtk_tree_model_get(model, &it, 0, &id, -1);
1493 univ = cid_production(id);
1494 worklist_append(&queue, &univ);
1495
1496 i++;
1497 } while (gtk_tree_model_iter_next(model, &it));
1498 }
1499
1500 /* dance around worklist braindamage. */
1501 if (ptr->pcity) {
1502 if (!city_set_queue(ptr->pcity, &queue)) {
1503 /* Failed to change worklist. This means worklist visible
1504 * on screen is not true. */
1505 refresh_worklist(ptr->editor);
1506 }
1507 } else {
1508 struct global_worklist *pgwl;
1509
1510 pgwl = global_worklist_by_id(ptr->global_worklist_id);
1511 if (pgwl) {
1512 global_worklist_set(pgwl, &queue);
1513 }
1514 }
1515}
city.h
city_owner
#define city_owner(_pcity_)
Definition city.h:563
get_city_dialog_production_row
void get_city_dialog_production_row(char *buf[], size_t column_size, struct universal *target, struct city *pcity)
Definition citydlg_common.c:373
city_set_queue
bool city_set_queue(struct city *pcity, const struct worklist *pqueue)
Definition citydlg_common.c:1486
city_change_production
int city_change_production(struct city *pcity, struct universal *target)
Definition citydlg_common.c:1289
city_get_queue
void city_get_queue(struct city *pcity, struct worklist *pqueue)
Definition citydlg_common.c:1469
citydlg_common.h
client
struct civclient client
Definition client_main.c:150
can_client_issue_orders
bool can_client_issue_orders(void)
Definition client_main.c:1264
client_main.h
collect_eventually_buildable_targets
int collect_eventually_buildable_targets(struct universal *targets, struct city *pcity, bool advanced_tech)
Definition climisc.c:809
name_and_sort_items
void name_and_sort_items(struct universal *targets, int num_targets, struct item *items, bool show_cost, struct city *pcity)
Definition climisc.c:640
cid_encode
cid cid_encode(struct universal target)
Definition climisc.c:482
cid_decode
struct universal cid_decode(cid id)
Definition climisc.c:525
climisc.h
MAX_NUM_PRODUCTION_TARGETS
#define MAX_NUM_PRODUCTION_TARGETS
Definition climisc.h:87
cid_production
#define cid_production
Definition climisc.h:71
cid
int cid
Definition climisc.h:31
list
static struct fc_sockaddr_list * list
Definition clinet.c:102
incite_cost
char * incite_cost
Definition comments.c:74
id
int int id
Definition editgui_g.h:28
editor
static struct editor_state * editor
Definition editor.c:100
fcintl.h
_
#define _(String)
Definition fcintl.h:67
N_
#define N_(String)
Definition fcintl.h:69
global_worklist_by_id
struct global_worklist * global_worklist_by_id(int id)
Definition global_worklist.c:298
global_worklist_set
bool global_worklist_set(struct global_worklist *pgwl, const struct worklist *pwl)
Definition global_worklist.c:263
global_worklist_name
const char * global_worklist_name(const struct global_worklist *pgwl)
Definition global_worklist.c:323
global_worklist_id
int global_worklist_id(const struct global_worklist *pgwl)
Definition global_worklist.c:288
global_worklist_destroy
void global_worklist_destroy(struct global_worklist *pgwl)
Definition global_worklist.c:214
global_worklist_get
const struct worklist * global_worklist_get(const struct global_worklist *pgwl)
Definition global_worklist.c:276
global_worklist_new
struct global_worklist * global_worklist_new(const char *name)
Definition global_worklist.c:244
global_worklist_set_name
void global_worklist_set_name(struct global_worklist *pgwl, const char *name)
Definition global_worklist.c:312
global_worklist.h
global_worklists_iterate
#define global_worklists_iterate(pgwl)
Definition global_worklist.h:65
global_worklists_iterate_end
#define global_worklists_iterate_end
Definition global_worklist.h:68
pos
static struct tile * pos
Definition finddlg.c:53
toplevel
GtkWidget * toplevel
Definition gui_main.c:125
GUI_GTK_OPTION
#define GUI_GTK_OPTION(optname)
Definition gui_main.h:25
icon_label_button_new
GtkWidget * icon_label_button_new(const gchar *icon_name, const gchar *label_text)
Definition gui_stuff.c:76
gtk_aux_menu_bar_new
GtkWidget * gtk_aux_menu_bar_new(void)
Definition gui_stuff.c:255
setup_dialog
void setup_dialog(GtkWidget *shell, GtkWidget *parent)
Definition gui_stuff.c:287
intl_slist
void intl_slist(int n, const char **s, bool *done)
Definition gui_stuff.c:111
popup_help_dialog_string
void popup_help_dialog_string(const char *item)
Definition helpdlg.c:212
popup_help_dialog_typed
void popup_help_dialog_typed(const char *item, enum help_page_type htype)
Definition helpdlg.c:196
shell
static struct gui_dialog * shell
Definition messagedlg.c:39
free_sprite
void free_sprite(struct sprite *s)
Definition sprite.c:278
sprite_scale
struct sprite * sprite_scale(struct sprite *src, int new_w, int new_h)
Definition sprite.c:291
sprite_get_pixbuf
GdkPixbuf * sprite_get_pixbuf(struct sprite *sprite)
Definition sprite.c:402
sprite_get_bounding_box
void sprite_get_bounding_box(struct sprite *sprite, int *start_x, int *start_y, int *end_x, int *end_y)
Definition sprite.c:321
hash
static GHashTable * hash
Definition wldlg.c:322
dst_dnd_callback
static gboolean dst_dnd_callback(GtkWidget *w, GdkDragContext *context, struct worklist_data *ptr)
Definition wldlg.c:924
dst_selection_callback
static void dst_selection_callback(GtkTreeSelection *selection, gpointer data)
Definition wldlg.c:891
worklists_response
static void worklists_response(GtkWidget *w, gint response)
Definition wldlg.c:134
update_worklist_report_dialog
void update_worklist_report_dialog(void)
Definition wldlg.c:116
queue_remove
static void queue_remove(struct worklist_data *ptr)
Definition wldlg.c:624
get_worklist
static GtkWidget * get_worklist(int global_worklist_id)
Definition wldlg.c:349
reset_global_worklist
static void reset_global_worklist(GtkWidget *editor, struct global_worklist *pgwl)
Definition wldlg.c:1304
future_callback
static void future_callback(GtkToggleButton *toggle, gpointer data)
Definition wldlg.c:579
blank_max_unit_size
void blank_max_unit_size(void)
Definition wldlg.c:79
src_selection_callback
static void src_selection_callback(GtkTreeSelection *selection, gpointer data)
Definition wldlg.c:860
help_callback
static void help_callback(GtkWidget *w, gpointer data)
Definition wldlg.c:521
wl_dnd_targets
static GtkTargetEntry wl_dnd_targets[]
Definition wldlg.c:331
src_row_callback
static void src_row_callback(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data)
Definition wldlg.c:732
dst_row_callback
static void dst_row_callback(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data)
Definition wldlg.c:766
delete_worklist
static void delete_worklist(int global_worklist_id)
Definition wldlg.c:375
refresh_worklist
void refresh_worklist(GtkWidget *editor)
Definition wldlg.c:1327
add_worklist_dnd_target
void add_worklist_dnd_target(GtkWidget *w)
Definition wldlg.c:339
WORKLISTS_NEW
@ WORKLISTS_NEW
Definition wldlg.c:59
WORKLISTS_CLOSE
@ WORKLISTS_CLOSE
Definition wldlg.c:62
WORKLISTS_DELETE
@ WORKLISTS_DELETE
Definition wldlg.c:60
WORKLISTS_PROPERTIES
@ WORKLISTS_PROPERTIES
Definition wldlg.c:61
TARGET_GTK_TREE_MODEL_ROW
@ TARGET_GTK_TREE_MODEL_ROW
Definition wldlg.c:328
src_key_press_callback
static gboolean src_key_press_callback(GtkWidget *w, GdkEventKey *ev, gpointer data)
Definition wldlg.c:785
popdown_worklist
static void popdown_worklist(struct global_worklist *pgwl)
Definition wldlg.c:420
worklists_shell
static GtkWidget * worklists_shell
Definition wldlg.c:55
popup_worklist
static void popup_worklist(struct global_worklist *pgwl)
Definition wldlg.c:385
worklists_list
static GtkWidget * worklists_list
Definition wldlg.c:56
queue_bubble_up
static void queue_bubble_up(struct worklist_data *ptr)
Definition wldlg.c:592
create_worklists_report
static GtkWidget * create_worklists_report(void)
Definition wldlg.c:213
popup_add_menu
static void popup_add_menu(GtkMenuShell *menu, gpointer data)
Definition wldlg.c:487
cell_edited
static void cell_edited(GtkCellRendererText *cell, const gchar *spath, const gchar *text, gpointer data)
Definition wldlg.c:185
cell_render_func
static void cell_render_func(GtkTreeViewColumn *col, GtkCellRenderer *rend, GtkTreeModel *model, GtkTreeIter *it, gpointer data)
Definition wldlg.c:934
dst_key_press_callback
static gboolean dst_key_press_callback(GtkWidget *w, GdkEventKey *ev, gpointer data)
Definition wldlg.c:810
worklist_destroy
static void worklist_destroy(GtkWidget *editor, gpointer data)
Definition wldlg.c:435
worklists_destroy_callback
static void worklists_destroy_callback(GtkWidget *w, gpointer data)
Definition wldlg.c:108
change_callback
static void change_callback(GtkWidget *w, gpointer data)
Definition wldlg.c:556
reset_city_worklist
void reset_city_worklist(GtkWidget *editor, struct city *pcity)
Definition wldlg.c:1279
queue_insert
static void queue_insert(struct worklist_data *ptr, bool prepend)
Definition wldlg.c:670
menu_item_callback
static void menu_item_callback(GtkMenuItem *item, struct worklist_data *ptr)
Definition wldlg.c:451
populate_view
static void populate_view(GtkTreeView *view, struct city **ppcity, GtkTreeViewColumn **pcol)
Definition wldlg.c:992
insert_worklist
static void insert_worklist(int global_worklist_id, GtkWidget *editor)
Definition wldlg.c:364
queue_append
static void queue_append(struct worklist_data *ptr)
Definition wldlg.c:724
create_worklist
GtkWidget * create_worklist(void)
Definition wldlg.c:1054
commit_worklist
static void commit_worklist(struct worklist_data *ptr)
Definition wldlg.c:1470
queue_bubble_down
static void queue_bubble_down(struct worklist_data *ptr)
Definition wldlg.c:639
max_unit_width
static int max_unit_width
Definition wldlg.c:67
max_unit_height
static int max_unit_height
Definition wldlg.c:67
update_max_unit_size
static void update_max_unit_size(void)
Definition wldlg.c:88
queue_prepend
static void queue_prepend(struct worklist_data *ptr)
Definition wldlg.c:716
worklists_store
static GtkListStore * worklists_store
Definition wldlg.c:65
popup_worklists_report
void popup_worklists_report(void)
Definition wldlg.c:287
gui_stuff.h
inputdlg.h
canvas.h
citydlg.h
graphics.h
gui_main.h
helpdlg.h
wldlg.h
HELP_WORKLIST_EDITOR_ITEM
#define HELP_WORKLIST_EDITOR_ITEM
HELP_IMPROVEMENT
@ HELP_IMPROVEMENT
Definition helpdlg_g.h:20
HELP_UNIT
@ HELP_UNIT
Definition helpdlg_g.h:20
HELP_WONDER
@ HELP_WONDER
Definition helpdlg_g.h:21
is_improvement_redundant
bool is_improvement_redundant(const struct city *pcity, const struct impr_type *pimprove)
Definition improvement.c:641
is_great_wonder
bool is_great_wonder(const struct impr_type *pimprove)
Definition improvement.c:772
improvement_name_translation
const char * improvement_name_translation(const struct impr_type *pimprove)
Definition improvement.c:243
log.h
fc_assert
#define fc_assert(condition)
Definition log.h:176
mem.h
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
options.h
packets.h
ARRAY_SIZE
#define ARRAY_SIZE(x)
Definition shared.h:85
MAX
#define MAX(x, y)
Definition shared.h:54
city
Definition city.h:320
civclient::conn
struct connection conn
Definition client_main.h:96
connection::playing
struct player * playing
Definition connection.h:151
global_worklist
Definition global_worklist.c:49
item
Definition climisc.h:80
sprite
Definition sprite.h:22
tileset
Definition tilespec.c:481
universal
Definition fc_types.h:908
universal::kind
enum universals_n kind
Definition fc_types.h:910
universal::value
universals_u value
Definition fc_types.h:909
view
Definition mapview_common.h:36
worklist_data
Definition wldlg.c:304
worklist_data::add_cmd
GtkWidget * add_cmd
Definition wldlg.c:316
worklist_data::prepend_cmd
GtkWidget * prepend_cmd
Definition wldlg.c:317
worklist_data::group
GActionGroup * group
Definition wldlg.c:311
worklist_data::dst_view
GtkWidget * dst_view
Definition wldlg.c:311
worklist_data::dst_col
GtkTreeViewColumn * dst_col
Definition wldlg.c:314
worklist_data::dst_selection
GtkTreeSelection * dst_selection
Definition wldlg.c:312
worklist_data::src_view
GtkWidget * src_view
Definition wldlg.c:311
worklist_data::up_cmd
GtkWidget * up_cmd
Definition wldlg.c:317
worklist_data::future
bool future
Definition wldlg.c:319
worklist_data::src_selection
GtkTreeSelection * src_selection
Definition wldlg.c:312
worklist_data::src
GtkListStore * src
Definition wldlg.c:310
worklist_data::src_col
GtkTreeViewColumn * src_col
Definition wldlg.c:314
worklist_data::remove_cmd
GtkWidget * remove_cmd
Definition wldlg.c:317
worklist_data::dst
GtkListStore * dst
Definition wldlg.c:310
worklist_data::editor
GtkWidget * editor
Definition wldlg.c:308
worklist_data::global_worklist_id
int global_worklist_id
Definition wldlg.c:305
worklist_data::append_cmd
GtkWidget * append_cmd
Definition wldlg.c:317
worklist_data::help_cmd
GtkWidget * help_cmd
Definition wldlg.c:316
worklist_data::pcity
struct city * pcity
Definition wldlg.c:306
worklist_data::menu
GMenu * menu
Definition wldlg.c:309
worklist_data::down_cmd
GtkWidget * down_cmd
Definition wldlg.c:317
worklist_data::change_cmd
GtkWidget * change_cmd
Definition wldlg.c:316
worklist
Definition worklist.h:28
worklist::entries
struct universal entries[MAX_LEN_WORKLIST]
Definition worklist.h:30
support.h
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
production_help
const char * production_help(const struct universal *uni, char *buf, size_t bufsize)
Definition text.c:2102
text.h
get_building_sprite
struct sprite * get_building_sprite(const struct tileset *t, const struct impr_type *pimprove)
Definition tilespec.c:6801
get_unittype_sprite
struct sprite * get_unittype_sprite(const struct tileset *t, const struct unit_type *punittype, enum unit_activity activity, enum direction8 facing)
Definition tilespec.c:6823
tilespec.h
universals_u::utype
const struct unit_type * utype
Definition fc_types.h:728
universals_u::building
const struct impr_type * building
Definition fc_types.h:721
utype_name_translation
const char * utype_name_translation(const struct unit_type *punittype)
Definition unittype.c:1560
unit_type_iterate
#define unit_type_iterate(_p)
Definition unittype.h:859
unit_type_iterate_end
#define unit_type_iterate_end
Definition unittype.h:866
worklist_copy
void worklist_copy(struct worklist *dst, const struct worklist *src)
Definition worklist.c:112
worklist_init
void worklist_init(struct worklist *pwl)
Definition worklist.c:38
worklist_append
bool worklist_append(struct worklist *pwl, const struct universal *prod)
Definition worklist.c:147
worklist_length
int worklist_length(const struct worklist *pwl)
Definition worklist.c:57
worklist.h
MAX_LEN_WORKLIST
#define MAX_LEN_WORKLIST
Definition worklist.h:24