Freeciv-3.1
Loading...
Searching...
No Matches
editprop.c
Go to the documentation of this file.
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.
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 <limits.h> /* USHRT_MAX */
19
20#include <gtk/gtk.h>
21#include <gdk/gdkkeysyms.h>
22
23/* utility */
24#include "bitvector.h"
25#include "fc_cmdline.h"
26#include "fcintl.h"
27#include "log.h"
28#include "mem.h"
29
30/* common */
31#include "fc_interface.h"
32#include "game.h"
33#include "government.h"
34#include "map.h"
35#include "movement.h"
36#include "research.h"
37#include "tile.h"
38
39/* client */
40#include "client_main.h"
41#include "climisc.h"
42#include "editor.h"
43#include "mapview_common.h"
44#include "tilespec.h"
45
46/* client/gui-gtk-4.0 */
47#include "canvas.h"
48#include "gui_main.h"
49#include "gui_stuff.h"
50#include "plrdlg.h"
51#include "sprite.h"
52
53#include "editprop.h"
54
55
56/* Forward declarations. */
57struct objprop;
58struct objbind;
59struct property_page;
60struct property_editor;
61struct extviewer;
62
63/****************************************************************************
64 Miscellaneous helpers.
65****************************************************************************/
66static GdkPixbuf *create_pixbuf_from_layers(const struct tile *ptile,
67 const struct unit *punit,
68 const struct city *pcity,
69 enum layer_category category);
70static GdkPixbuf *create_tile_pixbuf(const struct tile *ptile);
71static GdkPixbuf *create_unit_pixbuf(const struct unit *punit);
72static GdkPixbuf *create_city_pixbuf(const struct city *pcity);
73
74static void add_column(GtkWidget *view,
75 int col_id,
76 const char *name,
77 GType gtype,
78 bool editable,
79 bool is_radio,
80 GCallback edit_callback,
81 gpointer callback_userdata);
82
83static bool can_create_unit_at_tile(struct tile *ptile);
84
85static int get_next_unique_tag(void);
86
87/* 'struct stored_tag_hash' and related functions. */
88#define SPECHASH_TAG stored_tag
89#define SPECHASH_INT_KEY_TYPE
90#define SPECHASH_INT_DATA_TYPE
91#include "spechash.h"
92
93/* NB: If packet definitions change, be sure to
94 * update objbind_pack_current_values()!!! */
95union packetdata {
96 struct {
97 gpointer v_pointer1;
98 gpointer v_pointer2;
100 struct packet_edit_tile *tile;
102 struct packet_edit_city *city;
103 struct packet_edit_unit *unit;
105 struct {
106 struct packet_edit_game *game;
107 struct packet_edit_scenario_desc *desc;
109};
110
111/* Helpers for the OPID_TILE_VISION property. */
112struct tile_vision_data {
113 bv_player tile_known, tile_seen[V_COUNT];
114};
115const char *vision_layer_get_name(enum vision_layer);
116
117#define PF_MAX_CLAUSES 16
118#define PF_DISJUNCTION_SEPARATOR "|"
119#define PF_CONJUNCTION_SEPARATOR "&"
120
121struct pf_pattern {
122 bool negate;
123 char *text;
124};
125
126struct pf_conjunction {
128 int count;
129};
130
131struct property_filter {
133 int count;
134};
135
136static struct property_filter *property_filter_new(const char *filter);
137static bool property_filter_match(struct property_filter *pf,
138 const struct objprop *op);
139static void property_filter_free(struct property_filter *pf);
140
141
142/****************************************************************************
143 Object type declarations.
144
145 To add a new object type:
146 1. Add a value in enum editor_object_type in client/editor.h.
147 2. Add a string name to objtype_get_name.
148 3. Add code in objtype_get_id_from_object.
149 4. Add code in objtype_get_object_from_id.
150 5. Add a case handler in objtype_is_conserved, and if
151 the object type is not conserved, then also in
152 objbind_request_destroy_object and property_page_create_objects.
153 6. Add an if-block in objbind_get_value_from_object.
154 7. Add an if-block in objbind_get_allowed_value_span.
155 9. Add a case handler in property_page_setup_objprops.
156 10. Add a case handler in property_page_add_objbinds_from_tile
157 if applicable.
158
159 Furthermore, if the object type is to be editable:
160 11. Define its edit packet in common/networking/packets.def.
161 12. Add the packet handler in server/edithand.c.
162 13. Add its edit packet type to union packetdata.
163 14. Add an if-block in objbind_pack_current_values.
164 15. Add an if-block in objbind_pack_modified_value.
165 16. Add code in property_page_new_packet.
166 17. Add code in property_page_send_packet.
167 18. Add calls to editgui_notify_object_changed in
168 client/packhand.c or where applicable.
169
170****************************************************************************/
171
172/* OBJTYPE_* enum values defined in client/editor.h */
173
174static const char *objtype_get_name(enum editor_object_type objtype);
176 gpointer object);
178 int id);
180
181
182/****************************************************************************
183 Value type declarations.
184
185 To add a new value type:
186 1. Add a value in enum value_types.
187 2. Add its field in union propval_data.
188 3. Add a case handler in valtype_get_name.
189 4. Add a case handler in propval_copy if needed.
190 5. Add a case handler in propval_free if needed.
191 6. Add a case handler in propval_equal if needed.
192 7. Add a case handler in objprop_get_gtype.
193 8. Add a case handler in property_page_set_store_value.
194 9. Add a case handler in propval_as_string if needed.
195****************************************************************************/
212
213static const char *valtype_get_name(enum value_types valtype);
214
215
216/****************************************************************************
217 Propstate and propval declarations.
218
219 To add a new member to union propval_data, see the steps for adding a
220 new value type above.
221
222 New property values are "constructed" by objbind_get_value_from_object().
223****************************************************************************/
224union propval_data {
225 gpointer v_pointer;
226 int v_int;
227 bool v_bool;
228 char *v_string;
229 const char *v_const_string;
230 GdkPixbuf *v_pixbuf;
231 struct built_status *v_built;
232 bv_max_extras v_bv_special;
233 bv_max_extras v_bv_roads;
234 bv_max_extras v_bv_bases;
235 struct nation_type *v_nation;
236 struct nation_hash *v_nation_hash;
237 struct government *v_gov;
238 bv_techs v_bv_inventions;
240};
241
242struct propval {
243 union propval_data data;
244 enum value_types valtype;
245 bool must_free;
246};
247
248static void propval_free(struct propval *pv);
249static void propval_free_data(struct propval *pv);
250static struct propval *propval_copy(struct propval *pv);
251static bool propval_equal(struct propval *pva, struct propval *pvb);
252
253struct propstate {
254 int property_id;
255 struct propval *property_value;
256};
257
258static struct propstate *propstate_new(struct objprop *op,
259 struct propval *pv);
260static void propstate_destroy(struct propstate *ps);
261static void propstate_clear_value(struct propstate *ps);
262static void propstate_set_value(struct propstate *ps,
263 struct propval *pv);
264static struct propval *propstate_get_value(struct propstate *ps);
265
266#define SPECHASH_TAG propstate
267#define SPECHASH_INT_KEY_TYPE
268#define SPECHASH_IDATA_TYPE struct propstate *
269#define SPECHASH_IDATA_FREE propstate_destroy
270#include "spechash.h"
271
272
273/****************************************************************************
274 Objprop declarations.
275
276 To add a new object property:
277 1. Add a value in enum object_property_ids (grouped by
278 object type).
279 2. Define the property in property_page_setup_objprops.
280 3. Add a case handler in objbind_get_value_from_object
281 in the appropriate object type block.
282 4. Add a case handler in objprop_setup_widget.
283 5. Add a case handler in objprop_refresh_widget.
284
285 Furthermore, if the property is editable:
286 5. Add a field for this property in the edit
287 packet for this object type in common/networking/packets.def.
288 6. Add a case handler in objbind_pack_modified_value.
289 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
290 !!! 7. Add code to set the packet field in !!!
291 !!! objbind_pack_current_values(). !!!
292 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
293 8. Add code to handle changes in the packet field in
294 server/edithand.c handle_edit_<objtype>.
295
296 If the property makes use of an extviewer:
297 9. Handle widget creation in extviewer_new.
298 10. Handle refresh in extviewer_refresh_widgets.
299 11. Handle clear in extviewer_clear_widgets.
300 12. Handle any signal callbacks (e.g. toggled) if needed.
301
302 TODO: Add more object properties.
303****************************************************************************/
311#ifdef FREECIV_DEBUG
312 OPID_TILE_ADDRESS,
313#endif /* FREECIV_DEBUG */
321 OPID_TILE_VISION, /* tile_known and tile_seen */
323
328
330#ifdef FREECIV_DEBUG
331 OPID_UNIT_ADDRESS,
332#endif /* FREECIV_DEBUG */
343
346#ifdef FREECIV_DEBUG
347 OPID_CITY_ADDRESS,
348#endif /* FREECIV_DEBUG */
356
361#ifdef FREECIV_DEBUG
362 OPID_PLAYER_ADDRESS,
363#endif /* FREECIV_DEBUG */
368
380
387
388struct objprop {
389 int id;
390 const char *name;
391 const char *tooltip;
393 enum value_types valtype;
394 int column_id;
395 GtkTreeViewColumn *view_column;
396 GtkWidget *widget;
397 struct extviewer *extviewer;
399};
400
401static struct objprop *objprop_new(int id,
402 const char *name,
403 const char *tooltip,
405 enum value_types valtype,
406 struct property_page *parent);
407static int objprop_get_id(const struct objprop *op);
408static const char *objprop_get_name(const struct objprop *op);
409static const char *objprop_get_tooltip(const struct objprop *op);
410static enum value_types objprop_get_valtype(const struct objprop *op);
411static struct property_page *
412objprop_get_property_page(const struct objprop *op);
413
414static bool objprop_show_in_listview(const struct objprop *op);
415static bool objprop_is_sortable(const struct objprop *op);
416static bool objprop_is_readonly(const struct objprop *op);
417static bool objprop_has_widget(const struct objprop *op);
418
419static GType objprop_get_gtype(const struct objprop *op);
420static const char *objprop_get_attribute_type_string(const struct objprop *op);
421static void objprop_set_column_id(struct objprop *op, int col_id);
422static int objprop_get_column_id(const struct objprop *op);
423static void objprop_set_treeview_column(struct objprop *op,
424 GtkTreeViewColumn *col);
425static GtkTreeViewColumn *objprop_get_treeview_column(const struct objprop *op);
426static GtkCellRenderer *objprop_create_cell_renderer(const struct objprop *op);
427
428static void objprop_setup_widget(struct objprop *op);
429static GtkWidget *objprop_get_widget(struct objprop *op);
430static void objprop_set_child_widget(struct objprop *op,
431 const char *widget_name,
432 GtkWidget *widget);
433static GtkWidget *objprop_get_child_widget(struct objprop *op,
434 const char *widget_name);
435static void objprop_set_extviewer(struct objprop *op,
436 struct extviewer *ev);
437static struct extviewer *objprop_get_extviewer(struct objprop *op);
438static void objprop_refresh_widget(struct objprop *op,
439 struct objbind *ob);
440static void objprop_widget_text_changed(GtkEditable *text, gpointer userdata);
441static void objprop_widget_spin_button_changed(GtkSpinButton *spin,
442 gpointer userdata);
443static void objprop_widget_toggle_button_changed(GtkToggleButton *button,
444 gpointer userdata);
445
446#define SPECHASH_TAG objprop
447#define SPECHASH_INT_KEY_TYPE
448#define SPECHASH_IDATA_TYPE struct objprop *
449#include "spechash.h"
450
451
452/****************************************************************************
453 Objbind declarations.
454****************************************************************************/
455struct objbind {
457 int object_id;
459 struct propstate_hash *propstate_table;
460 GtkTreeRowReference *rowref;
461};
462
464 gpointer object);
465static void objbind_destroy(struct objbind *ob);
466static enum editor_object_type objbind_get_objtype(const struct objbind *ob);
467static void objbind_bind_properties(struct objbind *ob,
468 struct property_page *pp);
469static gpointer objbind_get_object(struct objbind *ob);
470static int objbind_get_object_id(struct objbind *ob);
471static void objbind_request_destroy_object(struct objbind *ob);
472static struct propval *objbind_get_value_from_object(struct objbind *ob,
473 struct objprop *op);
474static bool objbind_get_allowed_value_span(struct objbind *ob,
475 struct objprop *op,
476 double *pmin,
477 double *pmax,
478 double *pstep,
479 double *pbig_step);
480static bool objbind_set_modified_value(struct objbind *ob,
481 struct objprop *op,
482 struct propval *pv);
483static struct propval *objbind_get_modified_value(struct objbind *ob,
484 struct objprop *op);
485static void objbind_clear_modified_value(struct objbind *ob,
486 struct objprop *op);
487static bool objbind_property_is_modified(struct objbind *ob,
488 struct objprop *op);
489static bool objbind_has_modified_properties(struct objbind *ob);
490static void objbind_clear_all_modified_values(struct objbind *ob);
491static void objbind_pack_current_values(struct objbind *ob,
492 union packetdata packet);
493static void objbind_pack_modified_value(struct objbind *ob,
494 struct objprop *op,
495 union packetdata packet);
496static void objbind_set_rowref(struct objbind *ob,
497 GtkTreeRowReference *rr);
498static GtkTreeRowReference *objbind_get_rowref(struct objbind *ob);
499
500#define SPECHASH_TAG objbind
501#define SPECHASH_INT_KEY_TYPE
502#define SPECHASH_IDATA_TYPE struct objbind *
503#define SPECHASH_IDATA_FREE objbind_destroy
504#include "spechash.h"
505
506
507/****************************************************************************
508 Extended property viewer declarations. This is a set of widgets used
509 for viewing and/or editing properties with complex values (e.g. arrays).
510****************************************************************************/
511struct extviewer {
512 struct objprop *objprop;
513 struct propval *pv_cached;
514
515 GtkWidget *panel_widget;
516 GtkWidget *panel_label;
517 GtkWidget *panel_button;
518 GtkWidget *panel_image;
519
520 GtkWidget *view_widget;
521 GtkWidget *view_label;
522
523 GtkListStore *store;
524 GtkTextBuffer *textbuf;
525};
526
527static struct extviewer *extviewer_new(struct objprop *op);
528static struct objprop *extviewer_get_objprop(struct extviewer *ev);
529static GtkWidget *extviewer_get_panel_widget(struct extviewer *ev);
530static GtkWidget *extviewer_get_view_widget(struct extviewer *ev);
531static void extviewer_refresh_widgets(struct extviewer *ev,
532 struct propval *pv);
533static void extviewer_clear_widgets(struct extviewer *ev);
534static void extviewer_panel_button_clicked(GtkButton *button,
535 gpointer userdata);
536static void extviewer_view_cell_toggled(GtkCellRendererToggle *cell,
537 gchar *path,
538 gpointer userdata);
539static void extviewer_textbuf_changed(GtkTextBuffer *textbuf,
540 gpointer userdata);
541
542
543/****************************************************************************
544 Property page declarations.
545****************************************************************************/
546struct property_page {
548
549 GtkWidget *widget;
550 GtkListStore *object_store;
551 GtkWidget *object_view;
552 GtkWidget *extviewer_notebook;
553
555
556 struct objprop_hash *objprop_table;
557 struct objbind_hash *objbind_table;
558 struct stored_tag_hash *tag_table;
559
560 struct objbind *focused_objbind;
561};
562
563static struct property_page *
565 struct property_editor *parent);
566static void property_page_setup_objprops(struct property_page *pp);
567static const char *property_page_get_name(const struct property_page *pp);
568static enum editor_object_type
570static void property_page_load_tiles(struct property_page *pp,
571 const struct tile_list *tiles);
573 const struct tile *ptile);
574static int property_page_get_num_objbinds(const struct property_page *pp);
575static void property_page_clear_objbinds(struct property_page *pp);
576static void property_page_add_objbind(struct property_page *pp,
577 gpointer object_data);
578static void property_page_fill_widgets(struct property_page *pp);
579static struct objbind *
582 struct objbind *ob);
583static struct objbind *property_page_get_objbind(struct property_page *pp,
584 int object_id);
585static void property_page_selection_changed(GtkTreeSelection *sel,
586 gpointer userdata);
587static gboolean property_page_selection_func(GtkTreeSelection *sel,
588 GtkTreeModel *model,
589 GtkTreePath *path,
590 gboolean currently_selected,
591 gpointer data);
592static void property_page_quick_find_entry_changed(GtkWidget *entry,
593 gpointer userdata);
594static void property_page_change_value(struct property_page *pp,
595 struct objprop *op,
596 struct propval *pv);
597static void property_page_send_values(struct property_page *pp);
598static void property_page_reset_objbinds(struct property_page *pp);
599static void property_page_destroy_objects(struct property_page *pp);
600static void property_page_create_objects(struct property_page *pp,
601 struct tile_list *hint_tiles);
602static union packetdata property_page_new_packet(struct property_page *pp);
603static void property_page_send_packet(struct property_page *pp,
604 union packetdata packet);
605static void property_page_free_packet(struct property_page *pp,
606 union packetdata packet);
607static void property_page_object_changed(struct property_page *pp,
608 int object_id,
609 bool remove);
610static void property_page_object_created(struct property_page *pp,
611 int tag, int object_id);
612static void property_page_add_extviewer(struct property_page *pp,
613 struct extviewer *ev);
614static void property_page_show_extviewer(struct property_page *pp,
615 struct extviewer *ev);
617 int tag, int count);
619 int tag);
620static bool property_page_tag_is_known(struct property_page *pp, int tag);
621static void property_page_clear_tags(struct property_page *pp);
622static void property_page_apply_button_clicked(GtkButton *button,
623 gpointer userdata);
624static void property_page_refresh_button_clicked(GtkButton *button,
625 gpointer userdata);
626static void property_page_create_button_clicked(GtkButton *button,
627 gpointer userdata);
628static void property_page_destroy_button_clicked(GtkButton *button,
629 gpointer userdata);
630
631
632#define property_page_objprop_iterate(ARG_pp, NAME_op) \
633 TYPED_HASH_DATA_ITERATE(struct objprop *, (ARG_pp)->objprop_table, NAME_op)
634#define property_page_objprop_iterate_end HASH_DATA_ITERATE_END
635
636#define property_page_objbind_iterate(ARG_pp, NAME_ob) \
637 TYPED_HASH_DATA_ITERATE(struct objbind *, (ARG_pp)->objbind_table, NAME_ob)
638#define property_page_objbind_iterate_end HASH_DATA_ITERATE_END
639
640
641/****************************************************************************
642 Property editor declarations.
643****************************************************************************/
644struct property_editor {
645 GtkWidget *widget;
646 GtkWidget *notebook;
647
649};
650
651static struct property_editor *property_editor_new(void);
652static bool property_editor_add_page(struct property_editor *pe,
654static struct property_page *
657
659
660
661/************************************************************************/
665{
666 switch (objtype) {
667 case OBJTYPE_TILE:
668 return _("Tile");
669 case OBJTYPE_STARTPOS:
670 return _("Start Position");
671 case OBJTYPE_UNIT:
672 return _("Unit");
673 case OBJTYPE_CITY:
674 return _("City");
675 case OBJTYPE_PLAYER:
676 return _("Player");
677 case OBJTYPE_GAME:
678 return Q_("?play:Game");
679 case NUM_OBJTYPES:
680 break;
681 }
682
683 log_error("%s() Unhandled request to get name of object type %d.",
684 __FUNCTION__, objtype);
685 return "Unknown";
686}
687
688/************************************************************************/
694 gpointer object)
695{
696 switch (objtype) {
697 case OBJTYPE_TILE:
698 return tile_index((struct tile *) object);
699 case OBJTYPE_STARTPOS:
700 return startpos_number((struct startpos *) object);
701 case OBJTYPE_UNIT:
702 return ((struct unit *) object)->id;
703 case OBJTYPE_CITY:
704 return ((struct city *) object)->id;
705 case OBJTYPE_PLAYER:
706 return player_number((struct player *) object);
707 case OBJTYPE_GAME:
708 return 1;
709 case NUM_OBJTYPES:
710 break;
711 }
712
713 log_error("%s(): Unhandled request to get object ID from object %p of "
714 "type %d (%s).", __FUNCTION__, object, objtype,
716 return -1;
717}
718
719/************************************************************************/
723 int id)
724{
725 switch (objtype) {
726 case OBJTYPE_TILE:
727 return index_to_tile(&(wld.map), id);
728 case OBJTYPE_STARTPOS:
729 return map_startpos_by_number(id);
730 case OBJTYPE_UNIT:
731 return game_unit_by_number(id);
732 case OBJTYPE_CITY:
733 return game_city_by_number(id);
734 case OBJTYPE_PLAYER:
735 return player_by_number(id);
736 case OBJTYPE_GAME:
737 return &game;
738 case NUM_OBJTYPES:
739 break;
740 }
741
742 log_error("%s(): Unhandled request to get object of type %d (%s) "
743 "with ID %d.", __FUNCTION__, objtype,
745 return NULL;
746}
747
748/************************************************************************/
754{
755 switch (objtype) {
756 case OBJTYPE_TILE:
757 case OBJTYPE_GAME:
758 return TRUE;
759 case OBJTYPE_STARTPOS:
760 case OBJTYPE_UNIT:
761 case OBJTYPE_CITY:
762 case OBJTYPE_PLAYER:
763 return FALSE;
764 case NUM_OBJTYPES:
765 break;
766 }
767
768 log_error("%s(): Unhandled request for object type %d (%s)).",
769 __FUNCTION__, objtype, objtype_get_name(objtype));
770 return TRUE;
771}
772
773/************************************************************************/
776static const char *valtype_get_name(enum value_types valtype)
777{
778 switch (valtype) {
779 case VALTYPE_NONE:
780 return "none";
781 case VALTYPE_STRING:
782 return "string";
783 case VALTYPE_INT:
784 return "int";
785 case VALTYPE_BOOL:
786 return "bool";
787 case VALTYPE_PIXBUF:
788 return "pixbuf";
790 return "struct built_status[B_LAST]";
792 return "bool[A_LAST]";
794 return "bv_special";
795 case VALTYPE_BV_ROADS:
796 return "bv_roads";
797 case VALTYPE_BV_BASES:
798 return "bv_bases";
799 case VALTYPE_NATION:
800 return "nation";
802 return "struct nation_hash";
803 case VALTYPE_GOV:
804 return "government";
806 return "struct tile_vision_data";
807 }
808
809 log_error("%s(): unhandled value type %d.", __FUNCTION__, valtype);
810 return "void";
811}
812
813/************************************************************************/
817static void add_column(GtkWidget *view,
818 int col_id,
819 const char *name,
820 GType gtype,
821 bool editable,
822 bool is_radio,
823 GCallback edit_callback,
824 gpointer userdata)
825{
826 GtkCellRenderer *cell;
827 GtkTreeViewColumn *col;
828 const char *attr = NULL;
829
830 if (gtype == G_TYPE_BOOLEAN) {
831 cell = gtk_cell_renderer_toggle_new();
832 gtk_cell_renderer_toggle_set_radio(GTK_CELL_RENDERER_TOGGLE(cell),
833 is_radio);
834 if (editable) {
835 g_signal_connect(cell, "toggled", edit_callback, userdata);
836 }
837 attr = "active";
838 } else if (gtype == GDK_TYPE_PIXBUF) {
839 cell = gtk_cell_renderer_pixbuf_new();
840 attr = "pixbuf";
841 } else {
842 cell = gtk_cell_renderer_text_new();
843 if (editable) {
844 g_object_set(cell, "editable", TRUE, NULL);
845 g_signal_connect(cell, "edited", edit_callback, userdata);
846 }
847 attr = "text";
848 }
849
850 col = gtk_tree_view_column_new_with_attributes(name, cell,
851 attr, col_id, NULL);
852 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
853}
854
855/************************************************************************/
859static gchar *propval_as_string(struct propval *pv)
860{
861 int count = 0;
862
863 fc_assert_ret_val(NULL != pv, 0);
864
865 switch (pv->valtype) {
866 case VALTYPE_NONE:
867 return g_strdup("");
868
869 case VALTYPE_INT:
870 return g_strdup_printf("%d", pv->data.v_int);
871
872 case VALTYPE_BOOL:
873 return g_strdup_printf("%s", pv->data.v_bool ? _("TRUE") : _("FALSE"));
874
875 case VALTYPE_NATION:
876 return g_strdup_printf("%s", nation_adjective_translation(pv->data.v_nation));
877
878 case VALTYPE_GOV:
879 if (pv->data.v_gov != NULL) {
880 return g_strdup_printf("%s", government_name_translation(pv->data.v_gov));
881 } else {
883 }
884
886 {
887 int great_wonder_count = 0, small_wonder_count = 0, building_count = 0;
888 int id;
889
890 improvement_iterate(pimprove) {
891 id = improvement_index(pimprove);
892 if (pv->data.v_built[id].turn < 0) {
893 continue;
894 }
895 if (is_great_wonder(pimprove)) {
896 great_wonder_count++;
897 } else if (is_small_wonder(pimprove)) {
898 small_wonder_count++;
899 } else {
900 building_count++;
901 }
903 /* TRANS: "Number of buildings, number of small
904 * wonders (e.g. palace), number of great wonders." */
905 return g_strdup_printf(_("%db %ds %dW"),
906 building_count, small_wonder_count,
907 great_wonder_count);
908 }
909
912 if (BV_ISSET(pv->data.v_bv_inventions, tech)) {
913 count++;
914 }
916 /* TRANS: "Number of technologies known". */
917 return g_strdup_printf(_("%d known"), count);
918
921 if (BV_ISSET(pv->data.v_bv_special, spe->data.special_idx)) {
922 count++;
923 }
925 /* TRANS: "The number of terrain specials (e.g. hut,
926 * river, pollution, etc.) present on a tile." */
927 return g_strdup_printf(_("%d present"), count);
928
929 case VALTYPE_BV_ROADS:
930 extra_type_by_cause_iterate(EC_ROAD, pextra) {
931 struct road_type *proad = extra_road_get(pextra);
932
933 if (BV_ISSET(pv->data.v_bv_roads, road_number(proad))) {
934 count++;
935 }
937 return g_strdup_printf(_("%d present"), count);
938
939 case VALTYPE_BV_BASES:
940 extra_type_by_cause_iterate(EC_BASE, pextra) {
941 struct base_type *pbase = extra_base_get(pextra);
942
943 if (BV_ISSET(pv->data.v_bv_bases, base_number(pbase))) {
944 count++;
945 }
947 return g_strdup_printf(_("%d present"), count);
948
950 count = nation_hash_size(pv->data.v_nation_hash);
951 if (0 == count) {
952 return g_strdup(_("All nations"));
953 } else {
954 return g_strdup_printf(PL_("%d nation", "%d nations",
955 count), count);
956 }
957
958 case VALTYPE_STRING:
959 /* Assume it is a very long string. */
960 count = strlen(pv->data.v_const_string);
961 return g_strdup_printf(PL_("%d byte", "%d bytes", count),
962 count);
963
964 case VALTYPE_PIXBUF:
966 break;
967 }
968
969 log_error("%s(): Unhandled value type %d for property value %p.",
970 __FUNCTION__, pv->valtype, pv);
971 return g_strdup("");
972}
973
974/************************************************************************/
978static gchar *built_status_to_string(struct built_status *bs)
979{
980 int turn_built;
981
982 turn_built = bs->turn;
983
984 if (turn_built == I_NEVER) {
985 /* TRANS: Improvement never built. */
986 return g_strdup(_("(never)"));
987 } else if (turn_built == I_DESTROYED) {
988 /* TRANS: Improvement was destroyed. */
989 return g_strdup(_("(destroyed)"));
990 } else {
991 return g_strdup_printf("%d", turn_built);
992 }
993}
994
995/************************************************************************/
999static bool can_create_unit_at_tile(struct tile *ptile)
1000{
1001 struct unit *vunit;
1002 struct city *pcity;
1003 struct player *pplayer;
1004 bool ret;
1005
1006 if (!ptile) {
1007 return FALSE;
1008 }
1009
1011 if (!vunit) {
1012 return FALSE;
1013 }
1014
1015 pcity = tile_city(ptile);
1016 pplayer = unit_owner(vunit);
1017
1018 ret = (can_unit_exist_at_tile(&(wld.map), vunit, ptile)
1019 && !is_non_allied_unit_tile(ptile, pplayer)
1020 && (pcity == NULL
1021 || pplayers_allied(city_owner(pcity),
1022 unit_owner(vunit))));
1023 free(vunit);
1024
1025 return ret;
1026}
1027
1028/************************************************************************/
1031static int get_next_unique_tag(void)
1032{
1033 static int tag_series = 0;
1034
1035 tag_series++;
1036 return tag_series;
1037}
1038
1039/************************************************************************/
1042static struct propval *propval_copy(struct propval *pv)
1043{
1044 struct propval *pv_copy;
1045 size_t size;
1046
1047 if (!pv) {
1048 return NULL;
1049 }
1050
1051 pv_copy = fc_calloc(1, sizeof(*pv));
1052 pv_copy->valtype = pv->valtype;
1053
1054 switch (pv->valtype) {
1055 case VALTYPE_NONE:
1056 return pv_copy;
1057 case VALTYPE_INT:
1058 pv_copy->data.v_int = pv->data.v_int;
1059 return pv_copy;
1060 case VALTYPE_BOOL:
1061 pv_copy->data.v_bool = pv->data.v_bool;
1062 return pv_copy;
1063 case VALTYPE_STRING:
1064 pv_copy->data.v_string = fc_strdup(pv->data.v_string);
1065 pv_copy->must_free = TRUE;
1066 return pv_copy;
1067 case VALTYPE_PIXBUF:
1068 g_object_ref(pv->data.v_pixbuf);
1069 pv_copy->data.v_pixbuf = pv->data.v_pixbuf;
1070 pv_copy->must_free = TRUE;
1071 return pv_copy;
1073 size = B_LAST * sizeof(struct built_status);
1074 pv_copy->data.v_pointer = fc_malloc(size);
1075 memcpy(pv_copy->data.v_pointer, pv->data.v_pointer, size);
1076 pv_copy->must_free = TRUE;
1077 return pv_copy;
1078 case VALTYPE_BV_SPECIAL:
1079 pv_copy->data.v_bv_special = pv->data.v_bv_special;
1080 return pv_copy;
1081 case VALTYPE_BV_ROADS:
1082 pv_copy->data.v_bv_roads = pv->data.v_bv_roads;
1083 return pv_copy;
1084 case VALTYPE_BV_BASES:
1085 pv_copy->data.v_bv_bases = pv->data.v_bv_bases;
1086 return pv_copy;
1087 case VALTYPE_NATION:
1088 pv_copy->data.v_nation = pv->data.v_nation;
1089 return pv_copy;
1090 case VALTYPE_GOV:
1091 pv_copy->data.v_gov = pv->data.v_gov;
1092 return pv_copy;
1094 pv_copy->data.v_nation_hash
1095 = nation_hash_copy(pv->data.v_nation_hash);
1096 pv_copy->must_free = TRUE;
1097 return pv_copy;
1100 return pv_copy;
1102 size = sizeof(struct tile_vision_data);
1103 pv_copy->data.v_tile_vision = fc_malloc(size);
1104 pv_copy->data.v_tile_vision->tile_known
1107 pv_copy->data.v_tile_vision->tile_seen[v]
1108 = pv->data.v_tile_vision->tile_seen[v];
1110 pv_copy->must_free = TRUE;
1111 return pv_copy;
1112 }
1113
1114 log_error("%s(): Unhandled value type %d for property value %p.",
1115 __FUNCTION__, pv->valtype, pv);
1116 pv_copy->data = pv->data;
1117 return pv_copy;
1118}
1119
1120/************************************************************************/
1124static void propval_free(struct propval *pv)
1125{
1126 if (!pv) {
1127 return;
1128 }
1129
1131 free(pv);
1132}
1133
1134/************************************************************************/
1138static void propval_free_data(struct propval *pv)
1139{
1140 if (!pv || !pv->must_free) {
1141 return;
1142 }
1143
1144 switch (pv->valtype) {
1145 case VALTYPE_NONE:
1146 case VALTYPE_INT:
1147 case VALTYPE_BOOL:
1148 case VALTYPE_BV_SPECIAL:
1149 case VALTYPE_BV_ROADS:
1150 case VALTYPE_BV_BASES:
1151 case VALTYPE_NATION:
1152 case VALTYPE_GOV:
1153 return;
1154 case VALTYPE_PIXBUF:
1155 g_object_unref(pv->data.v_pixbuf);
1156 return;
1157 case VALTYPE_STRING:
1161 free(pv->data.v_pointer);
1162 return;
1164 nation_hash_destroy(pv->data.v_nation_hash);
1165 return;
1166 }
1167
1168 log_error("%s(): Unhandled request to free data %p (type %s).",
1169 __FUNCTION__, pv->data.v_pointer, valtype_get_name(pv->valtype));
1170}
1171
1172/************************************************************************/
1175static bool propval_equal(struct propval *pva,
1176 struct propval *pvb)
1177{
1178 if (!pva || !pvb) {
1179 return pva == pvb;
1180 }
1181
1182 if (pva->valtype != pvb->valtype) {
1183 return FALSE;
1184 }
1185
1186 switch (pva->valtype) {
1187 case VALTYPE_NONE:
1188 return TRUE;
1189 case VALTYPE_INT:
1190 return pva->data.v_int == pvb->data.v_int;
1191 case VALTYPE_BOOL:
1192 return pva->data.v_bool == pvb->data.v_bool;
1193 case VALTYPE_STRING:
1194 if (pva->data.v_const_string != NULL
1195 && pvb->data.v_const_string != NULL) {
1196 return !strcmp(pva->data.v_const_string,
1197 pvb->data.v_const_string);
1198 }
1199 return pva->data.v_const_string == pvb->data.v_const_string;
1200 case VALTYPE_PIXBUF:
1201 return pva->data.v_pixbuf == pvb->data.v_pixbuf;
1203 if (pva->data.v_pointer == pvb->data.v_pointer) {
1204 return TRUE;
1205 } else if (!pva->data.v_pointer || !pvb->data.v_pointer) {
1206 return FALSE;
1207 }
1208
1209 improvement_iterate(pimprove) {
1210 int id, vatb, vbtb;
1211 id = improvement_index(pimprove);
1212 vatb = pva->data.v_built[id].turn;
1213 vbtb = pvb->data.v_built[id].turn;
1214 if (vatb < 0 && vbtb < 0) {
1215 continue;
1216 }
1217 if (vatb != vbtb) {
1218 return FALSE;
1219 }
1221 return TRUE;
1224 case VALTYPE_BV_SPECIAL:
1225 return BV_ARE_EQUAL(pva->data.v_bv_special, pvb->data.v_bv_special);
1226 case VALTYPE_BV_ROADS:
1227 return BV_ARE_EQUAL(pva->data.v_bv_roads, pvb->data.v_bv_roads);
1228 case VALTYPE_BV_BASES:
1229 return BV_ARE_EQUAL(pva->data.v_bv_bases, pvb->data.v_bv_bases);
1230 case VALTYPE_NATION:
1231 return pva->data.v_nation == pvb->data.v_nation;
1233 return nation_hashes_are_equal(pva->data.v_nation_hash,
1234 pvb->data.v_nation_hash);
1235 case VALTYPE_GOV:
1236 return pva->data.v_gov == pvb->data.v_gov;
1239 pvb->data.v_tile_vision->tile_known)) {
1240 return FALSE;
1241 }
1244 pvb->data.v_tile_vision->tile_seen[v])) {
1245 return FALSE;
1246 }
1248 return TRUE;
1249 }
1250
1251 log_error("%s(): Unhandled value type %d for property values %p and %p.",
1252 __FUNCTION__, pva->valtype, pva, pvb);
1253 return pva->data.v_pointer == pvb->data.v_pointer;
1254}
1255
1256/************************************************************************/
1262static struct propstate *propstate_new(struct objprop *op,
1263 struct propval *pv)
1264{
1265 struct propstate *ps;
1266
1267 if (!op) {
1268 return NULL;
1269 }
1270
1271 ps = fc_calloc(1, sizeof(*ps));
1272 ps->property_id = objprop_get_id(op);
1273 ps->property_value = pv;
1274
1275 return ps;
1276}
1277
1278/************************************************************************/
1281static void propstate_clear_value(struct propstate *ps)
1282{
1283 if (!ps) {
1284 return;
1285 }
1286
1288 ps->property_value = NULL;
1289}
1290
1291/************************************************************************/
1294static void propstate_destroy(struct propstate *ps)
1295{
1296 if (!ps) {
1297 return;
1298 }
1300 free(ps);
1301}
1302
1303/************************************************************************/
1309static void propstate_set_value(struct propstate *ps,
1310 struct propval *pv)
1311{
1312 if (!ps) {
1313 return;
1314 }
1316 ps->property_value = pv;
1317}
1318
1319/************************************************************************/
1324static struct propval *propstate_get_value(struct propstate *ps)
1325{
1326 if (!ps) {
1327 return NULL;
1328 }
1329 return ps->property_value;
1330}
1331
1332/************************************************************************/
1337 gpointer object)
1338{
1339 struct objbind *ob;
1340 int id;
1341
1342 if (object == NULL) {
1343 return NULL;
1344 }
1345
1346 id = objtype_get_id_from_object(objtype, object);
1347 if (id < 0) {
1348 return NULL;
1349 }
1350
1351 ob = fc_calloc(1, sizeof(*ob));
1352 ob->object_id = id;
1353 ob->objtype = objtype;
1354 ob->propstate_table = propstate_hash_new();
1355
1356 return ob;
1357}
1358
1359/************************************************************************/
1362static gpointer objbind_get_object(struct objbind *ob)
1363{
1364 int id;
1365
1366 if (!ob) {
1367 return NULL;
1368 }
1369
1370 id = objbind_get_object_id(ob);
1371
1372 return objtype_get_object_from_id(ob->objtype, id);
1373}
1374
1375/************************************************************************/
1378static int objbind_get_object_id(struct objbind *ob)
1379{
1380 if (NULL == ob) {
1381 return -1;
1382 }
1383 return ob->object_id;
1384}
1385
1386/************************************************************************/
1392{
1393 struct connection *my_conn = &client.conn;
1395 int id;
1396
1397 if (!ob) {
1398 return;
1399 }
1400
1403 return;
1404 }
1405
1406 id = objbind_get_object_id(ob);
1407
1408 switch (objtype) {
1409 case OBJTYPE_STARTPOS:
1410 dsend_packet_edit_startpos(my_conn, id, TRUE, 0);
1411 return;
1412 case OBJTYPE_UNIT:
1413 dsend_packet_edit_unit_remove_by_id(my_conn, id, id);
1414 return;
1415 case OBJTYPE_CITY:
1416 dsend_packet_edit_city_remove(my_conn, id, id);
1417 return;
1418 case OBJTYPE_PLAYER:
1420 return;
1421 case OBJTYPE_TILE:
1422 case OBJTYPE_GAME:
1423 case NUM_OBJTYPES:
1424 break;
1425 }
1426
1427 log_error("%s(): Unhandled request to destroy object %p (ID %d) of type "
1428 "%d (%s).", __FUNCTION__, objbind_get_object(ob), id, objtype,
1430}
1431
1432/************************************************************************/
1440 struct objprop *op)
1441{
1443 enum object_property_ids propid;
1444 struct propval *pv;
1445
1446 if (!ob || !op) {
1447 return NULL;
1448 }
1449
1451 propid = objprop_get_id(op);
1452
1453 pv = fc_calloc(1, sizeof(*pv));
1454 pv->valtype = objprop_get_valtype(op);
1455
1456 switch (objtype) {
1457 case OBJTYPE_TILE:
1458 {
1459 const struct tile *ptile = objbind_get_object(ob);
1460 int tile_x, tile_y, nat_x, nat_y;
1461
1462 if (NULL == ptile) {
1463 goto FAILED;
1464 }
1465
1466 index_to_map_pos(&tile_x, &tile_y, tile_index(ptile));
1468
1469 switch (propid) {
1470 case OPID_TILE_IMAGE:
1471 pv->data.v_pixbuf = create_tile_pixbuf(ptile);
1472 pv->must_free = TRUE;
1473 break;
1474#ifdef FREECIV_DEBUG
1475 case OPID_TILE_ADDRESS:
1476 pv->data.v_string = g_strdup_printf("%p", ptile);
1477 pv->must_free = TRUE;
1478 break;
1479#endif /* FREECIV_DEBUG */
1480 case OPID_TILE_TERRAIN:
1481 {
1482 const struct terrain *pterrain = tile_terrain(ptile);
1483
1484 if (NULL != pterrain) {
1486 } else {
1487 pv->data.v_const_string = "";
1488 }
1489 }
1490 break;
1491 case OPID_TILE_RESOURCE:
1492 {
1493 const struct extra_type *presource = tile_resource(ptile);
1494
1495 if (NULL != presource) {
1497 } else {
1498 pv->data.v_const_string = "";
1499 }
1500 }
1501 break;
1502 case OPID_TILE_XY:
1503 pv->data.v_string = g_strdup_printf("(%d, %d)", tile_x, tile_y);
1504 pv->must_free = TRUE;
1505 break;
1506 case OPID_TILE_INDEX:
1507 pv->data.v_int = tile_index(ptile);
1508 break;
1509 case OPID_TILE_X:
1510 pv->data.v_int = tile_x;
1511 break;
1512 case OPID_TILE_Y:
1513 pv->data.v_int = tile_y;
1514 break;
1515 case OPID_TILE_NAT_X:
1516 pv->data.v_int = nat_x;
1517 break;
1518 case OPID_TILE_NAT_Y:
1519 pv->data.v_int = nat_y;
1520 break;
1522 pv->data.v_int = ptile->continent;
1523 break;
1524 case OPID_TILE_SPECIALS:
1527 if (tile_has_extra(ptile, pextra)) {
1528 BV_SET(pv->data.v_bv_special, pextra->data.special_idx);
1529 }
1531 break;
1532 case OPID_TILE_ROADS:
1534 extra_type_by_cause_iterate(EC_ROAD, pextra) {
1535 if (tile_has_extra(ptile, pextra)) {
1537 }
1539 break;
1540 case OPID_TILE_BASES:
1542 extra_type_by_cause_iterate(EC_BASE, pextra) {
1543 if (tile_has_extra(ptile, pextra)) {
1545 }
1547 break;
1548 case OPID_TILE_VISION:
1549 pv->data.v_tile_vision = fc_malloc(sizeof(struct tile_vision_data));
1550
1551 /* The server saves the known tiles and the player vision in special
1552 * bitvectors with the number of tiles as index. Here we want the
1553 * information for one tile. Thus, the data is transformed to
1554 * bitvectors with the number of player slots as index. */
1556 players_iterate(pplayer) {
1557 if (dbv_isset(&pplayer->tile_known, tile_index(ptile))) {
1559 player_index(pplayer));
1560 }
1562
1565 players_iterate(pplayer) {
1566 if (fc_funcs->player_tile_vision_get(ptile, pplayer, v)) {
1568 player_index(pplayer));
1569 }
1572 pv->must_free = TRUE;
1573 break;
1574 case OPID_TILE_LABEL:
1575 if (ptile->label != NULL) {
1576 pv->data.v_const_string = ptile->label;
1577 } else {
1578 pv->data.v_const_string = "";
1579 }
1580 break;
1581 default:
1582 log_error("%s(): Unhandled request for value of property %d "
1583 "(%s) from object of type \"%s\".", __FUNCTION__,
1585 goto FAILED;
1586 }
1587 }
1588 return pv;
1589
1590 case OBJTYPE_STARTPOS:
1591 {
1592 const struct startpos *psp = objbind_get_object(ob);
1593 const struct tile *ptile;
1594
1595 if (NULL == psp) {
1596 goto FAILED;
1597 }
1598
1599 switch (propid) {
1601 ptile = startpos_tile(psp);
1602 pv->data.v_pixbuf = create_tile_pixbuf(ptile);
1603 pv->must_free = TRUE;
1604 break;
1605 case OPID_STARTPOS_XY:
1606 ptile = startpos_tile(psp);
1607 pv->data.v_string = g_strdup_printf("(%d, %d)", TILE_XY(ptile));
1608 pv->must_free = TRUE;
1609 break;
1612 break;
1614 pv->data.v_nation_hash = nation_hash_copy(startpos_raw_nations(psp));
1615 pv->must_free = TRUE;
1616 break;
1617 default:
1618 log_error("%s(): Unhandled request for value of property %d "
1619 "(%s) from object of type \"%s\".", __FUNCTION__,
1621 goto FAILED;
1622 }
1623 }
1624 return pv;
1625
1626 case OBJTYPE_UNIT:
1627 {
1628 struct unit *punit = objbind_get_object(ob);
1629
1630 if (NULL == punit) {
1631 goto FAILED;
1632 }
1633
1634 switch (propid) {
1635 case OPID_UNIT_IMAGE:
1637 pv->must_free = TRUE;
1638 break;
1639#ifdef FREECIV_DEBUG
1640 case OPID_UNIT_ADDRESS:
1641 pv->data.v_string = g_strdup_printf("%p", punit);
1642 pv->must_free = TRUE;
1643 break;
1644#endif /* FREECIV_DEBUG */
1645 case OPID_UNIT_XY:
1646 {
1647 const struct tile *ptile = unit_tile(punit);
1648
1649 pv->data.v_string = g_strdup_printf("(%d, %d)", TILE_XY(ptile));
1650 pv->must_free = TRUE;
1651 }
1652 break;
1653 case OPID_UNIT_ID:
1654 pv->data.v_int = punit->id;
1655 break;
1656 case OPID_UNIT_TYPE:
1657 {
1658 const struct unit_type *putype = unit_type_get(punit);
1659
1661 }
1662 break;
1664 pv->data.v_int = punit->moves_left;
1665 break;
1666 case OPID_UNIT_FUEL:
1667 pv->data.v_int = punit->fuel;
1668 break;
1669 case OPID_UNIT_MOVED:
1670 pv->data.v_bool = punit->moved;
1671 break;
1674 break;
1675 case OPID_UNIT_HP:
1676 pv->data.v_int = punit->hp;
1677 break;
1678 case OPID_UNIT_VETERAN:
1679 pv->data.v_int = punit->veteran;
1680 break;
1681 case OPID_UNIT_STAY:
1682 pv->data.v_bool = punit->stay;
1683 break;
1684 default:
1685 log_error("%s(): Unhandled request for value of property %d "
1686 "(%s) from object of type \"%s\".", __FUNCTION__,
1688 goto FAILED;
1689 }
1690 }
1691 return pv;
1692
1693 case OBJTYPE_CITY:
1694 {
1695 const struct city *pcity = objbind_get_object(ob);
1696
1697 if (NULL == pcity) {
1698 goto FAILED;
1699 }
1700
1701 switch (propid) {
1702 case OPID_CITY_IMAGE:
1703 pv->data.v_pixbuf = create_city_pixbuf(pcity);
1704 pv->must_free = TRUE;
1705 break;
1706#ifdef FREECIV_DEBUG
1707 case OPID_CITY_ADDRESS:
1708 pv->data.v_string = g_strdup_printf("%p", pcity);
1709 pv->must_free = TRUE;
1710 break;
1711#endif /* FREECIV_DEBUG */
1712 case OPID_CITY_XY:
1713 {
1714 const struct tile *ptile = city_tile(pcity);
1715
1716 pv->data.v_string = g_strdup_printf("(%d, %d)", TILE_XY(ptile));
1717 pv->must_free = TRUE;
1718 }
1719 break;
1720 case OPID_CITY_ID:
1721 pv->data.v_int = pcity->id;
1722 break;
1723 case OPID_CITY_NAME:
1724 pv->data.v_const_string = pcity->name;
1725 break;
1726 case OPID_CITY_SIZE:
1727 pv->data.v_int = city_size_get(pcity);
1728 break;
1729 case OPID_CITY_HISTORY:
1730 pv->data.v_int = pcity->history;
1731 break;
1733 pv->data.v_built = fc_malloc(sizeof(pcity->built));
1734 memcpy(pv->data.v_built, pcity->built, sizeof(pcity->built));
1735 pv->must_free = TRUE;
1736 break;
1738 pv->data.v_int = pcity->food_stock;
1739 break;
1741 pv->data.v_int = pcity->shield_stock;
1742 break;
1743 default:
1744 log_error("%s(): Unhandled request for value of property %d "
1745 "(%s) from object of type \"%s\".", __FUNCTION__,
1747 goto FAILED;
1748 }
1749 }
1750 return pv;
1751
1752 case OBJTYPE_PLAYER:
1753 {
1754 const struct player *pplayer = objbind_get_object(ob);
1755 const struct research *presearch;
1756
1757 if (NULL == pplayer) {
1758 goto FAILED;
1759 }
1760
1761 switch (propid) {
1762 case OPID_PLAYER_NAME:
1763 pv->data.v_const_string = pplayer->name;
1764 break;
1765 case OPID_PLAYER_NATION:
1766 pv->data.v_nation = nation_of_player(pplayer);
1767 break;
1768 case OPID_PLAYER_GOV:
1769 pv->data.v_gov = pplayer->government;
1770 break;
1771 case OPID_PLAYER_AGE:
1772 pv->data.v_int = pplayer->turns_alive;
1773 break;
1774#ifdef FREECIV_DEBUG
1775 case OPID_PLAYER_ADDRESS:
1776 pv->data.v_string = g_strdup_printf("%p", pplayer);
1777 pv->must_free = TRUE;
1778 break;
1779#endif /* FREECIV_DEBUG */
1781 presearch = research_get(pplayer);
1784 if (TECH_KNOWN == research_invention_state(presearch, tech)) {
1785 BV_SET(pv->data.v_bv_inventions, tech);
1786 }
1788 break;
1790 pv->data.v_bool = player_has_flag(pplayer, PLRF_SCENARIO_RESERVED);
1791 break;
1793 presearch = research_get(pplayer);
1794 pv->data.v_int = presearch->bulbs_researched;
1795 break;
1796 case OPID_PLAYER_GOLD:
1797 pv->data.v_int = pplayer->economic.gold;
1798 break;
1799 default:
1800 log_error("%s(): Unhandled request for value of property %d "
1801 "(%s) from object of type \"%s\".", __FUNCTION__,
1803 goto FAILED;
1804 }
1805 }
1806 return pv;
1807
1808 case OBJTYPE_GAME:
1809 {
1810 const struct civ_game *pgame = objbind_get_object(ob);
1811
1812 if (NULL == pgame) {
1813 goto FAILED;
1814 }
1815
1816 switch (propid) {
1817 case OPID_GAME_SCENARIO:
1818 pv->data.v_bool = pgame->scenario.is_scenario;
1819 break;
1821 pv->data.v_const_string = pgame->scenario.name;
1822 break;
1824 pv->data.v_const_string = pgame->scenario.authors;
1825 break;
1828 break;
1830 pv->data.v_bool = pgame->scenario.save_random;
1831 break;
1833 pv->data.v_bool = pgame->scenario.players;
1834 break;
1836 pv->data.v_bool = pgame->scenario.startpos_nations;
1837 break;
1840 break;
1842 pv->data.v_bool = pgame->scenario.lake_flooding;
1843 break;
1845 pv->data.v_bool = pgame->scenario.ruleset_locked;
1846 break;
1847 default:
1848 log_error("%s(): Unhandled request for value of property %d "
1849 "(%s) from object of type \"%s\".", __FUNCTION__,
1851 goto FAILED;
1852 }
1853 }
1854 return pv;
1855
1856 case NUM_OBJTYPES:
1857 break;
1858 }
1859
1860 log_error("%s(): Unhandled request for object type \"%s\" (nb %d).",
1861 __FUNCTION__, objtype_get_name(objtype), objtype);
1862
1863FAILED:
1864 if (NULL != pv) {
1865 free(pv);
1866 }
1867 return NULL;
1868}
1869
1870/************************************************************************/
1875 struct objprop *op,
1876 double *pmin,
1877 double *pmax,
1878 double *pstep,
1879 double *pbig_step)
1880{
1882 enum object_property_ids propid;
1883 double dummy;
1884
1885 /* Fill the values with something. */
1886 if (NULL != pmin) {
1887 *pmin = 0;
1888 } else {
1889 pmin = &dummy;
1890 }
1891 if (NULL != pmax) {
1892 *pmax = 1;
1893 } else {
1894 pmax = &dummy;
1895 }
1896 if (NULL != pstep) {
1897 *pstep = 1;
1898 } else {
1899 pstep = &dummy;
1900 }
1901 if (NULL != pbig_step) {
1902 *pbig_step = 1;
1903 } else {
1904 pbig_step = &dummy;
1905 }
1906
1907 if (!ob || !op) {
1908 return FALSE;
1909 }
1910
1911 propid = objprop_get_id(op);
1913
1914 switch (objtype) {
1915 case OBJTYPE_TILE:
1916 case OBJTYPE_STARTPOS:
1917 log_error("%s(): Unhandled request for value range of property %d (%s) "
1918 "from object of type \"%s\".", __FUNCTION__,
1920 return FALSE;
1921
1922 case OBJTYPE_UNIT:
1923 {
1924 const struct unit *punit = objbind_get_object(ob);
1925 const struct unit_type *putype;
1926
1927 if (NULL == punit) {
1928 return FALSE;
1929 }
1930
1931 putype = unit_type_get(punit);
1932
1933 switch (propid) {
1935 *pmin = 0;
1936 *pmax = MAX_MOVE_FRAGS;
1937 *pstep = 1;
1938 *pbig_step = 5;
1939 return TRUE;
1940 case OPID_UNIT_FUEL:
1941 *pmin = 0;
1942 *pmax = utype_fuel(putype);
1943 *pstep = 1;
1944 *pbig_step = 5;
1945 return TRUE;
1946 case OPID_UNIT_HP:
1947 *pmin = 1;
1948 *pmax = putype->hp;
1949 *pstep = 1;
1950 *pbig_step = 10;
1951 return TRUE;
1952 case OPID_UNIT_VETERAN:
1953 *pmin = 0;
1954 *pmax = utype_veteran_levels(putype) - 1;
1955 *pstep = 1;
1956 *pbig_step = 3;
1957 return TRUE;
1958 default:
1959 break;
1960 }
1961 }
1962 log_error("%s(): Unhandled request for value range of property %d (%s) "
1963 "from object of type \"%s\".", __FUNCTION__,
1965 return FALSE;
1966
1967 case OBJTYPE_CITY:
1968 {
1969 const struct city *pcity = objbind_get_object(ob);
1970
1971 if (NULL == pcity) {
1972 return FALSE;
1973 }
1974
1975 switch (propid) {
1976 case OPID_CITY_SIZE:
1977 *pmin = 1;
1978 *pmax = MAX_CITY_SIZE;
1979 *pstep = 1;
1980 *pbig_step = 5;
1981 return TRUE;
1982 case OPID_CITY_HISTORY:
1983 *pmin = 0;
1984 *pmax = USHRT_MAX;
1985 *pstep = 1;
1986 *pbig_step = 10;
1987 return TRUE;
1989 *pmin = 0;
1990 *pmax = city_granary_size(city_size_get(pcity));
1991 *pstep = 1;
1992 *pbig_step = 5;
1993 return TRUE;
1995 *pmin = 0;
1996 *pmax = USHRT_MAX; /* Limited to uint16 by city info packet. */
1997 *pstep = 1;
1998 *pbig_step = 10;
1999 return TRUE;
2000 default:
2001 break;
2002 }
2003 }
2004 log_error("%s(): Unhandled request for value range of property %d (%s) "
2005 "from object of type \"%s\".", __FUNCTION__,
2007 return FALSE;
2008
2009 case OBJTYPE_PLAYER:
2010 switch (propid) {
2012 *pmin = 0;
2013 *pmax = 1000000; /* Arbitrary. */
2014 *pstep = 1;
2015 *pbig_step = 100;
2016 return TRUE;
2017 case OPID_PLAYER_GOLD:
2018 *pmin = 0;
2019 *pmax = 1000000; /* Arbitrary. */
2020 *pstep = 1;
2021 *pbig_step = 100;
2022 return TRUE;
2023 default:
2024 break;
2025 }
2026 log_error("%s(): Unhandled request for value range of property %d (%s) "
2027 "from object of type \"%s\".", __FUNCTION__,
2029 return FALSE;
2030
2031 case OBJTYPE_GAME:
2032 log_error("%s(): Unhandled request for value range of property %d (%s) "
2033 "from object of type \"%s\".", __FUNCTION__,
2035 return FALSE;
2036
2037 case NUM_OBJTYPES:
2038 break;
2039 }
2040
2041 log_error("%s(): Unhandled request for object type \"%s\" (nb %d).",
2042 __FUNCTION__, objtype_get_name(objtype), objtype);
2043 return FALSE;
2044}
2045
2046/************************************************************************/
2050 struct objprop *op)
2051{
2052 if (!ob || !op || !ob->propstate_table) {
2053 return;
2054 }
2055
2056 propstate_hash_remove(ob->propstate_table, objprop_get_id(op));
2057}
2058
2059/************************************************************************/
2064 struct objprop *op)
2065{
2066 if (!ob || !op) {
2067 return FALSE;
2068 }
2069
2070 if (objprop_is_readonly(op)) {
2071 return FALSE;
2072 }
2073
2074 return propstate_hash_lookup(ob->propstate_table,
2075 objprop_get_id(op), NULL);
2076}
2077
2078/************************************************************************/
2083{
2084 if (!ob) {
2085 return FALSE;
2086 }
2087
2088 return (0 < propstate_hash_size(ob->propstate_table));
2089}
2090
2091/************************************************************************/
2095{
2096 if (!ob) {
2097 return;
2098 }
2099 propstate_hash_clear(ob->propstate_table);
2100}
2101
2102/************************************************************************/
2109 struct objprop *op,
2110 struct propval *pv)
2111{
2112 struct propstate *ps;
2113 bool equal;
2114 struct propval *pv_old, *pv_copy;
2115 enum object_property_ids propid;
2116
2117 if (!ob || !op) {
2118 return FALSE;
2119 }
2120
2121 propid = objprop_get_id(op);
2122
2123 pv_old = objbind_get_value_from_object(ob, op);
2124 if (!pv_old) {
2125 return FALSE;
2126 }
2127
2128 equal = propval_equal(pv, pv_old);
2129 propval_free(pv_old);
2130
2131 if (equal) {
2133 return FALSE;
2134 }
2135
2136 pv_copy = propval_copy(pv);
2137
2138 if (propstate_hash_lookup(ob->propstate_table, propid, &ps)) {
2139 propstate_set_value(ps, pv_copy);
2140 } else {
2141 ps = propstate_new(op, pv_copy);
2142 propstate_hash_insert(ob->propstate_table, propid, ps);
2143 }
2144
2145 return TRUE;
2146}
2147
2148/************************************************************************/
2155 struct objprop *op)
2156{
2157 struct propstate *ps;
2158
2159 if (!ob || !op) {
2160 return NULL;
2161 }
2162
2163 if (propstate_hash_lookup(ob->propstate_table, objprop_get_id(op), &ps)) {
2164 return propstate_get_value(ps);
2165 } else {
2166 return NULL;
2167 }
2168}
2169
2170/************************************************************************/
2173static void objbind_destroy(struct objbind *ob)
2174{
2175 if (!ob) {
2176 return;
2177 }
2178 if (ob->propstate_table) {
2179 propstate_hash_destroy(ob->propstate_table);
2180 ob->propstate_table = NULL;
2181 }
2182 if (ob->rowref) {
2183 gtk_tree_row_reference_free(ob->rowref);
2184 ob->rowref = NULL;
2185 }
2186 free(ob);
2187}
2188
2189/************************************************************************/
2193{
2194 if (!ob) {
2195 return NUM_OBJTYPES;
2196 }
2197 return ob->objtype;
2198}
2199
2200/************************************************************************/
2203static void objbind_bind_properties(struct objbind *ob,
2204 struct property_page *pp)
2205{
2206 if (!ob) {
2207 return;
2208 }
2209 ob->parent_property_page = pp;
2210}
2211
2212/************************************************************************/
2218 union packetdata pd)
2219{
2221
2222 if (!ob || !pd.pointers.v_pointer1) {
2223 return;
2224 }
2225
2227
2228 switch (objtype) {
2229 case OBJTYPE_TILE:
2230 {
2231 struct packet_edit_tile *packet = pd.tile;
2232 const struct tile *ptile = objbind_get_object(ob);
2233
2234 if (NULL == ptile) {
2235 return;
2236 }
2237
2238 packet->tile = tile_index(ptile);
2239 packet->extras = *tile_extras(ptile);
2240 /* TODO: Set more packet fields. */
2241 }
2242 return;
2243
2244 case OBJTYPE_STARTPOS:
2245 {
2246 struct packet_edit_startpos_full *packet = pd.startpos;
2247 const struct startpos *psp = objbind_get_object(ob);
2248
2249 if (NULL != psp) {
2250 startpos_pack(psp, packet);
2251 }
2252 }
2253 return;
2254
2255 case OBJTYPE_UNIT:
2256 {
2257 struct packet_edit_unit *packet = pd.unit;
2258 const struct unit *punit = objbind_get_object(ob);
2259
2260 if (NULL == punit) {
2261 return;
2262 }
2263
2264 packet->id32 = punit->id;
2265 packet->id16 = packet->id32;
2266 packet->moves_left = punit->moves_left;
2267 packet->fuel = punit->fuel;
2268 packet->moved = punit->moved;
2269 packet->done_moving = punit->done_moving;
2270 packet->hp = punit->hp;
2271 packet->veteran = punit->veteran;
2272 packet->stay = punit->stay;
2273 /* TODO: Set more packet fields. */
2274 }
2275 return;
2276
2277 case OBJTYPE_CITY:
2278 {
2279 struct packet_edit_city *packet = pd.city;
2280 const struct city *pcity = objbind_get_object(ob);
2281 int i;
2282
2283 if (NULL == pcity) {
2284 return;
2285 }
2286
2287 packet->id32 = pcity->id;
2288 packet->id16 = packet->id32;
2289 sz_strlcpy(packet->name, pcity->name);
2290 packet->size = city_size_get(pcity);
2291 packet->history = pcity->history;
2292 for (i = 0; i < B_LAST; i++) {
2293 packet->built[i] = pcity->built[i].turn;
2294 }
2295 packet->food_stock = pcity->food_stock;
2296 packet->shield_stock = pcity->shield_stock;
2297 /* TODO: Set more packet fields. */
2298 }
2299 return;
2300
2301 case OBJTYPE_PLAYER:
2302 {
2303 struct packet_edit_player *packet = pd.player;
2304 const struct player *pplayer = objbind_get_object(ob);
2305 const struct nation_type *pnation;
2306 const struct research *presearch;
2307
2308 if (NULL == pplayer) {
2309 return;
2310 }
2311
2312 packet->id = player_number(pplayer);
2313 sz_strlcpy(packet->name, pplayer->name);
2314 pnation = nation_of_player(pplayer);
2315 packet->nation = nation_index(pnation);
2316 presearch = research_get(pplayer);
2318 packet->inventions[tech]
2319 = TECH_KNOWN == research_invention_state(presearch, tech);
2321 packet->gold = pplayer->economic.gold;
2322 packet->government = government_index(pplayer->government);
2323 packet->scenario_reserved = player_has_flag(pplayer, PLRF_SCENARIO_RESERVED);
2324 /* TODO: Set more packet fields. */
2325 }
2326 return;
2327
2328 case OBJTYPE_GAME:
2329 {
2330 struct packet_edit_game *packet = pd.game.game;
2331 const struct civ_game *pgame = objbind_get_object(ob);
2332
2333 if (NULL == pgame) {
2334 return;
2335 }
2336
2337 packet->scenario = pgame->scenario.is_scenario;
2338 sz_strlcpy(packet->scenario_name, pgame->scenario.name);
2340 sz_strlcpy(pd.game.desc->scenario_desc, pgame->scenario_desc.description);
2341 packet->scenario_random = pgame->scenario.save_random;
2342 packet->scenario_players = pgame->scenario.players;
2345 packet->lake_flooding = pgame->scenario.lake_flooding;
2346 }
2347 return;
2348
2349 case NUM_OBJTYPES:
2350 break;
2351 }
2352
2353 log_error("%s(): Unhandled object type %s (nb %d).", __FUNCTION__,
2355}
2356
2357/************************************************************************/
2361 struct objprop *op,
2362 union packetdata pd)
2363{
2364 struct propval *pv;
2366 enum object_property_ids propid;
2367
2368 if (!op || !ob || !pd.pointers.v_pointer1) {
2369 return;
2370 }
2371
2372 if (NULL == objbind_get_object(ob)) {
2373 return;
2374 }
2375
2377 return;
2378 }
2379
2380 pv = objbind_get_modified_value(ob, op);
2381 if (!pv) {
2382 return;
2383 }
2384
2386 propid = objprop_get_id(op);
2387
2388 switch (objtype) {
2389 case OBJTYPE_TILE:
2390 {
2391 struct packet_edit_tile *packet = pd.tile;
2392
2393 switch (propid) {
2394 case OPID_TILE_SPECIALS:
2396 if (BV_ISSET(pv->data.v_bv_special, pextra->data.special_idx)) {
2397 BV_SET(packet->extras, pextra->data.special_idx);
2398 } else {
2399 BV_CLR(packet->extras, pextra->data.special_idx);
2400 }
2402 return;
2403 case OPID_TILE_ROADS:
2404 extra_type_by_cause_iterate(EC_ROAD, pextra) {
2405 int ridx = road_number(extra_road_get(pextra));
2406
2407 if (BV_ISSET(pv->data.v_bv_roads, ridx)) {
2408 BV_SET(packet->extras, extra_index(pextra));
2409 } else {
2410 BV_CLR(packet->extras, extra_index(pextra));
2411 }
2413 return;
2414 case OPID_TILE_BASES:
2415 extra_type_by_cause_iterate(EC_BASE, pextra) {
2416 int bidx = base_number(extra_base_get(pextra));
2417
2418 if (BV_ISSET(pv->data.v_bv_bases, bidx)) {
2419 BV_SET(packet->extras, extra_index(pextra));
2420 } else {
2421 BV_CLR(packet->extras, extra_index(pextra));
2422 }
2424 return;
2425 case OPID_TILE_LABEL:
2426 sz_strlcpy(packet->label, pv->data.v_string);
2427 return;
2428 default:
2429 break;
2430 }
2431 }
2432 log_error("%s(): Unhandled request to pack value of property "
2433 "%d (%s) from object of type \"%s\".", __FUNCTION__,
2435 return;
2436
2437 case OBJTYPE_STARTPOS:
2438 {
2439 struct packet_edit_startpos_full *packet = pd.startpos;
2440
2441 switch (propid) {
2443 packet->exclude = pv->data.v_bool;
2444 return;
2446 BV_CLR_ALL(packet->nations);
2447 nation_hash_iterate(pv->data.v_nation_hash, pnation) {
2448 BV_SET(packet->nations, nation_number(pnation));
2450 return;
2451 default:
2452 break;
2453 }
2454 }
2455 log_error("%s(): Unhandled request to pack value of property "
2456 "%d (%s) from object of type \"%s\".", __FUNCTION__,
2458 return;
2459
2460 case OBJTYPE_UNIT:
2461 {
2462 struct packet_edit_unit *packet = pd.unit;
2463
2464 switch (propid) {
2466 packet->moves_left = pv->data.v_int;
2467 return;
2468 case OPID_UNIT_FUEL:
2469 packet->fuel = pv->data.v_int;
2470 return;
2471 case OPID_UNIT_MOVED:
2472 packet->moved = pv->data.v_bool;
2473 return;
2475 packet->done_moving = pv->data.v_bool;
2476 return;
2477 case OPID_UNIT_HP:
2478 packet->hp = pv->data.v_int;
2479 return;
2480 case OPID_UNIT_VETERAN:
2481 packet->veteran = pv->data.v_int;
2482 return;
2483 case OPID_UNIT_STAY:
2484 packet->stay = pv->data.v_bool;
2485 return;
2486 default:
2487 break;
2488 }
2489 }
2490 log_error("%s(): Unhandled request to pack value of property "
2491 "%d (%s) from object of type \"%s\".", __FUNCTION__,
2493 return;
2494
2495 case OBJTYPE_CITY:
2496 {
2497 struct packet_edit_city *packet = pd.city;
2498
2499 switch (propid) {
2500 case OPID_CITY_NAME:
2501 sz_strlcpy(packet->name, pv->data.v_string);
2502 return;
2503 case OPID_CITY_SIZE:
2504 packet->size = pv->data.v_int;
2505 return;
2506 case OPID_CITY_HISTORY:
2507 packet->history = pv->data.v_int;
2508 return;
2510 packet->food_stock = pv->data.v_int;
2511 return;
2513 packet->shield_stock = pv->data.v_int;
2514 return;
2516 {
2517 int i;
2518
2519 for (i = 0; i < B_LAST; i++) {
2520 packet->built[i] = pv->data.v_built[i].turn;
2521 }
2522 }
2523 return;
2524 default:
2525 break;
2526 }
2527 }
2528 log_error("%s(): Unhandled request to pack value of property "
2529 "%d (%s) from object of type \"%s\".", __FUNCTION__,
2531 return;
2532
2533 case OBJTYPE_PLAYER:
2534 {
2535 struct packet_edit_player *packet = pd.player;
2536
2537 switch (propid) {
2538 case OPID_PLAYER_NAME:
2539 sz_strlcpy(packet->name, pv->data.v_string);
2540 return;
2541 case OPID_PLAYER_NATION:
2542 packet->nation = nation_index(pv->data.v_nation);
2543 return;
2544 case OPID_PLAYER_GOV:
2545 packet->government = government_index(pv->data.v_gov);
2546 return;
2549 packet->inventions[tech] = BV_ISSET(pv->data.v_bv_inventions, tech);
2551 return;
2553 packet->scenario_reserved = pv->data.v_bool;
2554 return;
2556 packet->bulbs_researched = pv->data.v_int;
2557 return;
2558 case OPID_PLAYER_GOLD:
2559 packet->gold = pv->data.v_int;
2560 return;
2561 default:
2562 break;
2563 }
2564 }
2565 log_error("%s(): Unhandled request to pack value of property "
2566 "%d (%s) from object of type \"%s\".", __FUNCTION__,
2568 return;
2569
2570 case OBJTYPE_GAME:
2571 {
2572 struct packet_edit_game *packet = pd.game.game;
2573
2574 switch (propid) {
2575 case OPID_GAME_SCENARIO:
2576 packet->scenario = pv->data.v_bool;
2577 return;
2580 return;
2583 return;
2585 sz_strlcpy(pd.game.desc->scenario_desc, pv->data.v_const_string);
2586 return;
2588 packet->scenario_random = pv->data.v_bool;
2589 return;
2591 packet->scenario_players = pv->data.v_bool;
2592 return;
2594 packet->startpos_nations = pv->data.v_bool;
2595 return;
2597 packet->prevent_new_cities = pv->data.v_bool;
2598 return;
2600 packet->lake_flooding = pv->data.v_bool;
2601 return;
2603 packet->ruleset_locked = pv->data.v_bool;
2604 return;
2605 default:
2606 break;
2607 }
2608 }
2609 log_error("%s(): Unhandled request to pack value of property "
2610 "%d (%s) from object of type \"%s\".", __FUNCTION__,
2612 return;
2613
2614 case NUM_OBJTYPES:
2615 break;
2616 }
2617
2618 log_error("%s(): Unhandled request for object type \"%s\" (nb %d).",
2619 __FUNCTION__, objtype_get_name(objtype), objtype);
2620
2621}
2622
2623/************************************************************************/
2626static void objbind_set_rowref(struct objbind *ob,
2627 GtkTreeRowReference *rr)
2628{
2629 if (!ob) {
2630 return;
2631 }
2632 ob->rowref = rr;
2633}
2634
2635/************************************************************************/
2638static GtkTreeRowReference *objbind_get_rowref(struct objbind *ob)
2639{
2640 if (!ob) {
2641 return NULL;
2642 }
2643 return ob->rowref;
2644}
2645
2646/************************************************************************/
2649static int objprop_get_id(const struct objprop *op)
2650{
2651 if (!op) {
2652 return -1;
2653 }
2654 return op->id;
2655}
2656
2657/************************************************************************/
2664static GType objprop_get_gtype(const struct objprop *op)
2665{
2666 fc_assert_ret_val(NULL != op, G_TYPE_NONE);
2667
2668 switch (op->valtype) {
2669 case VALTYPE_NONE:
2671 return G_TYPE_NONE;
2672 case VALTYPE_INT:
2673 return G_TYPE_INT;
2674 case VALTYPE_BOOL:
2675 /* We want to show it as translated string, not as untranslated G_TYPE_BOOLEAN */
2676 return G_TYPE_STRING;
2677 case VALTYPE_STRING:
2680 case VALTYPE_BV_SPECIAL:
2681 case VALTYPE_BV_ROADS:
2682 case VALTYPE_BV_BASES:
2684 return G_TYPE_STRING;
2685 case VALTYPE_PIXBUF:
2686 case VALTYPE_NATION:
2687 case VALTYPE_GOV:
2688 return GDK_TYPE_PIXBUF;
2689 }
2690 log_error("%s(): Unhandled value type %d.", __FUNCTION__, op->valtype);
2691 return G_TYPE_NONE;
2692}
2693
2694/************************************************************************/
2697static enum value_types objprop_get_valtype(const struct objprop *op)
2698{
2699 if (!op) {
2700 return VALTYPE_NONE;
2701 }
2702 return op->valtype;
2703}
2704
2705/************************************************************************/
2708static bool objprop_show_in_listview(const struct objprop *op)
2709{
2710 if (!op) {
2711 return FALSE;
2712 }
2713 return op->flags & OPF_IN_LISTVIEW;
2714}
2715
2716/************************************************************************/
2719static bool objprop_has_widget(const struct objprop *op)
2720{
2721 if (!op) {
2722 return FALSE;
2723 }
2724 return op->flags & OPF_HAS_WIDGET;
2725}
2726
2727/************************************************************************/
2733static const char *objprop_get_attribute_type_string(const struct objprop *op)
2734{
2735 GType gtype;
2736
2737 if (!op) {
2738 return NULL;
2739 }
2740
2741 gtype = objprop_get_gtype(op);
2742 if (gtype == G_TYPE_INT || gtype == G_TYPE_STRING
2743 || gtype == G_TYPE_BOOLEAN) {
2744 return "text";
2745 } else if (gtype == GDK_TYPE_PIXBUF) {
2746 return "pixbuf";
2747 }
2748
2749 return NULL;
2750}
2751
2752/************************************************************************/
2758static void objprop_set_column_id(struct objprop *op, int col_id)
2759{
2760 if (!op) {
2761 return;
2762 }
2763 op->column_id = col_id;
2764}
2765
2766/************************************************************************/
2771static int objprop_get_column_id(const struct objprop *op)
2772{
2773 if (!op) {
2774 return -1;
2775 }
2776 return op->column_id;
2777}
2778
2779/************************************************************************/
2783 GtkTreeViewColumn *col)
2784{
2785 if (!op) {
2786 return;
2787 }
2788 op->view_column = col;
2789}
2790
2791/************************************************************************/
2795static GtkTreeViewColumn *objprop_get_treeview_column(const struct objprop *op)
2796{
2797 if (!op) {
2798 return NULL;
2799 }
2800 return op->view_column;
2801}
2802
2803/************************************************************************/
2806static const char *objprop_get_name(const struct objprop *op)
2807{
2808 if (!op) {
2809 return NULL;
2810 }
2811 return op->name;
2812}
2813
2814/************************************************************************/
2817static const char *objprop_get_tooltip(const struct objprop *op)
2818{
2819 if (!op) {
2820 return NULL;
2821 }
2822 return op->tooltip;
2823}
2824
2825/************************************************************************/
2830static GtkCellRenderer *objprop_create_cell_renderer(const struct objprop *op)
2831{
2832 GtkCellRenderer *cell = NULL;
2833 GType gtype;
2834
2835 gtype = objprop_get_gtype(op);
2836
2837 if (gtype == G_TYPE_INT || gtype == G_TYPE_STRING
2838 || gtype == G_TYPE_BOOLEAN) {
2839 cell = gtk_cell_renderer_text_new();
2840 } else if (gtype == GDK_TYPE_PIXBUF) {
2841 cell = gtk_cell_renderer_pixbuf_new();
2842 }
2843
2844 return cell;
2845}
2846
2847/************************************************************************/
2851static bool objprop_is_sortable(const struct objprop *op)
2852{
2853 GType gtype;
2854 if (!op) {
2855 return FALSE;
2856 }
2857 gtype = objprop_get_gtype(op);
2858 return gtype == G_TYPE_INT || gtype == G_TYPE_STRING;
2859}
2860
2861/************************************************************************/
2865static bool objprop_is_readonly(const struct objprop *op)
2866{
2867 if (!op) {
2868 return TRUE;
2869 }
2870 return !(op->flags & OPF_EDITABLE);
2871}
2872
2873/************************************************************************/
2876static void objprop_widget_text_changed(GtkEditable *text, gpointer userdata)
2877{
2878 struct objprop *op;
2879 struct property_page *pp;
2880 struct propval value = {{0,}, VALTYPE_STRING, FALSE};
2881
2882 op = userdata;
2884 value.data.v_const_string = gtk_entry_buffer_get_text(gtk_text_get_buffer(GTK_TEXT(text)));
2885
2886 property_page_change_value(pp, op, &value);
2887}
2888
2889/************************************************************************/
2892static void objprop_widget_spin_button_changed(GtkSpinButton *spin,
2893 gpointer userdata)
2894{
2895 struct objprop *op;
2896 struct property_page *pp;
2897 struct propval value = {{0,}, VALTYPE_INT, FALSE};
2898
2899 op = userdata;
2901 value.data.v_int = gtk_spin_button_get_value_as_int(spin);
2902
2903 property_page_change_value(pp, op, &value);
2904}
2905
2906/************************************************************************/
2909static void objprop_widget_toggle_button_changed(GtkToggleButton *button,
2910 gpointer userdata)
2911{
2912 struct objprop *op;
2913 struct property_page *pp;
2914 struct propval value = {{0,}, VALTYPE_BOOL, FALSE};
2915
2916 op = userdata;
2918 value.data.v_bool = gtk_toggle_button_get_active(button);
2919
2920 property_page_change_value(pp, op, &value);
2921}
2922
2923/************************************************************************/
2926static void objprop_setup_widget(struct objprop *op)
2927{
2928 GtkWidget *hbox, *hbox2, *label, *image, *text, *spin, *button;
2929 struct extviewer *ev = NULL;
2930 enum object_property_ids propid;
2931
2932 if (!op) {
2933 return;
2934 }
2935
2936 if (!objprop_has_widget(op)) {
2937 return;
2938 }
2939
2940 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
2941 op->widget = hbox;
2942
2943 label = gtk_label_new(objprop_get_name(op));
2944 gtk_widget_set_halign(label, GTK_ALIGN_START);
2945 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
2946 gtk_box_append(GTK_BOX(hbox), label);
2947 objprop_set_child_widget(op, "name-label", label);
2948
2949 propid = objprop_get_id(op);
2950
2951 switch (propid) {
2952 case OPID_TILE_INDEX:
2953 case OPID_TILE_X:
2954 case OPID_TILE_Y:
2955 case OPID_TILE_NAT_X:
2956 case OPID_TILE_NAT_Y:
2958 case OPID_TILE_TERRAIN:
2959 case OPID_TILE_RESOURCE:
2960 case OPID_TILE_XY:
2961 case OPID_STARTPOS_XY:
2962 case OPID_UNIT_ID:
2963 case OPID_UNIT_XY:
2964 case OPID_UNIT_TYPE:
2965 case OPID_CITY_ID:
2966 case OPID_CITY_XY:
2967 case OPID_PLAYER_AGE:
2968#ifdef FREECIV_DEBUG
2969 case OPID_TILE_ADDRESS:
2970 case OPID_UNIT_ADDRESS:
2971 case OPID_CITY_ADDRESS:
2972 case OPID_PLAYER_ADDRESS:
2973#endif /* FREECIV_DEBUG */
2974 label = gtk_label_new(NULL);
2975 gtk_widget_set_hexpand(label, TRUE);
2976 gtk_widget_set_halign(label, GTK_ALIGN_START);
2977 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
2978 gtk_box_append(GTK_BOX(hbox), label);
2979 objprop_set_child_widget(op, "value-label", label);
2980 return;
2981
2982 case OPID_TILE_IMAGE:
2984 case OPID_UNIT_IMAGE:
2985 case OPID_CITY_IMAGE:
2986 image = gtk_image_new();
2987 gtk_widget_set_size_request(image,
2990 gtk_widget_set_hexpand(image, TRUE);
2991 gtk_widget_set_halign(image, GTK_ALIGN_START);
2992 gtk_widget_set_valign(image, GTK_ALIGN_CENTER);
2993 gtk_box_append(GTK_BOX(hbox), image);
2994 objprop_set_child_widget(op, "image", image);
2995 return;
2996
2997 case OPID_CITY_NAME:
2998 case OPID_PLAYER_NAME:
3000 case OPID_TILE_LABEL:
3001 text = gtk_text_new();
3002 gtk_widget_set_hexpand(text, TRUE);
3003 gtk_widget_set_halign(text, GTK_ALIGN_END);
3004 gtk_editable_set_width_chars(GTK_EDITABLE(text), 8);
3005 g_signal_connect(text, "changed",
3006 G_CALLBACK(objprop_widget_text_changed), op);
3007 gtk_box_append(GTK_BOX(hbox), text);
3008 objprop_set_child_widget(op, "text", text);
3009 return;
3010
3012 case OPID_CITY_SIZE:
3013 case OPID_CITY_HISTORY:
3016 case OPID_PLAYER_GOLD:
3017 spin = gtk_spin_button_new_with_range(0.0, 100.0, 1.0);
3018 gtk_widget_set_hexpand(spin, TRUE);
3019 gtk_widget_set_halign(spin, GTK_ALIGN_END);
3020 g_signal_connect(spin, "value-changed",
3021 G_CALLBACK(objprop_widget_spin_button_changed), op);
3022 gtk_box_append(GTK_BOX(hbox), spin);
3023 objprop_set_child_widget(op, "spin", spin);
3024 return;
3025
3026 case OPID_UNIT_FUEL:
3027 case OPID_UNIT_HP:
3028 case OPID_UNIT_VETERAN:
3030 hbox2 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
3031 gtk_widget_set_hexpand(hbox2, TRUE);
3032 gtk_widget_set_halign(hbox2, GTK_ALIGN_END);
3033 gtk_box_append(GTK_BOX(hbox), hbox2);
3034 spin = gtk_spin_button_new_with_range(0.0, 100.0, 1.0);
3035 g_signal_connect(spin, "value-changed",
3036 G_CALLBACK(objprop_widget_spin_button_changed), op);
3037 gtk_box_append(GTK_BOX(hbox2), spin);
3038 objprop_set_child_widget(op, "spin", spin);
3039 label = gtk_label_new(NULL);
3040 gtk_widget_set_halign(label, GTK_ALIGN_START);
3041 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
3042 gtk_box_append(GTK_BOX(hbox2), label);
3043 objprop_set_child_widget(op, "max-value-label", label);
3044 return;
3045
3046 case OPID_TILE_SPECIALS:
3047 case OPID_TILE_ROADS:
3048 case OPID_TILE_BASES:
3049 case OPID_TILE_VISION:
3052 case OPID_PLAYER_NATION:
3053 case OPID_PLAYER_GOV:
3057 ev = extviewer_new(op);
3058 objprop_set_extviewer(op, ev);
3059 gtk_widget_set_hexpand(extviewer_get_panel_widget(ev), TRUE);
3060 gtk_widget_set_halign(extviewer_get_panel_widget(ev), GTK_ALIGN_END);
3061 gtk_box_append(GTK_BOX(hbox), extviewer_get_panel_widget(ev));
3063 return;
3064
3066 case OPID_UNIT_MOVED:
3068 case OPID_UNIT_STAY:
3069 case OPID_GAME_SCENARIO:
3077 button = gtk_toggle_button_new();
3078 gtk_widget_set_hexpand(button, TRUE);
3079 gtk_widget_set_halign(button, GTK_ALIGN_END);
3080 g_signal_connect(button, "toggled",
3082 op);
3083 gtk_box_append(GTK_BOX(hbox), button);
3084 objprop_set_child_widget(op, "togglebutton", button);
3085 return;
3086 }
3087
3088 log_error("%s(): Unhandled request to create widget for property %d (%s).",
3089 __FUNCTION__, propid, objprop_get_name(op));
3090}
3091
3092/************************************************************************/
3100static void objprop_refresh_widget(struct objprop *op,
3101 struct objbind *ob)
3102{
3103 GtkWidget *w, *label, *image, *text, *spin, *button;
3104 struct extviewer *ev;
3105 struct propval *pv;
3106 bool modified;
3107 enum object_property_ids propid;
3108 double min, max, step, big_step;
3109 char buf[256];
3110 const char *newtext;
3111 GtkEntryBuffer *buffer;
3112
3113 if (!op || !objprop_has_widget(op)) {
3114 return;
3115 }
3116
3117 w = objprop_get_widget(op);
3118 if (!w) {
3119 return;
3120 }
3121
3122 propid = objprop_get_id(op);
3123
3124 /* NB: We must take care to propval_free() the return value of
3125 * objbind_get_value_from_object(), since it always makes a
3126 * copy, but to NOT free the result of objbind_get_modified_value()
3127 * since it returns its own stored value. */
3128 pv = objbind_get_value_from_object(ob, op);
3129 modified = objbind_property_is_modified(ob, op);
3130
3131 if (pv && modified) {
3132 struct propval *pv_mod;
3133
3134 pv_mod = objbind_get_modified_value(ob, op);
3135 if (pv_mod) {
3136 if (propval_equal(pv, pv_mod)) {
3138 modified = FALSE;
3139 } else {
3140 propval_free(pv);
3141 pv = pv_mod;
3142 modified = TRUE;
3143 }
3144 } else {
3145 modified = FALSE;
3146 }
3147 }
3148
3149 switch (propid) {
3150 case OPID_TILE_IMAGE:
3152 case OPID_UNIT_IMAGE:
3153 case OPID_CITY_IMAGE:
3154 image = objprop_get_child_widget(op, "image");
3155 if (pv) {
3156 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pv->data.v_pixbuf);
3157 } else {
3158 gtk_image_set_from_pixbuf(GTK_IMAGE(image), NULL);
3159 }
3160 break;
3161
3162 case OPID_TILE_XY:
3163 case OPID_TILE_TERRAIN:
3164 case OPID_TILE_RESOURCE:
3165 case OPID_STARTPOS_XY:
3166 case OPID_UNIT_XY:
3167 case OPID_UNIT_TYPE:
3168 case OPID_CITY_XY:
3169#ifdef FREECIV_DEBUG
3170 case OPID_TILE_ADDRESS:
3171 case OPID_UNIT_ADDRESS:
3172 case OPID_CITY_ADDRESS:
3173 case OPID_PLAYER_ADDRESS:
3174#endif /* FREECIV_DEBUG */
3175 label = objprop_get_child_widget(op, "value-label");
3176 if (pv) {
3177 gtk_label_set_text(GTK_LABEL(label), pv->data.v_string);
3178 } else {
3179 gtk_label_set_text(GTK_LABEL(label), NULL);
3180 }
3181 break;
3182
3183 case OPID_TILE_INDEX:
3184 case OPID_TILE_X:
3185 case OPID_TILE_Y:
3186 case OPID_TILE_NAT_X:
3187 case OPID_TILE_NAT_Y:
3189 case OPID_UNIT_ID:
3190 case OPID_CITY_ID:
3191 case OPID_PLAYER_AGE:
3192 label = objprop_get_child_widget(op, "value-label");
3193 if (pv) {
3194 char agebuf[16];
3195
3196 fc_snprintf(agebuf, sizeof(agebuf), "%d", pv->data.v_int);
3197 gtk_label_set_text(GTK_LABEL(label), agebuf);
3198 } else {
3199 gtk_label_set_text(GTK_LABEL(label), NULL);
3200 }
3201 break;
3202
3203 case OPID_CITY_NAME:
3204 case OPID_PLAYER_NAME:
3206 case OPID_TILE_LABEL:
3207 text = objprop_get_child_widget(op, "text");
3208 if (pv) {
3209 /* Most of these are semantically in "v_const_string",
3210 * but this works as the address is the same regardless. */
3211 newtext = pv->data.v_string;
3212 } else {
3213 newtext = "";
3214 }
3215 buffer = gtk_text_get_buffer(GTK_TEXT(text));
3216
3217 /* Only set the text if it has changed. This breaks
3218 * recursive loop. */
3219 if (strcmp(newtext, gtk_entry_buffer_get_text(buffer))) {
3220 gtk_entry_buffer_set_text(buffer, newtext, -1);
3221 }
3222 gtk_widget_set_sensitive(text, pv != NULL);
3223 break;
3224
3226 case OPID_CITY_SIZE:
3227 case OPID_CITY_HISTORY:
3230 case OPID_PLAYER_GOLD:
3231 spin = objprop_get_child_widget(op, "spin");
3232 if (pv) {
3233 disable_gobject_callback(G_OBJECT(spin),
3235 if (objbind_get_allowed_value_span(ob, op, &min, &max,
3236 &step, &big_step)) {
3237 gtk_spin_button_set_range(GTK_SPIN_BUTTON(spin), min, max);
3238 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(spin),
3239 step, big_step);
3240 }
3241 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), pv->data.v_int);
3242 enable_gobject_callback(G_OBJECT(spin),
3244 }
3245 gtk_widget_set_sensitive(spin, pv != NULL);
3246 break;
3247
3248 case OPID_UNIT_FUEL:
3249 case OPID_UNIT_HP:
3250 case OPID_UNIT_VETERAN:
3252 spin = objprop_get_child_widget(op, "spin");
3253 label = objprop_get_child_widget(op, "max-value-label");
3254 if (pv) {
3255 disable_gobject_callback(G_OBJECT(spin),
3257 if (objbind_get_allowed_value_span(ob, op, &min, &max,
3258 &step, &big_step)) {
3259 gtk_spin_button_set_range(GTK_SPIN_BUTTON(spin), min, max);
3260 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(spin),
3261 step, big_step);
3262 fc_snprintf(buf, sizeof(buf), "/%d", (int) max);
3263 gtk_label_set_text(GTK_LABEL(label), buf);
3264 } else {
3265 gtk_label_set_text(GTK_LABEL(label), NULL);
3266 }
3267 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), pv->data.v_int);
3268 enable_gobject_callback(G_OBJECT(spin),
3270 } else {
3271 gtk_label_set_text(GTK_LABEL(label), NULL);
3272 }
3273 gtk_widget_set_sensitive(spin, pv != NULL);
3274 break;
3275
3276 case OPID_TILE_SPECIALS:
3277 case OPID_TILE_ROADS:
3278 case OPID_TILE_BASES:
3279 case OPID_TILE_VISION:
3282 case OPID_PLAYER_NATION:
3283 case OPID_PLAYER_GOV:
3287 ev = objprop_get_extviewer(op);
3288 if (pv) {
3290 } else {
3292 }
3293 break;
3294
3296 case OPID_UNIT_MOVED:
3298 case OPID_UNIT_STAY:
3299 case OPID_GAME_SCENARIO:
3307 button = objprop_get_child_widget(op, "togglebutton");
3308 disable_gobject_callback(G_OBJECT(button),
3310 if (pv) {
3311 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
3312 pv->data.v_bool);
3313 } else {
3314 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
3315 }
3316 enable_gobject_callback(G_OBJECT(button),
3318 gtk_widget_set_sensitive(button, pv != NULL);
3319 break;
3320 }
3321
3322 if (!modified) {
3323 propval_free(pv);
3324 }
3325
3326 label = objprop_get_child_widget(op, "name-label");
3327 if (label) {
3328 const char *name = objprop_get_name(op);
3329 if (modified) {
3330 char namebuf[128];
3331
3332 fc_snprintf(namebuf, sizeof(namebuf),
3333 "<span foreground=\"red\">%s</span>", name);
3334 gtk_label_set_markup(GTK_LABEL(label), namebuf);
3335 } else {
3336 gtk_label_set_text(GTK_LABEL(label), name);
3337 }
3338 }
3339}
3340
3341/************************************************************************/
3345static GtkWidget *objprop_get_widget(struct objprop *op)
3346{
3347 if (!op) {
3348 return NULL;
3349 }
3350 if (!op->widget) {
3352 }
3353 return op->widget;
3354}
3355
3356/************************************************************************/
3360static void objprop_set_child_widget(struct objprop *op,
3361 const char *widget_name,
3362 GtkWidget *widget)
3363{
3364 GtkWidget *w;
3365
3366 if (!op || !widget_name || !widget) {
3367 return;
3368 }
3369
3370 w = objprop_get_widget(op);
3371 if (!w) {
3372 log_error("Cannot store child widget %p under name "
3373 "\"%s\" using objprop_set_child_widget for object "
3374 "property %d (%s) because objprop_get_widget does "
3375 "not return a valid widget.",
3376 widget, widget_name, objprop_get_id(op), objprop_get_name(op));
3377 return;
3378 }
3379
3380 g_object_set_data(G_OBJECT(w), widget_name, widget);
3381}
3382
3383/************************************************************************/
3387static GtkWidget *objprop_get_child_widget(struct objprop *op,
3388 const char *widget_name)
3389{
3390 GtkWidget *w, *child;
3391
3392 if (!op || !widget_name) {
3393 return NULL;
3394 }
3395
3396 w = objprop_get_widget(op);
3397 if (!w) {
3398 log_error("Cannot retrieve child widget under name "
3399 "\"%s\" using objprop_get_child_widget for object "
3400 "property %d (%s) because objprop_get_widget does "
3401 "not return a valid widget.",
3402 widget_name, objprop_get_id(op), objprop_get_name(op));
3403 return NULL;
3404 }
3405
3406 child = g_object_get_data(G_OBJECT(w), widget_name);
3407 if (!child) {
3408 log_error("Child widget \"%s\" not found for object "
3409 "property %d (%s) via objprop_get_child_widget.",
3410 widget_name, objprop_get_id(op), objprop_get_name(op));
3411 return NULL;
3412 }
3413
3414 return child;
3415}
3416
3417/************************************************************************/
3420static void objprop_set_extviewer(struct objprop *op,
3421 struct extviewer *ev)
3422{
3423 if (!op) {
3424 return;
3425 }
3426 op->extviewer = ev;
3427}
3428
3429/************************************************************************/
3432static struct extviewer *objprop_get_extviewer(struct objprop *op)
3433{
3434 if (!op) {
3435 return NULL;
3436 }
3437 return op->extviewer;
3438}
3439
3440/************************************************************************/
3443static struct property_page *objprop_get_property_page(const struct objprop *op)
3444{
3445 if (!op) {
3446 return NULL;
3447 }
3448 return op->parent_page;
3449}
3450
3451/************************************************************************/
3454static struct objprop *objprop_new(int id,
3455 const char *name,
3456 const char *tooltip,
3458 enum value_types valtype,
3459 struct property_page *parent)
3460{
3461 struct objprop *op;
3462
3463 op = fc_calloc(1, sizeof(*op));
3464 op->id = id;
3465 op->name = name;
3466 op->tooltip = tooltip;
3467 op->flags = flags;
3468 op->valtype = valtype;
3469 op->column_id = -1;
3470 op->parent_page = parent;
3471
3472 return op;
3473}
3474
3475/************************************************************************/
3479static struct extviewer *extviewer_new(struct objprop *op)
3480{
3481 struct extviewer *ev;
3482 GtkWidget *hbox, *vbox, *label, *button, *scrollwin, *image;
3483 GtkWidget *view = NULL;
3484 GtkTreeSelection *sel;
3485 GtkListStore *store = NULL;
3486 GtkTextBuffer *textbuf = NULL;
3487 GType *gtypes;
3488 enum object_property_ids propid;
3489 int num_cols;
3490
3491 if (!op) {
3492 return NULL;
3493 }
3494
3495 ev = fc_calloc(1, sizeof(*ev));
3496 ev->objprop = op;
3497
3498 propid = objprop_get_id(op);
3499
3500
3501 /* Create the panel widget. */
3502
3503 switch (propid) {
3504 case OPID_TILE_SPECIALS:
3505 case OPID_TILE_ROADS:
3506 case OPID_TILE_BASES:
3512 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
3513 ev->panel_widget = hbox;
3514
3515 label = gtk_label_new(NULL);
3516 gtk_widget_set_halign(label, GTK_ALIGN_START);
3517 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
3518 gtk_box_append(GTK_BOX(hbox), label);
3519 ev->panel_label = label;
3520 break;
3521
3522 case OPID_PLAYER_NATION:
3523 case OPID_PLAYER_GOV:
3524 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
3525 ev->panel_widget = vbox;
3526
3527 label = gtk_label_new(NULL);
3528 gtk_widget_set_halign(label, GTK_ALIGN_START);
3529 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
3530 gtk_box_append(GTK_BOX(vbox), label);
3531 ev->panel_label = label;
3532
3533 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
3534 gtk_box_append(GTK_BOX(vbox), hbox);
3535
3536 image = gtk_image_new();
3537 if (propid == OPID_PLAYER_GOV) {
3538 gtk_widget_set_size_request(image,
3541 } else {
3542 /* propid OPID_PLAYER_NATION */
3543 gtk_widget_set_size_request(image, 100, 40);
3544 }
3545 gtk_widget_set_halign(image, GTK_ALIGN_START);
3546 gtk_widget_set_valign(image, GTK_ALIGN_CENTER);
3547 gtk_box_append(GTK_BOX(hbox), image);
3548 ev->panel_image = image;
3549 break;
3550
3551 case OPID_TILE_VISION:
3552 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
3553 ev->panel_widget = hbox;
3554 break;
3555
3556 default:
3557 log_error("Unhandled request to create panel widget "
3558 "for property %d (%s) in extviewer_new().",
3559 propid, objprop_get_name(op));
3560 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
3561 ev->panel_widget = hbox;
3562 break;
3563 }
3564
3565 if (objprop_is_readonly(op)) {
3566 button = gtk_button_new_with_label(Q_("?verb:View"));
3567 } else {
3568 button = gtk_button_new_with_label(_("Edit"));
3569 }
3570 g_signal_connect(button, "clicked",
3571 G_CALLBACK(extviewer_panel_button_clicked), ev);
3572 gtk_box_append(GTK_BOX(hbox), button);
3573 ev->panel_button = button;
3574
3575
3576 /* Create the data store. */
3577
3578 switch (propid) {
3579 case OPID_TILE_SPECIALS:
3580 case OPID_TILE_ROADS:
3581 case OPID_TILE_BASES:
3583 store = gtk_list_store_new(3, G_TYPE_BOOLEAN, G_TYPE_INT,
3584 G_TYPE_STRING);
3585 break;
3586 case OPID_TILE_VISION:
3587 num_cols = 3 + 1 + V_COUNT;
3588 gtypes = fc_malloc(num_cols * sizeof(GType));
3589 gtypes[0] = G_TYPE_INT; /* player number */
3590 gtypes[1] = GDK_TYPE_PIXBUF; /* player flag */
3591 gtypes[2] = G_TYPE_STRING; /* player name */
3592 gtypes[3] = G_TYPE_BOOLEAN; /* tile_known */
3594 gtypes[4 + v] = G_TYPE_BOOLEAN; /* tile_seen[v] */
3596 store = gtk_list_store_newv(num_cols, gtypes);
3597 free(gtypes);
3598 break;
3600 store = gtk_list_store_new(4, G_TYPE_BOOLEAN, G_TYPE_INT,
3601 G_TYPE_STRING, G_TYPE_STRING);
3602 break;
3604 case OPID_PLAYER_NATION:
3605 case OPID_PLAYER_GOV:
3606 store = gtk_list_store_new(4, G_TYPE_BOOLEAN, G_TYPE_INT,
3607 GDK_TYPE_PIXBUF, G_TYPE_STRING);
3608 break;
3611 textbuf = gtk_text_buffer_new(NULL);
3612 break;
3613 default:
3614 log_error("Unhandled request to create data store "
3615 "for property %d (%s) in extviewer_new().",
3616 propid, objprop_get_name(op));
3617 break;
3618 }
3619
3620 ev->store = store;
3621 ev->textbuf = textbuf;
3622
3623 /* Create the view widget. */
3624
3625 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
3626 ev->view_widget = vbox;
3627
3628 label = gtk_label_new(objprop_get_name(op));
3629 gtk_widget_set_halign(label, GTK_ALIGN_START);
3630 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
3631 gtk_box_append(GTK_BOX(vbox), label);
3632 ev->view_label = label;
3633
3634 if (store || textbuf) {
3635 scrollwin = gtk_scrolled_window_new();
3636 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(scrollwin),
3637 TRUE);
3638 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
3639 GTK_POLICY_AUTOMATIC,
3640 GTK_POLICY_AUTOMATIC);
3641 gtk_box_append(GTK_BOX(vbox), scrollwin);
3642
3643 if (store) {
3644 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
3645 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
3646 gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
3647 } else {
3648 const bool editable = !objprop_is_readonly(op);
3649
3650 view = gtk_text_view_new_with_buffer(textbuf);
3651 gtk_text_view_set_editable(GTK_TEXT_VIEW(view), editable);
3652 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(view), editable);
3653 }
3654 gtk_widget_set_hexpand(view, TRUE);
3655 gtk_widget_set_vexpand(view, TRUE);
3656
3657 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrollwin), view);
3658 }
3659
3660 switch (propid) {
3661
3662 case OPID_TILE_SPECIALS:
3663 case OPID_TILE_ROADS:
3664 case OPID_TILE_BASES:
3665 /* TRANS: As in "this tile special is present". */
3666 add_column(view, 0, _("Present"), G_TYPE_BOOLEAN, TRUE, FALSE,
3667 G_CALLBACK(extviewer_view_cell_toggled), ev);
3668 add_column(view, 1, _("ID"), G_TYPE_INT,
3669 FALSE, FALSE, NULL, NULL);
3670 add_column(view, 2, _("Name"), G_TYPE_STRING,
3671 FALSE, FALSE, NULL, NULL);
3672 break;
3673
3674 case OPID_TILE_VISION:
3675 add_column(view, 0, _("ID"), G_TYPE_INT,
3676 FALSE, FALSE, NULL, NULL);
3677 add_column(view, 1, _("Nation"), GDK_TYPE_PIXBUF,
3678 FALSE, FALSE, NULL, NULL);
3679 add_column(view, 2, _("Name"), G_TYPE_STRING,
3680 FALSE, FALSE, NULL, NULL);
3681 add_column(view, 3, _("Known"), G_TYPE_BOOLEAN,
3682 FALSE, FALSE, NULL, NULL);
3685 G_TYPE_BOOLEAN, FALSE, FALSE, NULL, NULL);
3687 break;
3688
3690 /* TRANS: As in "this building is present". */
3691 add_column(view, 0, _("Present"), G_TYPE_BOOLEAN, TRUE, FALSE,
3692 G_CALLBACK(extviewer_view_cell_toggled), ev);
3693 add_column(view, 1, _("ID"), G_TYPE_INT,
3694 FALSE, FALSE, NULL, NULL);
3695 add_column(view, 2, _("Name"), G_TYPE_STRING,
3696 FALSE, FALSE, NULL, NULL);
3697 /* TRANS: As in "the turn when this building was built". */
3698 add_column(view, 3, _("Turn Built"), G_TYPE_STRING,
3699 FALSE, FALSE, NULL, NULL);
3700 break;
3701
3703 /* TRANS: As in "the player has set this nation". */
3704 add_column(view, 0, _("Set"), G_TYPE_BOOLEAN, TRUE, FALSE,
3705 G_CALLBACK(extviewer_view_cell_toggled), ev);
3706 add_column(view, 1, _("ID"), G_TYPE_INT,
3707 FALSE, FALSE, NULL, NULL);
3708 add_column(view, 2, _("Flag"), GDK_TYPE_PIXBUF,
3709 FALSE, FALSE, NULL, NULL);
3710 add_column(view, 3, _("Name"), G_TYPE_STRING,
3711 FALSE, FALSE, NULL, NULL);
3712 break;
3713
3714 case OPID_PLAYER_NATION:
3715 case OPID_PLAYER_GOV:
3716 /* TRANS: As in "the player has set this nation". */
3717 add_column(view, 0, _("Set"), G_TYPE_BOOLEAN, TRUE, TRUE,
3718 G_CALLBACK(extviewer_view_cell_toggled), ev);
3719 add_column(view, 1, _("ID"), G_TYPE_INT,
3720 FALSE, FALSE, NULL, NULL);
3721 add_column(view, 2,
3722 propid == OPID_PLAYER_GOV ? _("Icon") : _("Flag"),
3723 GDK_TYPE_PIXBUF,
3724 FALSE, FALSE, NULL, NULL);
3725 add_column(view, 3, _("Name"), G_TYPE_STRING,
3726 FALSE, FALSE, NULL, NULL);
3727 break;
3728
3730 /* TRANS: As in "this invention is known". */
3731 add_column(view, 0, _("Known"), G_TYPE_BOOLEAN, TRUE, FALSE,
3732 G_CALLBACK(extviewer_view_cell_toggled), ev);
3733 add_column(view, 1, _("ID"), G_TYPE_INT,
3734 FALSE, FALSE, NULL, NULL);
3735 add_column(view, 2, _("Name"), G_TYPE_STRING,
3736 FALSE, FALSE, NULL, NULL);
3737 break;
3738
3741 g_signal_connect(textbuf, "changed",
3742 G_CALLBACK(extviewer_textbuf_changed), ev);
3743 break;
3744
3745 default:
3746 log_error("Unhandled request to configure view widget "
3747 "for property %d (%s) in extviewer_new().",
3748 propid, objprop_get_name(op));
3749 break;
3750 }
3751
3752 gtk_widget_show(ev->panel_widget);
3753 gtk_widget_show(ev->view_widget);
3754
3755 return ev;
3756}
3757
3758/************************************************************************/
3761static struct objprop *extviewer_get_objprop(struct extviewer *ev)
3762{
3763 if (!ev) {
3764 return NULL;
3765 }
3766 return ev->objprop;
3767}
3768
3769/************************************************************************/
3773static GtkWidget *extviewer_get_panel_widget(struct extviewer *ev)
3774{
3775 if (!ev) {
3776 return NULL;
3777 }
3778 return ev->panel_widget;
3779}
3780
3781/************************************************************************/
3785static GtkWidget *extviewer_get_view_widget(struct extviewer *ev)
3786{
3787 if (!ev) {
3788 return NULL;
3789 }
3790 return ev->view_widget;
3791}
3792
3793/************************************************************************/
3797 struct propval *pv)
3798{
3799 struct objprop *op;
3800 enum object_property_ids propid;
3801 int id, turn_built;
3802 bool present, all;
3803 const char *name;
3804 GdkPixbuf *pixbuf;
3805 GtkListStore *store;
3806 GtkTextBuffer *textbuf;
3807 GtkTreeIter iter;
3808 gchar *buf;
3809
3810 if (!ev) {
3811 return;
3812 }
3813
3814 op = extviewer_get_objprop(ev);
3815 propid = objprop_get_id(op);
3816
3817 if (propval_equal(pv, ev->pv_cached)) {
3818 return;
3819 }
3821 ev->pv_cached = propval_copy(pv);
3822 store = ev->store;
3823 textbuf = ev->textbuf;
3824
3825
3826 /* NB: Remember to have -1 as the last argument to
3827 * gtk_list_store_set() and to use the correct column
3828 * number when inserting data. :) */
3829 switch (propid) {
3830
3831 case OPID_TILE_SPECIALS:
3832 gtk_list_store_clear(store);
3834 id = spe->data.special_idx;
3836 present = BV_ISSET(pv->data.v_bv_special, id);
3837 gtk_list_store_append(store, &iter);
3838 gtk_list_store_set(store, &iter, 0, present, 1, id, 2, name, -1);
3840 buf = propval_as_string(pv);
3841 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
3842 g_free(buf);
3843 break;
3844
3845 case OPID_TILE_ROADS:
3846 gtk_list_store_clear(store);
3847 extra_type_by_cause_iterate(EC_ROAD, pextra) {
3848 struct road_type *proad = extra_road_get(pextra);
3849
3850 id = road_number(proad);
3851 name = extra_name_translation(pextra);
3852 present = BV_ISSET(pv->data.v_bv_roads, id);
3853 gtk_list_store_append(store, &iter);
3854 gtk_list_store_set(store, &iter, 0, present, 1, id, 2, name, -1);
3856 buf = propval_as_string(pv);
3857 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
3858 g_free(buf);
3859 break;
3860
3861 case OPID_TILE_BASES:
3862 gtk_list_store_clear(store);
3863 extra_type_by_cause_iterate(EC_BASE, pextra) {
3864 struct base_type *pbase = extra_base_get(pextra);
3865
3866 id = base_number(pbase);
3867 name = extra_name_translation(pextra);
3868 present = BV_ISSET(pv->data.v_bv_bases, id);
3869 gtk_list_store_append(store, &iter);
3870 gtk_list_store_set(store, &iter, 0, present, 1, id, 2, name, -1);
3872 buf = propval_as_string(pv);
3873 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
3874 g_free(buf);
3875 break;
3876
3877 case OPID_TILE_VISION:
3878 gtk_list_store_clear(store);
3879 player_slots_iterate(pslot) {
3880 id = player_slot_index(pslot);
3881 if (player_slot_is_used(pslot)) {
3882 struct player *pplayer = player_slot_get_player(pslot);
3883
3884 name = player_name(pplayer);
3885 pixbuf = get_flag(pplayer->nation);
3886 } else {
3887 name = "";
3888 pixbuf = NULL;
3889 }
3890 gtk_list_store_append(store, &iter);
3891 gtk_list_store_set(store, &iter, 0, id, 2, name, -1);
3892 if (pixbuf) {
3893 gtk_list_store_set(store, &iter, 1, pixbuf, -1);
3894 g_object_unref(pixbuf);
3895 pixbuf = NULL;
3896 }
3897 present = BV_ISSET(pv->data.v_tile_vision->tile_known, id);
3898 gtk_list_store_set(store, &iter, 3, present, -1);
3900 present = BV_ISSET(pv->data.v_tile_vision->tile_seen[v], id);
3901 gtk_list_store_set(store, &iter, 4 + v, present, -1);
3904 break;
3905
3907 gtk_list_store_clear(store);
3908 gtk_list_store_append(store, &iter);
3909 all = (0 == nation_hash_size(pv->data.v_nation_hash));
3910 gtk_list_store_set(store, &iter, 0, all, 1, -1, 3,
3911 _("All nations"), -1);
3912 nations_iterate(pnation) {
3914 && is_nation_playable(pnation)) {
3915 present = (!all && nation_hash_lookup(pv->data.v_nation_hash,
3916 pnation, NULL));
3917 id = nation_number(pnation);
3918 pixbuf = get_flag(pnation);
3920 gtk_list_store_append(store, &iter);
3921 gtk_list_store_set(store, &iter, 0, present, 1, id,
3922 2, pixbuf, 3, name, -1);
3923 if (pixbuf) {
3924 g_object_unref(pixbuf);
3925 }
3926 }
3928 buf = propval_as_string(pv);
3929 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
3930 g_free(buf);
3931 break;
3932
3934 gtk_list_store_clear(store);
3935 improvement_iterate(pimprove) {
3936 if (is_special_improvement(pimprove)) {
3937 continue;
3938 }
3939 id = improvement_index(pimprove);
3941 turn_built = pv->data.v_built[id].turn;
3942 present = turn_built >= 0;
3943 buf = built_status_to_string(&pv->data.v_built[id]);
3944 gtk_list_store_append(store, &iter);
3945 gtk_list_store_set(store, &iter, 0, present, 1, id, 2, name,
3946 3, buf, -1);
3947 g_free(buf);
3949 buf = propval_as_string(pv);
3950 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
3951 g_free(buf);
3952 break;
3953
3954 case OPID_PLAYER_NATION:
3955 {
3956 enum barbarian_type barbarian_type =
3958
3959 gtk_list_store_clear(store);
3960 nations_iterate(pnation) {
3962 && nation_barbarian_type(pnation) == barbarian_type
3963 && (barbarian_type != NOT_A_BARBARIAN
3964 || is_nation_playable(pnation))) {
3965 present = (pnation == pv->data.v_nation);
3966 id = nation_index(pnation);
3967 pixbuf = get_flag(pnation);
3969 gtk_list_store_append(store, &iter);
3970 gtk_list_store_set(store, &iter, 0, present, 1, id,
3971 2, pixbuf, 3, name, -1);
3972 if (pixbuf) {
3973 g_object_unref(pixbuf);
3974 }
3975 }
3977 gtk_label_set_text(GTK_LABEL(ev->panel_label),
3979 pixbuf = get_flag(pv->data.v_nation);
3980 gtk_image_set_from_pixbuf(GTK_IMAGE(ev->panel_image), pixbuf);
3981 if (pixbuf) {
3982 g_object_unref(pixbuf);
3983 }
3984 }
3985 break;
3986
3987 case OPID_PLAYER_GOV:
3988 {
3989 gtk_list_store_clear(store);
3990 governments_iterate(pgov) {
3991 present = (pgov == pv->data.v_gov);
3992 id = government_index(pgov);
3995 gtk_list_store_append(store, &iter);
3996 gtk_list_store_set(store, &iter, 0, present, 1, id,
3997 2, pixbuf, 3, name, -1);
3998 if (pixbuf) {
3999 g_object_unref(pixbuf);
4000 }
4002 if (pv->data.v_gov != NULL) {
4003 gtk_label_set_text(GTK_LABEL(ev->panel_label),
4006 } else {
4007 gtk_label_set_text(GTK_LABEL(ev->panel_label), "?");
4010 }
4011
4012 gtk_image_set_from_pixbuf(GTK_IMAGE(ev->panel_image), pixbuf);
4013 if (pixbuf) {
4014 g_object_unref(pixbuf);
4015 }
4016 }
4017 break;
4018
4020 gtk_list_store_clear(store);
4021 advance_iterate(A_FIRST, padvance) {
4022 id = advance_index(padvance);
4023 present = BV_ISSET(pv->data.v_bv_inventions, id);
4024 name = advance_name_translation(padvance);
4025 gtk_list_store_append(store, &iter);
4026 gtk_list_store_set(store, &iter, 0, present, 1, id, 2, name, -1);
4028 buf = propval_as_string(pv);
4029 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4030 g_free(buf);
4031 break;
4032
4035 disable_gobject_callback(G_OBJECT(ev->textbuf),
4036 G_CALLBACK(extviewer_textbuf_changed));
4037 {
4038 GtkTextIter start, end;
4039 char *oldtext;
4040
4041 /* Don't re-set content if unchanged, to avoid moving cursor */
4042 gtk_text_buffer_get_bounds(textbuf, &start, &end);
4043 oldtext = gtk_text_buffer_get_text(textbuf, &start, &end, TRUE);
4044 if (strcmp(oldtext, pv->data.v_const_string) != 0) {
4045 gtk_text_buffer_set_text(textbuf, pv->data.v_const_string, -1);
4046 }
4047 }
4048 enable_gobject_callback(G_OBJECT(ev->textbuf),
4049 G_CALLBACK(extviewer_textbuf_changed));
4050 gtk_widget_set_sensitive(ev->view_widget, TRUE);
4051 buf = propval_as_string(pv);
4052 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4053 g_free(buf);
4054 break;
4055
4056 default:
4057 log_error("Unhandled request to refresh widgets "
4058 "extviewer_refresh_widgets() for objprop id=%d "
4059 "name \"%s\".", propid, objprop_get_name(op));
4060 break;
4061 }
4062}
4063
4064/************************************************************************/
4067static void extviewer_clear_widgets(struct extviewer *ev)
4068{
4069 struct objprop *op;
4070 enum object_property_ids propid;
4071
4072 if (!ev) {
4073 return;
4074 }
4075
4076 op = extviewer_get_objprop(ev);
4077 propid = objprop_get_id(op);
4078
4080 ev->pv_cached = NULL;
4081
4082 if (ev->panel_label != NULL) {
4083 gtk_label_set_text(GTK_LABEL(ev->panel_label), NULL);
4084 }
4085
4086 switch (propid) {
4087 case OPID_TILE_SPECIALS:
4088 case OPID_TILE_ROADS:
4089 case OPID_TILE_BASES:
4090 case OPID_TILE_VISION:
4094 gtk_list_store_clear(ev->store);
4095 break;
4096 case OPID_PLAYER_NATION:
4097 case OPID_PLAYER_GOV:
4098 gtk_list_store_clear(ev->store);
4099 gtk_image_set_from_pixbuf(GTK_IMAGE(ev->panel_image), NULL);
4100 break;
4103 disable_gobject_callback(G_OBJECT(ev->textbuf),
4104 G_CALLBACK(extviewer_textbuf_changed));
4105 gtk_text_buffer_set_text(ev->textbuf, "", -1);
4106 enable_gobject_callback(G_OBJECT(ev->textbuf),
4107 G_CALLBACK(extviewer_textbuf_changed));
4108 gtk_widget_set_sensitive(ev->view_widget, FALSE);
4109 break;
4110 default:
4111 log_error("Unhandled request to clear widgets "
4112 "in extviewer_clear_widgets() for objprop id=%d "
4113 "name \"%s\".", propid, objprop_get_name(op));
4114 break;
4115 }
4116}
4117
4118/************************************************************************/
4122static void extviewer_panel_button_clicked(GtkButton *button,
4123 gpointer userdata)
4124{
4125 struct extviewer *ev;
4126 struct property_page *pp;
4127 struct objprop *op;
4128
4129 ev = userdata;
4130 if (!ev) {
4131 return;
4132 }
4133
4134 op = extviewer_get_objprop(ev);
4137}
4138
4139/************************************************************************/
4142static void extviewer_view_cell_toggled(GtkCellRendererToggle *cell,
4143 gchar *path,
4144 gpointer userdata)
4145{
4146 struct extviewer *ev;
4147 struct objprop *op;
4148 struct property_page *pp;
4149 enum object_property_ids propid;
4150 GtkTreeModel *model;
4151 GtkTreeIter iter;
4152 int id, old_id, turn_built;
4153 struct propval *pv;
4154 bool active, present;
4155 gchar *buf;
4156 GdkPixbuf *pixbuf = NULL;
4157
4158 ev = userdata;
4159 if (!ev) {
4160 return;
4161 }
4162
4163 pv = ev->pv_cached;
4164 if (!pv) {
4165 return;
4166 }
4167
4168 op = extviewer_get_objprop(ev);
4169 propid = objprop_get_id(op);
4170 active = gtk_cell_renderer_toggle_get_active(cell);
4172
4173 model = GTK_TREE_MODEL(ev->store);
4174 if (!gtk_tree_model_get_iter_from_string(model, &iter, path)) {
4175 return;
4176 }
4177 present = !active;
4178
4179
4180 switch (propid) {
4181
4182 case OPID_TILE_SPECIALS:
4183 gtk_tree_model_get(model, &iter, 1, &id, -1);
4184 if (id < 0 || id >= extra_type_list_size(extra_type_list_by_cause(EC_SPECIAL))) {
4185 return;
4186 }
4187 if (present) {
4188 BV_SET(pv->data.v_bv_special, id);
4189 } else {
4190 BV_CLR(pv->data.v_bv_special, id);
4191 }
4192 gtk_list_store_set(ev->store, &iter, 0, present, -1);
4193 buf = propval_as_string(pv);
4194 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4195 g_free(buf);
4196 break;
4197
4198 case OPID_TILE_ROADS:
4199 gtk_tree_model_get(model, &iter, 1, &id, -1);
4200 if (!(0 <= id && id < road_count())) {
4201 return;
4202 }
4203 if (present) {
4204 BV_SET(pv->data.v_bv_roads, id);
4205 } else {
4206 BV_CLR(pv->data.v_bv_roads, id);
4207 }
4208 gtk_list_store_set(ev->store, &iter, 0, present, -1);
4209 buf = propval_as_string(pv);
4210 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4211 g_free(buf);
4212 break;
4213
4214 case OPID_TILE_BASES:
4215 gtk_tree_model_get(model, &iter, 1, &id, -1);
4216 if (!(0 <= id && id < base_count())) {
4217 return;
4218 }
4219 if (present) {
4220 BV_SET(pv->data.v_bv_bases, id);
4221 } else {
4222 BV_CLR(pv->data.v_bv_bases, id);
4223 }
4224 gtk_list_store_set(ev->store, &iter, 0, present, -1);
4225 buf = propval_as_string(pv);
4226 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4227 g_free(buf);
4228 break;
4229
4231 gtk_tree_model_get(model, &iter, 1, &id, -1);
4232 if (-1 > id && id >= nation_count()) {
4233 return;
4234 }
4235
4236 if (-1 == id) {
4237 gtk_list_store_set(ev->store, &iter, 0, present, -1);
4238 gtk_tree_model_get_iter_first(model, &iter);
4239 if (present) {
4240 while (gtk_tree_model_iter_next(model, &iter)) {
4241 gtk_list_store_set(ev->store, &iter, 0, FALSE, -1);
4242 }
4243 nation_hash_clear(pv->data.v_nation_hash);
4244 } else {
4245 const struct nation_type *pnation;
4246 int id2;
4247
4248 gtk_tree_model_iter_next(model, &iter);
4249 gtk_tree_model_get(model, &iter, 0, &id2, -1);
4250 gtk_list_store_set(ev->store, &iter, 0, TRUE, -1);
4251 pnation = nation_by_number(id2);
4252 nation_hash_insert(pv->data.v_nation_hash, pnation, NULL);
4253 }
4254 } else {
4255 const struct nation_type *pnation;
4256 bool all;
4257
4258 gtk_list_store_set(ev->store, &iter, 0, present, -1);
4259 pnation = nation_by_number(id);
4260 if (present) {
4261 nation_hash_insert(pv->data.v_nation_hash, pnation, NULL);
4262 } else {
4263 nation_hash_remove(pv->data.v_nation_hash, pnation);
4264 }
4265 gtk_tree_model_get_iter_first(model, &iter);
4266 all = (0 == nation_hash_size(pv->data.v_nation_hash));
4267 gtk_list_store_set(ev->store, &iter, 0, all, -1);
4268 }
4269 buf = propval_as_string(pv);
4270 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4271 g_free(buf);
4272 break;
4273
4275 gtk_tree_model_get(model, &iter, 1, &id, -1);
4276 if (!(0 <= id && id < B_LAST)) {
4277 return;
4278 }
4279 turn_built = present ? game.info.turn : I_NEVER;
4280 pv->data.v_built[id].turn = turn_built;
4281 buf = built_status_to_string(&pv->data.v_built[id]);
4282 gtk_list_store_set(ev->store, &iter, 0, present, 3, buf, -1);
4283 g_free(buf);
4284 buf = propval_as_string(pv);
4285 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4286 g_free(buf);
4287 break;
4288
4289 case OPID_PLAYER_NATION:
4290 gtk_tree_model_get(model, &iter, 1, &id, -1);
4291 if (!(0 <= id && id < nation_count()) || !present) {
4292 return;
4293 }
4294 old_id = nation_index(pv->data.v_nation);
4295 pv->data.v_nation = nation_by_number(id);
4296 gtk_list_store_set(ev->store, &iter, 0, TRUE, -1);
4297 gtk_tree_model_iter_nth_child(model, &iter, NULL, old_id);
4298 gtk_list_store_set(ev->store, &iter, 0, FALSE, -1);
4299 gtk_label_set_text(GTK_LABEL(ev->panel_label),
4301 pixbuf = get_flag(pv->data.v_nation);
4302 gtk_image_set_from_pixbuf(GTK_IMAGE(ev->panel_image), pixbuf);
4303 if (pixbuf) {
4304 g_object_unref(pixbuf);
4305 }
4306 break;
4307
4308 case OPID_PLAYER_GOV:
4309 gtk_tree_model_get(model, &iter, 1, &id, -1);
4310 if (!(0 <= id && id < government_count()) || !present) {
4311 return;
4312 }
4313 if (pv->data.v_gov != NULL) {
4314 old_id = government_index(pv->data.v_gov);
4316 gtk_list_store_set(ev->store, &iter, 0, TRUE, -1);
4317 gtk_tree_model_iter_nth_child(model, &iter, NULL, old_id);
4318 gtk_list_store_set(ev->store, &iter, 0, FALSE, -1);
4319 } else {
4321 gtk_list_store_set(ev->store, &iter, 0, TRUE, -1);
4322 }
4323
4324 gtk_label_set_text(GTK_LABEL(ev->panel_label),
4327 gtk_image_set_from_pixbuf(GTK_IMAGE(ev->panel_image), pixbuf);
4328 if (pixbuf) {
4329 g_object_unref(pixbuf);
4330 }
4331 break;
4332
4334 gtk_tree_model_get(model, &iter, 1, &id, -1);
4335 if (!(A_FIRST <= id && id < advance_count())) {
4336 return;
4337 }
4338 if (present) {
4339 BV_SET(pv->data.v_bv_inventions, id);
4340 } else {
4341 BV_CLR(pv->data.v_bv_inventions, id);
4342 }
4343 gtk_list_store_set(ev->store, &iter, 0, present, -1);
4344 buf = propval_as_string(pv);
4345 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4346 g_free(buf);
4347 break;
4348
4349 default:
4350 log_error("Unhandled widget toggled signal in "
4351 "extviewer_view_cell_toggled() for objprop id=%d "
4352 "name \"%s\".", propid, objprop_get_name(op));
4353 return;
4354 break;
4355 }
4356
4357 property_page_change_value(pp, op, pv);
4358}
4359
4360/************************************************************************/
4363static void extviewer_textbuf_changed(GtkTextBuffer *textbuf,
4364 gpointer userdata)
4365{
4366 struct extviewer *ev;
4367 struct objprop *op;
4368 struct property_page *pp;
4369 enum object_property_ids propid;
4370 struct propval value = {{0,}, VALTYPE_STRING, FALSE}, *pv;
4371 GtkTextIter start, end;
4372 char *text;
4373 gchar *buf;
4374
4375 ev = userdata;
4376 if (!ev) {
4377 return;
4378 }
4379
4380 op = extviewer_get_objprop(ev);
4381 propid = objprop_get_id(op);
4383
4384 gtk_text_buffer_get_start_iter(textbuf, &start);
4385 gtk_text_buffer_get_end_iter(textbuf, &end);
4386 text = gtk_text_buffer_get_text(textbuf, &start, &end, FALSE);
4387 value.data.v_const_string = text;
4388 pv = &value;
4389
4390 switch (propid) {
4393 buf = propval_as_string(pv);
4394 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4395 g_free(buf);
4396 break;
4397 default:
4398 log_error("Unhandled widget modified signal in "
4399 "extviewer_textbuf_changed() for objprop id=%d "
4400 "name \"%s\".", propid, objprop_get_name(op));
4401 return;
4402 break;
4403 }
4404
4405 property_page_change_value(pp, op, pv);
4406 g_free(text);
4407}
4408
4409/************************************************************************/
4413{
4414#define ADDPROP(ARG_id, ARG_name, ARG_tooltip, ARG_flags, ARG_valtype) do { \
4415 struct objprop *MY_op = objprop_new(ARG_id, ARG_name, ARG_tooltip, \
4416 ARG_flags, ARG_valtype, pp); \
4417 objprop_hash_insert(pp->objprop_table, MY_op->id, MY_op); \
4418} while (FALSE)
4419
4420 switch (property_page_get_objtype(pp)) {
4421 case OBJTYPE_TILE:
4422 ADDPROP(OPID_TILE_IMAGE, _("Image"), NULL,
4424 ADDPROP(OPID_TILE_TERRAIN, _("Terrain"), NULL,
4426 ADDPROP(OPID_TILE_RESOURCE, _("Resource"), NULL,
4428 ADDPROP(OPID_TILE_INDEX, _("Index"), NULL,
4430 ADDPROP(OPID_TILE_X, Q_("?coordinate:X"), NULL,
4432 ADDPROP(OPID_TILE_Y, Q_("?coordinate:Y"), NULL,
4434 /* TRANS: The coordinate X in native coordinates.
4435 * The freeciv coordinate system is described in doc/HACKING. */
4436 ADDPROP(OPID_TILE_NAT_X, _("NAT X"), NULL,
4438 /* TRANS: The coordinate Y in native coordinates.
4439 * The freeciv coordinate system is described in doc/HACKING. */
4440 ADDPROP(OPID_TILE_NAT_Y, _("NAT Y"), NULL,
4442 ADDPROP(OPID_TILE_CONTINENT, _("Continent"), NULL,
4444 ADDPROP(OPID_TILE_XY, Q_("?coordinates:X,Y"), NULL,
4446 ADDPROP(OPID_TILE_SPECIALS, _("Specials"), NULL,
4449 ADDPROP(OPID_TILE_ROADS, _("Roads"), NULL,
4452 ADDPROP(OPID_TILE_BASES, _("Bases"), NULL,
4455#ifdef FREECIV_DEBUG
4456 ADDPROP(OPID_TILE_ADDRESS, _("Address"), NULL,
4458#endif /* FREECIV_DEBUG */
4459#if 0
4460 /* Disabled entirely for now as server is not sending other
4461 * players' vision information anyway. */
4462 ADDPROP(OPID_TILE_VISION, _("Vision"), NULL,
4464#endif
4465 /* TRANS: Tile property "Label" label in editor */
4466 ADDPROP(OPID_TILE_LABEL, Q_("?property:Label"), NULL,
4468 return;
4469
4470 case OBJTYPE_STARTPOS:
4471 ADDPROP(OPID_STARTPOS_IMAGE, _("Image"), NULL,
4473 ADDPROP(OPID_STARTPOS_XY, Q_("?coordinates:X,Y"), NULL,
4475 ADDPROP(OPID_STARTPOS_EXCLUDE, _("Exclude Nations"), NULL,
4477 ADDPROP(OPID_STARTPOS_NATIONS, _("Nations"), NULL,
4480 return;
4481
4482 case OBJTYPE_UNIT:
4483 ADDPROP(OPID_UNIT_IMAGE, _("Image"), NULL,
4485#ifdef FREECIV_DEBUG
4486 ADDPROP(OPID_UNIT_ADDRESS, _("Address"), NULL,
4488#endif /* FREECIV_DEBUG */
4489 ADDPROP(OPID_UNIT_TYPE, _("Type"), NULL,
4491 ADDPROP(OPID_UNIT_ID, _("ID"), NULL,
4493 ADDPROP(OPID_UNIT_XY, Q_("?coordinates:X,Y"), NULL,
4495 ADDPROP(OPID_UNIT_MOVES_LEFT, _("Moves Left"), NULL,
4497 ADDPROP(OPID_UNIT_FUEL, _("Fuel"), NULL,
4499 ADDPROP(OPID_UNIT_MOVED, _("Moved"), NULL,
4501 ADDPROP(OPID_UNIT_DONE_MOVING, _("Done Moving"), NULL,
4503 /* TRANS: HP = Hit Points of a unit. */
4504 ADDPROP(OPID_UNIT_HP, _("HP"), NULL,
4506 ADDPROP(OPID_UNIT_VETERAN, _("Veteran"), NULL,
4508 ADDPROP(OPID_UNIT_STAY, _("Stay put"), NULL,
4510 return;
4511
4512 case OBJTYPE_CITY:
4513 ADDPROP(OPID_CITY_IMAGE, _("Image"), NULL,
4515 ADDPROP(OPID_CITY_NAME, _("Name"), NULL,
4517#ifdef FREECIV_DEBUG
4518 ADDPROP(OPID_CITY_ADDRESS, _("Address"), NULL,
4520#endif /* FREECIV_DEBUG */
4521 ADDPROP(OPID_CITY_ID, _("ID"), NULL,
4523 ADDPROP(OPID_CITY_XY, Q_("?coordinates:X,Y"), NULL,
4525 ADDPROP(OPID_CITY_SIZE, _("Size"), NULL,
4527 ADDPROP(OPID_CITY_HISTORY, _("History"), NULL,
4529 ADDPROP(OPID_CITY_BUILDINGS, _("Buildings"), NULL,
4532 ADDPROP(OPID_CITY_FOOD_STOCK, _("Food Stock"), NULL,
4534 ADDPROP(OPID_CITY_SHIELD_STOCK, _("Shield Stock"), NULL,
4536 return;
4537
4538 case OBJTYPE_PLAYER:
4539 ADDPROP(OPID_PLAYER_NAME, _("Name"), NULL,
4542#ifdef FREECIV_DEBUG
4543 ADDPROP(OPID_PLAYER_ADDRESS, _("Address"), NULL,
4545#endif /* FREECIV_DEBUG */
4546 ADDPROP(OPID_PLAYER_NATION, _("Nation"), NULL,
4549 ADDPROP(OPID_PLAYER_GOV, _("Government"), NULL,
4551 VALTYPE_GOV);
4552 ADDPROP(OPID_PLAYER_AGE, _("Age"), NULL,
4554 ADDPROP(OPID_PLAYER_INVENTIONS, _("Inventions"), NULL,
4557 ADDPROP(OPID_PLAYER_SCENARIO_RESERVED, _("Reserved"), NULL,
4559 ADDPROP(OPID_PLAYER_SCIENCE, _("Science"), NULL,
4561 ADDPROP(OPID_PLAYER_GOLD, _("Gold"), NULL,
4563 VALTYPE_INT);
4564 return;
4565
4566 case OBJTYPE_GAME:
4567 ADDPROP(OPID_GAME_SCENARIO, _("Scenario"), NULL,
4569 VALTYPE_BOOL);
4571 _("Scenario Name"), NULL,
4575 _("Scenario Authors"), NULL,
4579 _("Scenario Description"), NULL,
4583 _("Save Random Number State"), NULL,
4586 _("Save Players"), NULL,
4589 _("Nation Start Positions"), NULL,
4592 _("Prevent New Cities"), NULL,
4595 _("Saltwater Flooding Lakes"), NULL,
4598 _("Lock to current Ruleset"), NULL,
4600 return;
4601
4602 case NUM_OBJTYPES:
4603 break;
4604 }
4605
4606 log_error("%s(): Unhandled page object type %s (nb %d).", __FUNCTION__,
4609#undef ADDPROP
4610}
4611
4612/************************************************************************/
4615static void property_page_selection_changed(GtkTreeSelection *sel,
4616 gpointer userdata)
4617{
4618 struct property_page *pp;
4619 struct objbind *ob = NULL;
4620
4621 pp = userdata;
4622 if (!pp) {
4623 return;
4624 }
4625
4626 if (gtk_tree_selection_count_selected_rows(sel) < 1) {
4628 }
4629
4632 objprop_refresh_widget(op, ob);
4634}
4635
4636/************************************************************************/
4640static gboolean property_page_selection_func(GtkTreeSelection *sel,
4641 GtkTreeModel *model,
4642 GtkTreePath *sel_path,
4643 gboolean currently_selected,
4644 gpointer data)
4645{
4646 struct property_page *pp;
4647 struct objbind *ob = NULL, *old_ob;
4648 GtkTreeIter iter;
4649
4650 pp = data;
4651 if (!pp || !sel_path) {
4652 return TRUE;
4653 }
4654
4655 if (!gtk_tree_model_get_iter(model, &iter, sel_path)) {
4656 return TRUE;
4657 }
4658
4660 gtk_tree_model_get(model, &iter, 0, &ob, -1);
4661 if (currently_selected) {
4662 if (ob == old_ob) {
4663 GList *rows, *p;
4664 GtkTreePath *path;
4665 struct objbind *new_ob = NULL;
4666
4667 rows = gtk_tree_selection_get_selected_rows(sel, NULL);
4668 for (p = rows; p != NULL; p = p->next) {
4669 path = p->data;
4670 if (gtk_tree_model_get_iter(model, &iter, path)) {
4671 struct objbind *test_ob = NULL;
4672 gtk_tree_model_get(model, &iter, 0, &test_ob, -1);
4673 if (test_ob == ob) {
4674 continue;
4675 }
4676 new_ob = test_ob;
4677 break;
4678 }
4679 }
4680 g_list_foreach(rows, (GFunc) gtk_tree_path_free, NULL);
4681 g_list_free(rows);
4682
4684 }
4685 } else {
4687 }
4688
4689 return TRUE;
4690}
4691
4692/************************************************************************/
4696 gpointer userdata)
4697{
4698 struct property_page *pp;
4699 const gchar *text;
4700 GtkWidget *w;
4701 GtkTreeViewColumn *col;
4702 struct property_filter *pf;
4703 bool matched;
4704
4705 pp = userdata;
4706 text = gtk_entry_buffer_get_text(gtk_entry_get_buffer(GTK_ENTRY(entry)));
4707 pf = property_filter_new(text);
4708
4710 if (!objprop_has_widget(op)
4711 && !objprop_show_in_listview(op)) {
4712 continue;
4713 }
4714 matched = property_filter_match(pf, op);
4715 w = objprop_get_widget(op);
4716 if (objprop_has_widget(op) && w != NULL) {
4717 if (matched) {
4718 gtk_widget_show(w);
4719 } else {
4720 gtk_widget_hide(w);
4721 }
4722 }
4724 if (objprop_show_in_listview(op) && col != NULL) {
4725 gtk_tree_view_column_set_visible(col, matched);
4726 }
4728
4730}
4731
4732/************************************************************************/
4736static struct property_page *
4738 struct property_editor *pe)
4739{
4740 struct property_page *pp;
4741 GtkWidget *vgrid, *vgrid2, *hgrid, *hgrid2, *paned, *frame, *w;
4742 GtkWidget *scrollwin, *view, *label, *entry, *notebook;
4743 GtkWidget *button, *hsep;
4744 GtkTreeSelection *sel;
4745 GtkCellRenderer *cell;
4746 GtkTreeViewColumn *col;
4747 GtkSizeGroup *sizegroup;
4748 int num_columns = 0;
4749 GType *gtype_array;
4750 int col_id = 1;
4751 const char *attr_type_str, *name, *tooltip;
4752 gchar *title;
4753 int grid_row = 0;
4754 int grid2_row = 0;
4755 int grid_col = 0;
4756 int grid2_col = 0;
4757
4758 if (!(objtype < NUM_OBJTYPES)) {
4759 return NULL;
4760 }
4761
4762 pp = fc_calloc(1, sizeof(struct property_page));
4763 pp->objtype = objtype;
4764 pp->pe_parent = pe;
4765
4766 sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
4767
4768 pp->objprop_table = objprop_hash_new();
4770
4771 pp->objbind_table = objbind_hash_new();
4772
4773 pp->tag_table = stored_tag_hash_new();
4774
4776 if (objprop_show_in_listview(op)) {
4777 num_columns++;
4778 }
4780
4781 /* Column zero in the store holds an objbind
4782 * pointer and is never displayed. */
4783 num_columns++;
4784 gtype_array = fc_malloc(num_columns * sizeof(GType));
4785 gtype_array[0] = G_TYPE_POINTER;
4786
4788 if (objprop_show_in_listview(op)) {
4789 gtype_array[col_id] = objprop_get_gtype(op);
4790 objprop_set_column_id(op, col_id);
4791 col_id++;
4792 }
4794
4795 pp->object_store = gtk_list_store_newv(num_columns, gtype_array);
4796 free(gtype_array);
4797
4798 paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
4799 gtk_paned_set_position(GTK_PANED(paned), 256);
4800 pp->widget = paned;
4801
4802 /* Left side object list view. */
4803
4804 vgrid = gtk_grid_new();
4805 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
4806 GTK_ORIENTATION_VERTICAL);
4807 gtk_grid_set_row_spacing(GTK_GRID(vgrid), 4);
4808 gtk_widget_set_margin_start(vgrid, 4);
4809 gtk_widget_set_margin_end(vgrid, 4);
4810 gtk_widget_set_margin_top(vgrid, 4);
4811 gtk_widget_set_margin_bottom(vgrid, 4);
4812 gtk_paned_set_start_child(GTK_PANED(paned), vgrid);
4813
4814 scrollwin = gtk_scrolled_window_new();
4815 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(scrollwin),
4816 TRUE);
4817 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
4818 GTK_POLICY_AUTOMATIC,
4819 GTK_POLICY_AUTOMATIC);
4820 gtk_grid_attach(GTK_GRID(vgrid), scrollwin, 0, grid_row++, 1, 1);
4821
4822 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pp->object_store));
4823 gtk_widget_set_hexpand(view, TRUE);
4824 gtk_widget_set_vexpand(view, TRUE);
4825
4827 if (!objprop_show_in_listview(op)) {
4828 continue;
4829 }
4830
4831 attr_type_str = objprop_get_attribute_type_string(op);
4832 if (!attr_type_str) {
4833 continue;
4834 }
4835 col_id = objprop_get_column_id(op);
4836 if (col_id < 0) {
4837 continue;
4838 }
4839 name = objprop_get_name(op);
4840 if (!name) {
4841 continue;
4842 }
4844 if (!cell) {
4845 continue;
4846 }
4847
4848 col = gtk_tree_view_column_new_with_attributes(name, cell,
4849 attr_type_str, col_id,
4850 NULL);
4851
4852 gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
4853 gtk_tree_view_column_set_resizable(col, TRUE);
4854 gtk_tree_view_column_set_reorderable(col, TRUE);
4855 if (objprop_is_sortable(op)) {
4856 gtk_tree_view_column_set_clickable(col, TRUE);
4857 gtk_tree_view_column_set_sort_column_id(col, col_id);
4858 } else {
4859 gtk_tree_view_column_set_clickable(col, FALSE);
4860 }
4861 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
4863
4865
4866 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
4867 gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
4868 g_signal_connect(sel, "changed",
4869 G_CALLBACK(property_page_selection_changed), pp);
4870 gtk_tree_selection_set_select_function(sel,
4872
4873 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrollwin), view);
4874 pp->object_view = view;
4875
4877 hgrid = gtk_grid_new();
4878 gtk_grid_set_column_spacing(GTK_GRID(hgrid), 4);
4879 gtk_grid_attach(GTK_GRID(vgrid), hgrid, 0, grid_row++, 1, 1);
4880
4881 button = gtk_button_new();
4882 gtk_button_set_icon_name(GTK_BUTTON(button), "list-add");
4883 gtk_button_set_label(GTK_BUTTON(button), _("Create"));
4884 gtk_size_group_add_widget(sizegroup, button);
4885 gtk_widget_set_tooltip_text(button,
4886 _("Pressing this button will create a new object of the "
4887 "same type as the current property page and add it to "
4888 "the page. The specific type and count of the objects "
4889 "is taken from the editor tool state. So for example, "
4890 "the \"tool value\" of the unit tool and its \"count\" "
4891 "parameter affect unit creation."));
4892 g_signal_connect(button, "clicked",
4893 G_CALLBACK(property_page_create_button_clicked), pp);
4894 gtk_grid_attach(GTK_GRID(hgrid), button, grid_col++, 0, 1, 1);
4895
4896 button = gtk_button_new();
4897 gtk_button_set_icon_name(GTK_BUTTON(button), "list-remove");
4898 gtk_button_set_label(GTK_BUTTON(button), _("Destroy"));
4899 gtk_size_group_add_widget(sizegroup, button);
4900 gtk_widget_set_tooltip_text(button,
4901 _("Pressing this button will send a request to the server "
4902 "to destroy (i.e. erase) the objects selected in the object "
4903 "list."));
4904 g_signal_connect(button, "clicked",
4905 G_CALLBACK(property_page_destroy_button_clicked), pp);
4906 gtk_grid_attach(GTK_GRID(hgrid), button, grid_col++, 0, 1, 1);
4907 }
4908
4909 /* Right side properties panel. */
4910
4911 hgrid = gtk_grid_new();
4912 grid_col = 0;
4913 gtk_grid_set_column_spacing(GTK_GRID(hgrid), 4);
4914 gtk_paned_set_end_child(GTK_PANED(paned), hgrid);
4915
4916 vgrid = gtk_grid_new();
4917 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
4918 GTK_ORIENTATION_VERTICAL);
4919 gtk_grid_set_row_spacing(GTK_GRID(vgrid), 4);
4920 gtk_widget_set_margin_start(vgrid, 4);
4921 gtk_widget_set_margin_end(vgrid, 4);
4922 gtk_widget_set_margin_top(vgrid, 4);
4923 gtk_widget_set_margin_bottom(vgrid, 4);
4924 gtk_grid_attach(GTK_GRID(hgrid), vgrid, grid_col++, 0, 1, 1);
4925
4926 /* Extended property viewer to the right of the properties panel.
4927 * This needs to be created before property widgets, since some
4928 * might try to append themselves to this notebook. */
4929
4930 vgrid2 = gtk_grid_new();
4931 gtk_widget_set_hexpand(vgrid2, TRUE);
4932 gtk_widget_set_vexpand(vgrid, TRUE);
4933 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid2),
4934 GTK_ORIENTATION_VERTICAL);
4935 gtk_grid_set_row_spacing(GTK_GRID(vgrid2), 4);
4936 gtk_grid_attach(GTK_GRID(hgrid), vgrid2, grid_col++, 0, 1, 1);
4937
4938 notebook = gtk_notebook_new();
4939 gtk_widget_set_vexpand(notebook, TRUE);
4940 gtk_widget_set_size_request(notebook, 256, -1);
4941 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
4942 gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
4943 gtk_grid_attach(GTK_GRID(vgrid2), notebook, 0, grid2_row++, 1, 1);
4944 pp->extviewer_notebook = notebook;
4945
4946 hsep = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
4947 gtk_grid_attach(GTK_GRID(vgrid2), hsep, 0, grid2_row++, 1, 1);
4948
4949 hgrid2 = gtk_grid_new();
4950 gtk_widget_set_margin_start(hgrid2, 4);
4951 gtk_widget_set_margin_end(hgrid2, 4);
4952 gtk_widget_set_margin_top(hgrid2, 4);
4953 gtk_widget_set_margin_bottom(hgrid2, 4);
4954 gtk_grid_attach(GTK_GRID(vgrid2), hgrid2, 0, grid2_row++, 1, 1);
4955
4956 button = gtk_button_new_with_mnemonic(_("_Close"));
4957 gtk_size_group_add_widget(sizegroup, button);
4958 g_signal_connect_swapped(button, "clicked",
4959 G_CALLBACK(gtk_widget_hide), pe->widget);
4960 gtk_grid_attach(GTK_GRID(hgrid2), button, grid2_col++, 0, 1, 1);
4961
4962 /* Now create the properties panel. */
4963
4964 /* TRANS: %s is a type of object that can be edited, such as "Tile",
4965 * "Unit", "Start Position", etc. */
4966 title = g_strdup_printf(_("%s Properties"),
4968 frame = gtk_frame_new(title);
4969 g_free(title);
4970 gtk_widget_set_size_request(frame, 256, -1);
4971 gtk_grid_attach(GTK_GRID(vgrid), frame, 0, grid_row++, 1, 1);
4972
4973 scrollwin = gtk_scrolled_window_new();
4974 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(scrollwin),
4975 FALSE);
4976 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
4977 GTK_POLICY_AUTOMATIC,
4978 GTK_POLICY_AUTOMATIC);
4979 gtk_frame_set_child(GTK_FRAME(frame), scrollwin);
4980
4981 vgrid2 = gtk_grid_new();
4982 grid2_row = 0;
4983 gtk_widget_set_vexpand(vgrid2, TRUE);
4984 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid2),
4985 GTK_ORIENTATION_VERTICAL);
4986 gtk_grid_set_row_spacing(GTK_GRID(vgrid2), 4);
4987 gtk_widget_set_margin_start(vgrid2, 4);
4988 gtk_widget_set_margin_end(vgrid2, 4);
4989 gtk_widget_set_margin_top(vgrid2, 4);
4990 gtk_widget_set_margin_bottom(vgrid2, 4);
4991 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrollwin), vgrid2);
4992
4994 if (!objprop_has_widget(op)) {
4995 continue;
4996 }
4997 w = objprop_get_widget(op);
4998 if (!w) {
4999 continue;
5000 }
5001 gtk_grid_attach(GTK_GRID(vgrid2), w, 0, grid2_row++, 1, 1);
5003 if (NULL != tooltip) {
5004 gtk_widget_set_tooltip_text(w, tooltip);
5005 }
5007
5008 hgrid2 = gtk_grid_new();
5009 grid2_col = 0;
5010 gtk_widget_set_margin_top(hgrid2, 4);
5011 gtk_widget_set_margin_bottom(hgrid2, 4);
5012 gtk_grid_set_column_spacing(GTK_GRID(hgrid2), 4);
5013 gtk_grid_attach(GTK_GRID(vgrid), hgrid2, 0, grid_row++, 1, 1);
5014
5015 label = gtk_label_new(_("Filter:"));
5016 gtk_grid_attach(GTK_GRID(hgrid2), label, grid2_col++, 0, 1, 1);
5017
5018 entry = gtk_entry_new();
5019 gtk_widget_set_tooltip_text(entry,
5020 _("Enter a filter string to limit which properties are shown. "
5021 "The filter is one or more text patterns separated by | "
5022 "(\"or\") or & (\"and\"). The symbol & has higher precedence "
5023 "than |. A pattern may also be negated by prefixing it with !."));
5024 g_signal_connect(entry, "changed",
5026 gtk_grid_attach(GTK_GRID(hgrid2), entry, grid2_col++, 0, 1, 1);
5027
5028 hgrid2 = gtk_grid_new();
5029 grid2_col = 0;
5030 gtk_grid_set_column_spacing(GTK_GRID(hgrid2), 4);
5031 gtk_grid_attach(GTK_GRID(vgrid), hgrid2, 0, grid_row++, 1, 1);
5032
5033 button = gtk_button_new_with_mnemonic(_("_Refresh"));
5034 gtk_size_group_add_widget(sizegroup, button);
5035 gtk_widget_set_tooltip_text(button,
5036 _("Pressing this button will reset all modified properties of "
5037 "the selected objects to their current values (the values "
5038 "they have on the server)."));
5039 g_signal_connect(button, "clicked",
5040 G_CALLBACK(property_page_refresh_button_clicked), pp);
5041 gtk_grid_attach(GTK_GRID(hgrid2), button, grid2_col++, 0, 1, 1);
5042
5043 button = gtk_button_new_with_mnemonic(_("_Apply"));
5044 gtk_size_group_add_widget(sizegroup, button);
5045 gtk_widget_set_tooltip_text(button,
5046 _("Pressing this button will send all modified properties of "
5047 "the objects selected in the object list to the server. "
5048 "Modified properties' names are shown in red in the properties "
5049 "panel."));
5050 g_signal_connect(button, "clicked",
5051 G_CALLBACK(property_page_apply_button_clicked), pp);
5052 gtk_grid_attach(GTK_GRID(hgrid2), button, grid2_col++, 0, 1, 1);
5053
5054 return pp;
5055}
5056
5057/************************************************************************/
5060static const char *property_page_get_name(const struct property_page *pp)
5061{
5062 if (!pp) {
5063 return "";
5064 }
5066}
5067
5068/************************************************************************/
5071static enum editor_object_type
5073{
5074 if (!pp) {
5075 return -1;
5076 }
5077 return pp->objtype;
5078}
5079
5080/************************************************************************/
5088static GdkPixbuf *create_tile_pixbuf(const struct tile *ptile)
5089{
5090 return create_pixbuf_from_layers(ptile, NULL, NULL, LAYER_CATEGORY_TILE);
5091}
5092
5093/************************************************************************/
5100static GdkPixbuf *create_unit_pixbuf(const struct unit *punit)
5101{
5103}
5104
5105/************************************************************************/
5112static GdkPixbuf *create_city_pixbuf(const struct city *pcity)
5113{
5114 return create_pixbuf_from_layers(city_tile(pcity), NULL, pcity,
5116}
5117
5118/************************************************************************/
5126static GdkPixbuf *create_pixbuf_from_layers(const struct tile *ptile,
5127 const struct unit *punit,
5128 const struct city *pcity,
5129 enum layer_category category)
5130{
5132 int h, fh, fw, canvas_x, canvas_y;
5133 GdkPixbuf *pixbuf;
5134 cairo_t *cr;
5135
5139
5140 canvas.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, fw, fh);
5141
5142 cr = cairo_create(canvas.surface);
5143 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
5144 cairo_paint(cr);
5145 cairo_destroy(cr);
5146
5147 canvas_x = 0;
5148 canvas_y = 0;
5149
5150 canvas_y += (fh - h);
5151
5152 mapview_layer_iterate(layer) {
5153 if (tileset_layer_in_category(layer, category)) {
5154 put_one_element(&canvas, 1.0, layer,
5155 ptile, NULL, NULL, punit, pcity,
5156 canvas_x, canvas_y, NULL, NULL);
5157 }
5159 pixbuf = surface_get_pixbuf(canvas.surface, fw, fh);
5160 cairo_surface_destroy(canvas.surface);
5161
5162 return pixbuf;
5163}
5164
5165/************************************************************************/
5169{
5170 if (!pp) {
5171 return;
5172 }
5173
5174 gtk_list_store_clear(pp->object_store);
5175 objbind_hash_clear(pp->objbind_table);
5177}
5178
5179/************************************************************************/
5184 gpointer object_data)
5185{
5186 struct objbind *ob;
5188 int id;
5189
5190 if (!pp) {
5191 return;
5192 }
5193
5195 id = objtype_get_id_from_object(objtype, object_data);
5196 if (id < 0) {
5197 return;
5198 }
5199
5200 if (objbind_hash_lookup(pp->objbind_table, id, NULL)) {
5201 /* Object already exists. */
5202 return;
5203 }
5204
5205 ob = objbind_new(objtype, object_data);
5206 if (!ob) {
5207 return;
5208 }
5209
5211
5212 objbind_hash_insert(pp->objbind_table, ob->object_id, ob);
5213}
5214
5215/************************************************************************/
5220 const struct tile *ptile)
5221{
5222
5223 if (!pp || !ptile) {
5224 return;
5225 }
5226
5227 switch (property_page_get_objtype(pp)) {
5228 case OBJTYPE_TILE:
5229 property_page_add_objbind(pp, (gpointer) ptile);
5230 return;
5231
5232 case OBJTYPE_STARTPOS:
5233 {
5234 struct startpos *psp = map_startpos_get(ptile);
5235
5236 if (NULL != psp) {
5238 }
5239 }
5240 return;
5241
5242 case OBJTYPE_UNIT:
5243 unit_list_iterate(ptile->units, punit) {
5246 return;
5247
5248 case OBJTYPE_CITY:
5249 if (tile_city(ptile)) {
5251 }
5252 return;
5253
5254 case OBJTYPE_PLAYER:
5255 case OBJTYPE_GAME:
5256 return;
5257
5258 case NUM_OBJTYPES:
5259 break;
5260 }
5261
5262 log_error("%s(): Unhandled page object type %s (nb %d).", __FUNCTION__,
5265}
5266
5267/************************************************************************/
5274 struct objprop *op,
5275 struct objbind *ob,
5276 GtkTreeIter *iter)
5277{
5278 int col_id;
5279 struct propval *pv;
5280 enum value_types valtype;
5281 char buf[128], *p;
5282 GdkPixbuf *pixbuf = NULL;
5283 GtkListStore *store;
5284 gchar *buf2;
5285
5286 if (!pp || !pp->object_store || !op || !ob) {
5287 return FALSE;
5288 }
5289
5290 if (!objprop_show_in_listview(op)) {
5291 return FALSE;
5292 }
5293
5294 col_id = objprop_get_column_id(op);
5295 if (col_id < 0) {
5296 return FALSE;
5297 }
5298
5299 pv = objbind_get_value_from_object(ob, op);
5300 if (!pv) {
5301 return FALSE;
5302 }
5303
5305 store = pp->object_store;
5306
5307 switch (valtype) {
5308 case VALTYPE_NONE:
5309 break;
5310 case VALTYPE_INT:
5311 gtk_list_store_set(store, iter, col_id, pv->data.v_int, -1);
5312 break;
5313 case VALTYPE_BOOL:
5314 /* Set as translated string, not as untranslated G_TYPE_BOOLEAN */
5315 gtk_list_store_set(store, iter, col_id, propval_as_string(pv), -1);
5316 break;
5317 case VALTYPE_STRING:
5318 if (fc_strlcpy(buf, pv->data.v_string, 28) >= 28) {
5319 sz_strlcat(buf, "...");
5320 }
5321 for (p = buf; *p; p++) {
5322 if (*p == '\n' || *p == '\t' || *p == '\r') {
5323 *p = ' ';
5324 }
5325 }
5326 gtk_list_store_set(store, iter, col_id, buf, -1);
5327 break;
5328 case VALTYPE_PIXBUF:
5329 gtk_list_store_set(store, iter, col_id, pv->data.v_pixbuf, -1);
5330 break;
5333 case VALTYPE_BV_SPECIAL:
5334 case VALTYPE_BV_ROADS:
5335 case VALTYPE_BV_BASES:
5337 buf2 = propval_as_string(pv);
5338 gtk_list_store_set(store, iter, col_id, buf2, -1);
5339 g_free(buf2);
5340 break;
5341 case VALTYPE_NATION:
5342 pixbuf = get_flag(pv->data.v_nation);
5343 gtk_list_store_set(store, iter, col_id, pixbuf, -1);
5344 if (pixbuf) {
5345 g_object_unref(pixbuf);
5346 }
5347 break;
5348 case VALTYPE_GOV:
5349 if (pv->data.v_gov != NULL) {
5351 } else {
5354 }
5355 gtk_list_store_set(store, iter, col_id, pixbuf, -1);
5356 if (pixbuf) {
5357 g_object_unref(pixbuf);
5358 }
5359 break;
5361 break;
5362 }
5363
5364 propval_free(pv);
5365
5366 return TRUE;
5367}
5368
5369/************************************************************************/
5374{
5375 struct objbind *focused;
5376
5377 if (!pp || !pp->objbind_table) {
5378 return;
5379 }
5380
5381 if (pp->object_store) {
5382 GtkTreeIter iter;
5383 GtkTreeRowReference *rr;
5384 GtkTreeModel *model;
5385 GtkTreePath *path;
5386
5387 model = GTK_TREE_MODEL(pp->object_store);
5388
5390 if (objbind_get_rowref(ob)) {
5391 continue;
5392 }
5393 gtk_list_store_append(pp->object_store, &iter);
5394 gtk_list_store_set(pp->object_store, &iter, 0, ob, -1);
5395 path = gtk_tree_model_get_path(model, &iter);
5396 rr = gtk_tree_row_reference_new(model, path);
5397 gtk_tree_path_free(path);
5398 objbind_set_rowref(ob, rr);
5399
5401 property_page_set_store_value(pp, op, ob, &iter);
5404
5405 if (gtk_tree_model_get_iter_first(model, &iter)) {
5406 GtkTreeSelection *sel;
5407 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pp->object_view));
5408 gtk_tree_selection_select_iter(sel, &iter);
5409 }
5410 }
5411
5414 objprop_refresh_widget(op, focused);
5416}
5417
5418/************************************************************************/
5423{
5424 if (!pp) {
5425 return NULL;
5426 }
5427 return pp->focused_objbind;
5428}
5429
5430/************************************************************************/
5435 struct objbind *ob)
5436{
5437 if (!pp) {
5438 return;
5439 }
5440 pp->focused_objbind = ob;
5441}
5442
5443/************************************************************************/
5448 int object_id)
5449{
5450 struct objbind *ob;
5451
5452 if (!pp || !pp->objbind_table) {
5453 return NULL;
5454 }
5455
5456 objbind_hash_lookup(pp->objbind_table, object_id, &ob);
5457 return ob;
5458}
5459
5460/************************************************************************/
5465 const struct tile_list *tiles)
5466{
5467 if (!pp || !tiles) {
5468 return;
5469 }
5470
5471 tile_list_iterate(tiles, ptile) {
5474
5476}
5477
5478/************************************************************************/
5482{
5483 if (!pp || !pp->objbind_table) {
5484 return 0;
5485 }
5486 return objbind_hash_size(pp->objbind_table);
5487}
5488
5489/************************************************************************/
5494 struct objprop *op,
5495 struct propval *pv)
5496{
5497 GtkTreeSelection *sel;
5498 GtkTreeModel *model;
5499 GList *rows, *p;
5500 GtkTreePath *path;
5501 GtkTreeIter iter;
5502 struct objbind *ob;
5503 bool changed = FALSE;
5504
5505 if (!pp || !op || !pp->object_view) {
5506 return;
5507 }
5508
5509 if (objprop_is_readonly(op)) {
5510 return;
5511 }
5512
5513 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pp->object_view));
5514 rows = gtk_tree_selection_get_selected_rows(sel, &model);
5515
5516 for (p = rows; p != NULL; p = p->next) {
5517 path = p->data;
5518 if (gtk_tree_model_get_iter(model, &iter, path)) {
5519 gtk_tree_model_get(model, &iter, 0, &ob, -1);
5520 changed |= objbind_set_modified_value(ob, op, pv);
5521 }
5522 gtk_tree_path_free(path);
5523 }
5524 g_list_free(rows);
5525
5526 if (changed) {
5528 objprop_refresh_widget(op, ob);
5529 }
5530}
5531
5532/************************************************************************/
5536{
5537 GtkTreeSelection *sel;
5538 GtkTreeModel *model;
5539 GList *rows, *p;
5540 GtkTreePath *path;
5541 GtkTreeIter iter;
5542 struct objbind *ob;
5543 union packetdata packet;
5544 struct connection *my_conn = &client.conn;
5545
5546 if (!pp || !pp->object_view) {
5547 return;
5548 }
5549
5550 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pp->object_view));
5551 if (gtk_tree_selection_count_selected_rows(sel) < 1) {
5552 return;
5553 }
5554
5555 packet = property_page_new_packet(pp);
5556 if (!packet.pointers.v_pointer1) {
5557 return;
5558 }
5559
5560 rows = gtk_tree_selection_get_selected_rows(sel, &model);
5561 connection_do_buffer(my_conn);
5562 for (p = rows; p != NULL; p = p->next) {
5563 path = p->data;
5564 if (gtk_tree_model_get_iter(model, &iter, path)) {
5565 gtk_tree_model_get(model, &iter, 0, &ob, -1);
5567 objbind_pack_current_values(ob, packet);
5569 if (objprop_is_readonly(op)) {
5570 continue;
5571 }
5572 objbind_pack_modified_value(ob, op, packet);
5574 property_page_send_packet(pp, packet);
5575 }
5576 }
5577 gtk_tree_path_free(path);
5578 }
5579 connection_do_unbuffer(my_conn);
5580 g_list_free(rows);
5581
5582 property_page_free_packet(pp, packet);
5583}
5584
5585/************************************************************************/
5590{
5591 union packetdata packet;
5592
5593 packet.pointers.v_pointer2 = NULL;
5594
5595 if (!pp) {
5596 packet.pointers.v_pointer1 = NULL;
5597 return packet;
5598 }
5599
5600 switch (property_page_get_objtype(pp)) {
5601 case OBJTYPE_TILE:
5602 packet.tile = fc_calloc(1, sizeof(*packet.tile));
5603 break;
5604 case OBJTYPE_STARTPOS:
5605 packet.startpos = fc_calloc(1, sizeof(*packet.startpos));
5606 break;
5607 case OBJTYPE_UNIT:
5608 packet.unit = fc_calloc(1, sizeof(*packet.unit));
5609 break;
5610 case OBJTYPE_CITY:
5611 packet.city = fc_calloc(1, sizeof(*packet.city));
5612 break;
5613 case OBJTYPE_PLAYER:
5614 packet.player = fc_calloc(1, sizeof(*packet.player));
5615 break;
5616 case OBJTYPE_GAME:
5617 packet.game.game = fc_calloc(1, sizeof(*packet.game.game));
5618 packet.game.desc = fc_calloc(1, sizeof(*packet.game.desc));
5619 break;
5620 case NUM_OBJTYPES:
5621 break;
5622 }
5623
5624 return packet;
5625}
5626
5627/************************************************************************/
5631 union packetdata packet)
5632{
5633 struct connection *my_conn = &client.conn;
5634
5635 if (!pp || !packet.pointers.v_pointer1) {
5636 return;
5637 }
5638
5639 switch (property_page_get_objtype(pp)) {
5640 case OBJTYPE_TILE:
5641 send_packet_edit_tile(my_conn, packet.tile);
5642 return;
5643 case OBJTYPE_STARTPOS:
5645 return;
5646 case OBJTYPE_UNIT:
5647 send_packet_edit_unit(my_conn, packet.unit);
5648 return;
5649 case OBJTYPE_CITY:
5650 send_packet_edit_city(my_conn, packet.city);
5651 return;
5652 case OBJTYPE_PLAYER:
5653 send_packet_edit_player(my_conn, packet.player);
5654 return;
5655 case OBJTYPE_GAME:
5656 send_packet_edit_game(my_conn, packet.game.game);
5657 send_packet_edit_scenario_desc(my_conn, packet.game.desc);
5658 return;
5659 case NUM_OBJTYPES:
5660 break;
5661 }
5662
5663 log_error("%s(): Unhandled object type %s (nb %d).",
5666}
5667
5668/************************************************************************/
5672 union packetdata packet)
5673{
5674 if (!packet.pointers.v_pointer1) {
5675 return;
5676 }
5677
5678 free(packet.pointers.v_pointer1);
5679 packet.pointers.v_pointer1 = NULL;
5680
5681 if (packet.pointers.v_pointer2 != NULL) {
5682 free(packet.pointers.v_pointer2);
5683 packet.pointers.v_pointer2 = NULL;
5684 }
5685}
5686
5687/************************************************************************/
5692{
5693 GtkTreeSelection *sel;
5694 GtkTreeModel *model;
5695 GtkTreeIter iter;
5696 GtkTreePath *path;
5697 GList *rows, *p;
5698 struct objbind *ob;
5699
5700 if (!pp || !pp->object_view) {
5701 return;
5702 }
5703
5704 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pp->object_view));
5705 if (gtk_tree_selection_count_selected_rows(sel) < 1) {
5706 return;
5707 }
5708
5709 rows = gtk_tree_selection_get_selected_rows(sel, &model);
5710 for (p = rows; p != NULL; p = p->next) {
5711 path = p->data;
5712 if (gtk_tree_model_get_iter(model, &iter, path)) {
5713 gtk_tree_model_get(model, &iter, 0, &ob, -1);
5716 property_page_set_store_value(pp, op, ob, &iter);
5718 }
5719 gtk_tree_path_free(path);
5720 }
5721 g_list_free(rows);
5722
5725 objprop_refresh_widget(op, ob);
5727}
5728
5729/************************************************************************/
5733{
5734 GtkTreeSelection *sel;
5735 GtkTreeModel *model;
5736 GtkTreeIter iter;
5737 GtkTreePath *path;
5738 GList *rows, *p;
5739 struct objbind *ob;
5740 struct connection *my_conn = &client.conn;
5741
5742 if (!pp || !pp->object_view) {
5743 return;
5744 }
5745
5746 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pp->object_view));
5747 if (gtk_tree_selection_count_selected_rows(sel) < 1) {
5748 return;
5749 }
5750
5751 rows = gtk_tree_selection_get_selected_rows(sel, &model);
5752 connection_do_buffer(my_conn);
5753 for (p = rows; p != NULL; p = p->next) {
5754 path = p->data;
5755 if (gtk_tree_model_get_iter(model, &iter, path)) {
5756 gtk_tree_model_get(model, &iter, 0, &ob, -1);
5758 }
5759 gtk_tree_path_free(path);
5760 }
5761 connection_do_unbuffer(my_conn);
5762 g_list_free(rows);
5763}
5764
5765/************************************************************************/
5772 struct tile_list *hint_tiles)
5773{
5775 int apno, value, count, size;
5776 int tag;
5777 struct connection *my_conn = &client.conn;
5778 struct tile *ptile = NULL;
5779 struct player *pplayer;
5780
5781 if (!pp) {
5782 return;
5783 }
5784
5787 return;
5788 }
5789
5790 tag = get_next_unique_tag();
5791 count = 1;
5792
5793 switch (objtype) {
5794 case OBJTYPE_STARTPOS:
5795 if (hint_tiles) {
5796 tile_list_iterate(hint_tiles, atile) {
5797 if (NULL == map_startpos_get(atile)) {
5798 ptile = atile;
5799 break;
5800 }
5802 }
5803
5804 if (NULL == ptile) {
5805 ptile = get_center_tile_mapcanvas();
5806 }
5807
5808 if (NULL == ptile) {
5809 break;
5810 }
5811
5812 dsend_packet_edit_startpos(my_conn, tile_index(ptile), FALSE, tag);
5813 break;
5814
5815 case OBJTYPE_UNIT:
5816 if (hint_tiles) {
5817 tile_list_iterate(hint_tiles, atile) {
5818 if (can_create_unit_at_tile(atile)) {
5819 ptile = atile;
5820 break;
5821 }
5823 }
5824
5825 if (!ptile) {
5826 struct unit *punit;
5830 ptile = unit_tile(punit);
5831 break;
5832 }
5834 }
5835
5836 if (!ptile) {
5837 ptile = get_center_tile_mapcanvas();
5838 }
5839
5840 if (!ptile) {
5841 break;
5842 }
5843
5847 dsend_packet_edit_unit_create(my_conn, apno, tile_index(ptile),
5848 value, count, tag);
5849 break;
5850
5851 case OBJTYPE_CITY:
5853 pplayer = player_by_number(apno);
5854 if (pplayer && hint_tiles) {
5855 tile_list_iterate(hint_tiles, atile) {
5856 if (!is_enemy_unit_tile(atile, pplayer)
5857 && city_can_be_built_here(&(wld.map), atile,
5858 NULL, FALSE)) {
5859 ptile = atile;
5860 break;
5861 }
5863 }
5864
5865 if (!ptile) {
5866 ptile = get_center_tile_mapcanvas();
5867 }
5868
5869 if (!ptile) {
5870 break;
5871 }
5872
5874 dsend_packet_edit_city_create(my_conn, apno, tile_index(ptile),
5875 size, tag);
5876 break;
5877
5878 case OBJTYPE_PLAYER:
5879 dsend_packet_edit_player_create(my_conn, tag);
5880 break;
5881
5882 case OBJTYPE_TILE:
5883 case OBJTYPE_GAME:
5884 case NUM_OBJTYPES:
5885 break;
5886 }
5887
5888 property_page_store_creation_tag(pp, tag, count);
5889}
5890
5891/************************************************************************/
5897 int object_id,
5898 bool removed)
5899{
5900 struct objbind *ob;
5901 GtkTreeRowReference *rr;
5902
5904 if (!ob) {
5905 return;
5906 }
5907
5908 rr = objbind_get_rowref(ob);
5909 if (rr && gtk_tree_row_reference_valid(rr)) {
5910 GtkTreePath *path;
5911 GtkTreeIter iter;
5912 GtkTreeModel *model;
5913
5914 model = GTK_TREE_MODEL(pp->object_store);
5915 path = gtk_tree_row_reference_get_path(rr);
5916
5917 if (gtk_tree_model_get_iter(model, &iter, path)) {
5918 if (removed) {
5919 gtk_list_store_remove(pp->object_store, &iter);
5920 } else {
5922 property_page_set_store_value(pp, op, ob, &iter);
5924 }
5925 }
5926
5927 gtk_tree_path_free(path);
5928 }
5929
5930 if (removed) {
5931 objbind_hash_remove(pp->objbind_table, object_id);
5932 return;
5933 }
5934
5935 if (ob == property_page_get_focused_objbind(pp)) {
5937 objprop_refresh_widget(op, ob);
5939 }
5940}
5941
5942/************************************************************************/
5949 int tag, int object_id)
5950{
5951 gpointer object;
5953
5954 if (!property_page_tag_is_known(pp, tag)) {
5955 return;
5956 }
5958
5961
5962 if (!object) {
5963 return;
5964 }
5965
5966 property_page_add_objbind(pp, object);
5968}
5969
5970/************************************************************************/
5975 struct extviewer *ev)
5976{
5977 GtkWidget *w;
5978
5979 if (!pp || !ev) {
5980 return;
5981 }
5982
5984 if (!w) {
5985 return;
5986 }
5987 gtk_notebook_append_page(GTK_NOTEBOOK(pp->extviewer_notebook), w, NULL);
5988}
5989
5990/************************************************************************/
5995 struct extviewer *ev)
5996{
5997 GtkWidget *w;
5998 GtkNotebook *notebook;
5999 int page;
6000
6001 if (!pp || !ev) {
6002 return;
6003 }
6004
6006 if (!w) {
6007 return;
6008 }
6009
6010 notebook = GTK_NOTEBOOK(pp->extviewer_notebook);
6011 page = gtk_notebook_page_num(notebook, w);
6012 gtk_notebook_set_current_page(notebook, page);
6013}
6014
6015/************************************************************************/
6020 int tag, int count)
6021{
6022 if (!pp || !pp->tag_table) {
6023 return;
6024 }
6025
6026 if (stored_tag_hash_lookup(pp->tag_table, tag, NULL)) {
6027 log_error("Attempted to insert object creation tag %d "
6028 "twice into tag table for property page %p (%d %s).",
6029 tag, pp, property_page_get_objtype(pp),
6031 return;
6032 }
6033
6034 stored_tag_hash_insert(pp->tag_table, tag, count);
6035}
6036
6037/************************************************************************/
6042 int tag)
6043{
6044 int count;
6045
6046 if (!pp || !pp->tag_table) {
6047 return;
6048 }
6049
6050 if (stored_tag_hash_lookup(pp->tag_table, tag, &count)) {
6051 if (0 >= --count) {
6052 stored_tag_hash_remove(pp->tag_table, tag);
6053 }
6054 }
6055}
6056
6057/************************************************************************/
6060static bool property_page_tag_is_known(struct property_page *pp, int tag)
6061{
6062 if (!pp || !pp->tag_table) {
6063 return FALSE;
6064 }
6065 return stored_tag_hash_lookup(pp->tag_table, tag, NULL);
6066}
6067
6068/************************************************************************/
6072{
6073 if (!pp || !pp->tag_table) {
6074 return;
6075 }
6076 stored_tag_hash_clear(pp->tag_table);
6077}
6078
6079/************************************************************************/
6082static void property_page_apply_button_clicked(GtkButton *button,
6083 gpointer userdata)
6084{
6085 struct property_page *pp = userdata;
6087}
6088
6089/************************************************************************/
6093static void property_page_refresh_button_clicked(GtkButton *button,
6094 gpointer userdata)
6095{
6096 struct property_page *pp = userdata;
6098}
6099
6100/************************************************************************/
6103static void property_page_create_button_clicked(GtkButton *button,
6104 gpointer userdata)
6105{
6106 struct property_page *pp = userdata, *tile_pp;
6107 struct tile_list *tiles = NULL;
6108 struct tile *ptile;
6109
6110 if (!pp) {
6111 return;
6112 }
6113
6115 tiles = tile_list_new();
6116
6117 property_page_objbind_iterate(tile_pp, ob) {
6118 ptile = objbind_get_object(ob);
6119 if (ptile) {
6120 tile_list_append(tiles, ptile);
6121 }
6123
6125 tile_list_destroy(tiles);
6126}
6127
6128/************************************************************************/
6131static void property_page_destroy_button_clicked(GtkButton *button,
6132 gpointer userdata)
6133{
6134 struct property_page *pp = userdata;
6136}
6137
6138/************************************************************************/
6144{
6145 struct property_page *pp;
6146 GtkWidget *label;
6147 const char *name;
6148
6149 if (!pe || !pe->notebook) {
6150 return FALSE;
6151 }
6152
6153 if (!(objtype < NUM_OBJTYPES)) {
6154 return FALSE;
6155 }
6156
6157 pp = property_page_new(objtype, pe);
6158 if (!pp) {
6159 return FALSE;
6160 }
6161
6163 label = gtk_label_new(name);
6164 gtk_notebook_append_page(GTK_NOTEBOOK(pe->notebook),
6165 pp->widget, label);
6166
6167 pe->property_pages[objtype] = pp;
6168
6169 return TRUE;
6170}
6171
6172/************************************************************************/
6175static struct property_page *
6178{
6179 if (!pe || !(objtype < NUM_OBJTYPES)) {
6180 return NULL;
6181 }
6182
6183 return pe->property_pages[objtype];
6184}
6185
6186/************************************************************************/
6190{
6191 struct property_editor *pe;
6192 GtkWidget *win, *notebook, *vgrid;
6194 int grid_row = 0;
6195
6196 pe = fc_calloc(1, sizeof(*pe));
6197
6198 /* The property editor dialog window. */
6199
6200 win = gtk_window_new();
6201 gtk_window_set_title(GTK_WINDOW(win), _("Property Editor"));
6202 gtk_window_set_resizable(GTK_WINDOW(win), TRUE);
6203 gtk_window_set_default_size(GTK_WINDOW(win), 780, 560);
6204 gtk_window_set_transient_for(GTK_WINDOW(win), GTK_WINDOW(toplevel));
6205 gtk_window_set_destroy_with_parent(GTK_WINDOW(win), TRUE);
6206 gtk_widget_set_margin_start(win, 4);
6207 gtk_widget_set_margin_end(win, 4);
6208 gtk_widget_set_margin_top(win, 4);
6209 gtk_widget_set_margin_bottom(win, 4);
6210 gtk_window_set_hide_on_close(GTK_WINDOW(win), TRUE);
6211 pe->widget = win;
6212
6213 vgrid = gtk_grid_new();
6214 gtk_window_set_child(GTK_WINDOW(win), vgrid);
6215
6216 /* Property pages. */
6217
6218 notebook = gtk_notebook_new();
6219 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), TRUE);
6220 gtk_grid_attach(GTK_GRID(vgrid), notebook, 0, grid_row++, 1, 1);
6221 pe->notebook = notebook;
6222
6223 for (objtype = 0; objtype < NUM_OBJTYPES; objtype++) {
6225 }
6226
6227 return pe;
6228}
6229
6230/************************************************************************/
6240
6241/************************************************************************/
6245 const struct tile_list *tiles)
6246{
6247 struct property_page *pp;
6249 int i;
6250 const enum editor_object_type preferred[] = {
6255 };
6256
6257 if (!pe || !tiles) {
6258 return;
6259 }
6260
6261 for (objtype = 0; objtype < NUM_OBJTYPES; objtype++) {
6263 property_page_load_tiles(pp, tiles);
6264 }
6265
6266 for (i = 0; i < ARRAY_SIZE(preferred) - 1; i++) {
6267 pp = property_editor_get_page(pe, preferred[i]);
6268 if (property_page_get_num_objbinds(pp) > 0) {
6269 break;
6270 }
6271 }
6272 objtype = preferred[i];
6273 gtk_notebook_set_current_page(GTK_NOTEBOOK(pe->notebook), objtype);
6274}
6275
6276/************************************************************************/
6282{
6283 if (!pe || !pe->widget) {
6284 return;
6285 }
6286
6287 gtk_widget_show(pe->widget);
6288
6289 gtk_window_present(GTK_WINDOW(pe->widget));
6290 if (objtype < NUM_OBJTYPES) {
6291 gtk_notebook_set_current_page(GTK_NOTEBOOK(pe->notebook), objtype);
6292 }
6293}
6294
6295/************************************************************************/
6299{
6300 if (!pe || !pe->widget) {
6301 return;
6302 }
6303 gtk_widget_hide(pe->widget);
6304}
6305
6306/************************************************************************/
6312 int object_id,
6313 bool remove)
6314{
6315 struct property_page *pp;
6316
6317 if (!pe) {
6318 return;
6319 }
6320
6321 if (!(objtype < NUM_OBJTYPES)) {
6322 return;
6323 }
6324
6326 property_page_object_changed(pp, object_id, remove);
6327}
6328
6329/************************************************************************/
6333 int tag, int object_id)
6334{
6336 struct property_page *pp;
6337
6338 for (objtype = 0; objtype < NUM_OBJTYPES; objtype++) {
6340 continue;
6341 }
6343 property_page_object_created(pp, tag, object_id);
6344 }
6345}
6346
6347/************************************************************************/
6351{
6353 struct property_page *pp;
6354
6355 if (!pe) {
6356 return;
6357 }
6358
6359 for (objtype = 0; objtype < NUM_OBJTYPES; objtype++) {
6363 }
6364}
6365
6366/************************************************************************/
6372{
6373 struct property_page *pp;
6374
6375 if (!pe) {
6376 return;
6377 }
6378
6380 if (!pp) {
6381 return;
6382 }
6383
6385
6386 switch (objtype) {
6387 case OBJTYPE_PLAYER:
6388 players_iterate(pplayer) {
6389 property_page_add_objbind(pp, pplayer);
6391 break;
6392 case OBJTYPE_GAME:
6394 break;
6395 case OBJTYPE_TILE:
6396 case OBJTYPE_STARTPOS:
6397 case OBJTYPE_UNIT:
6398 case OBJTYPE_CITY:
6399 case NUM_OBJTYPES:
6400 break;
6401 }
6402
6404 gtk_notebook_set_current_page(GTK_NOTEBOOK(pe->notebook), objtype);
6405}
6406
6407/************************************************************************/
6418static struct property_filter *property_filter_new(const char *filter)
6419{
6420 struct property_filter *pf;
6421 struct pf_conjunction *pfc;
6422 struct pf_pattern *pfp;
6423 int or_clause_count, and_clause_count;
6424 char *or_clauses[PF_MAX_CLAUSES], *and_clauses[PF_MAX_CLAUSES];
6425 const char *pattern;
6426 int i, j;
6427
6428 pf = fc_calloc(1, sizeof(*pf));
6429
6430 if (!filter || filter[0] == '\0') {
6431 return pf;
6432 }
6433
6434 or_clause_count = get_tokens(filter, or_clauses,
6437
6438 for (i = 0; i < or_clause_count; i++) {
6439 if (or_clauses[i][0] == '\0') {
6440 continue;
6441 }
6442 pfc = &pf->disjunction[pf->count];
6443
6444 and_clause_count = get_tokens(or_clauses[i], and_clauses,
6447
6448 for (j = 0; j < and_clause_count; j++) {
6449 if (and_clauses[j][0] == '\0') {
6450 continue;
6451 }
6452 pfp = &pfc->conjunction[pfc->count];
6453 pattern = and_clauses[j];
6454
6455 switch (pattern[0]) {
6456 case '!':
6457 pfp->negate = TRUE;
6458 pfp->text = fc_strdup(pattern + 1);
6459 break;
6460 default:
6461 pfp->text = fc_strdup(pattern);
6462 break;
6463 }
6464 pfc->count++;
6465 }
6466 free_tokens(and_clauses, and_clause_count);
6467 pf->count++;
6468 }
6469
6470 free_tokens(or_clauses, or_clause_count);
6471
6472 return pf;
6473}
6474
6475/************************************************************************/
6493 const struct objprop *op)
6494{
6495 struct pf_pattern *pfp;
6496 struct pf_conjunction *pfc;
6497 const char *name;
6498 bool match, or_result, and_result;
6499 int i, j;
6500
6501 if (!pf) {
6502 return TRUE;
6503 }
6504 if (!op) {
6505 return FALSE;
6506 }
6507
6508 name = objprop_get_name(op);
6509 if (!name) {
6510 return FALSE;
6511 }
6512
6513 if (pf->count < 1) {
6514 return TRUE;
6515 }
6516
6517 or_result = FALSE;
6518
6519 for (i = 0; i < pf->count; i++) {
6520 pfc = &pf->disjunction[i];
6521 and_result = TRUE;
6522 for (j = 0; j < pfc->count; j++) {
6523 pfp = &pfc->conjunction[j];
6524 match = (pfp->text[0] == '\0'
6525 || fc_strcasestr(name, pfp->text));
6526 if (pfp->negate) {
6527 match = !match;
6528 }
6529 and_result = and_result && match;
6530 if (!and_result) {
6531 break;
6532 }
6533 }
6534 or_result = or_result || and_result;
6535 if (or_result) {
6536 break;
6537 }
6538 }
6539
6540 return or_result;
6541}
6542
6543/************************************************************************/
6547{
6548 struct pf_pattern *pfp;
6549 struct pf_conjunction *pfc;
6550 int i, j;
6551
6552 if (!pf) {
6553 return;
6554 }
6555
6556 for (i = 0; i < pf->count; i++) {
6557 pfc = &pf->disjunction[i];
6558 for (j = 0; j < pfc->count; j++) {
6559 pfp = &pfc->conjunction[j];
6560 if (pfp->text != NULL) {
6561 free(pfp->text);
6562 pfp->text = NULL;
6563 }
6564 }
6565 pfc->count = 0;
6566 }
6567 pf->count = 0;
6568 free(pf);
6569}
6570
6571/************************************************************************/
6574const char *vision_layer_get_name(enum vision_layer vl)
6575{
6576 switch (vl) {
6577 case V_MAIN:
6578 /* TRANS: Vision layer name. Feel free to leave untranslated. */
6579 return _("Seen (Main)");
6580 case V_INVIS:
6581 /* TRANS: Vision layer name. Feel free to leave untranslated. */
6582 return _("Seen (Invis)");
6583 case V_SUBSURFACE:
6584 /* TRANS: Vision layer name. Feel free to leave untranslated. */
6585 return _("Seen (Subsurface)");
6586 case V_COUNT:
6587 break;
6588 }
6589
6590 log_error("%s(): Unrecognized vision layer %d.", __FUNCTION__, vl);
6591 return _("Unknown");
6592}
Base_type_id base_number(const struct base_type *pbase)
Definition base.c:92
Base_type_id base_count(void)
Definition base.c:109
bool dbv_isset(const struct dbv *pdbv, int bit)
Definition bitvector.c:120
#define BV_CLR_ALL(bv)
Definition bitvector.h:95
#define BV_SET(bv, bit)
Definition bitvector.h:81
#define BV_ARE_EQUAL(vec1, vec2)
Definition bitvector.h:113
#define BV_ISSET(bv, bit)
Definition bitvector.h:78
#define BV_CLR(bv, bit)
Definition bitvector.h:86
struct canvas int int canvas_y
Definition canvas_g.h:43
struct canvas int canvas_x
Definition canvas_g.h:43
int city_granary_size(int city_size)
Definition city.c:2104
bool city_can_be_built_here(const struct civ_map *nmap, const struct tile *ptile, const struct unit *punit, bool hut_test)
Definition city.c:1460
#define city_tile(_pcity_)
Definition city.h:544
static citizens city_size_get(const struct city *pcity)
Definition city.h:549
#define city_owner(_pcity_)
Definition city.h:543
#define MAX_CITY_SIZE
Definition city.h:98
#define I_DESTROYED
Definition city.h:240
#define I_NEVER
Definition city.h:239
struct civclient client
bool client_nation_is_in_current_set(const struct nation_type *pnation)
Definition climisc.c:1502
void connection_do_buffer(struct connection *pc)
Definition connection.c:323
void connection_do_unbuffer(struct connection *pc)
Definition connection.c:335
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit * punit
Definition dialogs_g.h:73
int objtype
Definition editgui_g.h:28
int int id
Definition editgui_g.h:28
int editor_tool_get_size(enum editor_tool_type ett)
Definition editor.c:1218
int editor_tool_get_value(enum editor_tool_type ett)
Definition editor.c:409
int editor_tool_get_count(enum editor_tool_type ett)
Definition editor.c:1252
struct unit * editor_unit_virtual_create(void)
Definition editor.c:1405
int editor_tool_get_applied_player(enum editor_tool_type ett)
Definition editor.c:1341
editor_object_type
Definition editor.h:25
@ OBJTYPE_PLAYER
Definition editor.h:30
@ OBJTYPE_UNIT
Definition editor.h:28
@ OBJTYPE_STARTPOS
Definition editor.h:27
@ OBJTYPE_GAME
Definition editor.h:31
@ NUM_OBJTYPES
Definition editor.h:33
@ OBJTYPE_CITY
Definition editor.h:29
@ OBJTYPE_TILE
Definition editor.h:26
@ ETT_UNIT
Definition editor.h:42
@ ETT_CITY
Definition editor.h:43
struct extra_type_list * extra_type_list_by_cause(enum extra_cause cause)
Definition extras.c:241
const char * extra_name_translation(const struct extra_type *pextra)
Definition extras.c:186
#define extra_index(_e_)
Definition extras.h:177
#define extra_base_get(_e_)
Definition extras.h:184
#define extra_road_get(_e_)
Definition extras.h:185
#define extra_type_by_cause_iterate_end
Definition extras.h:315
#define extra_type_by_cause_iterate(_cause, _extra)
Definition extras.h:309
void free_tokens(char **tokens, size_t ntokens)
Definition fc_cmdline.c:203
int get_tokens(const char *str, char **tokens, size_t num_tokens, const char *delimiterset)
Definition fc_cmdline.c:166
const struct functions * fc_funcs
#define EC_SPECIAL
Definition fc_types.h:968
#define Q_(String)
Definition fcintl.h:70
#define PL_(String1, String2, n)
Definition fcintl.h:71
#define _(String)
Definition fcintl.h:67
struct civ_game game
Definition game.c:57
struct world wld
Definition game.c:58
struct unit * game_unit_by_number(int id)
Definition game.c:111
struct city * game_city_by_number(int id)
Definition game.c:102
const char * government_name_translation(const struct government *pgovern)
Definition government.c:142
Government_type_id government_count(void)
Definition government.c:70
struct government * government_by_number(const Government_type_id gov)
Definition government.c:102
Government_type_id government_index(const struct government *pgovern)
Definition government.c:81
#define governments_iterate(NAME_pgov)
Definition government.h:121
#define governments_iterate_end
Definition government.h:124
#define FC_STATIC_CANVAS_INIT
Definition canvas.h:27
static void add_column(GtkWidget *view, int col_id, const char *name, GType gtype, bool editable, bool is_radio, GCallback edit_callback, gpointer callback_userdata)
Definition editprop.c:817
static void property_page_reset_objbinds(struct property_page *pp)
Definition editprop.c:5666
static void property_page_send_values(struct property_page *pp)
Definition editprop.c:5510
static void objprop_setup_widget(struct objprop *op)
Definition editprop.c:2926
static void property_page_store_creation_tag(struct property_page *pp, int tag, int count)
Definition editprop.c:5994
static gchar * propval_as_string(struct propval *pv)
Definition editprop.c:859
static struct property_page * objprop_get_property_page(const struct objprop *op)
Definition editprop.c:3434
static const char * objprop_get_name(const struct objprop *op)
Definition editprop.c:2806
const char * vision_layer_get_name(enum vision_layer)
Definition editprop.c:6548
static int objbind_get_object_id(struct objbind *ob)
Definition editprop.c:1378
static void objprop_set_extviewer(struct objprop *op, struct extviewer *ev)
Definition editprop.c:3411
static GtkWidget * extviewer_get_panel_widget(struct extviewer *ev)
Definition editprop.c:3767
static gpointer objtype_get_object_from_id(enum editor_object_type objtype, int id)
Definition editprop.c:722
void property_editor_handle_object_changed(struct property_editor *pe, enum editor_object_type objtype, int object_id, bool remove)
Definition editprop.c:6284
static struct propstate * propstate_new(struct objprop *op, struct propval *pv)
Definition editprop.c:1262
static const char * valtype_get_name(enum value_types valtype)
Definition editprop.c:776
static void propstate_destroy(struct propstate *ps)
Definition editprop.c:1294
static bool objbind_set_modified_value(struct objbind *ob, struct objprop *op, struct propval *pv)
Definition editprop.c:2108
static GtkCellRenderer * objprop_create_cell_renderer(const struct objprop *op)
Definition editprop.c:2830
static void extviewer_clear_widgets(struct extviewer *ev)
Definition editprop.c:4060
value_types
Definition editprop.c:196
@ VALTYPE_STRING
Definition editprop.c:200
@ VALTYPE_BV_SPECIAL
Definition editprop.c:204
@ VALTYPE_BV_BASES
Definition editprop.c:206
@ VALTYPE_INT
Definition editprop.c:198
@ VALTYPE_INVENTIONS_ARRAY
Definition editprop.c:203
@ VALTYPE_BV_ROADS
Definition editprop.c:205
@ VALTYPE_PIXBUF
Definition editprop.c:201
@ VALTYPE_TILE_VISION_DATA
Definition editprop.c:210
@ VALTYPE_NONE
Definition editprop.c:197
@ VALTYPE_NATION_HASH
Definition editprop.c:208
@ VALTYPE_BOOL
Definition editprop.c:199
@ VALTYPE_NATION
Definition editprop.c:207
@ VALTYPE_GOV
Definition editprop.c:209
@ VALTYPE_BUILT_ARRAY
Definition editprop.c:202
static void objprop_set_child_widget(struct objprop *op, const char *widget_name, GtkWidget *widget)
Definition editprop.c:3351
static bool property_editor_add_page(struct property_editor *pe, enum editor_object_type objtype)
Definition editprop.c:6117
static void propstate_clear_value(struct propstate *ps)
Definition editprop.c:1281
static void objbind_pack_modified_value(struct objbind *ob, struct objprop *op, union packetdata packet)
Definition editprop.c:2360
static struct objbind * property_page_get_focused_objbind(struct property_page *pp)
Definition editprop.c:5397
static bool objprop_has_widget(const struct objprop *op)
Definition editprop.c:2719
static int objtype_get_id_from_object(enum editor_object_type objtype, gpointer object)
Definition editprop.c:693
static enum editor_object_type objbind_get_objtype(const struct objbind *ob)
Definition editprop.c:2192
static struct extviewer * objprop_get_extviewer(struct objprop *op)
Definition editprop.c:3423
static void extviewer_refresh_widgets(struct extviewer *ev, struct propval *pv)
Definition editprop.c:3790
static enum editor_object_type property_page_get_objtype(const struct property_page *pp)
Definition editprop.c:5047
#define property_page_objbind_iterate_end
Definition editprop.c:638
static void property_page_show_extviewer(struct property_page *pp, struct extviewer *ev)
Definition editprop.c:5969
static gpointer objbind_get_object(struct objbind *ob)
Definition editprop.c:1362
static const char * property_page_get_name(const struct property_page *pp)
Definition editprop.c:5035
void property_editor_handle_object_created(struct property_editor *pe, int tag, int object_id)
Definition editprop.c:6306
static bool objbind_property_is_modified(struct objbind *ob, struct objprop *op)
Definition editprop.c:2063
static struct propval * propstate_get_value(struct propstate *ps)
Definition editprop.c:1324
static void property_page_clear_tags(struct property_page *pp)
Definition editprop.c:6046
static void property_page_object_created(struct property_page *pp, int tag, int object_id)
Definition editprop.c:5923
static bool property_page_tag_is_known(struct property_page *pp, int tag)
Definition editprop.c:6035
static void property_page_remove_creation_tag(struct property_page *pp, int tag)
Definition editprop.c:6016
static void property_page_load_tiles(struct property_page *pp, const struct tile_list *tiles)
Definition editprop.c:5439
static void property_page_create_objects(struct property_page *pp, struct tile_list *hint_tiles)
Definition editprop.c:5746
static void property_page_add_extviewer(struct property_page *pp, struct extviewer *ev)
Definition editprop.c:5949
static void property_page_refresh_button_clicked(GtkButton *button, gpointer userdata)
Definition editprop.c:6068
static void property_page_set_focused_objbind(struct property_page *pp, struct objbind *ob)
Definition editprop.c:5409
static void property_page_setup_objprops(struct property_page *pp)
Definition editprop.c:4405
static void objbind_set_rowref(struct objbind *ob, GtkTreeRowReference *rr)
Definition editprop.c:2626
object_property_flags
Definition editprop.c:381
@ OPF_IN_LISTVIEW
Definition editprop.c:384
@ OPF_EDITABLE
Definition editprop.c:383
@ OPF_HAS_WIDGET
Definition editprop.c:385
@ OPF_NO_FLAGS
Definition editprop.c:382
static void objbind_clear_modified_value(struct objbind *ob, struct objprop *op)
Definition editprop.c:2049
static struct propval * objbind_get_value_from_object(struct objbind *ob, struct objprop *op)
Definition editprop.c:1439
static void propval_free(struct propval *pv)
Definition editprop.c:1124
static struct property_filter * property_filter_new(const char *filter)
Definition editprop.c:6392
static bool property_page_set_store_value(struct property_page *pp, struct objprop *op, struct objbind *ob, GtkTreeIter *iter)
Definition editprop.c:5248
static const char * objtype_get_name(enum editor_object_type objtype)
Definition editprop.c:664
static void objbind_clear_all_modified_values(struct objbind *ob)
Definition editprop.c:2094
static bool property_filter_match(struct property_filter *pf, const struct objprop *op)
Definition editprop.c:6466
void property_editor_popup(struct property_editor *pe, enum editor_object_type objtype)
Definition editprop.c:6254
static void property_page_destroy_button_clicked(GtkButton *button, gpointer userdata)
Definition editprop.c:6106
static struct objbind * objbind_new(enum editor_object_type objtype, gpointer object)
Definition editprop.c:1336
static gboolean property_page_selection_func(GtkTreeSelection *sel, GtkTreeModel *model, GtkTreePath *path, gboolean currently_selected, gpointer data)
Definition editprop.c:4631
static int property_page_get_num_objbinds(const struct property_page *pp)
Definition editprop.c:5456
static bool objprop_show_in_listview(const struct objprop *op)
Definition editprop.c:2708
static GType objprop_get_gtype(const struct objprop *op)
Definition editprop.c:2664
static void objprop_set_treeview_column(struct objprop *op, GtkTreeViewColumn *col)
Definition editprop.c:2782
static void objbind_pack_current_values(struct objbind *ob, union packetdata packet)
Definition editprop.c:2217
static const char * objprop_get_attribute_type_string(const struct objprop *op)
Definition editprop.c:2733
static struct propval * propval_copy(struct propval *pv)
Definition editprop.c:1042
struct property_editor * editprop_get_property_editor(void)
Definition editprop.c:6207
void property_editor_reload(struct property_editor *pe, enum editor_object_type objtype)
Definition editprop.c:6344
static GdkPixbuf * create_unit_pixbuf(const struct unit *punit)
Definition editprop.c:5075
static void extviewer_view_cell_toggled(GtkCellRendererToggle *cell, gchar *path, gpointer userdata)
Definition editprop.c:4135
static struct property_editor * property_editor_new(void)
Definition editprop.c:6164
static void property_page_send_packet(struct property_page *pp, union packetdata packet)
Definition editprop.c:5605
static gchar * built_status_to_string(struct built_status *bs)
Definition editprop.c:978
static int objprop_get_id(const struct objprop *op)
Definition editprop.c:2649
object_property_ids
Definition editprop.c:304
@ OPID_STARTPOS_IMAGE
Definition editprop.c:324
@ OPID_TILE_Y
Definition editprop.c:307
@ OPID_TILE_BASES
Definition editprop.c:320
@ OPID_CITY_XY
Definition editprop.c:350
@ OPID_UNIT_ID
Definition editprop.c:334
@ OPID_CITY_BUILDINGS
Definition editprop.c:353
@ OPID_CITY_NAME
Definition editprop.c:345
@ OPID_TILE_NAT_Y
Definition editprop.c:309
@ OPID_CITY_SIZE
Definition editprop.c:351
@ OPID_UNIT_VETERAN
Definition editprop.c:341
@ OPID_CITY_IMAGE
Definition editprop.c:344
@ OPID_CITY_SHIELD_STOCK
Definition editprop.c:355
@ OPID_PLAYER_NAME
Definition editprop.c:357
@ OPID_PLAYER_AGE
Definition editprop.c:360
@ OPID_STARTPOS_NATIONS
Definition editprop.c:327
@ OPID_GAME_LAKE_FLOODING
Definition editprop.c:377
@ OPID_UNIT_IMAGE
Definition editprop.c:329
@ OPID_TILE_TERRAIN
Definition editprop.c:314
@ OPID_TILE_SPECIALS
Definition editprop.c:318
@ OPID_TILE_RESOURCE
Definition editprop.c:317
@ OPID_TILE_IMAGE
Definition editprop.c:305
@ OPID_TILE_VISION
Definition editprop.c:321
@ OPID_PLAYER_INVENTIONS
Definition editprop.c:364
@ OPID_GAME_SCENARIO_NAME
Definition editprop.c:370
@ OPID_PLAYER_SCIENCE
Definition editprop.c:366
@ OPID_TILE_CONTINENT
Definition editprop.c:310
@ OPID_CITY_HISTORY
Definition editprop.c:352
@ OPID_TILE_XY
Definition editprop.c:316
@ OPID_GAME_SCENARIO_AUTHORS
Definition editprop.c:371
@ OPID_TILE_X
Definition editprop.c:306
@ OPID_TILE_NAT_X
Definition editprop.c:308
@ OPID_PLAYER_NATION
Definition editprop.c:358
@ OPID_GAME_PREVENT_CITIES
Definition editprop.c:376
@ OPID_STARTPOS_XY
Definition editprop.c:325
@ OPID_UNIT_MOVED
Definition editprop.c:338
@ OPID_TILE_LABEL
Definition editprop.c:322
@ OPID_CITY_FOOD_STOCK
Definition editprop.c:354
@ OPID_UNIT_DONE_MOVING
Definition editprop.c:339
@ OPID_UNIT_MOVES_LEFT
Definition editprop.c:336
@ OPID_GAME_SCENARIO_DESC
Definition editprop.c:372
@ OPID_GAME_STARTPOS_NATIONS
Definition editprop.c:375
@ OPID_UNIT_HP
Definition editprop.c:340
@ OPID_UNIT_FUEL
Definition editprop.c:337
@ OPID_PLAYER_SCENARIO_RESERVED
Definition editprop.c:365
@ OPID_TILE_ROADS
Definition editprop.c:319
@ OPID_PLAYER_GOLD
Definition editprop.c:367
@ OPID_CITY_ID
Definition editprop.c:349
@ OPID_GAME_SCENARIO_RANDSTATE
Definition editprop.c:373
@ OPID_GAME_SCENARIO_PLAYERS
Definition editprop.c:374
@ OPID_UNIT_STAY
Definition editprop.c:342
@ OPID_PLAYER_GOV
Definition editprop.c:359
@ OPID_STARTPOS_EXCLUDE
Definition editprop.c:326
@ OPID_UNIT_TYPE
Definition editprop.c:333
@ OPID_GAME_SCENARIO
Definition editprop.c:369
@ OPID_GAME_RULESET_LOCKED
Definition editprop.c:378
@ OPID_UNIT_XY
Definition editprop.c:335
@ OPID_TILE_INDEX
Definition editprop.c:315
static enum value_types objprop_get_valtype(const struct objprop *op)
Definition editprop.c:2697
static int get_next_unique_tag(void)
Definition editprop.c:1031
static bool objprop_is_sortable(const struct objprop *op)
Definition editprop.c:2851
static void property_page_add_objbinds_from_tile(struct property_page *pp, const struct tile *ptile)
Definition editprop.c:5194
static const char * objprop_get_tooltip(const struct objprop *op)
Definition editprop.c:2817
static GtkTreeRowReference * objbind_get_rowref(struct objbind *ob)
Definition editprop.c:2638
static void property_filter_free(struct property_filter *pf)
Definition editprop.c:6520
static void objprop_widget_spin_button_changed(GtkSpinButton *spin, gpointer userdata)
Definition editprop.c:2892
#define PF_DISJUNCTION_SEPARATOR
Definition editprop.c:118
static GtkWidget * objprop_get_child_widget(struct objprop *op, const char *widget_name)
Definition editprop.c:3378
static void property_page_selection_changed(GtkTreeSelection *sel, gpointer userdata)
Definition editprop.c:4606
static bool objtype_is_conserved(enum editor_object_type objtype)
Definition editprop.c:753
static struct extviewer * extviewer_new(struct objprop *op)
Definition editprop.c:3470
static bool propval_equal(struct propval *pva, struct propval *pvb)
Definition editprop.c:1175
static void property_page_quick_find_entry_changed(GtkWidget *entry, gpointer userdata)
Definition editprop.c:4686
static void objprop_refresh_widget(struct objprop *op, struct objbind *ob)
Definition editprop.c:3102
#define PF_MAX_CLAUSES
Definition editprop.c:117
void property_editor_popdown(struct property_editor *pe)
Definition editprop.c:6272
static void objbind_destroy(struct objbind *ob)
Definition editprop.c:2173
static void property_page_add_objbind(struct property_page *pp, gpointer object_data)
Definition editprop.c:5158
static void objbind_request_destroy_object(struct objbind *ob)
Definition editprop.c:1391
static void property_page_create_button_clicked(GtkButton *button, gpointer userdata)
Definition editprop.c:6078
static GdkPixbuf * create_pixbuf_from_layers(const struct tile *ptile, const struct unit *punit, const struct city *pcity, enum layer_category category)
Definition editprop.c:5101
static union packetdata property_page_new_packet(struct property_page *pp)
Definition editprop.c:5564
static void propstate_set_value(struct propstate *ps, struct propval *pv)
Definition editprop.c:1309
static int objprop_get_column_id(const struct objprop *op)
Definition editprop.c:2771
static GdkPixbuf * create_tile_pixbuf(const struct tile *ptile)
Definition editprop.c:5063
static struct objprop * extviewer_get_objprop(struct extviewer *ev)
Definition editprop.c:3755
static bool can_create_unit_at_tile(struct tile *ptile)
Definition editprop.c:999
static struct objbind * property_page_get_objbind(struct property_page *pp, int object_id)
Definition editprop.c:5422
static bool objbind_get_allowed_value_span(struct objbind *ob, struct objprop *op, double *pmin, double *pmax, double *pstep, double *pbig_step)
Definition editprop.c:1874
static void property_page_free_packet(struct property_page *pp, union packetdata packet)
Definition editprop.c:5646
static GdkPixbuf * create_city_pixbuf(const struct city *pcity)
Definition editprop.c:5087
#define ADDPROP(ARG_id, ARG_name, ARG_tooltip, ARG_flags, ARG_valtype)
static void extviewer_panel_button_clicked(GtkButton *button, gpointer userdata)
Definition editprop.c:4115
static void property_page_destroy_objects(struct property_page *pp)
Definition editprop.c:5707
void property_editor_load_tiles(struct property_editor *pe, const struct tile_list *tiles)
Definition editprop.c:6218
static struct property_page * property_page_new(enum editor_object_type objtype, struct property_editor *parent)
Definition editprop.c:4728
#define property_page_objprop_iterate_end
Definition editprop.c:634
static void property_page_clear_objbinds(struct property_page *pp)
Definition editprop.c:5143
void property_editor_clear(struct property_editor *pe)
Definition editprop.c:6324
#define property_page_objprop_iterate(ARG_pp, NAME_op)
Definition editprop.c:632
static void objprop_set_column_id(struct objprop *op, int col_id)
Definition editprop.c:2758
static void objbind_bind_properties(struct objbind *ob, struct property_page *pp)
Definition editprop.c:2203
static void property_page_fill_widgets(struct property_page *pp)
Definition editprop.c:5348
static bool objbind_has_modified_properties(struct objbind *ob)
Definition editprop.c:2082
static void property_page_change_value(struct property_page *pp, struct objprop *op, struct propval *pv)
Definition editprop.c:5468
static void objprop_widget_toggle_button_changed(GtkToggleButton *button, gpointer userdata)
Definition editprop.c:2909
#define PF_CONJUNCTION_SEPARATOR
Definition editprop.c:119
static void property_page_apply_button_clicked(GtkButton *button, gpointer userdata)
Definition editprop.c:6057
static struct objprop * objprop_new(int id, const char *name, const char *tooltip, enum object_property_flags flags, enum value_types valtype, struct property_page *parent)
Definition editprop.c:3445
static GtkWidget * extviewer_get_view_widget(struct extviewer *ev)
Definition editprop.c:3779
static GtkWidget * objprop_get_widget(struct objprop *op)
Definition editprop.c:3336
static void propval_free_data(struct propval *pv)
Definition editprop.c:1138
static void extviewer_textbuf_changed(GtkTextBuffer *textbuf, gpointer userdata)
Definition editprop.c:4356
static struct property_editor * the_property_editor
Definition editprop.c:658
static void property_page_object_changed(struct property_page *pp, int object_id, bool remove)
Definition editprop.c:5871
static bool objprop_is_readonly(const struct objprop *op)
Definition editprop.c:2865
#define property_page_objbind_iterate(ARG_pp, NAME_ob)
Definition editprop.c:636
static GtkTreeViewColumn * objprop_get_treeview_column(const struct objprop *op)
Definition editprop.c:2795
static struct property_page * property_editor_get_page(struct property_editor *pe, enum editor_object_type objtype)
Definition editprop.c:6151
static struct propval * objbind_get_modified_value(struct objbind *ob, struct objprop *op)
Definition editprop.c:2154
GtkWidget * toplevel
Definition gui_main.c:124
void disable_gobject_callback(GObject *obj, GCallback cb)
Definition gui_stuff.c:1087
void enable_gobject_callback(GObject *obj, GCallback cb)
Definition gui_stuff.c:1103
GdkPixbuf * get_flag(const struct nation_type *nation)
Definition plrdlg.c:609
const char * tooltip
Definition repodlgs.c:1314
const char * title
Definition repodlgs.c:1313
GdkPixbuf * surface_get_pixbuf(cairo_surface_t *surf, int width, int height)
Definition sprite.c:418
GdkPixbuf * sprite_get_pixbuf(struct sprite *sprite)
Definition sprite.c:402
static void objprop_widget_text_changed(GtkEditable *text, gpointer userdata)
Definition editprop.c:2876
#define PF_MAX_CLAUSES
Definition editprop.c:117
bool is_special_improvement(const struct impr_type *pimprove)
Impr_type_id improvement_index(const struct impr_type *pimprove)
bool is_great_wonder(const struct impr_type *pimprove)
const char * improvement_name_translation(const struct impr_type *pimprove)
bool is_small_wonder(const struct impr_type *pimprove)
#define improvement_iterate_end
#define improvement_iterate(_p)
#define B_LAST
Definition improvement.h:42
const char * name
Definition inputfile.c:127
#define fc_assert_ret_val(condition, val)
Definition log.h:194
#define log_error(message,...)
Definition log.h:103
struct startpos * map_startpos_get(const struct tile *ptile)
Definition map.c:1686
int startpos_number(const struct startpos *psp)
Definition map.c:1436
#define nat_x
#define nat_y
struct tile * startpos_tile(const struct startpos *psp)
Definition map.c:1479
const struct nation_hash * startpos_raw_nations(const struct startpos *psp)
Definition map.c:1568
bool startpos_pack(const struct startpos *psp, struct packet_edit_startpos_full *packet)
Definition map.c:1509
struct tile * index_to_tile(const struct civ_map *imap, int mindex)
Definition map.c:454
bool startpos_is_excluding(const struct startpos *psp)
Definition map.c:1556
struct startpos * map_startpos_by_number(int id)
Definition map.c:1427
#define index_to_native_pos(pnat_x, pnat_y, mindex)
Definition map.h:151
#define index_to_map_pos(pmap_x, pmap_y, mindex)
Definition map.h:227
struct tile * get_center_tile_mapcanvas(void)
void put_one_element(struct canvas *pcanvas, float zoom, enum mapview_layer layer, const struct tile *ptile, const struct tile_edge *pedge, const struct tile_corner *pcorner, const struct unit *punit, const struct city *pcity, int canvas_x, int canvas_y, const struct city *citymode, const struct unit_type *putype)
#define fc_calloc(n, esz)
Definition mem.h:38
#define fc_strdup(str)
Definition mem.h:43
#define fc_malloc(sz)
Definition mem.h:34
bool can_unit_exist_at_tile(const struct civ_map *nmap, const struct unit *punit, const struct tile *ptile)
Definition movement.c:304
#define MAX_MOVE_FRAGS
Definition movement.h:27
Nation_type_id nation_count(void)
Definition nation.c:506
Nation_type_id nation_number(const struct nation_type *pnation)
Definition nation.c:485
const char * nation_adjective_translation(const struct nation_type *pnation)
Definition nation.c:148
struct nation_type * nation_by_number(const Nation_type_id nation)
Definition nation.c:474
struct nation_type * nation_of_player(const struct player *pplayer)
Definition nation.c:443
bool is_nation_playable(const struct nation_type *nation)
Definition nation.c:199
Nation_type_id nation_index(const struct nation_type *pnation)
Definition nation.c:497
enum barbarian_type nation_barbarian_type(const struct nation_type *nation)
Definition nation.c:210
#define nation_hash_iterate(nationhash, pnation)
Definition nation.h:92
#define nations_iterate_end
Definition nation.h:335
#define nations_iterate(NAME_pnation)
Definition nation.h:332
#define nation_hash_iterate_end
Definition nation.h:94
int dsend_packet_edit_city_create(struct connection *pc, int owner, int tile, int size, int tag)
int send_packet_edit_city(struct connection *pc, const struct packet_edit_city *packet)
int send_packet_edit_game(struct connection *pc, const struct packet_edit_game *packet)
int dsend_packet_edit_city_remove(struct connection *pc, int id16, int id32)
int dsend_packet_edit_unit_remove_by_id(struct connection *pc, int id16, int id32)
int send_packet_edit_startpos_full(struct connection *pc, const struct packet_edit_startpos_full *packet)
int dsend_packet_edit_startpos(struct connection *pc, int id, bool removal, int tag)
int send_packet_edit_player(struct connection *pc, const struct packet_edit_player *packet)
int dsend_packet_edit_player_create(struct connection *pc, int tag)
int send_packet_edit_unit(struct connection *pc, const struct packet_edit_unit *packet)
int send_packet_edit_scenario_desc(struct connection *pc, const struct packet_edit_scenario_desc *packet)
int dsend_packet_edit_unit_create(struct connection *pc, int owner, int tile, Unit_type_id type, int count, int tag)
int dsend_packet_edit_player_remove(struct connection *pc, int id)
int send_packet_edit_tile(struct connection *pc, const struct packet_edit_tile *packet)
bool player_slot_is_used(const struct player_slot *pslot)
Definition player.c:441
struct player * player_by_number(const int player_id)
Definition player.c:840
int player_number(const struct player *pplayer)
Definition player.c:828
const char * player_name(const struct player *pplayer)
Definition player.c:886
int player_slot_index(const struct player_slot *pslot)
Definition player.c:419
bool player_has_flag(const struct player *pplayer, enum plr_flag_id flag)
Definition player.c:1954
int player_index(const struct player *pplayer)
Definition player.c:820
bool pplayers_allied(const struct player *pplayer, const struct player *pplayer2)
Definition player.c:1381
struct player * player_slot_get_player(const struct player_slot *pslot)
Definition player.c:430
#define players_iterate_end
Definition player.h:535
#define players_iterate(_pplayer)
Definition player.h:530
#define player_slots_iterate(_pslot)
Definition player.h:521
#define player_slots_iterate_end
Definition player.h:525
struct research * research_get(const struct player *pplayer)
Definition research.c:126
enum tech_state research_invention_state(const struct research *presearch, Tech_type_id tech)
Definition research.c:616
Road_type_id road_count(void)
Definition road.c:50
Road_type_id road_number(const struct road_type *proad)
Definition road.c:32
#define ARRAY_SIZE(x)
Definition shared.h:85
int step
Definition specpq.h:92
size_t size
Definition specvec.h:72
int turn
Definition city.h:238
cairo_surface_t * surface
Definition canvas.h:22
Definition city.h:309
int food_stock
Definition city.h:354
struct built_status built[B_LAST]
Definition city.h:380
int history
Definition city.h:393
int id
Definition city.h:315
char * name
Definition city.h:310
int shield_stock
Definition city.h:355
struct packet_scenario_description scenario_desc
Definition game.h:88
struct packet_game_info info
Definition game.h:89
struct packet_scenario_info scenario
Definition game.h:87
struct government * government_during_revolution
Definition game.h:94
struct connection conn
Definition client_main.h:96
GtkWidget * view_widget
Definition editprop.c:520
GtkWidget * panel_button
Definition editprop.c:517
GtkWidget * view_label
Definition editprop.c:521
GtkWidget * panel_image
Definition editprop.c:518
GtkTextBuffer * textbuf
Definition editprop.c:524
struct objprop * objprop
Definition editprop.c:512
GtkWidget * panel_label
Definition editprop.c:516
struct propval * pv_cached
Definition editprop.c:513
GtkListStore * store
Definition editprop.c:523
GtkWidget * panel_widget
Definition editprop.c:515
bool(* player_tile_vision_get)(const struct tile *ptile, const struct player *pplayer, enum vision_layer vision)
int object_id
Definition editprop.c:457
struct propstate_hash * propstate_table
Definition editprop.c:459
struct property_page * parent_property_page
Definition editprop.c:458
GtkTreeRowReference * rowref
Definition editprop.c:460
enum editor_object_type objtype
Definition editprop.c:456
const char * name
Definition editprop.c:390
const char * tooltip
Definition editprop.c:391
GtkWidget * widget
Definition editprop.c:396
struct property_page * parent_page
Definition editprop.c:398
enum object_property_flags flags
Definition editprop.c:392
struct extviewer * extviewer
Definition editprop.c:397
int id
Definition editprop.c:389
enum value_types valtype
Definition editprop.c:393
int column_id
Definition editprop.c:394
GtkTreeViewColumn * view_column
Definition editprop.c:395
int built[B_LAST]
char name[MAX_LEN_CITYNAME]
char scenario_name[256]
char scenario_authors[MAX_LEN_PACKET/3]
Nation_type_id nation
char name[MAX_LEN_NAME]
Government_type_id government
bool inventions[A_LAST+1]
bv_startpos_nations nations
char label[MAX_LEN_NAME]
char description[MAX_LEN_CONTENT]
char authors[MAX_LEN_PACKET/3]
struct pf_pattern conjunction[PF_MAX_CLAUSES]
Definition editprop.c:127
char * text
Definition editprop.c:123
bool negate
Definition editprop.c:122
struct government * government
Definition player.h:258
int turns_alive
Definition player.h:266
struct player_economic economic
Definition player.h:284
char name[MAX_LEN_NAME]
Definition player.h:251
struct nation_type * nation
Definition player.h:260
GtkWidget * notebook
Definition editprop.c:646
struct property_page * property_pages[NUM_OBJTYPES]
Definition editprop.c:648
GtkWidget * widget
Definition editprop.c:645
struct pf_conjunction disjunction[PF_MAX_CLAUSES]
Definition editprop.c:132
GtkListStore * object_store
Definition editprop.c:550
struct property_editor * pe_parent
Definition editprop.c:554
GtkWidget * extviewer_notebook
Definition editprop.c:552
GtkWidget * widget
Definition editprop.c:549
struct objbind_hash * objbind_table
Definition editprop.c:557
GtkWidget * object_view
Definition editprop.c:551
struct objbind * focused_objbind
Definition editprop.c:560
struct stored_tag_hash * tag_table
Definition editprop.c:558
enum editor_object_type objtype
Definition editprop.c:547
struct objprop_hash * objprop_table
Definition editprop.c:556
struct propval * property_value
Definition editprop.c:255
int property_id
Definition editprop.c:254
union propval_data data
Definition editprop.c:243
enum value_types valtype
Definition editprop.c:244
bool must_free
Definition editprop.c:245
int bulbs_researched
Definition research.h:53
Definition map.c:41
bv_player tile_known
Definition editprop.c:113
bv_player tile_seen[V_COUNT]
Definition editprop.c:113
Definition tile.h:49
char * label
Definition tile.h:64
Continent_id continent
Definition tile.h:53
Definition unit.h:138
int moves_left
Definition unit.h:150
int id
Definition unit.h:145
bool moved
Definition unit.h:173
int hp
Definition unit.h:151
int fuel
Definition unit.h:153
bool stay
Definition unit.h:205
bool done_moving
Definition unit.h:181
int veteran
Definition unit.h:152
struct civ_map map
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:787
char * fc_strcasestr(const char *haystack, const char *needle)
Definition support.c:439
#define sz_strlcpy(dest, src)
Definition support.h:167
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define sz_strlcat(dest, src)
Definition support.h:168
const char * advance_name_translation(const struct advance *padvance)
Definition tech.c:290
Tech_type_id advance_index(const struct advance *padvance)
Definition tech.c:89
#define advance_index_iterate_end
Definition tech.h:248
#define advance_iterate(_start, _p)
Definition tech.h:264
static Tech_type_id advance_count(void)
Definition tech.h:170
#define A_FIRST
Definition tech.h:44
#define advance_iterate_end
Definition tech.h:270
#define advance_index_iterate(_start, _index)
Definition tech.h:244
const char * terrain_name_translation(const struct terrain *pterrain)
Definition terrain.c:226
struct city * tile_city(const struct tile *ptile)
Definition tile.c:83
#define tile_index(_pt_)
Definition tile.h:87
#define tile_resource(_tile)
Definition tile.h:101
#define tile_list_iterate(tile_list, ptile)
Definition tile.h:72
#define tile_terrain(_tile)
Definition tile.h:109
#define TILE_XY(ptile)
Definition tile.h:42
#define tile_list_iterate_end
Definition tile.h:74
static const bv_extras * tile_extras(const struct tile *ptile)
Definition tile.h:119
#define tile_has_extra(ptile, pextra)
Definition tile.h:146
struct sprite * get_government_sprite(const struct tileset *t, const struct government *gov)
Definition tilespec.c:6504
int tileset_small_sprite_width(const struct tileset *t)
Definition tilespec.c:864
int tileset_full_tile_height(const struct tileset *t)
Definition tilespec.c:752
bool tileset_layer_in_category(enum mapview_layer layer, enum layer_category cat)
Definition tilespec.c:7025
int tileset_small_sprite_height(const struct tileset *t)
Definition tilespec.c:900
int tileset_tile_height(const struct tileset *t)
Definition tilespec.c:728
int tileset_full_tile_width(const struct tileset *t)
Definition tilespec.c:739
int tileset_tile_width(const struct tileset *t)
Definition tilespec.c:716
#define mapview_layer_iterate(layer)
Definition tilespec.h:174
#define mapview_layer_iterate_end
Definition tilespec.h:182
layer_category
Definition tilespec.h:188
@ LAYER_CATEGORY_TILE
Definition tilespec.h:190
@ LAYER_CATEGORY_CITY
Definition tilespec.h:189
@ LAYER_CATEGORY_UNIT
Definition tilespec.h:191
gpointer v_pointer2
Definition editprop.c:98
struct packet_edit_tile * tile
Definition editprop.c:100
gpointer v_pointer1
Definition editprop.c:97
struct packet_edit_unit * unit
Definition editprop.c:103
struct packetdata::@145 pointers
struct packet_edit_player * player
Definition editprop.c:104
struct packet_edit_city * city
Definition editprop.c:102
struct packet_edit_game * game
Definition editprop.c:106
struct packet_edit_startpos_full * startpos
Definition editprop.c:101
struct government * v_gov
Definition editprop.c:237
bv_techs v_bv_inventions
Definition editprop.c:238
bv_max_extras v_bv_special
Definition editprop.c:232
struct tile_vision_data * v_tile_vision
Definition editprop.c:239
char * v_string
Definition editprop.c:228
struct built_status * v_built
Definition editprop.c:231
bv_max_extras v_bv_roads
Definition editprop.c:233
gpointer v_pointer
Definition editprop.c:225
struct nation_type * v_nation
Definition editprop.c:235
struct nation_hash * v_nation_hash
Definition editprop.c:236
bv_max_extras v_bv_bases
Definition editprop.c:234
GdkPixbuf * v_pixbuf
Definition editprop.c:230
const char * v_const_string
Definition editprop.c:229
#define unit_tile(_pu)
Definition unit.h:395
static bool is_enemy_unit_tile(const struct tile *ptile, const struct player *pplayer)
Definition unit.h:418
#define unit_owner(_pu)
Definition unit.h:394
static bool is_non_allied_unit_tile(const struct tile *ptile, const struct player *pplayer)
Definition unit.h:430
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
#define unit_list_iterate_end
Definition unitlist.h:33
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:123
int utype_veteran_levels(const struct unit_type *punittype)
Definition unittype.c:2673
const char * utype_name_translation(const struct unit_type *punittype)
Definition unittype.c:1612
#define utype_fuel(ptype)
Definition unittype.h:825
#define vision_layer_iterate(v)
Definition vision.h:77
#define vision_layer_iterate_end
Definition vision.h:80