Rulesave saves trade.type and trade.bonus correctly.
[freeciv.git] / client / gui-gtk-2.0 / editgui.c
blob7fad3e853fb9a3b05ff96bccf8ede4c1954c9003
1 /***********************************************************************
2 Freeciv - Copyright (C) 2005 - The Freeciv Project
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.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 #include <math.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
23 #include <gtk/gtk.h>
24 #include <gdk/gdkkeysyms.h>
26 /* utility */
27 #include "fcintl.h"
28 #include "log.h"
29 #include "shared.h"
30 #include "support.h"
32 /* common */
33 #include "connection.h"
34 #include "game.h"
35 #include "government.h"
36 #include "packets.h"
38 /* client */
39 #include "chatline_common.h"
40 #include "client_main.h"
41 #include "editor.h"
42 #include "mapview_common.h"
43 #include "tilespec.h"
45 #include "dialogs_g.h"
47 /* client/gui-gtk-2.0 */
48 #include "canvas.h"
49 #include "editgui.h"
50 #include "editprop.h"
51 #include "gui_main.h"
52 #include "gui_stuff.h"
53 #include "plrdlg.h"
56 enum tool_value_selector_columns {
57 TVS_COL_IMAGE = 0,
58 TVS_COL_ID,
59 TVS_COL_NAME,
61 TVS_NUM_COLS
64 enum player_pov_combo_columns {
65 PPV_COL_FLAG = 0,
66 PPV_COL_NAME,
67 PPV_COL_PLAYER_NO,
69 PPV_NUM_COLS
72 enum tool_applied_player_columns {
73 TAP_COL_FLAG = 0,
74 TAP_COL_NAME,
75 TAP_COL_PLAYER_NO,
77 TAP_NUM_COLS
80 enum spin_button_types {
81 SPIN_BUTTON_SIZE,
82 SPIN_BUTTON_COUNT
85 struct tool_value_selector {
86 struct editbar *editbar_parent;
88 GtkWidget *dialog;
90 GtkListStore *store;
91 GtkWidget *view;
94 static struct tool_value_selector *
95 create_tool_value_selector(struct editbar *eb_parent,
96 enum editor_tool_type ett);
97 static void editinfobox_refresh(struct editinfobox *ei);
98 static void editbar_player_pov_combobox_changed(GtkComboBox *combo,
99 gpointer user_data);
100 static void editbar_mode_button_toggled(GtkToggleButton *tb,
101 gpointer userdata);
102 static void editbar_tool_button_toggled(GtkToggleButton *tb,
103 gpointer userdata);
104 static void try_to_set_editor_tool(enum editor_tool_type ett);
106 static struct editbar *editor_toolbar;
107 static struct editinfobox *editor_infobox;
109 /****************************************************************************
110 Refresh the buttons in the given editbar according to the current
111 editor state.
112 ****************************************************************************/
113 static void refresh_all_buttons(struct editbar *eb)
115 enum editor_tool_type ett;
116 enum editor_tool_mode etm;
117 GtkWidget *tb = NULL;
118 int i;
120 if (eb == NULL) {
121 return;
124 ett = editor_get_tool();
125 etm = editor_tool_get_mode(ett);
127 for (i = 0; i < NUM_EDITOR_TOOL_MODES; i++) {
128 tb = eb->mode_buttons[i];
129 if (tb == NULL) {
130 continue;
132 disable_gobject_callback(G_OBJECT(tb),
133 G_CALLBACK(editbar_mode_button_toggled));
134 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tb), i == etm);
135 enable_gobject_callback(G_OBJECT(tb),
136 G_CALLBACK(editbar_mode_button_toggled));
137 gtk_widget_set_sensitive(tb, editor_tool_has_mode(ett, i));
140 if (0 <= ett && ett < NUM_EDITOR_TOOL_TYPES
141 && eb->tool_buttons[ett] != NULL) {
142 tb = eb->tool_buttons[ett];
143 disable_gobject_callback(G_OBJECT(tb),
144 G_CALLBACK(editbar_tool_button_toggled));
145 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tb), TRUE);
146 enable_gobject_callback(G_OBJECT(tb),
147 G_CALLBACK(editbar_tool_button_toggled));
151 /****************************************************************************
152 Callback for all tool mode toggle buttons.
153 ****************************************************************************/
154 static void editbar_mode_button_toggled(GtkToggleButton *tb,
155 gpointer userdata)
157 gboolean active;
158 enum editor_tool_mode etm;
159 enum editor_tool_type ett;
161 etm = GPOINTER_TO_INT(userdata);
162 if (!(0 <= etm && etm < NUM_EDITOR_TOOL_MODES)) {
163 return;
166 active = gtk_toggle_button_get_active(tb);
167 ett = editor_get_tool();
169 editor_tool_set_mode(ett, active ? etm : ETM_PAINT);
170 editgui_refresh();
173 /****************************************************************************
174 Try to set the given tool as the current editor tool. If the tool is
175 unavailable (editor_tool_is_usable) an error popup is displayed.
176 ****************************************************************************/
177 static void try_to_set_editor_tool(enum editor_tool_type ett)
179 if (!(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
180 return;
183 if (!editor_tool_is_usable(ett)) {
184 GtkWidget *dialog;
185 dialog = gtk_message_dialog_new(GTK_WINDOW(toplevel),
186 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
187 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s",
188 _("The current ruleset does not define any "
189 "objects corresponding to this editor tool."));
190 gtk_window_set_title(GTK_WINDOW(dialog), editor_tool_get_name(ett));
191 gtk_dialog_run(GTK_DIALOG(dialog));
192 gtk_widget_destroy(dialog);
193 } else {
194 editor_set_tool(ett);
198 /****************************************************************************
199 Callback to handle toggling of any of the tool buttons.
200 ****************************************************************************/
201 static void editbar_tool_button_toggled(GtkToggleButton *tb,
202 gpointer userdata)
204 gboolean active;
205 enum editor_tool_type ett;
207 active = gtk_toggle_button_get_active(tb);
208 ett = GPOINTER_TO_INT(userdata);
210 if (active) {
211 try_to_set_editor_tool(ett);
212 editgui_refresh();
216 /****************************************************************************
217 Refresh the player point-of-view indicator based on the client and
218 editor state.
220 NB: The convention is that the first entry (index 0) in the combo box
221 corresponds to the "global observer".
222 ****************************************************************************/
223 static void refresh_player_pov_indicator(struct editbar *eb)
225 GtkListStore *store;
226 GdkPixbuf *flag;
227 GtkTreeIter iter;
228 GtkWidget *combo;
229 int index = -1, i;
231 if (eb == NULL || eb->player_pov_store == NULL) {
232 return;
235 store = eb->player_pov_store;
236 gtk_list_store_clear(store);
238 gtk_list_store_append(store, &iter);
239 gtk_list_store_set(store, &iter, PPV_COL_NAME, _("Global Observer"),
240 PPV_COL_PLAYER_NO, -1, -1);
242 i = 1;
243 players_iterate(pplayer) {
244 gtk_list_store_append(store, &iter);
245 gtk_list_store_set(store, &iter, PPV_COL_NAME, player_name(pplayer),
246 PPV_COL_PLAYER_NO, player_number(pplayer), -1);
248 if (pplayer->nation != NO_NATION_SELECTED) {
249 flag = get_flag(pplayer->nation);
251 if (flag != NULL) {
252 gtk_list_store_set(store, &iter, PPV_COL_FLAG, flag, -1);
253 g_object_unref(flag);
256 if (pplayer == client_player()) {
257 index = i;
259 i++;
260 } players_iterate_end;
262 if (client_is_global_observer()) {
263 index = 0;
266 combo = eb->player_pov_combobox;
267 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), index);
270 /****************************************************************************
271 Callback to handle selection of a player/global observer in the
272 player pov indicator.
274 NB: The convention is that the first entry (index 0) in the combo box
275 corresponds to the "global observer".
276 ****************************************************************************/
277 static void editbar_player_pov_combobox_changed(GtkComboBox *combo,
278 gpointer user_data)
280 struct editbar *eb = user_data;
281 int id;
282 struct player *pplayer;
283 GtkTreeIter iter;
284 GtkTreeModel *model;
286 if (eb == NULL || eb->widget == NULL
287 || !GTK_WIDGET_VISIBLE(eb->widget)) {
288 return;
291 if (!gtk_combo_box_get_active_iter(combo, &iter)) {
292 return;
295 model = gtk_combo_box_get_model(combo);
296 gtk_tree_model_get(model, &iter, PPV_COL_PLAYER_NO, &id, -1);
298 if ((client_is_global_observer() && id == -1)
299 || client_player_number() == id) {
300 return;
303 /* Ugh... hard-coded server command strings. :( */
304 if (id == -1) {
305 send_chat("/observe");
306 return;
309 pplayer = player_by_number(id);
310 if (pplayer != NULL) {
311 send_chat_printf("/take \"%s\"", pplayer->name);
315 /****************************************************************************
316 Run the tool value selection dialog and return the value ID selected.
317 Returns -1 if cancelled.
318 ****************************************************************************/
319 static int tool_value_selector_run(struct tool_value_selector *tvs)
321 gint res;
322 GtkWidget *dialog;
323 GtkTreeSelection *sel;
324 GtkTreeIter iter;
325 GtkTreeModel *model;
326 int id;
328 if (tvs == NULL) {
329 return -1;
332 dialog = tvs->dialog;
333 res = gtk_dialog_run(GTK_DIALOG(dialog));
334 gtk_widget_hide(dialog);
336 if (res != GTK_RESPONSE_ACCEPT) {
337 return -1;
340 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tvs->view));
341 if (!gtk_tree_selection_get_selected(sel, &model, &iter)) {
342 return -1;
345 gtk_tree_model_get(model, &iter, TVS_COL_ID, &id, -1);
347 return id;
350 /****************************************************************************
351 Run the tool value selector for the given tool type. Sets the editor state
352 and refreshes the editor GUI depending on the user's choices.
354 Returns FALSE if running the dialog is not possible.
355 ****************************************************************************/
356 static bool editgui_run_tool_selection(enum editor_tool_type ett)
358 struct editbar *eb;
359 struct tool_value_selector *tvs;
360 int res = -1;
362 eb = editgui_get_editbar();
363 if (eb == NULL || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
364 return FALSE;
367 if (!editor_tool_has_value(ett)) {
368 return FALSE;
371 tvs = eb->tool_selectors[ett];
372 if (!tvs) {
373 return FALSE;
376 res = tool_value_selector_run(tvs);
378 if (res >= 0) {
379 editor_tool_set_value(ett, res);
380 editinfobox_refresh(editgui_get_editinfobox());
383 return TRUE;
386 /****************************************************************************
387 Handle a mouse click on any of the tool buttons.
388 ****************************************************************************/
389 static gboolean editbar_tool_button_mouse_click(GtkWidget *w,
390 GdkEventButton *ev,
391 gpointer userdata)
393 int ett;
395 if (ev->button != 3) {
396 return FALSE; /* Propagate event further. */
399 ett = GPOINTER_TO_INT(userdata);
400 return editgui_run_tool_selection(ett);
403 /****************************************************************************
404 A helper function to create a toolbar button for the given editor tool.
405 Packs the newly created button into the hbox 'eb->widget'.
406 ****************************************************************************/
407 static void editbar_add_tool_button(struct editbar *eb,
408 enum editor_tool_type ett)
410 GdkPixbuf *pixbuf;
411 GtkWidget *image, *button, *hbox;
412 GtkRadioButton *parent = NULL;
413 struct sprite *sprite;
414 int i;
416 if (!eb || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
417 return;
420 for (i = 0; i < NUM_EDITOR_TOOL_TYPES; i++) {
421 if (eb->tool_buttons[i] != NULL) {
422 parent = GTK_RADIO_BUTTON(eb->tool_buttons[i]);
423 break;
427 if (parent == NULL) {
428 button = gtk_radio_button_new(NULL);
429 } else {
430 button = gtk_radio_button_new_from_widget(parent);
433 sprite = editor_tool_get_sprite(ett);
434 fc_assert_ret(sprite != NULL);
435 pixbuf = sprite_get_pixbuf(sprite);
436 image = gtk_image_new_from_pixbuf(pixbuf);
438 gtk_container_add(GTK_CONTAINER(button), image);
439 gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(button), FALSE);
440 gtk_widget_set_tooltip_text(button, editor_tool_get_tooltip(ett));
441 gtk_size_group_add_widget(eb->size_group, button);
442 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
443 gtk_button_set_focus_on_click(GTK_BUTTON(button), FALSE);
445 g_signal_connect(button, "toggled",
446 G_CALLBACK(editbar_tool_button_toggled), GINT_TO_POINTER(ett));
447 g_signal_connect(button, "button_press_event",
448 G_CALLBACK(editbar_tool_button_mouse_click), GINT_TO_POINTER(ett));
450 hbox = eb->widget;
451 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
452 eb->tool_buttons[ett] = button;
454 if (editor_tool_has_value(ett)) {
455 eb->tool_selectors[ett] = create_tool_value_selector(eb, ett);
459 /****************************************************************************
460 Handle a click on the player properties button in the editor toolbar.
461 ****************************************************************************/
462 static void editbar_player_properties_button_clicked(GtkButton *b,
463 gpointer userdata)
465 struct property_editor *pe;
467 pe = editprop_get_property_editor();
468 property_editor_reload(pe, OBJTYPE_GAME);
469 property_editor_reload(pe, OBJTYPE_PLAYER);
470 property_editor_popup(pe, OBJTYPE_PLAYER);
473 /****************************************************************************
474 Helper function to add a tool mode button to the editor toolbar. The
475 button will be packed into the start of the hbox 'eb->widget'.
476 ****************************************************************************/
477 static void editbar_add_mode_button(struct editbar *eb,
478 enum editor_tool_mode etm)
480 GdkPixbuf *pixbuf;
481 GtkWidget *image, *button, *hbox;
482 struct sprite *sprite;
483 const char *tooltip;
485 if (!eb || !(0 <= etm && etm < NUM_EDITOR_TOOL_MODES)) {
486 return;
489 button = gtk_toggle_button_new();
491 sprite = editor_get_mode_sprite(etm);
492 fc_assert_ret(sprite != NULL);
493 pixbuf = sprite_get_pixbuf(sprite);
494 image = gtk_image_new_from_pixbuf(pixbuf);
496 gtk_container_add(GTK_CONTAINER(button), image);
497 gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(button), FALSE);
498 tooltip = editor_get_mode_tooltip(etm);
499 if (tooltip != NULL) {
500 gtk_widget_set_tooltip_text(button, tooltip);
502 gtk_size_group_add_widget(eb->size_group, button);
503 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
504 gtk_button_set_focus_on_click(GTK_BUTTON(button), FALSE);
506 g_signal_connect(button, "toggled",
507 G_CALLBACK(editbar_mode_button_toggled), GINT_TO_POINTER(etm));
509 hbox = eb->widget;
510 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
511 eb->mode_buttons[etm] = button;
514 /****************************************************************************
515 Create and return an editor toolbar.
516 ****************************************************************************/
517 static struct editbar *editbar_create(void)
519 struct editbar *eb;
520 GtkWidget *hbox, *button, *combo, *image, *separator, *vbox, *evbox;
521 GtkListStore *store;
522 GtkCellRenderer *cell;
523 GdkPixbuf *pixbuf;
524 const struct editor_sprites *sprites;
526 eb = fc_calloc(1, sizeof(struct editbar));
528 hbox = gtk_hbox_new(FALSE, 4);
529 eb->widget = hbox;
530 eb->size_group = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
532 sprites = get_editor_sprites(tileset);
534 editbar_add_mode_button(eb, ETM_ERASE);
536 separator = gtk_vseparator_new();
537 gtk_box_pack_start(GTK_BOX(hbox), separator, FALSE, FALSE, 0);
539 editbar_add_tool_button(eb, ETT_TERRAIN);
540 editbar_add_tool_button(eb, ETT_TERRAIN_RESOURCE);
541 editbar_add_tool_button(eb, ETT_TERRAIN_SPECIAL);
542 editbar_add_tool_button(eb, ETT_ROAD);
543 editbar_add_tool_button(eb, ETT_MILITARY_BASE);
544 editbar_add_tool_button(eb, ETT_UNIT);
545 editbar_add_tool_button(eb, ETT_CITY);
546 editbar_add_tool_button(eb, ETT_VISION);
547 editbar_add_tool_button(eb, ETT_STARTPOS);
548 editbar_add_tool_button(eb, ETT_COPYPASTE);
550 separator = gtk_vseparator_new();
551 gtk_box_pack_start(GTK_BOX(hbox), separator, FALSE, FALSE, 0);
553 /* Player POV indicator. */
554 vbox = gtk_vbox_new(FALSE, 0);
555 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
557 store = gtk_list_store_new(PPV_NUM_COLS,
558 GDK_TYPE_PIXBUF,
559 G_TYPE_STRING,
560 G_TYPE_INT);
561 eb->player_pov_store = store;
563 combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
565 cell = gtk_cell_renderer_pixbuf_new();
566 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), cell, FALSE);
567 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(combo),
568 cell, "pixbuf", PPV_COL_FLAG);
570 cell = gtk_cell_renderer_text_new();
571 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), cell, TRUE);
572 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(combo),
573 cell, "text", PPV_COL_NAME);
575 gtk_widget_set_size_request(combo, 140, -1);
576 g_signal_connect(combo, "changed",
577 G_CALLBACK(editbar_player_pov_combobox_changed), eb);
579 evbox = gtk_event_box_new();
580 gtk_widget_set_tooltip_text(evbox,
581 _("Switch player point-of-view. Use this to edit "
582 "from the perspective of different players, or "
583 "even as a global observer."));
584 gtk_container_add(GTK_CONTAINER(evbox), combo);
585 gtk_box_pack_start(GTK_BOX(vbox), evbox, TRUE, FALSE, 0);
586 eb->player_pov_combobox = combo;
588 /* Property editor button. */
589 button = gtk_button_new();
590 pixbuf = sprite_get_pixbuf(sprites->properties);
591 image = gtk_image_new_from_pixbuf(pixbuf);
592 gtk_container_add(GTK_CONTAINER(button), image);
593 gtk_widget_set_tooltip_text(button, _("Show the property editor."));
594 gtk_size_group_add_widget(eb->size_group, button);
595 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
596 gtk_button_set_focus_on_click(GTK_BUTTON(button), FALSE);
597 g_signal_connect(button, "clicked",
598 G_CALLBACK(editbar_player_properties_button_clicked), eb);
599 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
600 eb->player_properties_button = button;
602 return eb;
605 /****************************************************************************
606 Refresh the tool value selector in the given toolbar for the given tool
607 type with data from the editor state.
608 ****************************************************************************/
609 static void refresh_tool_value_selector(struct editbar *eb,
610 enum editor_tool_type ett)
612 GtkTreeSelection *sel;
613 GtkTreeIter iter;
614 GtkTreeModel *model;
615 int value, store_value;
616 struct tool_value_selector *tvs;
618 if (!editor_is_active() || !eb || !editor_tool_has_value(ett)) {
619 return;
622 tvs = eb->tool_selectors[ett];
624 if (!tvs) {
625 return;
628 value = editor_tool_get_value(ett);
629 model = GTK_TREE_MODEL(tvs->store);
630 if (!gtk_tree_model_get_iter_first(model, &iter)) {
631 return;
634 do {
635 gtk_tree_model_get(model, &iter, TVS_COL_ID, &store_value, -1);
636 if (value == store_value) {
637 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tvs->view));
638 gtk_tree_selection_select_iter(sel, &iter);
639 break;
641 } while (gtk_tree_model_iter_next(model, &iter));
644 /****************************************************************************
645 Refresh all tool value selectors in the given toolbar according to the
646 current editor state.
647 ****************************************************************************/
648 static void refresh_all_tool_value_selectors(struct editbar *eb)
650 int ett;
652 if (!eb) {
653 return;
656 for (ett = 0; ett < NUM_EDITOR_TOOL_TYPES; ett++) {
657 if (editor_tool_has_value(ett)) {
658 refresh_tool_value_selector(eb, ett);
663 /****************************************************************************
664 Refresh the given toolbar according to the current editor state.
665 ****************************************************************************/
666 static void editbar_refresh(struct editbar *eb)
668 if (eb == NULL || eb->widget == NULL) {
669 return;
672 if (!editor_is_active()) {
673 gtk_widget_hide_all(eb->widget);
674 return;
677 refresh_all_buttons(eb);
678 refresh_all_tool_value_selectors(eb);
679 refresh_player_pov_indicator(eb);
681 gtk_widget_show_all(eb->widget);
684 /****************************************************************************
685 Create a pixbuf containing a representative image for the given extra
686 type, to be used as an icon in the GUI.
688 May return NULL on error.
690 NB: You must call g_object_unref on the non-NULL return value when you
691 no longer need it.
692 ****************************************************************************/
693 static GdkPixbuf *create_extra_pixbuf(const struct extra_type *pextra)
695 struct drawn_sprite sprs[80];
696 int count, w, h, canvas_x, canvas_y;
697 GdkPixbuf *pixbuf;
698 struct canvas canvas;
700 w = tileset_tile_width(tileset);
701 h = tileset_tile_height(tileset);
703 pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, w, h);
704 if (pixbuf == NULL) {
705 return NULL;
707 gdk_pixbuf_fill(pixbuf, 0x00000000);
709 canvas.type = CANVAS_PIXBUF;
710 canvas.v.pixbuf = pixbuf;
711 canvas_x = 0;
712 canvas_y = 0;
714 count = fill_basic_extra_sprite_array(tileset, sprs, pextra);
715 put_drawn_sprites(&canvas, 1.0, canvas_x, canvas_y, count, sprs, FALSE);
717 return pixbuf;
720 /****************************************************************************
721 Create a pixbuf containing a representative image for the given terrain
722 type, to be used as an icon in the GUI.
724 May return NULL on error.
726 NB: You must call g_object_unref on the non-NULL return value when you
727 no longer need it.
728 ****************************************************************************/
729 static GdkPixbuf *create_terrain_pixbuf(struct terrain *pterrain)
731 struct drawn_sprite sprs[80];
732 int count, w, h, canvas_x, canvas_y, i;
733 GdkPixbuf *pixbuf;
734 struct canvas canvas;
736 w = tileset_tile_width(tileset);
737 h = tileset_tile_height(tileset);
739 pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, w, h);
740 if (pixbuf == NULL) {
741 return NULL;
743 gdk_pixbuf_fill(pixbuf, 0x00000000);
745 canvas.type = CANVAS_PIXBUF;
746 canvas.v.pixbuf = pixbuf;
747 canvas_x = 0;
748 canvas_y = 0;
750 for (i = 0; i < 3; i++) {
751 count = fill_basic_terrain_layer_sprite_array(tileset, sprs,
752 i, pterrain);
753 put_drawn_sprites(&canvas, 1.0, canvas_x, canvas_y, count, sprs, FALSE);
756 return pixbuf;
759 /****************************************************************************
760 Reload all tool value data from the tileset for the given toolbar.
761 ****************************************************************************/
762 static void editbar_reload_tileset(struct editbar *eb)
764 GtkTreeIter iter;
765 GtkListStore *store;
766 GdkPixbuf *pixbuf;
767 struct sprite *sprite;
768 struct tool_value_selector *tvs;
770 if (eb == NULL || tileset == NULL) {
771 return;
775 /* Reload terrains. */
777 tvs = eb->tool_selectors[ETT_TERRAIN];
778 store = tvs->store;
779 gtk_list_store_clear(store);
781 terrain_type_iterate(pterrain) {
782 gtk_list_store_append(store, &iter);
783 gtk_list_store_set(store, &iter,
784 TVS_COL_ID, terrain_number(pterrain),
785 TVS_COL_NAME, terrain_name_translation(pterrain),
786 -1);
787 pixbuf = create_terrain_pixbuf(pterrain);
788 if (pixbuf != NULL) {
789 gtk_list_store_set(store, &iter, TVS_COL_IMAGE, pixbuf, -1);
790 g_object_unref(pixbuf);
792 } terrain_type_iterate_end;
795 /* Reload terrain resources. */
797 tvs = eb->tool_selectors[ETT_TERRAIN_RESOURCE];
798 store = tvs->store;
799 gtk_list_store_clear(store);
801 resource_type_iterate(presource) {
802 gtk_list_store_append(store, &iter);
803 gtk_list_store_set(store, &iter,
804 TVS_COL_ID, resource_number(presource),
805 TVS_COL_NAME, resource_name_translation(presource),
806 -1);
807 sprite = get_resource_sprite(tileset, presource);
808 if (sprite == NULL) {
809 continue;
811 pixbuf = sprite_get_pixbuf(sprite);
812 if (pixbuf != NULL) {
813 gtk_list_store_set(store, &iter, TVS_COL_IMAGE, pixbuf, -1);
814 /* pixbuf unref will happen automatically when the sprite it was gotten
815 * from gets freed. */
817 } resource_type_iterate_end;
820 /* Reload terrain specials. */
822 tvs = eb->tool_selectors[ETT_TERRAIN_SPECIAL];
823 store = tvs->store;
824 gtk_list_store_clear(store);
826 extra_type_by_cause_iterate(EC_SPECIAL, pextra) {
827 gtk_list_store_append(store, &iter);
828 gtk_list_store_set(store, &iter,
829 TVS_COL_ID, extra_index(pextra),
830 TVS_COL_NAME, extra_name_translation(pextra),
831 -1);
832 pixbuf = create_extra_pixbuf(pextra);
833 if (pixbuf != NULL) {
834 gtk_list_store_set(store, &iter, TVS_COL_IMAGE, pixbuf, -1);
835 g_object_unref(pixbuf);
837 } extra_type_by_cause_iterate_end;
839 tvs = eb->tool_selectors[ETT_ROAD];
840 store = tvs->store;
841 gtk_list_store_clear(store);
843 extra_type_by_cause_iterate(EC_ROAD, pextra) {
844 gtk_list_store_append(store, &iter);
845 gtk_list_store_set(store, &iter,
846 TVS_COL_ID, extra_index(pextra),
847 TVS_COL_NAME, extra_name_translation(pextra),
848 -1);
849 pixbuf = create_extra_pixbuf(pextra);
850 if (pixbuf != NULL) {
851 gtk_list_store_set(store, &iter, TVS_COL_IMAGE, pixbuf, -1);
852 g_object_unref(pixbuf);
854 } extra_type_by_cause_iterate_end;
856 /* Reload military bases. */
858 tvs = eb->tool_selectors[ETT_MILITARY_BASE];
859 store = tvs->store;
860 gtk_list_store_clear(store);
862 extra_type_by_cause_iterate(EC_BASE, pextra) {
863 gtk_list_store_append(store, &iter);
864 gtk_list_store_set(store, &iter,
865 TVS_COL_ID, extra_index(pextra),
866 TVS_COL_NAME, extra_name_translation(pextra),
867 -1);
868 pixbuf = create_extra_pixbuf(pextra);
869 if (pixbuf != NULL) {
870 gtk_list_store_set(store, &iter, TVS_COL_IMAGE, pixbuf, -1);
871 g_object_unref(pixbuf);
873 } extra_type_by_cause_iterate_end;
876 /* Reload unit types. */
878 tvs = eb->tool_selectors[ETT_UNIT];
879 store = tvs->store;
880 gtk_list_store_clear(store);
882 unit_type_iterate(putype) {
883 gtk_list_store_append(store, &iter);
884 gtk_list_store_set(store, &iter,
885 TVS_COL_ID, utype_number(putype),
886 TVS_COL_NAME, utype_name_translation(putype),
887 -1);
888 sprite = get_unittype_sprite(tileset, putype, direction8_invalid(),
889 TRUE);
890 if (sprite == NULL) {
891 continue;
893 pixbuf = sprite_get_pixbuf(sprite);
894 if (pixbuf != NULL) {
895 gtk_list_store_set(store, &iter, TVS_COL_IMAGE, pixbuf, -1);
896 /* pixbuf unref will happen automatically when the sprite it was gotten
897 * from gets freed. */
899 } unit_type_iterate_end;
902 /****************************************************************************
903 Convert gdk modifier values to editor modifier values.
904 ****************************************************************************/
905 static int convert_modifiers(int gdk_event_state)
907 int modifiers = EKM_NONE;
909 if (gdk_event_state & GDK_SHIFT_MASK) {
910 modifiers |= EKM_SHIFT;
912 if (gdk_event_state & GDK_CONTROL_MASK) {
913 modifiers |= EKM_CTRL;
915 if (gdk_event_state & GDK_MOD1_MASK) {
916 modifiers |= EKM_ALT;
919 return modifiers;
922 /****************************************************************************
923 Convert gdk mouse button values to editor mouse button values.
924 ****************************************************************************/
925 static int convert_mouse_button(int gdk_mouse_button)
927 switch (gdk_mouse_button) {
928 case 1:
929 return MOUSE_BUTTON_LEFT;
930 break;
931 case 2:
932 return MOUSE_BUTTON_MIDDLE;
933 break;
934 case 3:
935 return MOUSE_BUTTON_RIGHT;
936 break;
937 default:
938 break;
941 return MOUSE_BUTTON_OTHER;
944 /****************************************************************************
945 Pass on the gdk mouse event to the editor's handler.
946 ****************************************************************************/
947 gboolean handle_edit_mouse_button_press(GdkEventButton *ev)
949 if (ev->type != GDK_BUTTON_PRESS) {
950 return TRUE;
953 editor_mouse_button_press(ev->x, ev->y,
954 convert_mouse_button(ev->button),
955 convert_modifiers(ev->state));
957 return TRUE;
960 /****************************************************************************
961 Pass on the gdk mouse event to the editor's handler.
962 ****************************************************************************/
963 gboolean handle_edit_mouse_button_release(GdkEventButton *ev)
965 if (ev->type != GDK_BUTTON_RELEASE) {
966 return TRUE;
969 editor_mouse_button_release(ev->x, ev->y,
970 convert_mouse_button(ev->button),
971 convert_modifiers(ev->state));
972 return TRUE;
975 /****************************************************************************
976 Pass on the gdk mouse event to the editor's handler.
977 ****************************************************************************/
978 gboolean handle_edit_mouse_move(GdkEventMotion *ev)
980 editor_mouse_move(ev->x, ev->y, convert_modifiers(ev->state));
981 return TRUE;
984 /****************************************************************************
985 Handle a double-click on the tool value list.
986 ****************************************************************************/
987 static void tool_value_selector_treeview_row_activated(GtkTreeView *view,
988 GtkTreePath *path,
989 GtkTreeViewColumn *col,
990 gpointer user_data)
992 struct tool_value_selector *tvs = user_data;
994 gtk_dialog_response(GTK_DIALOG(tvs->dialog), GTK_RESPONSE_ACCEPT);
997 /****************************************************************************
998 Create a tool value selection dialog for the given toolbar.
999 ****************************************************************************/
1000 static struct tool_value_selector *
1001 create_tool_value_selector(struct editbar *eb,
1002 enum editor_tool_type ett)
1004 struct tool_value_selector *tvs;
1005 GtkWidget *vbox, *view, *scrollwin;
1006 GtkCellRenderer *cell;
1007 GtkListStore *store;
1008 GtkTreeViewColumn *col;
1009 GtkTreeSelection *sel;
1011 tvs = fc_calloc(1, sizeof(struct tool_value_selector));
1013 tvs->editbar_parent = eb;
1015 tvs->dialog = gtk_dialog_new_with_buttons(_("Select Tool Value"),
1016 GTK_WINDOW(toplevel), GTK_DIALOG_MODAL,
1017 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1018 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1019 NULL);
1020 vbox = GTK_DIALOG(tvs->dialog)->vbox;
1022 store = gtk_list_store_new(TVS_NUM_COLS,
1023 GDK_TYPE_PIXBUF,
1024 G_TYPE_INT,
1025 G_TYPE_STRING);
1026 tvs->store = store;
1028 scrollwin = gtk_scrolled_window_new(NULL, NULL);
1029 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwin),
1030 GTK_SHADOW_ETCHED_IN);
1031 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
1032 GTK_POLICY_NEVER,
1033 GTK_POLICY_AUTOMATIC);
1034 gtk_box_pack_start(GTK_BOX(vbox), scrollwin, TRUE, TRUE, 0);
1036 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(tvs->store));
1037 gtk_widget_set_size_request(view, -1, 10 * tileset_tile_height(tileset));
1038 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
1039 gtk_tree_view_set_search_column(GTK_TREE_VIEW(view), TVS_COL_NAME);
1040 g_signal_connect(view, "row-activated",
1041 G_CALLBACK(tool_value_selector_treeview_row_activated), tvs);
1043 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
1044 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
1046 cell = gtk_cell_renderer_pixbuf_new();
1047 col = gtk_tree_view_column_new_with_attributes(editor_tool_get_name(ett),
1048 cell, "pixbuf",
1049 TVS_COL_IMAGE, NULL);
1050 gtk_tree_view_column_set_resizable(col, FALSE);
1051 gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1052 gtk_tree_view_column_set_reorderable(col, FALSE);
1053 gtk_tree_view_column_set_clickable(col, FALSE);
1054 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
1056 cell = gtk_cell_renderer_text_new();
1057 col = gtk_tree_view_column_new_with_attributes("ID", cell,
1058 "text", TVS_COL_ID, NULL);
1059 gtk_tree_view_column_set_resizable(col, FALSE);
1060 gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1061 gtk_tree_view_column_set_reorderable(col, FALSE);
1062 gtk_tree_view_column_set_clickable(col, FALSE);
1063 gtk_tree_view_column_set_sort_column_id(col, TVS_COL_ID);
1064 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
1066 cell = gtk_cell_renderer_text_new();
1067 col = gtk_tree_view_column_new_with_attributes("Name", cell,
1068 "text", TVS_COL_NAME, NULL);
1069 gtk_tree_view_column_set_resizable(col, FALSE);
1070 gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1071 gtk_tree_view_column_set_reorderable(col, FALSE);
1072 gtk_tree_view_column_set_clickable(col, FALSE);
1073 gtk_tree_view_column_set_sort_column_id(col, TVS_COL_NAME);
1074 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
1076 gtk_container_add(GTK_CONTAINER(scrollwin), view);
1077 tvs->view = view;
1079 /* Show everything but the window itself. */
1080 gtk_widget_show_all(vbox);
1082 return tvs;
1085 /****************************************************************************
1086 Handle a mouse click on the tool image area in the editor info box.
1087 ****************************************************************************/
1088 static gboolean editinfobox_handle_tool_image_button_press(GtkWidget *evbox,
1089 GdkEventButton *ev,
1090 gpointer data)
1092 editgui_run_tool_selection(editor_get_tool());
1093 return TRUE;
1096 /****************************************************************************
1097 Handle a mouse click on the mode image area in the editor info box.
1098 ****************************************************************************/
1099 static gboolean editinfobox_handle_mode_image_button_press(GtkWidget *evbox,
1100 GdkEventButton *ev,
1101 gpointer data)
1103 editor_tool_cycle_mode(editor_get_tool());
1104 editgui_refresh();
1106 return TRUE;
1109 /****************************************************************************
1110 Callback for spin button changes in the editor info box.
1111 ****************************************************************************/
1112 static void editinfobox_spin_button_value_changed(GtkSpinButton *spinbutton,
1113 gpointer userdata)
1115 struct editinfobox *ei;
1116 int which, value;
1117 enum editor_tool_type ett;
1119 ei = editgui_get_editinfobox();
1121 if (!ei) {
1122 return;
1125 value = gtk_spin_button_get_value_as_int(spinbutton);
1126 which = GPOINTER_TO_INT(userdata);
1127 ett = editor_get_tool();
1129 switch (which) {
1130 case SPIN_BUTTON_SIZE:
1131 editor_tool_set_size(ett, value);
1132 break;
1133 case SPIN_BUTTON_COUNT:
1134 editor_tool_set_count(ett, value);
1135 break;
1136 default:
1137 return;
1138 break;
1141 editinfobox_refresh(ei);
1144 /****************************************************************************
1145 Callback for changes in the applied player combobox in the editor
1146 info box.
1147 ****************************************************************************/
1148 static void editinfobox_tool_applied_player_changed(GtkComboBox *combo,
1149 gpointer userdata)
1151 struct editinfobox *ei = userdata;
1152 GtkTreeIter iter;
1153 GtkTreeModel *model;
1154 int player_no = -1;
1156 if (ei == NULL) {
1157 return;
1160 if (!gtk_combo_box_get_active_iter(combo, &iter)) {
1161 return;
1164 model = gtk_combo_box_get_model(combo);
1165 gtk_tree_model_get(model, &iter, TAP_COL_PLAYER_NO, &player_no, -1);
1167 editor_tool_set_applied_player(editor_get_tool(), player_no);
1170 /****************************************************************************
1171 Create and return an editor info box widget bundle.
1172 ****************************************************************************/
1173 static struct editinfobox *editinfobox_create(void)
1175 GtkWidget *label, *vbox, *frame, *hbox, *vbox2, *image, *evbox;
1176 GtkWidget *spin, *combo;
1177 GtkListStore *store;
1178 GtkCellRenderer *cell;
1179 struct editinfobox *ei;
1180 char buf[128];
1182 ei = fc_calloc(1, sizeof(*ei));
1184 frame = gtk_frame_new(_("Editor Tool"));
1185 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1186 ei->widget = frame;
1188 vbox = gtk_vbox_new(FALSE, 8);
1189 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
1190 gtk_container_add(GTK_CONTAINER(frame), vbox);
1192 /* tool section */
1193 hbox = gtk_hbox_new(FALSE, 8);
1194 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1196 evbox = gtk_event_box_new();
1197 gtk_widget_set_tooltip_text(evbox, _("Click to change value if applicable."));
1198 g_signal_connect(evbox, "button_press_event",
1199 G_CALLBACK(editinfobox_handle_tool_image_button_press), NULL);
1200 gtk_box_pack_start(GTK_BOX(hbox), evbox, FALSE, FALSE, 0);
1202 image = gtk_image_new();
1203 gtk_container_add(GTK_CONTAINER(evbox), image);
1204 ei->tool_image = image;
1206 vbox2 = gtk_vbox_new(FALSE, 4);
1207 gtk_box_pack_start(GTK_BOX(hbox), vbox2, FALSE, FALSE, 0);
1209 label = gtk_label_new(NULL);
1210 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1211 gtk_box_pack_start(GTK_BOX(vbox2), label, FALSE, FALSE, 0);
1212 ei->tool_label = label;
1214 label = gtk_label_new(NULL);
1215 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1216 gtk_box_pack_start(GTK_BOX(vbox2), label, FALSE, FALSE, 0);
1217 ei->tool_value_label = label;
1219 /* mode section */
1220 hbox = gtk_hbox_new(FALSE, 8);
1221 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1223 evbox = gtk_event_box_new();
1224 gtk_widget_set_tooltip_text(evbox, _("Click to change tool mode."));
1225 g_signal_connect(evbox, "button_press_event",
1226 G_CALLBACK(editinfobox_handle_mode_image_button_press), NULL);
1227 gtk_box_pack_start(GTK_BOX(hbox), evbox, FALSE, FALSE, 0);
1229 image = gtk_image_new();
1230 gtk_container_add(GTK_CONTAINER(evbox), image);
1231 ei->mode_image = image;
1233 vbox2 = gtk_vbox_new(FALSE, 4);
1234 gtk_box_pack_start(GTK_BOX(hbox), vbox2, FALSE, FALSE, 0);
1236 label = gtk_label_new(NULL);
1237 fc_snprintf(buf, sizeof(buf), "<span weight=\"bold\">%s</span>",
1238 _("Mode"));
1239 gtk_label_set_markup(GTK_LABEL(label), buf);
1240 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1241 gtk_box_pack_start(GTK_BOX(vbox2), label, FALSE, FALSE, 0);
1243 label = gtk_label_new(NULL);
1244 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1245 gtk_box_pack_start(GTK_BOX(vbox2), label, FALSE, FALSE, 0);
1246 ei->mode_label = label;
1248 /* spinner section */
1249 hbox = gtk_hbox_new(FALSE, 8);
1250 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1251 ei->size_hbox = hbox;
1252 spin = gtk_spin_button_new_with_range(1, 255, 1);
1253 gtk_widget_set_tooltip_text(spin,
1254 _("Use this to change the \"size\" parameter for the tool. "
1255 "This parameter controls for example the half-width "
1256 "of the square of tiles that will be affected by the "
1257 "tool, or the size of a created city."));
1258 g_signal_connect(spin, "value-changed",
1259 G_CALLBACK(editinfobox_spin_button_value_changed),
1260 GINT_TO_POINTER(SPIN_BUTTON_SIZE));
1261 gtk_box_pack_start(GTK_BOX(hbox), spin, FALSE, FALSE, 0);
1262 ei->size_spin_button = spin;
1263 label = gtk_label_new(_("Size"));
1264 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1266 hbox = gtk_hbox_new(FALSE, 8);
1267 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1268 ei->count_hbox = hbox;
1269 spin = gtk_spin_button_new_with_range(1, 255, 1);
1270 gtk_widget_set_tooltip_text(spin,
1271 _("Use this to change the tool's \"count\" parameter. "
1272 "This controls for example how many units are placed "
1273 "at once with the unit tool."));
1274 g_signal_connect(spin, "value-changed",
1275 G_CALLBACK(editinfobox_spin_button_value_changed),
1276 GINT_TO_POINTER(SPIN_BUTTON_COUNT));
1277 gtk_box_pack_start(GTK_BOX(hbox), spin, FALSE, FALSE, 0);
1278 ei->count_spin_button = spin;
1279 label = gtk_label_new(_("Count"));
1280 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1282 /* combo section */
1283 store = gtk_list_store_new(TAP_NUM_COLS,
1284 GDK_TYPE_PIXBUF,
1285 G_TYPE_STRING,
1286 G_TYPE_INT);
1287 ei->tool_applied_player_store = store;
1288 combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
1290 cell = gtk_cell_renderer_pixbuf_new();
1291 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), cell, FALSE);
1292 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(combo),
1293 cell, "pixbuf", TAP_COL_FLAG);
1295 cell = gtk_cell_renderer_text_new();
1296 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), cell, TRUE);
1297 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(combo),
1298 cell, "text", TAP_COL_NAME);
1300 gtk_widget_set_size_request(combo, 132, -1);
1301 g_signal_connect(combo, "changed",
1302 G_CALLBACK(editinfobox_tool_applied_player_changed), ei);
1304 evbox = gtk_event_box_new();
1305 gtk_widget_set_tooltip_text(evbox,
1306 _("Use this to change the \"applied player\" tool parameter. "
1307 "This controls for example under which player units and cities "
1308 "are created."));
1309 gtk_container_add(GTK_CONTAINER(evbox), combo);
1310 gtk_box_pack_start(GTK_BOX(vbox), evbox, FALSE, FALSE, 0);
1311 ei->tool_applied_player_combobox = combo;
1313 /* We add a ref to the editinfobox widget so that it is
1314 * not destroyed when replaced by the unit info box when
1315 * we leave edit mode. See editinfobox_refresh(). */
1316 g_object_ref(ei->widget);
1318 /* The edit info box starts with no parent, so we have to
1319 * show its internal widgets manually. */
1320 gtk_widget_show_all(ei->widget);
1322 return ei;
1325 /****************************************************************************
1326 Refresh the given editinfobox's applied player combobox according to the
1327 current editor state.
1328 ****************************************************************************/
1329 static void refresh_tool_applied_player_combo(struct editinfobox *ei)
1331 enum editor_tool_type ett;
1332 GtkListStore *store;
1333 GtkWidget *combo;
1334 GtkTreeIter iter;
1335 GdkPixbuf *flag;
1336 int apno, index, i;
1338 if (!ei) {
1339 return;
1342 ett = editor_get_tool();
1343 combo = ei->tool_applied_player_combobox;
1344 store = ei->tool_applied_player_store;
1346 if (!combo || !store) {
1347 return;
1350 if (!editor_tool_has_applied_player(ett)) {
1351 gtk_widget_hide(combo);
1352 return;
1355 gtk_list_store_clear(store);
1357 apno = editor_tool_get_applied_player(ett);
1358 index = -1;
1359 i = 0;
1361 players_iterate(pplayer) {
1362 gtk_list_store_append(store, &iter);
1363 gtk_list_store_set(store, &iter,
1364 TAP_COL_PLAYER_NO, player_number(pplayer),
1365 TAP_COL_NAME, player_name(pplayer), -1);
1367 if (pplayer->nation != NO_NATION_SELECTED) {
1368 flag = get_flag(pplayer->nation);
1370 if (flag != NULL) {
1371 gtk_list_store_set(store, &iter, TAP_COL_FLAG, flag, -1);
1372 g_object_unref(flag);
1375 if (apno == player_number(pplayer)) {
1376 index = i;
1378 i++;
1379 } players_iterate_end;
1381 if (index == -1) {
1382 if (player_count() > 0) {
1383 index = 0;
1385 editor_tool_set_applied_player(ett, index);
1387 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), index);
1388 gtk_widget_show(combo);
1391 /****************************************************************************
1392 Return a pixbuf containing an image for the given editor tool sub-value,
1393 if one exists.
1395 NB: Can return NULL. Must call g_object_unref on non-NULL when done.
1396 ****************************************************************************/
1397 static GdkPixbuf *get_tool_value_pixbuf(enum editor_tool_type ett,
1398 int value)
1400 struct sprite *sprite = NULL;
1401 GdkPixbuf *pixbuf = NULL;
1402 struct terrain *pterrain;
1403 struct resource *presource;
1404 struct unit_type *putype;
1405 const struct editor_sprites *sprites;
1407 sprites = get_editor_sprites(tileset);
1408 if (!sprites) {
1409 return NULL;
1412 switch (ett) {
1413 case ETT_TERRAIN:
1414 pterrain = terrain_by_number(value);
1415 if (pterrain) {
1416 pixbuf = create_terrain_pixbuf(pterrain);
1418 break;
1419 case ETT_TERRAIN_RESOURCE:
1420 presource = resource_by_number(value);
1421 if (presource) {
1422 sprite = get_resource_sprite(tileset, presource);
1424 break;
1425 case ETT_TERRAIN_SPECIAL:
1426 case ETT_ROAD:
1427 case ETT_MILITARY_BASE:
1428 if (value >= 0) {
1429 pixbuf = create_extra_pixbuf(extra_by_number(value));
1431 break;
1432 case ETT_UNIT:
1433 putype = utype_by_number(value);
1434 if (putype) {
1435 sprite = get_unittype_sprite(tileset, putype, direction8_invalid(),
1436 TRUE);
1438 break;
1439 case ETT_CITY:
1440 sprite = sprites->city;
1441 break;
1442 case ETT_VISION:
1443 sprite = sprites->vision;
1444 break;
1445 case ETT_STARTPOS:
1446 sprite = sprites->startpos;
1447 break;
1448 case ETT_COPYPASTE:
1449 sprite = sprites->copypaste;
1450 break;
1451 default:
1452 break;
1455 if (sprite) {
1456 pixbuf = sprite_get_pixbuf(sprite);
1457 if (pixbuf) {
1458 g_object_ref(pixbuf);
1460 sprite = NULL;
1463 return pixbuf;
1466 /****************************************************************************
1467 Return a pixbuf containing an image suitable for use as an icon
1468 respresenting the given editor tool mode.
1470 NB: May return NULL. Must call g_object_unref on non-NULL when done.
1471 ****************************************************************************/
1472 static GdkPixbuf *get_tool_mode_pixbuf(enum editor_tool_mode etm)
1474 struct sprite *sprite = NULL;
1475 GdkPixbuf *pixbuf = NULL;
1477 sprite = editor_get_mode_sprite(etm);
1479 if (sprite) {
1480 pixbuf = sprite_get_pixbuf(sprite);
1481 if (pixbuf) {
1482 g_object_ref(pixbuf);
1486 return pixbuf;
1489 /****************************************************************************
1490 NB: Assumes that widget 'old' has enough references to not be destroyed
1491 when removed from its parent container, and that the parent container
1492 is a GtkBox (or is descended from it).
1493 ****************************************************************************/
1494 static void replace_widget(GtkWidget *old, GtkWidget *new)
1496 GtkWidget *parent;
1498 parent = gtk_widget_get_parent(old);
1499 if (!parent) {
1500 return;
1503 gtk_container_remove(GTK_CONTAINER(parent), old);
1504 gtk_box_pack_start(GTK_BOX(parent), new, FALSE, FALSE, 0);
1507 /****************************************************************************
1508 Refresh the given editinfobox according to the current editor state.
1509 ****************************************************************************/
1510 static void editinfobox_refresh(struct editinfobox *ei)
1512 GdkPixbuf *pixbuf = NULL;
1513 GtkLabel *label;
1514 enum editor_tool_type ett;
1515 enum editor_tool_mode etm;
1516 int value;
1517 char buf[256];
1519 if (ei == NULL) {
1520 return;
1523 if (!editor_is_active()) {
1524 replace_widget(ei->widget, unit_info_box);
1525 return;
1528 ett = editor_get_tool();
1529 etm = editor_tool_get_mode(ett);
1530 value = editor_tool_get_value(ett);
1532 label = GTK_LABEL(ei->mode_label);
1533 gtk_label_set_text(label, editor_tool_get_mode_name(ett, etm));
1535 pixbuf = get_tool_mode_pixbuf(etm);
1536 gtk_image_set_from_pixbuf(GTK_IMAGE(ei->mode_image), pixbuf);
1537 if (pixbuf) {
1538 g_object_unref(pixbuf);
1539 pixbuf = NULL;
1542 fc_snprintf(buf, sizeof(buf), "<span weight=\"bold\">%s</span>",
1543 editor_tool_get_name(ett));
1544 gtk_label_set_markup(GTK_LABEL(ei->tool_label), buf);
1546 if (etm == ETM_COPY || etm == ETM_PASTE) {
1547 struct edit_buffer *ebuf;
1548 struct sprite *spr;
1549 char status[256];
1551 ebuf = editor_get_copy_buffer();
1552 edit_buffer_get_status_string(ebuf, status, sizeof(status));
1553 gtk_label_set_text(GTK_LABEL(ei->tool_value_label), status);
1555 spr = editor_tool_get_sprite(ett);
1556 pixbuf = spr ? sprite_get_pixbuf(spr) : NULL;
1557 gtk_image_set_from_pixbuf(GTK_IMAGE(ei->tool_image), pixbuf);
1558 pixbuf = NULL;
1559 } else {
1560 pixbuf = get_tool_value_pixbuf(ett, value);
1561 gtk_image_set_from_pixbuf(GTK_IMAGE(ei->tool_image), pixbuf);
1562 if (pixbuf) {
1563 g_object_unref(pixbuf);
1564 pixbuf = NULL;
1566 gtk_label_set_text(GTK_LABEL(ei->tool_value_label),
1567 editor_tool_get_value_name(ett, value));
1570 if (editor_tool_has_size(ett)) {
1571 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ei->size_spin_button),
1572 editor_tool_get_size(ett));
1573 gtk_widget_show(ei->size_hbox);
1574 } else {
1575 gtk_widget_hide(ei->size_hbox);
1578 if (editor_tool_has_count(ett)) {
1579 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ei->count_spin_button),
1580 editor_tool_get_count(ett));
1581 gtk_widget_show(ei->count_hbox);
1582 } else {
1583 gtk_widget_hide(ei->count_hbox);
1586 refresh_tool_applied_player_combo(ei);
1588 replace_widget(unit_info_box, ei->widget);
1591 /****************************************************************************
1592 Handle ctrl+<key> combinations.
1593 ****************************************************************************/
1594 static gboolean handle_edit_key_press_with_ctrl(GdkEventKey *ev)
1596 return FALSE; /* Don't gobble. */
1599 /****************************************************************************
1600 Handle shift+<key> combinations.
1601 ****************************************************************************/
1602 static gboolean handle_edit_key_press_with_shift(GdkEventKey *ev)
1604 enum editor_tool_type ett;
1606 ett = editor_get_tool();
1607 switch (ev->keyval) {
1608 case GDK_D:
1609 editor_tool_toggle_mode(ett, ETM_ERASE);
1610 break;
1611 case GDK_C:
1612 editor_set_tool(ETT_COPYPASTE);
1613 editor_tool_toggle_mode(ett, ETM_COPY);
1614 break;
1615 case GDK_V:
1616 editor_set_tool(ETT_COPYPASTE);
1617 editor_tool_toggle_mode(ett, ETM_PASTE);
1618 break;
1619 case GDK_T:
1620 editgui_run_tool_selection(ETT_TERRAIN);
1621 break;
1622 case GDK_R:
1623 editgui_run_tool_selection(ETT_TERRAIN_RESOURCE);
1624 break;
1625 case GDK_S:
1626 editgui_run_tool_selection(ETT_TERRAIN_SPECIAL);
1627 break;
1628 case GDK_P:
1629 editgui_run_tool_selection(ETT_ROAD);
1630 break;
1631 case GDK_M:
1632 editgui_run_tool_selection(ETT_MILITARY_BASE);
1633 break;
1634 case GDK_U:
1635 editgui_run_tool_selection(ETT_UNIT);
1636 break;
1637 default:
1638 return TRUE; /* Gobble? */
1639 break;
1642 editgui_refresh();
1644 return TRUE;
1647 /****************************************************************************
1648 Handle any kind of key press event.
1649 ****************************************************************************/
1650 gboolean handle_edit_key_press(GdkEventKey *ev)
1652 enum editor_tool_type ett, new_ett = NUM_EDITOR_TOOL_TYPES;
1654 if (ev->state & GDK_SHIFT_MASK) {
1655 return handle_edit_key_press_with_shift(ev);
1658 if (ev->state & GDK_CONTROL_MASK) {
1659 return handle_edit_key_press_with_ctrl(ev);
1662 ett = editor_get_tool();
1664 switch (ev->keyval) {
1665 case GDK_t:
1666 new_ett = ETT_TERRAIN;
1667 break;
1668 case GDK_r:
1669 new_ett = ETT_TERRAIN_RESOURCE;
1670 break;
1671 case GDK_s:
1672 new_ett = ETT_TERRAIN_SPECIAL;
1673 break;
1674 case GDK_p:
1675 new_ett = ETT_ROAD;
1676 break;
1677 case GDK_m:
1678 new_ett = ETT_MILITARY_BASE;
1679 break;
1680 case GDK_u:
1681 new_ett = ETT_UNIT;
1682 break;
1683 case GDK_c:
1684 new_ett = ETT_CITY;
1685 break;
1686 case GDK_v:
1687 new_ett = ETT_VISION;
1688 break;
1689 case GDK_b:
1690 new_ett = ETT_STARTPOS;
1691 break;
1692 case GDK_plus:
1693 case GDK_equal:
1694 case GDK_KP_Add:
1695 if (editor_tool_has_size(ett)) {
1696 int size = editor_tool_get_size(ett);
1697 editor_tool_set_size(ett, size + 1);
1698 } else if (editor_tool_has_count(ett)) {
1699 int count = editor_tool_get_count(ett);
1700 editor_tool_set_count(ett, count + 1);
1702 break;
1703 case GDK_minus:
1704 case GDK_underscore:
1705 case GDK_KP_Subtract:
1706 if (editor_tool_has_size(ett)) {
1707 int size = editor_tool_get_size(ett);
1708 editor_tool_set_size(ett, size - 1);
1709 } else if (editor_tool_has_count(ett)) {
1710 int count = editor_tool_get_count(ett);
1711 editor_tool_set_count(ett, count - 1);
1713 break;
1714 case GDK_1:
1715 case GDK_2:
1716 case GDK_3:
1717 case GDK_4:
1718 case GDK_5:
1719 case GDK_6:
1720 case GDK_7:
1721 case GDK_8:
1722 case GDK_9:
1723 if (editor_tool_has_size(ett)) {
1724 editor_tool_set_size(ett, ev->keyval - GDK_1 + 1);
1725 } else if (editor_tool_has_count(ett)) {
1726 editor_tool_set_count(ett, ev->keyval - GDK_1 + 1);
1728 break;
1729 case GDK_space:
1730 editor_apply_tool_to_selection();
1731 break;
1732 case GDK_Tab:
1733 editgui_run_tool_selection(ett);
1734 break;
1735 case GDK_F1:
1736 case GDK_F2:
1737 case GDK_F3:
1738 case GDK_F4:
1739 case GDK_F5:
1740 case GDK_F6:
1741 case GDK_F7:
1742 case GDK_F8:
1743 case GDK_F9:
1744 case GDK_F10:
1745 case GDK_F11:
1746 case GDK_F12:
1747 return FALSE; /* Allow default handler. */
1748 break;
1749 default:
1750 return TRUE; /* Gobbled... */
1751 break;
1754 if (new_ett != NUM_EDITOR_TOOL_TYPES) {
1755 try_to_set_editor_tool(new_ett);
1758 editgui_refresh();
1760 return TRUE;
1763 /****************************************************************************
1764 Key release handler.
1765 ****************************************************************************/
1766 gboolean handle_edit_key_release(GdkEventKey *ev)
1768 return FALSE;
1771 /****************************************************************************
1772 Get the pointer for the editbar embedded in the client's GUI.
1773 ****************************************************************************/
1774 struct editbar *editgui_get_editbar(void)
1776 return editor_toolbar;
1779 /****************************************************************************
1780 Refresh all editor GUI widgets according to the current editor state.
1781 ****************************************************************************/
1782 void editgui_refresh(void)
1784 struct property_editor *pe;
1785 struct editbar *eb;
1786 struct editinfobox *ei;
1788 eb = editgui_get_editbar();
1789 if (eb != NULL) {
1790 editbar_refresh(eb);
1793 ei = editgui_get_editinfobox();
1794 if (ei != NULL) {
1795 editinfobox_refresh(ei);
1798 pe = editprop_get_property_editor();
1799 if (!editor_is_active()) {
1800 property_editor_clear(pe);
1801 property_editor_popdown(pe);
1805 /****************************************************************************
1806 Create all editor GUI widgets.
1807 ****************************************************************************/
1808 void editgui_create_widgets(void)
1810 if (editor_toolbar == NULL) {
1811 editor_toolbar = editbar_create();
1813 if (editor_infobox == NULL) {
1814 editor_infobox = editinfobox_create();
1818 /****************************************************************************
1819 Return a pointer to the editor info box embedded in the client's GUI.
1820 ****************************************************************************/
1821 struct editinfobox *editgui_get_editinfobox(void)
1823 return editor_infobox;
1826 /****************************************************************************
1827 Update all editor widget internal data for the new tileset. Call this
1828 after a new tileset has finished loading.
1829 ****************************************************************************/
1830 void editgui_tileset_changed(void)
1832 editbar_reload_tileset(editgui_get_editbar());
1833 editinfobox_refresh(editgui_get_editinfobox());
1836 /****************************************************************************
1837 Popup the property editor. If 'tiles' is non-NULL, the tiles, units and
1838 cities in those tiles are added to the property editor's object list. If
1839 'objtype' is a valid object type, the corresponding page of the property
1840 editor notebook is focused. Otherwise which page is focused depends on
1841 what was loaded from 'tiles'.
1842 ****************************************************************************/
1843 void editgui_popup_properties(const struct tile_list *tiles, int objtype)
1845 struct property_editor *pe;
1847 pe = editprop_get_property_editor();
1848 property_editor_clear(pe);
1849 property_editor_reload(pe, OBJTYPE_PLAYER);
1850 property_editor_reload(pe, OBJTYPE_GAME);
1851 property_editor_load_tiles(pe, tiles);
1852 property_editor_popup(pe, objtype);
1855 /****************************************************************************
1856 Popup all dialog window of the editor.
1857 ****************************************************************************/
1858 void editgui_popdown_all(void)
1860 struct property_editor *pe;
1862 pe = editprop_get_property_editor();
1863 property_editor_popdown(pe);
1864 property_editor_clear(pe); /* And clear it. */
1867 /****************************************************************************
1868 This is called to notify the editor GUI that some object (e.g. tile, unit,
1869 etc.) has changed (usually because the corresponding packet was received)
1870 and that widgets displaying the object should be updated.
1872 Currently this is used to notify the property editor that some object
1873 has been removed or some property value has changed at the server.
1874 ****************************************************************************/
1875 void editgui_notify_object_changed(int objtype, int object_id, bool removal)
1877 struct property_editor *pe;
1879 if (!editor_is_active()) {
1880 return;
1883 pe = editprop_get_property_editor();
1884 property_editor_handle_object_changed(pe, objtype, object_id, removal);
1887 /****************************************************************************
1888 Pass on the object creation notification to the property editor.
1889 ****************************************************************************/
1890 void editgui_notify_object_created(int tag, int id)
1892 struct property_editor *pe;
1894 if (!editor_is_active()) {
1895 return;
1898 pe = editprop_get_property_editor();
1899 property_editor_handle_object_created(pe, tag, id);