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

Freeciv-3.3

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