Freeciv-3.2: /fast/freeciv/nightly/S3_2/client/gui-gtk-4.0/editprop.c Source File

Freeciv-3.2

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-4.0 */
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()!!! */
96union 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. */
113struct 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
122struct pf_pattern {
123 bool negate;
124 char *text;
125};
126
127struct pf_conjunction {
128 struct pf_pattern conjunction[PF_MAX_CLAUSES];
129 int count;
130};
131
132struct 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****************************************************************************/
225union 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
243struct 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
254struct 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
390struct 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_text_changed(GtkEditable *text, 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****************************************************************************/
457struct 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****************************************************************************/
513struct 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****************************************************************************/
548struct 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****************************************************************************/
646struct 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) {
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 && (pcity == NULL
1019 || pplayers_allied(city_owner(pcity),
1020 unit_owner(vunit))));
1021 free(vunit);
1022
1023 return ret;
1024}
1025
1026/************************************************************************/
1029 static int get_next_unique_tag(void)
1030{
1031 static int tag_series = 0;
1032
1033 tag_series++;
1034 return tag_series;
1035}
1036
1037/************************************************************************/
1040 static struct propval *propval_copy(struct propval *pv)
1041{
1042 struct propval *pv_copy;
1043 size_t size;
1044
1045 if (!pv) {
1046 return NULL;
1047 }
1048
1049 pv_copy = fc_calloc(1, sizeof(*pv));
1050 pv_copy->valtype = pv->valtype;
1051
1052 switch (pv->valtype) {
1053 case VALTYPE_NONE:
1054 return pv_copy;
1055 case VALTYPE_INT:
1056 pv_copy->data.v_int = pv->data.v_int;
1057 return pv_copy;
1058 case VALTYPE_BOOL:
1059 pv_copy->data.v_bool = pv->data.v_bool;
1060 return pv_copy;
1061 case VALTYPE_STRING:
1062 pv_copy->data.v_string = fc_strdup(pv->data.v_string);
1063 pv_copy->must_free = TRUE;
1064 return pv_copy;
1065 case VALTYPE_PIXBUF:
1066 g_object_ref(pv->data.v_pixbuf);
1067 pv_copy->data.v_pixbuf = pv->data.v_pixbuf;
1068 pv_copy->must_free = TRUE;
1069 return pv_copy;
1070 case VALTYPE_BUILT_ARRAY:
1071 size = B_LAST * sizeof(struct built_status);
1072 pv_copy->data.v_pointer = fc_malloc(size);
1073 memcpy(pv_copy->data.v_pointer, pv->data.v_pointer, size);
1074 pv_copy->must_free = TRUE;
1075 return pv_copy;
1076 case VALTYPE_BV_SPECIAL:
1077 pv_copy->data.v_bv_special = pv->data.v_bv_special;
1078 return pv_copy;
1079 case VALTYPE_BV_ROADS:
1080 pv_copy->data.v_bv_roads = pv->data.v_bv_roads;
1081 return pv_copy;
1082 case VALTYPE_BV_BASES:
1083 pv_copy->data.v_bv_bases = pv->data.v_bv_bases;
1084 return pv_copy;
1085 case VALTYPE_NATION:
1086 pv_copy->data.v_nation = pv->data.v_nation;
1087 return pv_copy;
1088 case VALTYPE_GOV:
1089 pv_copy->data.v_gov = pv->data.v_gov;
1090 return pv_copy;
1091 case VALTYPE_NATION_HASH:
1092 pv_copy->data.v_nation_hash
1093 = nation_hash_copy(pv->data.v_nation_hash);
1094 pv_copy->must_free = TRUE;
1095 return pv_copy;
1096 case VALTYPE_INVENTIONS_ARRAY:
1097 pv_copy->data.v_bv_inventions = pv->data.v_bv_inventions;
1098 return pv_copy;
1099 case VALTYPE_TILE_VISION_DATA:
1100 size = sizeof(struct tile_vision_data);
1101 pv_copy->data.v_tile_vision = fc_malloc(size);
1102 pv_copy->data.v_tile_vision->tile_known
1103 = pv->data.v_tile_vision->tile_known;
1104 vision_layer_iterate(v) {
1105 pv_copy->data.v_tile_vision->tile_seen[v]
1106 = pv->data.v_tile_vision->tile_seen[v];
1107 } vision_layer_iterate_end;
1108 pv_copy->must_free = TRUE;
1109 return pv_copy;
1110 }
1111
1112 log_error("%s(): Unhandled value type %d for property value %p.",
1113 __FUNCTION__, pv->valtype, pv);
1114 pv_copy->data = pv->data;
1115 return pv_copy;
1116}
1117
1118/************************************************************************/
1122 static void propval_free(struct propval *pv)
1123{
1124 if (!pv) {
1125 return;
1126 }
1127
1128 propval_free_data(pv);
1129 free(pv);
1130}
1131
1132/************************************************************************/
1136 static void propval_free_data(struct propval *pv)
1137{
1138 if (!pv || !pv->must_free) {
1139 return;
1140 }
1141
1142 switch (pv->valtype) {
1143 case VALTYPE_NONE:
1144 case VALTYPE_INT:
1145 case VALTYPE_BOOL:
1146 case VALTYPE_BV_SPECIAL:
1147 case VALTYPE_BV_ROADS:
1148 case VALTYPE_BV_BASES:
1149 case VALTYPE_NATION:
1150 case VALTYPE_GOV:
1151 return;
1152 case VALTYPE_PIXBUF:
1153 g_object_unref(pv->data.v_pixbuf);
1154 return;
1155 case VALTYPE_STRING:
1156 case VALTYPE_BUILT_ARRAY:
1157 case VALTYPE_INVENTIONS_ARRAY:
1158 case VALTYPE_TILE_VISION_DATA:
1159 free(pv->data.v_pointer);
1160 return;
1161 case VALTYPE_NATION_HASH:
1162 nation_hash_destroy(pv->data.v_nation_hash);
1163 return;
1164 }
1165
1166 log_error("%s(): Unhandled request to free data %p (type %s).",
1167 __FUNCTION__, pv->data.v_pointer, valtype_get_name(pv->valtype));
1168}
1169
1170/************************************************************************/
1173 static bool propval_equal(struct propval *pva,
1174 struct propval *pvb)
1175{
1176 if (!pva || !pvb) {
1177 return pva == pvb;
1178 }
1179
1180 if (pva->valtype != pvb->valtype) {
1181 return FALSE;
1182 }
1183
1184 switch (pva->valtype) {
1185 case VALTYPE_NONE:
1186 return TRUE;
1187 case VALTYPE_INT:
1188 return pva->data.v_int == pvb->data.v_int;
1189 case VALTYPE_BOOL:
1190 return pva->data.v_bool == pvb->data.v_bool;
1191 case VALTYPE_STRING:
1192 if (pva->data.v_const_string != NULL
1193 && pvb->data.v_const_string != NULL) {
1194 return !strcmp(pva->data.v_const_string,
1195 pvb->data.v_const_string);
1196 }
1197 return pva->data.v_const_string == pvb->data.v_const_string;
1198 case VALTYPE_PIXBUF:
1199 return pva->data.v_pixbuf == pvb->data.v_pixbuf;
1200 case VALTYPE_BUILT_ARRAY:
1201 if (pva->data.v_pointer == pvb->data.v_pointer) {
1202 return TRUE;
1203 } else if (!pva->data.v_pointer || !pvb->data.v_pointer) {
1204 return FALSE;
1205 }
1206
1207 improvement_iterate(pimprove) {
1208 int id, vatb, vbtb;
1209 id = improvement_index(pimprove);
1210 vatb = pva->data.v_built[id].turn;
1211 vbtb = pvb->data.v_built[id].turn;
1212 if (vatb < 0 && vbtb < 0) {
1213 continue;
1214 }
1215 if (vatb != vbtb) {
1216 return FALSE;
1217 }
1218 } improvement_iterate_end;
1219 return TRUE;
1220 case VALTYPE_INVENTIONS_ARRAY:
1221 return BV_ARE_EQUAL(pva->data.v_bv_inventions, pvb->data.v_bv_inventions);
1222 case VALTYPE_BV_SPECIAL:
1223 return BV_ARE_EQUAL(pva->data.v_bv_special, pvb->data.v_bv_special);
1224 case VALTYPE_BV_ROADS:
1225 return BV_ARE_EQUAL(pva->data.v_bv_roads, pvb->data.v_bv_roads);
1226 case VALTYPE_BV_BASES:
1227 return BV_ARE_EQUAL(pva->data.v_bv_bases, pvb->data.v_bv_bases);
1228 case VALTYPE_NATION:
1229 return pva->data.v_nation == pvb->data.v_nation;
1230 case VALTYPE_NATION_HASH:
1231 return nation_hashes_are_equal(pva->data.v_nation_hash,
1232 pvb->data.v_nation_hash);
1233 case VALTYPE_GOV:
1234 return pva->data.v_gov == pvb->data.v_gov;
1235 case VALTYPE_TILE_VISION_DATA:
1236 if (!BV_ARE_EQUAL(pva->data.v_tile_vision->tile_known,
1237 pvb->data.v_tile_vision->tile_known)) {
1238 return FALSE;
1239 }
1240 vision_layer_iterate(v) {
1241 if (!BV_ARE_EQUAL(pva->data.v_tile_vision->tile_seen[v],
1242 pvb->data.v_tile_vision->tile_seen[v])) {
1243 return FALSE;
1244 }
1245 } vision_layer_iterate_end;
1246 return TRUE;
1247 }
1248
1249 log_error("%s(): Unhandled value type %d for property values %p and %p.",
1250 __FUNCTION__, pva->valtype, pva, pvb);
1251 return pva->data.v_pointer == pvb->data.v_pointer;
1252}
1253
1254/************************************************************************/
1260 static struct propstate *propstate_new(struct objprop *op,
1261 struct propval *pv)
1262{
1263 struct propstate *ps;
1264
1265 if (!op) {
1266 return NULL;
1267 }
1268
1269 ps = fc_calloc(1, sizeof(*ps));
1270 ps->property_id = objprop_get_id(op);
1271 ps->property_value = pv;
1272
1273 return ps;
1274}
1275
1276/************************************************************************/
1279 static void propstate_clear_value(struct propstate *ps)
1280{
1281 if (!ps) {
1282 return;
1283 }
1284
1285 propval_free(ps->property_value);
1286 ps->property_value = NULL;
1287}
1288
1289/************************************************************************/
1292 static void propstate_destroy(struct propstate *ps)
1293{
1294 if (!ps) {
1295 return;
1296 }
1297 propstate_clear_value(ps);
1298 free(ps);
1299}
1300
1301/************************************************************************/
1307 static void propstate_set_value(struct propstate *ps,
1308 struct propval *pv)
1309{
1310 if (!ps) {
1311 return;
1312 }
1313 propstate_clear_value(ps);
1314 ps->property_value = pv;
1315}
1316
1317/************************************************************************/
1322 static struct propval *propstate_get_value(struct propstate *ps)
1323{
1324 if (!ps) {
1325 return NULL;
1326 }
1327 return ps->property_value;
1328}
1329
1330/************************************************************************/
1334 static struct objbind *objbind_new(enum editor_object_type objtype,
1335 gpointer object)
1336{
1337 struct objbind *ob;
1338 int id;
1339
1340 if (object == NULL) {
1341 return NULL;
1342 }
1343
1344 id = objtype_get_id_from_object(objtype, object);
1345 if (id < 0) {
1346 return NULL;
1347 }
1348
1349 ob = fc_calloc(1, sizeof(*ob));
1350 ob->object_id = id;
1351 ob->objtype = objtype;
1352 ob->propstate_table = propstate_hash_new();
1353
1354 return ob;
1355}
1356
1357/************************************************************************/
1360 static gpointer objbind_get_object(struct objbind *ob)
1361{
1362 int id;
1363
1364 if (!ob) {
1365 return NULL;
1366 }
1367
1368 id = objbind_get_object_id(ob);
1369
1370 return objtype_get_object_from_id(ob->objtype, id);
1371}
1372
1373/************************************************************************/
1376 static int objbind_get_object_id(struct objbind *ob)
1377{
1378 if (NULL == ob) {
1379 return -1;
1380 }
1381 return ob->object_id;
1382}
1383
1384/************************************************************************/
1389 static void objbind_request_destroy_object(struct objbind *ob)
1390{
1391 struct connection *my_conn = &client.conn;
1392 enum editor_object_type objtype;
1393 int id;
1394
1395 if (!ob) {
1396 return;
1397 }
1398
1399 objtype = objbind_get_objtype(ob);
1400 if (objtype_is_conserved(objtype)) {
1401 return;
1402 }
1403
1404 id = objbind_get_object_id(ob);
1405
1406 switch (objtype) {
1407 case OBJTYPE_STARTPOS:
1408 dsend_packet_edit_startpos(my_conn, id, TRUE, 0);
1409 return;
1410 case OBJTYPE_UNIT:
1411 dsend_packet_edit_unit_remove_by_id(my_conn, id);
1412 return;
1413 case OBJTYPE_CITY:
1414 dsend_packet_edit_city_remove(my_conn, id);
1415 return;
1416 case OBJTYPE_PLAYER:
1417 dsend_packet_edit_player_remove(my_conn, id);
1418 return;
1419 case OBJTYPE_TILE:
1420 case OBJTYPE_GAME:
1421 case NUM_OBJTYPES:
1422 break;
1423 }
1424
1425 log_error("%s(): Unhandled request to destroy object %p (ID %d) of type "
1426 "%d (%s).", __FUNCTION__, objbind_get_object(ob), id, objtype,
1427 objtype_get_name(objtype));
1428}
1429
1430/************************************************************************/
1437 static struct propval *objbind_get_value_from_object(struct objbind *ob,
1438 struct objprop *op)
1439{
1440 enum editor_object_type objtype;
1441 enum object_property_ids propid;
1442 struct propval *pv;
1443
1444 if (!ob || !op) {
1445 return NULL;
1446 }
1447
1448 objtype = objbind_get_objtype(ob);
1449 propid = objprop_get_id(op);
1450
1451 pv = fc_calloc(1, sizeof(*pv));
1452 pv->valtype = objprop_get_valtype(op);
1453
1454 switch (objtype) {
1455 case OBJTYPE_TILE:
1456 {
1457 const struct tile *ptile = objbind_get_object(ob);
1458 int tile_x, tile_y, nat_x, nat_y;
1459
1460 if (NULL == ptile) {
1461 goto FAILED;
1462 }
1463
1464 index_to_map_pos(&tile_x, &tile_y, tile_index(ptile));
1465 index_to_native_pos(&nat_x, &nat_y, tile_index(ptile));
1466
1467 switch (propid) {
1468 case OPID_TILE_IMAGE:
1469 pv->data.v_pixbuf = create_tile_pixbuf(ptile);
1470 pv->must_free = TRUE;
1471 break;
1472#ifdef FREECIV_DEBUG
1473 case OPID_TILE_ADDRESS:
1474 pv->data.v_string = g_strdup_printf("%p", ptile);
1475 pv->must_free = TRUE;
1476 break;
1477#endif /* FREECIV_DEBUG */
1478 case OPID_TILE_TERRAIN:
1479 {
1480 const struct terrain *pterrain = tile_terrain(ptile);
1481
1482 if (NULL != pterrain) {
1483 pv->data.v_const_string = terrain_name_translation(pterrain);
1484 } else {
1485 pv->data.v_const_string = "";
1486 }
1487 }
1488 break;
1489 case OPID_TILE_RESOURCE:
1490 {
1491 const struct extra_type *presource = tile_resource(ptile);
1492
1493 if (NULL != presource) {
1494 pv->data.v_const_string = extra_name_translation(presource);
1495 } else {
1496 pv->data.v_const_string = "";
1497 }
1498 }
1499 break;
1500 case OPID_TILE_XY:
1501 pv->data.v_string = g_strdup_printf("(%d, %d)", tile_x, tile_y);
1502 pv->must_free = TRUE;
1503 break;
1504 case OPID_TILE_INDEX:
1505 pv->data.v_int = tile_index(ptile);
1506 break;
1507 case OPID_TILE_X:
1508 pv->data.v_int = tile_x;
1509 break;
1510 case OPID_TILE_Y:
1511 pv->data.v_int = tile_y;
1512 break;
1513 case OPID_TILE_NAT_X:
1514 pv->data.v_int = nat_x;
1515 break;
1516 case OPID_TILE_NAT_Y:
1517 pv->data.v_int = nat_y;
1518 break;
1519 case OPID_TILE_CONTINENT:
1520 pv->data.v_int = ptile->continent;
1521 break;
1522 case OPID_TILE_SPECIALS:
1523 BV_CLR_ALL(pv->data.v_bv_special);
1524 extra_type_by_cause_iterate(EC_SPECIAL, pextra) {
1525 if (tile_has_extra(ptile, pextra)) {
1526 BV_SET(pv->data.v_bv_special, pextra->data.special_idx);
1527 }
1528 } extra_type_by_cause_iterate_end;
1529 break;
1530 case OPID_TILE_ROADS:
1531 BV_CLR_ALL(pv->data.v_bv_roads);
1532 extra_type_by_cause_iterate(EC_ROAD, pextra) {
1533 if (tile_has_extra(ptile, pextra)) {
1534 BV_SET(pv->data.v_bv_roads, road_number(extra_road_get(pextra)));
1535 }
1536 } extra_type_by_cause_iterate_end;
1537 break;
1538 case OPID_TILE_BASES:
1539 BV_CLR_ALL(pv->data.v_bv_bases);
1540 extra_type_by_cause_iterate(EC_BASE, pextra) {
1541 if (tile_has_extra(ptile, pextra)) {
1542 BV_SET(pv->data.v_bv_bases, base_number(extra_base_get(pextra)));
1543 }
1544 } extra_type_by_cause_iterate_end;
1545 break;
1546 case OPID_TILE_VISION:
1547 pv->data.v_tile_vision = fc_malloc(sizeof(struct tile_vision_data));
1548
1549 /* The server saves the known tiles and the player vision in special
1550 * bitvectors with the number of tiles as index. Here we want the
1551 * information for one tile. Thus, the data is transformed to
1552 * bitvectors with the number of player slots as index. */
1553 BV_CLR_ALL(pv->data.v_tile_vision->tile_known);
1554 players_iterate(pplayer) {
1555 if (dbv_isset(&pplayer->tile_known, tile_index(ptile))) {
1556 BV_SET(pv->data.v_tile_vision->tile_known,
1557 player_index(pplayer));
1558 }
1559 } players_iterate_end;
1560
1561 vision_layer_iterate(v) {
1562 BV_CLR_ALL(pv->data.v_tile_vision->tile_seen[v]);
1563 players_iterate(pplayer) {
1564 if (fc_funcs->player_tile_vision_get(ptile, pplayer, v)) {
1565 BV_SET(pv->data.v_tile_vision->tile_seen[v],
1566 player_index(pplayer));
1567 }
1568 } players_iterate_end;
1569 } vision_layer_iterate_end;
1570 pv->must_free = TRUE;
1571 break;
1572 case OPID_TILE_LABEL:
1573 if (ptile->label != NULL) {
1574 pv->data.v_const_string = ptile->label;
1575 } else {
1576 pv->data.v_const_string = "";
1577 }
1578 break;
1579 default:
1580 log_error("%s(): Unhandled request for value of property %d "
1581 "(%s) from object of type \"%s\".", __FUNCTION__,
1582 propid, objprop_get_name(op), objtype_get_name(objtype));
1583 goto FAILED;
1584 }
1585 }
1586 return pv;
1587
1588 case OBJTYPE_STARTPOS:
1589 {
1590 const struct startpos *psp = objbind_get_object(ob);
1591 const struct tile *ptile;
1592
1593 if (NULL == psp) {
1594 goto FAILED;
1595 }
1596
1597 switch (propid) {
1598 case OPID_STARTPOS_IMAGE:
1599 ptile = startpos_tile(psp);
1600 pv->data.v_pixbuf = create_tile_pixbuf(ptile);
1601 pv->must_free = TRUE;
1602 break;
1603 case OPID_STARTPOS_XY:
1604 ptile = startpos_tile(psp);
1605 pv->data.v_string = g_strdup_printf("(%d, %d)", TILE_XY(ptile));
1606 pv->must_free = TRUE;
1607 break;
1608 case OPID_STARTPOS_EXCLUDE:
1609 pv->data.v_bool = startpos_is_excluding(psp);
1610 break;
1611 case OPID_STARTPOS_NATIONS:
1612 pv->data.v_nation_hash = nation_hash_copy(startpos_raw_nations(psp));
1613 pv->must_free = TRUE;
1614 break;
1615 default:
1616 log_error("%s(): Unhandled request for value of property %d "
1617 "(%s) from object of type \"%s\".", __FUNCTION__,
1618 propid, objprop_get_name(op), objtype_get_name(objtype));
1619 goto FAILED;
1620 }
1621 }
1622 return pv;
1623
1624 case OBJTYPE_UNIT:
1625 {
1626 struct unit *punit = objbind_get_object(ob);
1627
1628 if (NULL == punit) {
1629 goto FAILED;
1630 }
1631
1632 switch (propid) {
1633 case OPID_UNIT_IMAGE:
1634 pv->data.v_pixbuf = create_unit_pixbuf(punit);
1635 pv->must_free = TRUE;
1636 break;
1637#ifdef FREECIV_DEBUG
1638 case OPID_UNIT_ADDRESS:
1639 pv->data.v_string = g_strdup_printf("%p", punit);
1640 pv->must_free = TRUE;
1641 break;
1642#endif /* FREECIV_DEBUG */
1643 case OPID_UNIT_XY:
1644 {
1645 const struct tile *ptile = unit_tile(punit);
1646
1647 pv->data.v_string = g_strdup_printf("(%d, %d)", TILE_XY(ptile));
1648 pv->must_free = TRUE;
1649 }
1650 break;
1651 case OPID_UNIT_ID:
1652 pv->data.v_int = punit->id;
1653 break;
1654 case OPID_UNIT_TYPE:
1655 {
1656 const struct unit_type *putype = unit_type_get(punit);
1657
1658 pv->data.v_const_string = utype_name_translation(putype);
1659 }
1660 break;
1661 case OPID_UNIT_MOVES_LEFT:
1662 pv->data.v_int = punit->moves_left;
1663 break;
1664 case OPID_UNIT_FUEL:
1665 pv->data.v_int = punit->fuel;
1666 break;
1667 case OPID_UNIT_MOVED:
1668 pv->data.v_bool = punit->moved;
1669 break;
1670 case OPID_UNIT_DONE_MOVING:
1671 pv->data.v_bool = punit->done_moving;
1672 break;
1673 case OPID_UNIT_HP:
1674 pv->data.v_int = punit->hp;
1675 break;
1676 case OPID_UNIT_VETERAN:
1677 pv->data.v_int = punit->veteran;
1678 break;
1679 case OPID_UNIT_STAY:
1680 pv->data.v_bool = punit->stay;
1681 break;
1682 default:
1683 log_error("%s(): Unhandled request for value of property %d "
1684 "(%s) from object of type \"%s\".", __FUNCTION__,
1685 propid, objprop_get_name(op), objtype_get_name(objtype));
1686 goto FAILED;
1687 }
1688 }
1689 return pv;
1690
1691 case OBJTYPE_CITY:
1692 {
1693 const struct city *pcity = objbind_get_object(ob);
1694
1695 if (NULL == pcity) {
1696 goto FAILED;
1697 }
1698
1699 switch (propid) {
1700 case OPID_CITY_IMAGE:
1701 pv->data.v_pixbuf = create_city_pixbuf(pcity);
1702 pv->must_free = TRUE;
1703 break;
1704#ifdef FREECIV_DEBUG
1705 case OPID_CITY_ADDRESS:
1706 pv->data.v_string = g_strdup_printf("%p", pcity);
1707 pv->must_free = TRUE;
1708 break;
1709#endif /* FREECIV_DEBUG */
1710 case OPID_CITY_XY:
1711 {
1712 const struct tile *ptile = city_tile(pcity);
1713
1714 pv->data.v_string = g_strdup_printf("(%d, %d)", TILE_XY(ptile));
1715 pv->must_free = TRUE;
1716 }
1717 break;
1718 case OPID_CITY_ID:
1719 pv->data.v_int = pcity->id;
1720 break;
1721 case OPID_CITY_NAME:
1722 pv->data.v_const_string = pcity->name;
1723 break;
1724 case OPID_CITY_SIZE:
1725 pv->data.v_int = city_size_get(pcity);
1726 break;
1727 case OPID_CITY_HISTORY:
1728 pv->data.v_int = pcity->history;
1729 break;
1730 case OPID_CITY_BUILDINGS:
1731 pv->data.v_built = fc_malloc(sizeof(pcity->built));
1732 memcpy(pv->data.v_built, pcity->built, sizeof(pcity->built));
1733 pv->must_free = TRUE;
1734 break;
1735 case OPID_CITY_FOOD_STOCK:
1736 pv->data.v_int = pcity->food_stock;
1737 break;
1738 case OPID_CITY_SHIELD_STOCK:
1739 pv->data.v_int = pcity->shield_stock;
1740 break;
1741 default:
1742 log_error("%s(): Unhandled request for value of property %d "
1743 "(%s) from object of type \"%s\".", __FUNCTION__,
1744 propid, objprop_get_name(op), objtype_get_name(objtype));
1745 goto FAILED;
1746 }
1747 }
1748 return pv;
1749
1750 case OBJTYPE_PLAYER:
1751 {
1752 const struct player *pplayer = objbind_get_object(ob);
1753 const struct research *presearch;
1754
1755 if (NULL == pplayer) {
1756 goto FAILED;
1757 }
1758
1759 switch (propid) {
1760 case OPID_PLAYER_NAME:
1761 pv->data.v_const_string = pplayer->name;
1762 break;
1763 case OPID_PLAYER_NATION:
1764 pv->data.v_nation = nation_of_player(pplayer);
1765 break;
1766 case OPID_PLAYER_GOV:
1767 pv->data.v_gov = pplayer->government;
1768 break;
1769 case OPID_PLAYER_AGE:
1770 pv->data.v_int = pplayer->turns_alive;
1771 break;
1772#ifdef FREECIV_DEBUG
1773 case OPID_PLAYER_ADDRESS:
1774 pv->data.v_string = g_strdup_printf("%p", pplayer);
1775 pv->must_free = TRUE;
1776 break;
1777#endif /* FREECIV_DEBUG */
1778 case OPID_PLAYER_INVENTIONS:
1779 presearch = research_get(pplayer);
1780 BV_CLR_ALL(pv->data.v_bv_inventions);
1781 advance_index_iterate(A_FIRST, tech) {
1782 if (TECH_KNOWN == research_invention_state(presearch, tech)) {
1783 BV_SET(pv->data.v_bv_inventions, tech);
1784 }
1785 } advance_index_iterate_end;
1786 break;
1787 case OPID_PLAYER_SCENARIO_RESERVED:
1788 pv->data.v_bool = player_has_flag(pplayer, PLRF_SCENARIO_RESERVED);
1789 break;
1790 case OPID_PLAYER_SELECT_WEIGHT:
1791 pv->data.v_int = pplayer->autoselect_weight;
1792 break;
1793 case OPID_PLAYER_SCIENCE:
1794 presearch = research_get(pplayer);
1795 pv->data.v_int = presearch->bulbs_researched;
1796 break;
1797 case OPID_PLAYER_GOLD:
1798 pv->data.v_int = pplayer->economic.gold;
1799 break;
1800 default:
1801 log_error("%s(): Unhandled request for value of property %d "
1802 "(%s) from object of type \"%s\".", __FUNCTION__,
1803 propid, objprop_get_name(op), objtype_get_name(objtype));
1804 goto FAILED;
1805 }
1806 }
1807 return pv;
1808
1809 case OBJTYPE_GAME:
1810 {
1811 const struct civ_game *pgame = objbind_get_object(ob);
1812
1813 if (NULL == pgame) {
1814 goto FAILED;
1815 }
1816
1817 switch (propid) {
1818 case OPID_GAME_SCENARIO:
1819 pv->data.v_bool = pgame->scenario.is_scenario;
1820 break;
1821 case OPID_GAME_SCENARIO_NAME:
1822 pv->data.v_const_string = pgame->scenario.name;
1823 break;
1824 case OPID_GAME_SCENARIO_AUTHORS:
1825 pv->data.v_const_string = pgame->scenario.authors;
1826 break;
1827 case OPID_GAME_SCENARIO_DESC:
1828 pv->data.v_const_string = pgame->scenario_desc.description;
1829 break;
1830 case OPID_GAME_SCENARIO_RANDSTATE:
1831 pv->data.v_bool = pgame->scenario.save_random;
1832 break;
1833 case OPID_GAME_SCENARIO_PLAYERS:
1834 pv->data.v_bool = pgame->scenario.players;
1835 break;
1836 case OPID_GAME_STARTPOS_NATIONS:
1837 pv->data.v_bool = pgame->scenario.startpos_nations;
1838 break;
1839 case OPID_GAME_PREVENT_CITIES:
1840 pv->data.v_bool = pgame->scenario.prevent_new_cities;
1841 break;
1842 case OPID_GAME_LAKE_FLOODING:
1843 pv->data.v_bool = pgame->scenario.lake_flooding;
1844 break;
1845 case OPID_GAME_RULESET_LOCKED:
1846 pv->data.v_bool = pgame->scenario.ruleset_locked;
1847 break;
1848 default:
1849 log_error("%s(): Unhandled request for value of property %d "
1850 "(%s) from object of type \"%s\".", __FUNCTION__,
1851 propid, objprop_get_name(op), objtype_get_name(objtype));
1852 goto FAILED;
1853 }
1854 }
1855 return pv;
1856
1857 case NUM_OBJTYPES:
1858 break;
1859 }
1860
1861 log_error("%s(): Unhandled request for object type \"%s\" (nb %d).",
1862 __FUNCTION__, objtype_get_name(objtype), objtype);
1863
1864 FAILED:
1865 if (NULL != pv) {
1866 free(pv);
1867 }
1868 return NULL;
1869}
1870
1871/************************************************************************/
1875 static bool objbind_get_allowed_value_span(struct objbind *ob,
1876 struct objprop *op,
1877 double *pmin,
1878 double *pmax,
1879 double *pstep,
1880 double *pbig_step)
1881{
1882 enum editor_object_type objtype;
1883 enum object_property_ids propid;
1884 double dummy;
1885
1886 /* Fill the values with something. */
1887 if (NULL != pmin) {
1888 *pmin = 0;
1889 } else {
1890 pmin = &dummy;
1891 }
1892 if (NULL != pmax) {
1893 *pmax = 1;
1894 } else {
1895 pmax = &dummy;
1896 }
1897 if (NULL != pstep) {
1898 *pstep = 1;
1899 } else {
1900 pstep = &dummy;
1901 }
1902 if (NULL != pbig_step) {
1903 *pbig_step = 1;
1904 } else {
1905 pbig_step = &dummy;
1906 }
1907
1908 if (!ob || !op) {
1909 return FALSE;
1910 }
1911
1912 propid = objprop_get_id(op);
1913 objtype = objbind_get_objtype(ob);
1914
1915 switch (objtype) {
1916 case OBJTYPE_TILE:
1917 case OBJTYPE_STARTPOS:
1918 log_error("%s(): Unhandled request for value range of property %d (%s) "
1919 "from object of type \"%s\".", __FUNCTION__,
1920 propid, objprop_get_name(op), objtype_get_name(objtype));
1921 return FALSE;
1922
1923 case OBJTYPE_UNIT:
1924 {
1925 const struct unit *punit = objbind_get_object(ob);
1926 const struct unit_type *putype;
1927
1928 if (NULL == punit) {
1929 return FALSE;
1930 }
1931
1932 putype = unit_type_get(punit);
1933
1934 switch (propid) {
1935 case OPID_UNIT_MOVES_LEFT:
1936 *pmin = 0;
1937 *pmax = MAX_MOVE_FRAGS;
1938 *pstep = 1;
1939 *pbig_step = 5;
1940 return TRUE;
1941 case OPID_UNIT_FUEL:
1942 *pmin = 0;
1943 *pmax = utype_fuel(putype);
1944 *pstep = 1;
1945 *pbig_step = 5;
1946 return TRUE;
1947 case OPID_UNIT_HP:
1948 *pmin = 1;
1949 *pmax = putype->hp;
1950 *pstep = 1;
1951 *pbig_step = 10;
1952 return TRUE;
1953 case OPID_UNIT_VETERAN:
1954 *pmin = 0;
1955 *pmax = utype_veteran_levels(putype) - 1;
1956 *pstep = 1;
1957 *pbig_step = 3;
1958 return TRUE;
1959 default:
1960 break;
1961 }
1962 }
1963 log_error("%s(): Unhandled request for value range of property %d (%s) "
1964 "from object of type \"%s\".", __FUNCTION__,
1965 propid, objprop_get_name(op), objtype_get_name(objtype));
1966 return FALSE;
1967
1968 case OBJTYPE_CITY:
1969 {
1970 const struct city *pcity = objbind_get_object(ob);
1971
1972 if (NULL == pcity) {
1973 return FALSE;
1974 }
1975
1976 switch (propid) {
1977 case OPID_CITY_SIZE:
1978 *pmin = 1;
1979 *pmax = MAX_CITY_SIZE;
1980 *pstep = 1;
1981 *pbig_step = 5;
1982 return TRUE;
1983 case OPID_CITY_HISTORY:
1984 *pmin = 0;
1985 *pmax = USHRT_MAX;
1986 *pstep = 1;
1987 *pbig_step = 10;
1988 return TRUE;
1989 case OPID_CITY_FOOD_STOCK:
1990 *pmin = 0;
1991 *pmax = city_granary_size(city_size_get(pcity));
1992 *pstep = 1;
1993 *pbig_step = 5;
1994 return TRUE;
1995 case OPID_CITY_SHIELD_STOCK:
1996 *pmin = 0;
1997 *pmax = USHRT_MAX; /* Limited to uint16 by city info packet. */
1998 *pstep = 1;
1999 *pbig_step = 10;
2000 return TRUE;
2001 default:
2002 break;
2003 }
2004 }
2005 log_error("%s(): Unhandled request for value range of property %d (%s) "
2006 "from object of type \"%s\".", __FUNCTION__,
2007 propid, objprop_get_name(op), objtype_get_name(objtype));
2008 return FALSE;
2009
2010 case OBJTYPE_PLAYER:
2011 switch (propid) {
2012 case OPID_PLAYER_SCIENCE:
2013 *pmin = 0;
2014 *pmax = 1000000; /* Arbitrary. */
2015 *pstep = 1;
2016 *pbig_step = 100;
2017 return TRUE;
2018 case OPID_PLAYER_GOLD:
2019 *pmin = 0;
2020 *pmax = 1000000; /* Arbitrary. */
2021 *pstep = 1;
2022 *pbig_step = 100;
2023 return TRUE;
2024 case OPID_PLAYER_SELECT_WEIGHT:
2025 *pmin = -1;
2026 *pmax = 10000; /* Keep it under SINT16 */
2027 *pstep = 1;
2028 *pbig_step = 10;
2029 return TRUE;
2030 default:
2031 break;
2032 }
2033 log_error("%s(): Unhandled request for value range of property %d (%s) "
2034 "from object of type \"%s\".", __FUNCTION__,
2035 propid, objprop_get_name(op), objtype_get_name(objtype));
2036 return FALSE;
2037
2038 case OBJTYPE_GAME:
2039 log_error("%s(): Unhandled request for value range of property %d (%s) "
2040 "from object of type \"%s\".", __FUNCTION__,
2041 propid, objprop_get_name(op), objtype_get_name(objtype));
2042 return FALSE;
2043
2044 case NUM_OBJTYPES:
2045 break;
2046 }
2047
2048 log_error("%s(): Unhandled request for object type \"%s\" (nb %d).",
2049 __FUNCTION__, objtype_get_name(objtype), objtype);
2050 return FALSE;
2051}
2052
2053/************************************************************************/
2056 static void objbind_clear_modified_value(struct objbind *ob,
2057 struct objprop *op)
2058{
2059 if (!ob || !op || !ob->propstate_table) {
2060 return;
2061 }
2062
2063 propstate_hash_remove(ob->propstate_table, objprop_get_id(op));
2064}
2065
2066/************************************************************************/
2070 static bool objbind_property_is_modified(struct objbind *ob,
2071 struct objprop *op)
2072{
2073 if (!ob || !op) {
2074 return FALSE;
2075 }
2076
2077 if (objprop_is_readonly(op)) {
2078 return FALSE;
2079 }
2080
2081 return propstate_hash_lookup(ob->propstate_table,
2082 objprop_get_id(op), NULL);
2083}
2084
2085/************************************************************************/
2089 static bool objbind_has_modified_properties(struct objbind *ob)
2090{
2091 if (!ob) {
2092 return FALSE;
2093 }
2094
2095 return (0 < propstate_hash_size(ob->propstate_table));
2096}
2097
2098/************************************************************************/
2101 static void objbind_clear_all_modified_values(struct objbind *ob)
2102{
2103 if (!ob) {
2104 return;
2105 }
2106 propstate_hash_clear(ob->propstate_table);
2107}
2108
2109/************************************************************************/
2115 static bool objbind_set_modified_value(struct objbind *ob,
2116 struct objprop *op,
2117 struct propval *pv)
2118{
2119 struct propstate *ps;
2120 bool equal;
2121 struct propval *pv_old, *pv_copy;
2122 enum object_property_ids propid;
2123
2124 if (!ob || !op) {
2125 return FALSE;
2126 }
2127
2128 propid = objprop_get_id(op);
2129
2130 pv_old = objbind_get_value_from_object(ob, op);
2131 if (!pv_old) {
2132 return FALSE;
2133 }
2134
2135 equal = propval_equal(pv, pv_old);
2136 propval_free(pv_old);
2137
2138 if (equal) {
2139 objbind_clear_modified_value(ob, op);
2140 return FALSE;
2141 }
2142
2143 pv_copy = propval_copy(pv);
2144
2145 if (propstate_hash_lookup(ob->propstate_table, propid, &ps)) {
2146 propstate_set_value(ps, pv_copy);
2147 } else {
2148 ps = propstate_new(op, pv_copy);
2149 propstate_hash_insert(ob->propstate_table, propid, ps);
2150 }
2151
2152 return TRUE;
2153}
2154
2155/************************************************************************/
2161 static struct propval *objbind_get_modified_value(struct objbind *ob,
2162 struct objprop *op)
2163{
2164 struct propstate *ps;
2165
2166 if (!ob || !op) {
2167 return NULL;
2168 }
2169
2170 if (propstate_hash_lookup(ob->propstate_table, objprop_get_id(op), &ps)) {
2171 return propstate_get_value(ps);
2172 } else {
2173 return NULL;
2174 }
2175}
2176
2177/************************************************************************/
2180 static void objbind_destroy(struct objbind *ob)
2181{
2182 if (!ob) {
2183 return;
2184 }
2185 if (ob->propstate_table) {
2186 propstate_hash_destroy(ob->propstate_table);
2187 ob->propstate_table = NULL;
2188 }
2189 if (ob->rowref) {
2190 gtk_tree_row_reference_free(ob->rowref);
2191 ob->rowref = NULL;
2192 }
2193 free(ob);
2194}
2195
2196/************************************************************************/
2199 static enum editor_object_type objbind_get_objtype(const struct objbind *ob)
2200{
2201 if (!ob) {
2202 return NUM_OBJTYPES;
2203 }
2204 return ob->objtype;
2205}
2206
2207/************************************************************************/
2210 static void objbind_bind_properties(struct objbind *ob,
2211 struct property_page *pp)
2212{
2213 if (!ob) {
2214 return;
2215 }
2216 ob->parent_property_page = pp;
2217}
2218
2219/************************************************************************/
2224 static void objbind_pack_current_values(struct objbind *ob,
2225 union packetdata pd)
2226{
2227 enum editor_object_type objtype;
2228
2229 if (!ob || !pd.pointers.v_pointer1) {
2230 return;
2231 }
2232
2233 objtype = objbind_get_objtype(ob);
2234
2235 switch (objtype) {
2236 case OBJTYPE_TILE:
2237 {
2238 struct packet_edit_tile *packet = pd.tile;
2239 const struct tile *ptile = objbind_get_object(ob);
2240
2241 if (NULL == ptile) {
2242 return;
2243 }
2244
2245 packet->tile = tile_index(ptile);
2246 packet->extras = *tile_extras(ptile);
2247 /* TODO: Set more packet fields. */
2248 }
2249 return;
2250
2251 case OBJTYPE_STARTPOS:
2252 {
2253 struct packet_edit_startpos_full *packet = pd.startpos;
2254 const struct startpos *psp = objbind_get_object(ob);
2255
2256 if (NULL != psp) {
2257 startpos_pack(psp, packet);
2258 }
2259 }
2260 return;
2261
2262 case OBJTYPE_UNIT:
2263 {
2264 struct packet_edit_unit *packet = pd.unit;
2265 const struct unit *punit = objbind_get_object(ob);
2266
2267 if (NULL == punit) {
2268 return;
2269 }
2270
2271 packet->id = punit->id;
2272 packet->moves_left = punit->moves_left;
2273 packet->fuel = punit->fuel;
2274 packet->moved = punit->moved;
2275 packet->done_moving = punit->done_moving;
2276 packet->hp = punit->hp;
2277 packet->veteran = punit->veteran;
2278 packet->stay = punit->stay;
2279 /* TODO: Set more packet fields. */
2280 }
2281 return;
2282
2283 case OBJTYPE_CITY:
2284 {
2285 struct packet_edit_city *packet = pd.city;
2286 const struct city *pcity = objbind_get_object(ob);
2287 int i;
2288
2289 if (NULL == pcity) {
2290 return;
2291 }
2292
2293 packet->id = pcity->id;
2294 sz_strlcpy(packet->name, pcity->name);
2295 packet->size = city_size_get(pcity);
2296 packet->history = pcity->history;
2297 for (i = 0; i < B_LAST; i++) {
2298 packet->built[i] = pcity->built[i].turn;
2299 }
2300 packet->food_stock = pcity->food_stock;
2301 packet->shield_stock = pcity->shield_stock;
2302 /* TODO: Set more packet fields. */
2303 }
2304 return;
2305
2306 case OBJTYPE_PLAYER:
2307 {
2308 struct packet_edit_player *packet = pd.player;
2309 const struct player *pplayer = objbind_get_object(ob);
2310 const struct nation_type *pnation;
2311 const struct research *presearch;
2312
2313 if (NULL == pplayer) {
2314 return;
2315 }
2316
2317 packet->id = player_number(pplayer);
2318 sz_strlcpy(packet->name, pplayer->name);
2319 pnation = nation_of_player(pplayer);
2320 packet->nation = nation_index(pnation);
2321 presearch = research_get(pplayer);
2322 advance_index_iterate(A_FIRST, tech) {
2323 packet->inventions[tech]
2324 = TECH_KNOWN == research_invention_state(presearch, tech);
2325 } advance_index_iterate_end;
2326 packet->autoselect_weight = pplayer->autoselect_weight;
2327 packet->gold = pplayer->economic.gold;
2328 packet->government = government_index(pplayer->government);
2329 packet->scenario_reserved = player_has_flag(pplayer, PLRF_SCENARIO_RESERVED);
2330 /* TODO: Set more packet fields. */
2331 }
2332 return;
2333
2334 case OBJTYPE_GAME:
2335 {
2336 struct packet_edit_game *packet = pd.game.game;
2337 const struct civ_game *pgame = objbind_get_object(ob);
2338
2339 if (NULL == pgame) {
2340 return;
2341 }
2342
2343 packet->scenario = pgame->scenario.is_scenario;
2344 sz_strlcpy(packet->scenario_name, pgame->scenario.name);
2345 sz_strlcpy(packet->scenario_authors, pgame->scenario.authors);
2346 sz_strlcpy(pd.game.desc->scenario_desc, pgame->scenario_desc.description);
2347 packet->scenario_random = pgame->scenario.save_random;
2348 packet->scenario_players = pgame->scenario.players;
2349 packet->startpos_nations = pgame->scenario.startpos_nations;
2350 packet->prevent_new_cities = pgame->scenario.prevent_new_cities;
2351 packet->lake_flooding = pgame->scenario.lake_flooding;
2352 }
2353 return;
2354
2355 case NUM_OBJTYPES:
2356 break;
2357 }
2358
2359 log_error("%s(): Unhandled object type %s (nb %d).", __FUNCTION__,
2360 objtype_get_name(objtype), objtype);
2361}
2362
2363/************************************************************************/
2366 static void objbind_pack_modified_value(struct objbind *ob,
2367 struct objprop *op,
2368 union packetdata pd)
2369{
2370 struct propval *pv;
2371 enum editor_object_type objtype;
2372 enum object_property_ids propid;
2373
2374 if (!op || !ob || !pd.pointers.v_pointer1) {
2375 return;
2376 }
2377
2378 if (NULL == objbind_get_object(ob)) {
2379 return;
2380 }
2381
2382 if (objprop_is_readonly(op) || !objbind_property_is_modified(ob, op)) {
2383 return;
2384 }
2385
2386 pv = objbind_get_modified_value(ob, op);
2387 if (!pv) {
2388 return;
2389 }
2390
2391 objtype = objbind_get_objtype(ob);
2392 propid = objprop_get_id(op);
2393
2394 switch (objtype) {
2395 case OBJTYPE_TILE:
2396 {
2397 struct packet_edit_tile *packet = pd.tile;
2398
2399 switch (propid) {
2400 case OPID_TILE_SPECIALS:
2401 extra_type_by_cause_iterate(EC_SPECIAL, pextra) {
2402 if (BV_ISSET(pv->data.v_bv_special, pextra->data.special_idx)) {
2403 BV_SET(packet->extras, pextra->data.special_idx);
2404 } else {
2405 BV_CLR(packet->extras, pextra->data.special_idx);
2406 }
2407 } extra_type_by_cause_iterate_end;
2408 return;
2409 case OPID_TILE_ROADS:
2410 extra_type_by_cause_iterate(EC_ROAD, pextra) {
2411 int ridx = road_number(extra_road_get(pextra));
2412
2413 if (BV_ISSET(pv->data.v_bv_roads, ridx)) {
2414 BV_SET(packet->extras, extra_index(pextra));
2415 } else {
2416 BV_CLR(packet->extras, extra_index(pextra));
2417 }
2418 } extra_type_by_cause_iterate_end;
2419 return;
2420 case OPID_TILE_BASES:
2421 extra_type_by_cause_iterate(EC_BASE, pextra) {
2422 int bidx = base_number(extra_base_get(pextra));
2423
2424 if (BV_ISSET(pv->data.v_bv_bases, bidx)) {
2425 BV_SET(packet->extras, extra_index(pextra));
2426 } else {
2427 BV_CLR(packet->extras, extra_index(pextra));
2428 }
2429 } extra_type_by_cause_iterate_end;
2430 return;
2431 case OPID_TILE_LABEL:
2432 sz_strlcpy(packet->label, pv->data.v_string);
2433 return;
2434 default:
2435 break;
2436 }
2437 }
2438 log_error("%s(): Unhandled request to pack value of property "
2439 "%d (%s) from object of type \"%s\".", __FUNCTION__,
2440 propid, objprop_get_name(op), objtype_get_name(objtype));
2441 return;
2442
2443 case OBJTYPE_STARTPOS:
2444 {
2445 struct packet_edit_startpos_full *packet = pd.startpos;
2446
2447 switch (propid) {
2448 case OPID_STARTPOS_EXCLUDE:
2449 packet->exclude = pv->data.v_bool;
2450 return;
2451 case OPID_STARTPOS_NATIONS:
2452 BV_CLR_ALL(packet->nations);
2453 nation_hash_iterate(pv->data.v_nation_hash, pnation) {
2454 BV_SET(packet->nations, nation_number(pnation));
2455 } nation_hash_iterate_end;
2456 return;
2457 default:
2458 break;
2459 }
2460 }
2461 log_error("%s(): Unhandled request to pack value of property "
2462 "%d (%s) from object of type \"%s\".", __FUNCTION__,
2463 propid, objprop_get_name(op), objtype_get_name(objtype));
2464 return;
2465
2466 case OBJTYPE_UNIT:
2467 {
2468 struct packet_edit_unit *packet = pd.unit;
2469
2470 switch (propid) {
2471 case OPID_UNIT_MOVES_LEFT:
2472 packet->moves_left = pv->data.v_int;
2473 return;
2474 case OPID_UNIT_FUEL:
2475 packet->fuel = pv->data.v_int;
2476 return;
2477 case OPID_UNIT_MOVED:
2478 packet->moved = pv->data.v_bool;
2479 return;
2480 case OPID_UNIT_DONE_MOVING:
2481 packet->done_moving = pv->data.v_bool;
2482 return;
2483 case OPID_UNIT_HP:
2484 packet->hp = pv->data.v_int;
2485 return;
2486 case OPID_UNIT_VETERAN:
2487 packet->veteran = pv->data.v_int;
2488 return;
2489 case OPID_UNIT_STAY:
2490 packet->stay = pv->data.v_bool;
2491 return;
2492 default:
2493 break;
2494 }
2495 }
2496 log_error("%s(): Unhandled request to pack value of property "
2497 "%d (%s) from object of type \"%s\".", __FUNCTION__,
2498 propid, objprop_get_name(op), objtype_get_name(objtype));
2499 return;
2500
2501 case OBJTYPE_CITY:
2502 {
2503 struct packet_edit_city *packet = pd.city;
2504
2505 switch (propid) {
2506 case OPID_CITY_NAME:
2507 sz_strlcpy(packet->name, pv->data.v_string);
2508 return;
2509 case OPID_CITY_SIZE:
2510 packet->size = pv->data.v_int;
2511 return;
2512 case OPID_CITY_HISTORY:
2513 packet->history = pv->data.v_int;
2514 return;
2515 case OPID_CITY_FOOD_STOCK:
2516 packet->food_stock = pv->data.v_int;
2517 return;
2518 case OPID_CITY_SHIELD_STOCK:
2519 packet->shield_stock = pv->data.v_int;
2520 return;
2521 case OPID_CITY_BUILDINGS:
2522 {
2523 int i;
2524
2525 for (i = 0; i < B_LAST; i++) {
2526 packet->built[i] = pv->data.v_built[i].turn;
2527 }
2528 }
2529 return;
2530 default:
2531 break;
2532 }
2533 }
2534 log_error("%s(): Unhandled request to pack value of property "
2535 "%d (%s) from object of type \"%s\".", __FUNCTION__,
2536 propid, objprop_get_name(op), objtype_get_name(objtype));
2537 return;
2538
2539 case OBJTYPE_PLAYER:
2540 {
2541 struct packet_edit_player *packet = pd.player;
2542
2543 switch (propid) {
2544 case OPID_PLAYER_NAME:
2545 sz_strlcpy(packet->name, pv->data.v_string);
2546 return;
2547 case OPID_PLAYER_NATION:
2548 packet->nation = nation_index(pv->data.v_nation);
2549 return;
2550 case OPID_PLAYER_GOV:
2551 packet->government = government_index(pv->data.v_gov);
2552 return;
2553 case OPID_PLAYER_INVENTIONS:
2554 advance_index_iterate(A_FIRST, tech) {
2555 packet->inventions[tech] = BV_ISSET(pv->data.v_bv_inventions, tech);
2556 } advance_index_iterate_end;
2557 return;
2558 case OPID_PLAYER_SCENARIO_RESERVED:
2559 packet->scenario_reserved = pv->data.v_bool;
2560 return;
2561 case OPID_PLAYER_SELECT_WEIGHT:
2562 packet->autoselect_weight = pv->data.v_int;
2563 return;
2564 case OPID_PLAYER_SCIENCE:
2565 packet->bulbs_researched = pv->data.v_int;
2566 return;
2567 case OPID_PLAYER_GOLD:
2568 packet->gold = pv->data.v_int;
2569 return;
2570 default:
2571 break;
2572 }
2573 }
2574 log_error("%s(): Unhandled request to pack value of property "
2575 "%d (%s) from object of type \"%s\".", __FUNCTION__,
2576 propid, objprop_get_name(op), objtype_get_name(objtype));
2577 return;
2578
2579 case OBJTYPE_GAME:
2580 {
2581 struct packet_edit_game *packet = pd.game.game;
2582
2583 switch (propid) {
2584 case OPID_GAME_SCENARIO:
2585 packet->scenario = pv->data.v_bool;
2586 return;
2587 case OPID_GAME_SCENARIO_NAME:
2588 sz_strlcpy(packet->scenario_name, pv->data.v_const_string);
2589 return;
2590 case OPID_GAME_SCENARIO_AUTHORS:
2591 sz_strlcpy(packet->scenario_authors, pv->data.v_const_string);
2592 return;
2593 case OPID_GAME_SCENARIO_DESC:
2594 sz_strlcpy(pd.game.desc->scenario_desc, pv->data.v_const_string);
2595 return;
2596 case OPID_GAME_SCENARIO_RANDSTATE:
2597 packet->scenario_random = pv->data.v_bool;
2598 return;
2599 case OPID_GAME_SCENARIO_PLAYERS:
2600 packet->scenario_players = pv->data.v_bool;
2601 return;
2602 case OPID_GAME_STARTPOS_NATIONS:
2603 packet->startpos_nations = pv->data.v_bool;
2604 return;
2605 case OPID_GAME_PREVENT_CITIES:
2606 packet->prevent_new_cities = pv->data.v_bool;
2607 return;
2608 case OPID_GAME_LAKE_FLOODING:
2609 packet->lake_flooding = pv->data.v_bool;
2610 return;
2611 case OPID_GAME_RULESET_LOCKED:
2612 packet->ruleset_locked = pv->data.v_bool;
2613 return;
2614 default:
2615 break;
2616 }
2617 }
2618 log_error("%s(): Unhandled request to pack value of property "
2619 "%d (%s) from object of type \"%s\".", __FUNCTION__,
2620 propid, objprop_get_name(op), objtype_get_name(objtype));
2621 return;
2622
2623 case NUM_OBJTYPES:
2624 break;
2625 }
2626
2627 log_error("%s(): Unhandled request for object type \"%s\" (nb %d).",
2628 __FUNCTION__, objtype_get_name(objtype), objtype);
2629
2630}
2631
2632/************************************************************************/
2635 static void objbind_set_rowref(struct objbind *ob,
2636 GtkTreeRowReference *rr)
2637{
2638 if (!ob) {
2639 return;
2640 }
2641 ob->rowref = rr;
2642}
2643
2644/************************************************************************/
2647 static GtkTreeRowReference *objbind_get_rowref(struct objbind *ob)
2648{
2649 if (!ob) {
2650 return NULL;
2651 }
2652 return ob->rowref;
2653}
2654
2655/************************************************************************/
2658 static int objprop_get_id(const struct objprop *op)
2659{
2660 if (!op) {
2661 return -1;
2662 }
2663 return op->id;
2664}
2665
2666/************************************************************************/
2673 static GType objprop_get_gtype(const struct objprop *op)
2674{
2675 fc_assert_ret_val(NULL != op, G_TYPE_NONE);
2676
2677 switch (op->valtype) {
2678 case VALTYPE_NONE:
2679 case VALTYPE_TILE_VISION_DATA:
2680 return G_TYPE_NONE;
2681 case VALTYPE_INT:
2682 return G_TYPE_INT;
2683 case VALTYPE_BOOL:
2684 /* We want to show it as translated string, not as untranslated G_TYPE_BOOLEAN */
2685 return G_TYPE_STRING;
2686 case VALTYPE_STRING:
2687 case VALTYPE_BUILT_ARRAY:
2688 case VALTYPE_INVENTIONS_ARRAY:
2689 case VALTYPE_BV_SPECIAL:
2690 case VALTYPE_BV_ROADS:
2691 case VALTYPE_BV_BASES:
2692 case VALTYPE_NATION_HASH:
2693 return G_TYPE_STRING;
2694 case VALTYPE_PIXBUF:
2695 case VALTYPE_NATION:
2696 case VALTYPE_GOV:
2697 return GDK_TYPE_PIXBUF;
2698 }
2699 log_error("%s(): Unhandled value type %d.", __FUNCTION__, op->valtype);
2700 return G_TYPE_NONE;
2701}
2702
2703/************************************************************************/
2706 static enum value_types objprop_get_valtype(const struct objprop *op)
2707{
2708 if (!op) {
2709 return VALTYPE_NONE;
2710 }
2711 return op->valtype;
2712}
2713
2714/************************************************************************/
2717 static bool objprop_show_in_listview(const struct objprop *op)
2718{
2719 if (!op) {
2720 return FALSE;
2721 }
2722 return op->flags & OPF_IN_LISTVIEW;
2723}
2724
2725/************************************************************************/
2728 static bool objprop_has_widget(const struct objprop *op)
2729{
2730 if (!op) {
2731 return FALSE;
2732 }
2733 return op->flags & OPF_HAS_WIDGET;
2734}
2735
2736/************************************************************************/
2742 static const char *objprop_get_attribute_type_string(const struct objprop *op)
2743{
2744 GType gtype;
2745
2746 if (!op) {
2747 return NULL;
2748 }
2749
2750 gtype = objprop_get_gtype(op);
2751 if (gtype == G_TYPE_INT || gtype == G_TYPE_STRING
2752 || gtype == G_TYPE_BOOLEAN) {
2753 return "text";
2754 } else if (gtype == GDK_TYPE_PIXBUF) {
2755 return "pixbuf";
2756 }
2757
2758 return NULL;
2759}
2760
2761/************************************************************************/
2767 static void objprop_set_column_id(struct objprop *op, int col_id)
2768{
2769 if (!op) {
2770 return;
2771 }
2772 op->column_id = col_id;
2773}
2774
2775/************************************************************************/
2780 static int objprop_get_column_id(const struct objprop *op)
2781{
2782 if (!op) {
2783 return -1;
2784 }
2785 return op->column_id;
2786}
2787
2788/************************************************************************/
2791 static void objprop_set_treeview_column(struct objprop *op,
2792 GtkTreeViewColumn *col)
2793{
2794 if (!op) {
2795 return;
2796 }
2797 op->view_column = col;
2798}
2799
2800/************************************************************************/
2804 static GtkTreeViewColumn *objprop_get_treeview_column(const struct objprop *op)
2805{
2806 if (!op) {
2807 return NULL;
2808 }
2809 return op->view_column;
2810}
2811
2812/************************************************************************/
2815 static const char *objprop_get_name(const struct objprop *op)
2816{
2817 if (!op) {
2818 return NULL;
2819 }
2820 return op->name;
2821}
2822
2823/************************************************************************/
2826 static const char *objprop_get_tooltip(const struct objprop *op)
2827{
2828 if (!op) {
2829 return NULL;
2830 }
2831 return op->tooltip;
2832}
2833
2834/************************************************************************/
2839 static GtkCellRenderer *objprop_create_cell_renderer(const struct objprop *op)
2840{
2841 GtkCellRenderer *cell = NULL;
2842 GType gtype;
2843
2844 gtype = objprop_get_gtype(op);
2845
2846 if (gtype == G_TYPE_INT || gtype == G_TYPE_STRING
2847 || gtype == G_TYPE_BOOLEAN) {
2848 cell = gtk_cell_renderer_text_new();
2849 } else if (gtype == GDK_TYPE_PIXBUF) {
2850 cell = gtk_cell_renderer_pixbuf_new();
2851 }
2852
2853 return cell;
2854}
2855
2856/************************************************************************/
2860 static bool objprop_is_sortable(const struct objprop *op)
2861{
2862 GType gtype;
2863 if (!op) {
2864 return FALSE;
2865 }
2866 gtype = objprop_get_gtype(op);
2867 return gtype == G_TYPE_INT || gtype == G_TYPE_STRING;
2868}
2869
2870/************************************************************************/
2874 static bool objprop_is_readonly(const struct objprop *op)
2875{
2876 if (!op) {
2877 return TRUE;
2878 }
2879 return !(op->flags & OPF_EDITABLE);
2880}
2881
2882/************************************************************************/
2885 static void objprop_widget_text_changed(GtkEditable *text, gpointer userdata)
2886{
2887 struct objprop *op;
2888 struct property_page *pp;
2889 struct propval value = {{0,}, VALTYPE_STRING, FALSE};
2890
2891 op = userdata;
2892 pp = objprop_get_property_page(op);
2893 value.data.v_const_string = gtk_entry_buffer_get_text(gtk_text_get_buffer(GTK_TEXT(text)));
2894
2895 property_page_change_value(pp, op, &value);
2896}
2897
2898/************************************************************************/
2901 static void objprop_widget_spin_button_changed(GtkSpinButton *spin,
2902 gpointer userdata)
2903{
2904 struct objprop *op;
2905 struct property_page *pp;
2906 struct propval value = {{0,}, VALTYPE_INT, FALSE};
2907
2908 op = userdata;
2909 pp = objprop_get_property_page(op);
2910 value.data.v_int = gtk_spin_button_get_value_as_int(spin);
2911
2912 property_page_change_value(pp, op, &value);
2913}
2914
2915/************************************************************************/
2918 static void objprop_widget_toggle_button_changed(GtkToggleButton *button,
2919 gpointer userdata)
2920{
2921 struct objprop *op;
2922 struct property_page *pp;
2923 struct propval value = {{0,}, VALTYPE_BOOL, FALSE};
2924
2925 op = userdata;
2926 pp = objprop_get_property_page(op);
2927 value.data.v_bool = gtk_toggle_button_get_active(button);
2928
2929 property_page_change_value(pp, op, &value);
2930}
2931
2932/************************************************************************/
2935 static void objprop_setup_widget(struct objprop *op)
2936{
2937 GtkWidget *hbox, *hbox2, *label, *image, *text, *spin, *button;
2938 struct extviewer *ev = NULL;
2939 enum object_property_ids propid;
2940
2941 if (!op) {
2942 return;
2943 }
2944
2945 if (!objprop_has_widget(op)) {
2946 return;
2947 }
2948
2949 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
2950 op->widget = hbox;
2951
2952 label = gtk_label_new(objprop_get_name(op));
2953 gtk_widget_set_halign(label, GTK_ALIGN_START);
2954 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
2955 gtk_box_append(GTK_BOX(hbox), label);
2956 objprop_set_child_widget(op, "name-label", label);
2957
2958 propid = objprop_get_id(op);
2959
2960 switch (propid) {
2961 case OPID_TILE_INDEX:
2962 case OPID_TILE_X:
2963 case OPID_TILE_Y:
2964 case OPID_TILE_NAT_X:
2965 case OPID_TILE_NAT_Y:
2966 case OPID_TILE_CONTINENT:
2967 case OPID_TILE_TERRAIN:
2968 case OPID_TILE_RESOURCE:
2969 case OPID_TILE_XY:
2970 case OPID_STARTPOS_XY:
2971 case OPID_UNIT_ID:
2972 case OPID_UNIT_XY:
2973 case OPID_UNIT_TYPE:
2974 case OPID_CITY_ID:
2975 case OPID_CITY_XY:
2976 case OPID_PLAYER_AGE:
2977#ifdef FREECIV_DEBUG
2978 case OPID_TILE_ADDRESS:
2979 case OPID_UNIT_ADDRESS:
2980 case OPID_CITY_ADDRESS:
2981 case OPID_PLAYER_ADDRESS:
2982#endif /* FREECIV_DEBUG */
2983 label = gtk_label_new(NULL);
2984 gtk_widget_set_hexpand(label, TRUE);
2985 gtk_widget_set_halign(label, GTK_ALIGN_START);
2986 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
2987 gtk_box_append(GTK_BOX(hbox), label);
2988 objprop_set_child_widget(op, "value-label", label);
2989 return;
2990
2991 case OPID_TILE_IMAGE:
2992 case OPID_STARTPOS_IMAGE:
2993 case OPID_UNIT_IMAGE:
2994 case OPID_CITY_IMAGE:
2995 image = gtk_image_new();
2996 gtk_widget_set_size_request(image,
2997 tileset_tile_width(tileset),
2998 tileset_tile_height(tileset));
2999 gtk_widget_set_hexpand(image, TRUE);
3000 gtk_widget_set_halign(image, GTK_ALIGN_START);
3001 gtk_widget_set_valign(image, GTK_ALIGN_CENTER);
3002 gtk_box_append(GTK_BOX(hbox), image);
3003 objprop_set_child_widget(op, "image", image);
3004 return;
3005
3006 case OPID_CITY_NAME:
3007 case OPID_PLAYER_NAME:
3008 case OPID_GAME_SCENARIO_NAME:
3009 case OPID_TILE_LABEL:
3010 text = gtk_text_new();
3011 gtk_widget_set_hexpand(text, TRUE);
3012 gtk_widget_set_halign(text, GTK_ALIGN_END);
3013 gtk_editable_set_width_chars(GTK_EDITABLE(text), 8);
3014 g_signal_connect(text, "changed",
3015 G_CALLBACK(objprop_widget_text_changed), op);
3016 gtk_box_append(GTK_BOX(hbox), text);
3017 objprop_set_child_widget(op, "text", text);
3018 return;
3019
3020 case OPID_UNIT_MOVES_LEFT:
3021 case OPID_CITY_SIZE:
3022 case OPID_CITY_HISTORY:
3023 case OPID_CITY_SHIELD_STOCK:
3024 case OPID_PLAYER_SELECT_WEIGHT:
3025 case OPID_PLAYER_SCIENCE:
3026 case OPID_PLAYER_GOLD:
3027 spin = gtk_spin_button_new_with_range(0.0, 100.0, 1.0);
3028 gtk_widget_set_hexpand(spin, TRUE);
3029 gtk_widget_set_halign(spin, GTK_ALIGN_END);
3030 g_signal_connect(spin, "value-changed",
3031 G_CALLBACK(objprop_widget_spin_button_changed), op);
3032 gtk_box_append(GTK_BOX(hbox), spin);
3033 objprop_set_child_widget(op, "spin", spin);
3034 return;
3035
3036 case OPID_UNIT_FUEL:
3037 case OPID_UNIT_HP:
3038 case OPID_UNIT_VETERAN:
3039 case OPID_CITY_FOOD_STOCK:
3040 hbox2 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
3041 gtk_widget_set_hexpand(hbox2, TRUE);
3042 gtk_widget_set_halign(hbox2, GTK_ALIGN_END);
3043 gtk_box_append(GTK_BOX(hbox), hbox2);
3044 spin = gtk_spin_button_new_with_range(0.0, 100.0, 1.0);
3045 g_signal_connect(spin, "value-changed",
3046 G_CALLBACK(objprop_widget_spin_button_changed), op);
3047 gtk_box_append(GTK_BOX(hbox2), spin);
3048 objprop_set_child_widget(op, "spin", spin);
3049 label = gtk_label_new(NULL);
3050 gtk_widget_set_halign(label, GTK_ALIGN_START);
3051 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
3052 gtk_box_append(GTK_BOX(hbox2), label);
3053 objprop_set_child_widget(op, "max-value-label", label);
3054 return;
3055
3056 case OPID_TILE_SPECIALS:
3057 case OPID_TILE_ROADS:
3058 case OPID_TILE_BASES:
3059 case OPID_TILE_VISION:
3060 case OPID_STARTPOS_NATIONS:
3061 case OPID_CITY_BUILDINGS:
3062 case OPID_PLAYER_NATION:
3063 case OPID_PLAYER_GOV:
3064 case OPID_PLAYER_INVENTIONS:
3065 case OPID_GAME_SCENARIO_AUTHORS:
3066 case OPID_GAME_SCENARIO_DESC:
3067 ev = extviewer_new(op);
3068 objprop_set_extviewer(op, ev);
3069 gtk_widget_set_hexpand(extviewer_get_panel_widget(ev), TRUE);
3070 gtk_widget_set_halign(extviewer_get_panel_widget(ev), GTK_ALIGN_END);
3071 gtk_box_append(GTK_BOX(hbox), extviewer_get_panel_widget(ev));
3072 property_page_add_extviewer(objprop_get_property_page(op), ev);
3073 return;
3074
3075 case OPID_STARTPOS_EXCLUDE:
3076 case OPID_UNIT_MOVED:
3077 case OPID_UNIT_DONE_MOVING:
3078 case OPID_UNIT_STAY:
3079 case OPID_GAME_SCENARIO:
3080 case OPID_GAME_SCENARIO_RANDSTATE:
3081 case OPID_GAME_SCENARIO_PLAYERS:
3082 case OPID_GAME_STARTPOS_NATIONS:
3083 case OPID_GAME_PREVENT_CITIES:
3084 case OPID_GAME_LAKE_FLOODING:
3085 case OPID_GAME_RULESET_LOCKED:
3086 case OPID_PLAYER_SCENARIO_RESERVED:
3087 button = gtk_toggle_button_new();
3088 gtk_widget_set_hexpand(button, TRUE);
3089 gtk_widget_set_halign(button, GTK_ALIGN_END);
3090 g_signal_connect(button, "toggled",
3091 G_CALLBACK(objprop_widget_toggle_button_changed),
3092 op);
3093 gtk_box_append(GTK_BOX(hbox), button);
3094 objprop_set_child_widget(op, "togglebutton", button);
3095 return;
3096 }
3097
3098 log_error("%s(): Unhandled request to create widget for property %d (%s).",
3099 __FUNCTION__, propid, objprop_get_name(op));
3100}
3101
3102/************************************************************************/
3110 static void objprop_refresh_widget(struct objprop *op,
3111 struct objbind *ob)
3112{
3113 GtkWidget *w, *label, *image, *text, *spin, *button;
3114 struct extviewer *ev;
3115 struct propval *pv;
3116 bool modified;
3117 enum object_property_ids propid;
3118 double min, max, step, big_step;
3119 char buf[256];
3120 const char *newtext;
3121 GtkEntryBuffer *buffer;
3122
3123 if (!op || !objprop_has_widget(op)) {
3124 return;
3125 }
3126
3127 w = objprop_get_widget(op);
3128 if (!w) {
3129 return;
3130 }
3131
3132 propid = objprop_get_id(op);
3133
3134 /* NB: We must take care to propval_free() the return value of
3135 * objbind_get_value_from_object(), since it always makes a
3136 * copy, but to NOT free the result of objbind_get_modified_value()
3137 * since it returns its own stored value. */
3138 pv = objbind_get_value_from_object(ob, op);
3139 modified = objbind_property_is_modified(ob, op);
3140
3141 if (pv && modified) {
3142 struct propval *pv_mod;
3143
3144 pv_mod = objbind_get_modified_value(ob, op);
3145 if (pv_mod) {
3146 if (propval_equal(pv, pv_mod)) {
3147 objbind_clear_modified_value(ob, op);
3148 modified = FALSE;
3149 } else {
3150 propval_free(pv);
3151 pv = pv_mod;
3152 modified = TRUE;
3153 }
3154 } else {
3155 modified = FALSE;
3156 }
3157 }
3158
3159 switch (propid) {
3160 case OPID_TILE_IMAGE:
3161 case OPID_STARTPOS_IMAGE:
3162 case OPID_UNIT_IMAGE:
3163 case OPID_CITY_IMAGE:
3164 image = objprop_get_child_widget(op, "image");
3165 if (pv) {
3166 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pv->data.v_pixbuf);
3167 } else {
3168 gtk_image_set_from_pixbuf(GTK_IMAGE(image), NULL);
3169 }
3170 break;
3171
3172 case OPID_TILE_XY:
3173 case OPID_TILE_TERRAIN:
3174 case OPID_TILE_RESOURCE:
3175 case OPID_STARTPOS_XY:
3176 case OPID_UNIT_XY:
3177 case OPID_UNIT_TYPE:
3178 case OPID_CITY_XY:
3179#ifdef FREECIV_DEBUG
3180 case OPID_TILE_ADDRESS:
3181 case OPID_UNIT_ADDRESS:
3182 case OPID_CITY_ADDRESS:
3183 case OPID_PLAYER_ADDRESS:
3184#endif /* FREECIV_DEBUG */
3185 label = objprop_get_child_widget(op, "value-label");
3186 if (pv) {
3187 gtk_label_set_text(GTK_LABEL(label), pv->data.v_string);
3188 } else {
3189 gtk_label_set_text(GTK_LABEL(label), NULL);
3190 }
3191 break;
3192
3193 case OPID_TILE_INDEX:
3194 case OPID_TILE_X:
3195 case OPID_TILE_Y:
3196 case OPID_TILE_NAT_X:
3197 case OPID_TILE_NAT_Y:
3198 case OPID_TILE_CONTINENT:
3199 case OPID_UNIT_ID:
3200 case OPID_CITY_ID:
3201 case OPID_PLAYER_AGE:
3202 label = objprop_get_child_widget(op, "value-label");
3203 if (pv) {
3204 char agebuf[16];
3205
3206 fc_snprintf(agebuf, sizeof(agebuf), "%d", pv->data.v_int);
3207 gtk_label_set_text(GTK_LABEL(label), agebuf);
3208 } else {
3209 gtk_label_set_text(GTK_LABEL(label), NULL);
3210 }
3211 break;
3212
3213 case OPID_CITY_NAME:
3214 case OPID_PLAYER_NAME:
3215 case OPID_GAME_SCENARIO_NAME:
3216 case OPID_TILE_LABEL:
3217 text = objprop_get_child_widget(op, "text");
3218 if (pv) {
3219 /* Most of these are semantically in "v_const_string",
3220 * but this works as the address is the same regardless. */
3221 newtext = pv->data.v_string;
3222 } else {
3223 newtext = "";
3224 }
3225 buffer = gtk_text_get_buffer(GTK_TEXT(text));
3226
3227 /* Only set the text if it has changed. This breaks
3228 * recursive loop. */
3229 if (strcmp(newtext, gtk_entry_buffer_get_text(buffer))) {
3230 gtk_entry_buffer_set_text(buffer, newtext, -1);
3231 }
3232 gtk_widget_set_sensitive(text, pv != NULL);
3233 break;
3234
3235 case OPID_UNIT_MOVES_LEFT:
3236 case OPID_CITY_SIZE:
3237 case OPID_CITY_HISTORY:
3238 case OPID_CITY_SHIELD_STOCK:
3239 case OPID_PLAYER_SELECT_WEIGHT:
3240 case OPID_PLAYER_SCIENCE:
3241 case OPID_PLAYER_GOLD:
3242 spin = objprop_get_child_widget(op, "spin");
3243 if (pv) {
3244 disable_gobject_callback(G_OBJECT(spin),
3245 G_CALLBACK(objprop_widget_spin_button_changed));
3246 if (objbind_get_allowed_value_span(ob, op, &min, &max,
3247 &step, &big_step)) {
3248 gtk_spin_button_set_range(GTK_SPIN_BUTTON(spin), min, max);
3249 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(spin),
3250 step, big_step);
3251 }
3252 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), pv->data.v_int);
3253 enable_gobject_callback(G_OBJECT(spin),
3254 G_CALLBACK(objprop_widget_spin_button_changed));
3255 }
3256 gtk_widget_set_sensitive(spin, pv != NULL);
3257 break;
3258
3259 case OPID_UNIT_FUEL:
3260 case OPID_UNIT_HP:
3261 case OPID_UNIT_VETERAN:
3262 case OPID_CITY_FOOD_STOCK:
3263 spin = objprop_get_child_widget(op, "spin");
3264 label = objprop_get_child_widget(op, "max-value-label");
3265 if (pv) {
3266 disable_gobject_callback(G_OBJECT(spin),
3267 G_CALLBACK(objprop_widget_spin_button_changed));
3268 if (objbind_get_allowed_value_span(ob, op, &min, &max,
3269 &step, &big_step)) {
3270 gtk_spin_button_set_range(GTK_SPIN_BUTTON(spin), min, max);
3271 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(spin),
3272 step, big_step);
3273 fc_snprintf(buf, sizeof(buf), "/%d", (int) max);
3274 gtk_label_set_text(GTK_LABEL(label), buf);
3275 } else {
3276 gtk_label_set_text(GTK_LABEL(label), NULL);
3277 }
3278 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), pv->data.v_int);
3279 enable_gobject_callback(G_OBJECT(spin),
3280 G_CALLBACK(objprop_widget_spin_button_changed));
3281 } else {
3282 gtk_label_set_text(GTK_LABEL(label), NULL);
3283 }
3284 gtk_widget_set_sensitive(spin, pv != NULL);
3285 break;
3286
3287 case OPID_TILE_SPECIALS:
3288 case OPID_TILE_ROADS:
3289 case OPID_TILE_BASES:
3290 case OPID_TILE_VISION:
3291 case OPID_STARTPOS_NATIONS:
3292 case OPID_CITY_BUILDINGS:
3293 case OPID_PLAYER_NATION:
3294 case OPID_PLAYER_GOV:
3295 case OPID_PLAYER_INVENTIONS:
3296 case OPID_GAME_SCENARIO_AUTHORS:
3297 case OPID_GAME_SCENARIO_DESC:
3298 ev = objprop_get_extviewer(op);
3299 if (pv) {
3300 extviewer_refresh_widgets(ev, pv);
3301 } else {
3302 extviewer_clear_widgets(ev);
3303 }
3304 break;
3305
3306 case OPID_STARTPOS_EXCLUDE:
3307 case OPID_UNIT_MOVED:
3308 case OPID_UNIT_DONE_MOVING:
3309 case OPID_UNIT_STAY:
3310 case OPID_GAME_SCENARIO:
3311 case OPID_GAME_SCENARIO_RANDSTATE:
3312 case OPID_GAME_SCENARIO_PLAYERS:
3313 case OPID_GAME_STARTPOS_NATIONS:
3314 case OPID_GAME_PREVENT_CITIES:
3315 case OPID_GAME_LAKE_FLOODING:
3316 case OPID_GAME_RULESET_LOCKED:
3317 case OPID_PLAYER_SCENARIO_RESERVED:
3318 button = objprop_get_child_widget(op, "togglebutton");
3319 disable_gobject_callback(G_OBJECT(button),
3320 G_CALLBACK(objprop_widget_toggle_button_changed));
3321 if (pv) {
3322 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
3323 pv->data.v_bool);
3324 } else {
3325 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
3326 }
3327 enable_gobject_callback(G_OBJECT(button),
3328 G_CALLBACK(objprop_widget_toggle_button_changed));
3329 gtk_widget_set_sensitive(button, pv != NULL);
3330 break;
3331 }
3332
3333 if (!modified) {
3334 propval_free(pv);
3335 }
3336
3337 label = objprop_get_child_widget(op, "name-label");
3338 if (label) {
3339 const char *name = objprop_get_name(op);
3340 if (modified) {
3341 char namebuf[128];
3342
3343 fc_snprintf(namebuf, sizeof(namebuf),
3344 "<span foreground=\"red\">%s</span>", name);
3345 gtk_label_set_markup(GTK_LABEL(label), namebuf);
3346 } else {
3347 gtk_label_set_text(GTK_LABEL(label), name);
3348 }
3349 }
3350}
3351
3352/************************************************************************/
3356 static GtkWidget *objprop_get_widget(struct objprop *op)
3357{
3358 if (!op) {
3359 return NULL;
3360 }
3361 if (!op->widget) {
3362 objprop_setup_widget(op);
3363 }
3364 return op->widget;
3365}
3366
3367/************************************************************************/
3371 static void objprop_set_child_widget(struct objprop *op,
3372 const char *widget_name,
3373 GtkWidget *widget)
3374{
3375 GtkWidget *w;
3376
3377 if (!op || !widget_name || !widget) {
3378 return;
3379 }
3380
3381 w = objprop_get_widget(op);
3382 if (!w) {
3383 log_error("Cannot store child widget %p under name "
3384 "\"%s\" using objprop_set_child_widget for object "
3385 "property %d (%s) because objprop_get_widget does "
3386 "not return a valid widget.",
3387 widget, widget_name, objprop_get_id(op), objprop_get_name(op));
3388 return;
3389 }
3390
3391 g_object_set_data(G_OBJECT(w), widget_name, widget);
3392}
3393
3394/************************************************************************/
3398 static GtkWidget *objprop_get_child_widget(struct objprop *op,
3399 const char *widget_name)
3400{
3401 GtkWidget *w, *child;
3402
3403 if (!op || !widget_name) {
3404 return NULL;
3405 }
3406
3407 w = objprop_get_widget(op);
3408 if (!w) {
3409 log_error("Cannot retrieve child widget under name "
3410 "\"%s\" using objprop_get_child_widget for object "
3411 "property %d (%s) because objprop_get_widget does "
3412 "not return a valid widget.",
3413 widget_name, objprop_get_id(op), objprop_get_name(op));
3414 return NULL;
3415 }
3416
3417 child = g_object_get_data(G_OBJECT(w), widget_name);
3418 if (!child) {
3419 log_error("Child widget \"%s\" not found for object "
3420 "property %d (%s) via objprop_get_child_widget.",
3421 widget_name, objprop_get_id(op), objprop_get_name(op));
3422 return NULL;
3423 }
3424
3425 return child;
3426}
3427
3428/************************************************************************/
3431 static void objprop_set_extviewer(struct objprop *op,
3432 struct extviewer *ev)
3433{
3434 if (!op) {
3435 return;
3436 }
3437 op->extviewer = ev;
3438}
3439
3440/************************************************************************/
3443 static struct extviewer *objprop_get_extviewer(struct objprop *op)
3444{
3445 if (!op) {
3446 return NULL;
3447 }
3448 return op->extviewer;
3449}
3450
3451/************************************************************************/
3454 static struct property_page *objprop_get_property_page(const struct objprop *op)
3455{
3456 if (!op) {
3457 return NULL;
3458 }
3459 return op->parent_page;
3460}
3461
3462/************************************************************************/
3465 static struct objprop *objprop_new(int id,
3466 const char *name,
3467 const char *tooltip,
3468 enum object_property_flags flags,
3469 enum value_types valtype,
3470 struct property_page *parent)
3471{
3472 struct objprop *op;
3473
3474 op = fc_calloc(1, sizeof(*op));
3475 op->id = id;
3476 op->name = name;
3477 op->tooltip = tooltip;
3478 op->flags = flags;
3479 op->valtype = valtype;
3480 op->column_id = -1;
3481 op->parent_page = parent;
3482
3483 return op;
3484}
3485
3486/************************************************************************/
3490 static struct extviewer *extviewer_new(struct objprop *op)
3491{
3492 struct extviewer *ev;
3493 GtkWidget *hbox, *vbox, *label, *button, *scrollwin, *image;
3494 GtkWidget *view = NULL;
3495 GtkTreeSelection *sel;
3496 GtkListStore *store = NULL;
3497 GtkTextBuffer *textbuf = NULL;
3498 GType *gtypes;
3499 enum object_property_ids propid;
3500 int num_cols;
3501
3502 if (!op) {
3503 return NULL;
3504 }
3505
3506 ev = fc_calloc(1, sizeof(*ev));
3507 ev->objprop = op;
3508
3509 propid = objprop_get_id(op);
3510
3511
3512 /* Create the panel widget. */
3513
3514 switch (propid) {
3515 case OPID_TILE_SPECIALS:
3516 case OPID_TILE_ROADS:
3517 case OPID_TILE_BASES:
3518 case OPID_STARTPOS_NATIONS:
3519 case OPID_CITY_BUILDINGS:
3520 case OPID_PLAYER_INVENTIONS:
3521 case OPID_GAME_SCENARIO_AUTHORS:
3522 case OPID_GAME_SCENARIO_DESC:
3523 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
3524 ev->panel_widget = hbox;
3525
3526 label = gtk_label_new(NULL);
3527 gtk_widget_set_halign(label, GTK_ALIGN_START);
3528 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
3529 gtk_box_append(GTK_BOX(hbox), label);
3530 ev->panel_label = label;
3531 break;
3532
3533 case OPID_PLAYER_NATION:
3534 case OPID_PLAYER_GOV:
3535 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
3536 ev->panel_widget = vbox;
3537
3538 label = gtk_label_new(NULL);
3539 gtk_widget_set_halign(label, GTK_ALIGN_START);
3540 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
3541 gtk_box_append(GTK_BOX(vbox), label);
3542 ev->panel_label = label;
3543
3544 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
3545 gtk_box_append(GTK_BOX(vbox), hbox);
3546
3547 image = gtk_image_new();
3548 if (propid == OPID_PLAYER_GOV) {
3549 gtk_widget_set_size_request(image,
3550 tileset_small_sprite_width(tileset),
3551 tileset_small_sprite_height(tileset));
3552 } else {
3553 /* propid OPID_PLAYER_NATION */
3554 gtk_widget_set_size_request(image, 100, 40);
3555 }
3556 gtk_widget_set_halign(image, GTK_ALIGN_START);
3557 gtk_widget_set_valign(image, GTK_ALIGN_CENTER);
3558 gtk_box_append(GTK_BOX(hbox), image);
3559 ev->panel_image = image;
3560 break;
3561
3562 case OPID_TILE_VISION:
3563 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
3564 ev->panel_widget = hbox;
3565 break;
3566
3567 default:
3568 log_error("Unhandled request to create panel widget "
3569 "for property %d (%s) in extviewer_new().",
3570 propid, objprop_get_name(op));
3571 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
3572 ev->panel_widget = hbox;
3573 break;
3574 }
3575
3576 if (objprop_is_readonly(op)) {
3577 button = gtk_button_new_with_label(Q_("?verb:View"));
3578 } else {
3579 button = gtk_button_new_with_label(_("Edit"));
3580 }
3581 g_signal_connect(button, "clicked",
3582 G_CALLBACK(extviewer_panel_button_clicked), ev);
3583 gtk_box_append(GTK_BOX(hbox), button);
3584 ev->panel_button = button;
3585
3586
3587 /* Create the data store. */
3588
3589 switch (propid) {
3590 case OPID_TILE_SPECIALS:
3591 case OPID_TILE_ROADS:
3592 case OPID_TILE_BASES:
3593 case OPID_PLAYER_INVENTIONS:
3594 store = gtk_list_store_new(3, G_TYPE_BOOLEAN, G_TYPE_INT,
3595 G_TYPE_STRING);
3596 break;
3597 case OPID_TILE_VISION:
3598 num_cols = 3 + 1 + V_COUNT;
3599 gtypes = fc_malloc(num_cols * sizeof(GType));
3600 gtypes[0] = G_TYPE_INT; /* player number */
3601 gtypes[1] = GDK_TYPE_PIXBUF; /* player flag */
3602 gtypes[2] = G_TYPE_STRING; /* player name */
3603 gtypes[3] = G_TYPE_BOOLEAN; /* tile_known */
3604 vision_layer_iterate(v) {
3605 gtypes[4 + v] = G_TYPE_BOOLEAN; /* tile_seen[v] */
3606 } vision_layer_iterate_end;
3607 store = gtk_list_store_newv(num_cols, gtypes);
3608 free(gtypes);
3609 break;
3610 case OPID_CITY_BUILDINGS:
3611 store = gtk_list_store_new(4, G_TYPE_BOOLEAN, G_TYPE_INT,
3612 G_TYPE_STRING, G_TYPE_STRING);
3613 break;
3614 case OPID_STARTPOS_NATIONS:
3615 case OPID_PLAYER_NATION:
3616 case OPID_PLAYER_GOV:
3617 store = gtk_list_store_new(4, G_TYPE_BOOLEAN, G_TYPE_INT,
3618 GDK_TYPE_PIXBUF, G_TYPE_STRING);
3619 break;
3620 case OPID_GAME_SCENARIO_AUTHORS:
3621 case OPID_GAME_SCENARIO_DESC:
3622 textbuf = gtk_text_buffer_new(NULL);
3623 break;
3624 default:
3625 log_error("Unhandled request to create data store "
3626 "for property %d (%s) in extviewer_new().",
3627 propid, objprop_get_name(op));
3628 break;
3629 }
3630
3631 ev->store = store;
3632 ev->textbuf = textbuf;
3633
3634 /* Create the view widget. */
3635
3636 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
3637 ev->view_widget = vbox;
3638
3639 label = gtk_label_new(objprop_get_name(op));
3640 gtk_widget_set_halign(label, GTK_ALIGN_START);
3641 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
3642 gtk_box_append(GTK_BOX(vbox), label);
3643 ev->view_label = label;
3644
3645 if (store || textbuf) {
3646 scrollwin = gtk_scrolled_window_new();
3647 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(scrollwin),
3648 TRUE);
3649 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
3650 GTK_POLICY_AUTOMATIC,
3651 GTK_POLICY_AUTOMATIC);
3652 gtk_box_append(GTK_BOX(vbox), scrollwin);
3653
3654 if (store) {
3655 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
3656 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
3657 gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
3658 } else {
3659 const bool editable = !objprop_is_readonly(op);
3660
3661 view = gtk_text_view_new_with_buffer(textbuf);
3662 gtk_text_view_set_editable(GTK_TEXT_VIEW(view), editable);
3663 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(view), editable);
3664 }
3665 gtk_widget_set_hexpand(view, TRUE);
3666 gtk_widget_set_vexpand(view, TRUE);
3667
3668 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrollwin), view);
3669 }
3670
3671 switch (propid) {
3672
3673 case OPID_TILE_SPECIALS:
3674 case OPID_TILE_ROADS:
3675 case OPID_TILE_BASES:
3676 /* TRANS: As in "this tile special is present". */
3677 add_column(view, 0, _("Present"), G_TYPE_BOOLEAN, TRUE, FALSE,
3678 G_CALLBACK(extviewer_view_cell_toggled), ev);
3679 add_column(view, 1, _("ID"), G_TYPE_INT,
3680 FALSE, FALSE, NULL, NULL);
3681 add_column(view, 2, _("Name"), G_TYPE_STRING,
3682 FALSE, FALSE, NULL, NULL);
3683 break;
3684
3685 case OPID_TILE_VISION:
3686 add_column(view, 0, _("ID"), G_TYPE_INT,
3687 FALSE, FALSE, NULL, NULL);
3688 add_column(view, 1, _("Nation"), GDK_TYPE_PIXBUF,
3689 FALSE, FALSE, NULL, NULL);
3690 add_column(view, 2, _("Name"), G_TYPE_STRING,
3691 FALSE, FALSE, NULL, NULL);
3692 add_column(view, 3, _("Known"), G_TYPE_BOOLEAN,
3693 FALSE, FALSE, NULL, NULL);
3694 vision_layer_iterate(v) {
3695 add_column(view, 4 + v, vision_layer_get_name(v),
3696 G_TYPE_BOOLEAN, FALSE, FALSE, NULL, NULL);
3697 } vision_layer_iterate_end;
3698 break;
3699
3700 case OPID_CITY_BUILDINGS:
3701 /* TRANS: As in "this building is present". */
3702 add_column(view, 0, _("Present"), G_TYPE_BOOLEAN, TRUE, FALSE,
3703 G_CALLBACK(extviewer_view_cell_toggled), ev);
3704 add_column(view, 1, _("ID"), G_TYPE_INT,
3705 FALSE, FALSE, NULL, NULL);
3706 add_column(view, 2, _("Name"), G_TYPE_STRING,
3707 FALSE, FALSE, NULL, NULL);
3708 /* TRANS: As in "the turn when this building was built". */
3709 add_column(view, 3, _("Turn Built"), G_TYPE_STRING,
3710 FALSE, FALSE, NULL, NULL);
3711 break;
3712
3713 case OPID_STARTPOS_NATIONS:
3714 /* TRANS: As in "the player has set this nation". */
3715 add_column(view, 0, _("Set"), G_TYPE_BOOLEAN, TRUE, FALSE,
3716 G_CALLBACK(extviewer_view_cell_toggled), ev);
3717 add_column(view, 1, _("ID"), G_TYPE_INT,
3718 FALSE, FALSE, NULL, NULL);
3719 add_column(view, 2, _("Flag"), GDK_TYPE_PIXBUF,
3720 FALSE, FALSE, NULL, NULL);
3721 add_column(view, 3, _("Name"), G_TYPE_STRING,
3722 FALSE, FALSE, NULL, NULL);
3723 break;
3724
3725 case OPID_PLAYER_NATION:
3726 case OPID_PLAYER_GOV:
3727 /* TRANS: As in "the player has set this nation". */
3728 add_column(view, 0, _("Set"), G_TYPE_BOOLEAN, TRUE, TRUE,
3729 G_CALLBACK(extviewer_view_cell_toggled), ev);
3730 add_column(view, 1, _("ID"), G_TYPE_INT,
3731 FALSE, FALSE, NULL, NULL);
3732 add_column(view, 2,
3733 propid == OPID_PLAYER_GOV ? _("Icon") : _("Flag"),
3734 GDK_TYPE_PIXBUF,
3735 FALSE, FALSE, NULL, NULL);
3736 add_column(view, 3, _("Name"), G_TYPE_STRING,
3737 FALSE, FALSE, NULL, NULL);
3738 break;
3739
3740 case OPID_PLAYER_INVENTIONS:
3741 /* TRANS: As in "this invention is known". */
3742 add_column(view, 0, _("Known"), G_TYPE_BOOLEAN, TRUE, FALSE,
3743 G_CALLBACK(extviewer_view_cell_toggled), ev);
3744 add_column(view, 1, _("ID"), G_TYPE_INT,
3745 FALSE, FALSE, NULL, NULL);
3746 add_column(view, 2, _("Name"), G_TYPE_STRING,
3747 FALSE, FALSE, NULL, NULL);
3748 break;
3749
3750 case OPID_GAME_SCENARIO_AUTHORS:
3751 case OPID_GAME_SCENARIO_DESC:
3752 g_signal_connect(textbuf, "changed",
3753 G_CALLBACK(extviewer_textbuf_changed), ev);
3754 break;
3755
3756 default:
3757 log_error("Unhandled request to configure view widget "
3758 "for property %d (%s) in extviewer_new().",
3759 propid, objprop_get_name(op));
3760 break;
3761 }
3762
3763 gtk_widget_set_visible(ev->panel_widget, TRUE);
3764 gtk_widget_set_visible(ev->view_widget, TRUE);
3765
3766 return ev;
3767}
3768
3769/************************************************************************/
3772 static struct objprop *extviewer_get_objprop(struct extviewer *ev)
3773{
3774 if (!ev) {
3775 return NULL;
3776 }
3777 return ev->objprop;
3778}
3779
3780/************************************************************************/
3784 static GtkWidget *extviewer_get_panel_widget(struct extviewer *ev)
3785{
3786 if (!ev) {
3787 return NULL;
3788 }
3789 return ev->panel_widget;
3790}
3791
3792/************************************************************************/
3796 static GtkWidget *extviewer_get_view_widget(struct extviewer *ev)
3797{
3798 if (!ev) {
3799 return NULL;
3800 }
3801 return ev->view_widget;
3802}
3803
3804/************************************************************************/
3807 static void extviewer_refresh_widgets(struct extviewer *ev,
3808 struct propval *pv)
3809{
3810 struct objprop *op;
3811 enum object_property_ids propid;
3812 int id, turn_built;
3813 bool present, all;
3814 const char *name;
3815 GdkPixbuf *pixbuf;
3816 GtkListStore *store;
3817 GtkTextBuffer *textbuf;
3818 GtkTreeIter iter;
3819 gchar *buf;
3820
3821 if (!ev) {
3822 return;
3823 }
3824
3825 op = extviewer_get_objprop(ev);
3826 propid = objprop_get_id(op);
3827
3828 if (propval_equal(pv, ev->pv_cached)) {
3829 return;
3830 }
3831 propval_free(ev->pv_cached);
3832 ev->pv_cached = propval_copy(pv);
3833 store = ev->store;
3834 textbuf = ev->textbuf;
3835
3836
3837 /* NB: Remember to have -1 as the last argument to
3838 * gtk_list_store_set() and to use the correct column
3839 * number when inserting data. :) */
3840 switch (propid) {
3841
3842 case OPID_TILE_SPECIALS:
3843 gtk_list_store_clear(store);
3844 extra_type_by_cause_iterate(EC_SPECIAL, spe) {
3845 id = spe->data.special_idx;
3846 name = extra_name_translation(spe);
3847 present = BV_ISSET(pv->data.v_bv_special, id);
3848 gtk_list_store_append(store, &iter);
3849 gtk_list_store_set(store, &iter, 0, present, 1, id, 2, name, -1);
3850 } extra_type_by_cause_iterate_end;
3851 buf = propval_as_string(pv);
3852 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
3853 g_free(buf);
3854 break;
3855
3856 case OPID_TILE_ROADS:
3857 gtk_list_store_clear(store);
3858 extra_type_by_cause_iterate(EC_ROAD, pextra) {
3859 struct road_type *proad = extra_road_get(pextra);
3860
3861 id = road_number(proad);
3862 name = extra_name_translation(pextra);
3863 present = BV_ISSET(pv->data.v_bv_roads, id);
3864 gtk_list_store_append(store, &iter);
3865 gtk_list_store_set(store, &iter, 0, present, 1, id, 2, name, -1);
3866 } extra_type_by_cause_iterate_end;
3867 buf = propval_as_string(pv);
3868 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
3869 g_free(buf);
3870 break;
3871
3872 case OPID_TILE_BASES:
3873 gtk_list_store_clear(store);
3874 extra_type_by_cause_iterate(EC_BASE, pextra) {
3875 struct base_type *pbase = extra_base_get(pextra);
3876
3877 id = base_number(pbase);
3878 name = extra_name_translation(pextra);
3879 present = BV_ISSET(pv->data.v_bv_bases, id);
3880 gtk_list_store_append(store, &iter);
3881 gtk_list_store_set(store, &iter, 0, present, 1, id, 2, name, -1);
3882 } extra_type_by_cause_iterate_end;
3883 buf = propval_as_string(pv);
3884 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
3885 g_free(buf);
3886 break;
3887
3888 case OPID_TILE_VISION:
3889 gtk_list_store_clear(store);
3890 player_slots_iterate(pslot) {
3891 id = player_slot_index(pslot);
3892 if (player_slot_is_used(pslot)) {
3893 struct player *pplayer = player_slot_get_player(pslot);
3894
3895 name = player_name(pplayer);
3896 pixbuf = get_flag(pplayer->nation);
3897 } else {
3898 name = "";
3899 pixbuf = NULL;
3900 }
3901 gtk_list_store_append(store, &iter);
3902 gtk_list_store_set(store, &iter, 0, id, 2, name, -1);
3903 if (pixbuf) {
3904 gtk_list_store_set(store, &iter, 1, pixbuf, -1);
3905 g_object_unref(pixbuf);
3906 pixbuf = NULL;
3907 }
3908 present = BV_ISSET(pv->data.v_tile_vision->tile_known, id);
3909 gtk_list_store_set(store, &iter, 3, present, -1);
3910 vision_layer_iterate(v) {
3911 present = BV_ISSET(pv->data.v_tile_vision->tile_seen[v], id);
3912 gtk_list_store_set(store, &iter, 4 + v, present, -1);
3913 } vision_layer_iterate_end;
3914 } player_slots_iterate_end;
3915 break;
3916
3917 case OPID_STARTPOS_NATIONS:
3918 gtk_list_store_clear(store);
3919 gtk_list_store_append(store, &iter);
3920 all = (0 == nation_hash_size(pv->data.v_nation_hash));
3921 gtk_list_store_set(store, &iter, 0, all, 1, -1, 3,
3922 _("All nations"), -1);
3923 nations_iterate(pnation) {
3924 if (client_nation_is_in_current_set(pnation)
3925 && is_nation_playable(pnation)) {
3926 present = (!all && nation_hash_lookup(pv->data.v_nation_hash,
3927 pnation, NULL));
3928 id = nation_number(pnation);
3929 pixbuf = get_flag(pnation);
3930 name = nation_adjective_translation(pnation);
3931 gtk_list_store_append(store, &iter);
3932 gtk_list_store_set(store, &iter, 0, present, 1, id,
3933 2, pixbuf, 3, name, -1);
3934 if (pixbuf) {
3935 g_object_unref(pixbuf);
3936 }
3937 }
3938 } nations_iterate_end;
3939 buf = propval_as_string(pv);
3940 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
3941 g_free(buf);
3942 break;
3943
3944 case OPID_CITY_BUILDINGS:
3945 gtk_list_store_clear(store);
3946 improvement_iterate(pimprove) {
3947 if (is_special_improvement(pimprove)) {
3948 continue;
3949 }
3950 id = improvement_index(pimprove);
3951 name = improvement_name_translation(pimprove);
3952 turn_built = pv->data.v_built[id].turn;
3953 present = turn_built >= 0;
3954 buf = built_status_to_string(&pv->data.v_built[id]);
3955 gtk_list_store_append(store, &iter);
3956 gtk_list_store_set(store, &iter, 0, present, 1, id, 2, name,
3957 3, buf, -1);
3958 g_free(buf);
3959 } improvement_iterate_end;
3960 buf = propval_as_string(pv);
3961 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
3962 g_free(buf);
3963 break;
3964
3965 case OPID_PLAYER_NATION:
3966 {
3967 enum barbarian_type barbarian_type =
3968 nation_barbarian_type(pv->data.v_nation);
3969
3970 gtk_list_store_clear(store);
3971 nations_iterate(pnation) {
3972 if (client_nation_is_in_current_set(pnation)
3973 && nation_barbarian_type(pnation) == barbarian_type
3974 && (barbarian_type != NOT_A_BARBARIAN
3975 || is_nation_playable(pnation))) {
3976 present = (pnation == pv->data.v_nation);
3977 id = nation_index(pnation);
3978 pixbuf = get_flag(pnation);
3979 name = nation_adjective_translation(pnation);
3980 gtk_list_store_append(store, &iter);
3981 gtk_list_store_set(store, &iter, 0, present, 1, id,
3982 2, pixbuf, 3, name, -1);
3983 if (pixbuf) {
3984 g_object_unref(pixbuf);
3985 }
3986 }
3987 } nations_iterate_end;
3988 gtk_label_set_text(GTK_LABEL(ev->panel_label),
3989 nation_adjective_translation(pv->data.v_nation));
3990 pixbuf = get_flag(pv->data.v_nation);
3991 gtk_image_set_from_pixbuf(GTK_IMAGE(ev->panel_image), pixbuf);
3992 if (pixbuf) {
3993 g_object_unref(pixbuf);
3994 }
3995 }
3996 break;
3997
3998 case OPID_PLAYER_GOV:
3999 {
4000 gtk_list_store_clear(store);
4001 governments_iterate(pgov) {
4002 present = (pgov == pv->data.v_gov);
4003 id = government_index(pgov);
4004 pixbuf = sprite_get_pixbuf(get_government_sprite(tileset, pgov));
4005 name = government_name_translation(pgov);
4006 gtk_list_store_append(store, &iter);
4007 gtk_list_store_set(store, &iter, 0, present, 1, id,
4008 2, pixbuf, 3, name, -1);
4009 if (pixbuf) {
4010 g_object_unref(pixbuf);
4011 }
4012 } governments_iterate_end;
4013 gtk_label_set_text(GTK_LABEL(ev->panel_label),
4014 government_name_translation(pv->data.v_gov));
4015 pixbuf = sprite_get_pixbuf(get_government_sprite(tileset, pv->data.v_gov));
4016 gtk_image_set_from_pixbuf(GTK_IMAGE(ev->panel_image), pixbuf);
4017 if (pixbuf) {
4018 g_object_unref(pixbuf);
4019 }
4020 }
4021 break;
4022
4023 case OPID_PLAYER_INVENTIONS:
4024 gtk_list_store_clear(store);
4025 advance_iterate(padvance) {
4026 id = advance_index(padvance);
4027 present = BV_ISSET(pv->data.v_bv_inventions, id);
4028 name = advance_name_translation(padvance);
4029 gtk_list_store_append(store, &iter);
4030 gtk_list_store_set(store, &iter, 0, present, 1, id, 2, name, -1);
4031 } advance_iterate_end;
4032 buf = propval_as_string(pv);
4033 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4034 g_free(buf);
4035 break;
4036
4037 case OPID_GAME_SCENARIO_AUTHORS:
4038 case OPID_GAME_SCENARIO_DESC:
4039 disable_gobject_callback(G_OBJECT(ev->textbuf),
4040 G_CALLBACK(extviewer_textbuf_changed));
4041 {
4042 GtkTextIter start, end;
4043 char *oldtext;
4044
4045 /* Don't re-set content if unchanged, to avoid moving cursor */
4046 gtk_text_buffer_get_bounds(textbuf, &start, &end);
4047 oldtext = gtk_text_buffer_get_text(textbuf, &start, &end, TRUE);
4048 if (strcmp(oldtext, pv->data.v_const_string) != 0) {
4049 gtk_text_buffer_set_text(textbuf, pv->data.v_const_string, -1);
4050 }
4051 }
4052 enable_gobject_callback(G_OBJECT(ev->textbuf),
4053 G_CALLBACK(extviewer_textbuf_changed));
4054 gtk_widget_set_sensitive(ev->view_widget, TRUE);
4055 buf = propval_as_string(pv);
4056 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4057 g_free(buf);
4058 break;
4059
4060 default:
4061 log_error("Unhandled request to refresh widgets "
4062 "extviewer_refresh_widgets() for objprop id=%d "
4063 "name \"%s\".", propid, objprop_get_name(op));
4064 break;
4065 }
4066}
4067
4068/************************************************************************/
4071 static void extviewer_clear_widgets(struct extviewer *ev)
4072{
4073 struct objprop *op;
4074 enum object_property_ids propid;
4075
4076 if (!ev) {
4077 return;
4078 }
4079
4080 op = extviewer_get_objprop(ev);
4081 propid = objprop_get_id(op);
4082
4083 propval_free(ev->pv_cached);
4084 ev->pv_cached = NULL;
4085
4086 if (ev->panel_label != NULL) {
4087 gtk_label_set_text(GTK_LABEL(ev->panel_label), NULL);
4088 }
4089
4090 switch (propid) {
4091 case OPID_TILE_SPECIALS:
4092 case OPID_TILE_ROADS:
4093 case OPID_TILE_BASES:
4094 case OPID_TILE_VISION:
4095 case OPID_STARTPOS_NATIONS:
4096 case OPID_CITY_BUILDINGS:
4097 case OPID_PLAYER_INVENTIONS:
4098 gtk_list_store_clear(ev->store);
4099 break;
4100 case OPID_PLAYER_NATION:
4101 case OPID_PLAYER_GOV:
4102 gtk_list_store_clear(ev->store);
4103 gtk_image_set_from_pixbuf(GTK_IMAGE(ev->panel_image), NULL);
4104 break;
4105 case OPID_GAME_SCENARIO_AUTHORS:
4106 case OPID_GAME_SCENARIO_DESC:
4107 disable_gobject_callback(G_OBJECT(ev->textbuf),
4108 G_CALLBACK(extviewer_textbuf_changed));
4109 gtk_text_buffer_set_text(ev->textbuf, "", -1);
4110 enable_gobject_callback(G_OBJECT(ev->textbuf),
4111 G_CALLBACK(extviewer_textbuf_changed));
4112 gtk_widget_set_sensitive(ev->view_widget, FALSE);
4113 break;
4114 default:
4115 log_error("Unhandled request to clear widgets "
4116 "in extviewer_clear_widgets() for objprop id=%d "
4117 "name \"%s\".", propid, objprop_get_name(op));
4118 break;
4119 }
4120}
4121
4122/************************************************************************/
4126 static void extviewer_panel_button_clicked(GtkButton *button,
4127 gpointer userdata)
4128{
4129 struct extviewer *ev;
4130 struct property_page *pp;
4131 struct objprop *op;
4132
4133 ev = userdata;
4134 if (!ev) {
4135 return;
4136 }
4137
4138 op = extviewer_get_objprop(ev);
4139 pp = objprop_get_property_page(op);
4140 property_page_show_extviewer(pp, ev);
4141}
4142
4143/************************************************************************/
4146 static void extviewer_view_cell_toggled(GtkCellRendererToggle *cell,
4147 gchar *path,
4148 gpointer userdata)
4149{
4150 struct extviewer *ev;
4151 struct objprop *op;
4152 struct property_page *pp;
4153 enum object_property_ids propid;
4154 GtkTreeModel *model;
4155 GtkTreeIter iter;
4156 int id, old_id, turn_built;
4157 struct propval *pv;
4158 bool active, present;
4159 gchar *buf;
4160 GdkPixbuf *pixbuf = NULL;
4161
4162 ev = userdata;
4163 if (!ev) {
4164 return;
4165 }
4166
4167 pv = ev->pv_cached;
4168 if (!pv) {
4169 return;
4170 }
4171
4172 op = extviewer_get_objprop(ev);
4173 propid = objprop_get_id(op);
4174 active = gtk_cell_renderer_toggle_get_active(cell);
4175 pp = objprop_get_property_page(op);
4176
4177 model = GTK_TREE_MODEL(ev->store);
4178 if (!gtk_tree_model_get_iter_from_string(model, &iter, path)) {
4179 return;
4180 }
4181 present = !active;
4182
4183
4184 switch (propid) {
4185
4186 case OPID_TILE_SPECIALS:
4187 gtk_tree_model_get(model, &iter, 1, &id, -1);
4188 if (id < 0 || id >= extra_type_list_size(extra_type_list_by_cause(EC_SPECIAL))) {
4189 return;
4190 }
4191 if (present) {
4192 BV_SET(pv->data.v_bv_special, id);
4193 } else {
4194 BV_CLR(pv->data.v_bv_special, id);
4195 }
4196 gtk_list_store_set(ev->store, &iter, 0, present, -1);
4197 buf = propval_as_string(pv);
4198 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4199 g_free(buf);
4200 break;
4201
4202 case OPID_TILE_ROADS:
4203 gtk_tree_model_get(model, &iter, 1, &id, -1);
4204 if (!(0 <= id && id < road_count())) {
4205 return;
4206 }
4207 if (present) {
4208 BV_SET(pv->data.v_bv_roads, id);
4209 } else {
4210 BV_CLR(pv->data.v_bv_roads, id);
4211 }
4212 gtk_list_store_set(ev->store, &iter, 0, present, -1);
4213 buf = propval_as_string(pv);
4214 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4215 g_free(buf);
4216 break;
4217
4218 case OPID_TILE_BASES:
4219 gtk_tree_model_get(model, &iter, 1, &id, -1);
4220 if (!(0 <= id && id < base_count())) {
4221 return;
4222 }
4223 if (present) {
4224 BV_SET(pv->data.v_bv_bases, id);
4225 } else {
4226 BV_CLR(pv->data.v_bv_bases, id);
4227 }
4228 gtk_list_store_set(ev->store, &iter, 0, present, -1);
4229 buf = propval_as_string(pv);
4230 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4231 g_free(buf);
4232 break;
4233
4234 case OPID_STARTPOS_NATIONS:
4235 gtk_tree_model_get(model, &iter, 1, &id, -1);
4236 if (-1 > id && id >= nation_count()) {
4237 return;
4238 }
4239
4240 if (-1 == id) {
4241 gtk_list_store_set(ev->store, &iter, 0, present, -1);
4242 gtk_tree_model_get_iter_first(model, &iter);
4243 if (present) {
4244 while (gtk_tree_model_iter_next(model, &iter)) {
4245 gtk_list_store_set(ev->store, &iter, 0, FALSE, -1);
4246 }
4247 nation_hash_clear(pv->data.v_nation_hash);
4248 } else {
4249 const struct nation_type *pnation;
4250 int id2;
4251
4252 gtk_tree_model_iter_next(model, &iter);
4253 gtk_tree_model_get(model, &iter, 0, &id2, -1);
4254 gtk_list_store_set(ev->store, &iter, 0, TRUE, -1);
4255 pnation = nation_by_number(id2);
4256 nation_hash_insert(pv->data.v_nation_hash, pnation, NULL);
4257 }
4258 } else {
4259 const struct nation_type *pnation;
4260 bool all;
4261
4262 gtk_list_store_set(ev->store, &iter, 0, present, -1);
4263 pnation = nation_by_number(id);
4264 if (present) {
4265 nation_hash_insert(pv->data.v_nation_hash, pnation, NULL);
4266 } else {
4267 nation_hash_remove(pv->data.v_nation_hash, pnation);
4268 }
4269 gtk_tree_model_get_iter_first(model, &iter);
4270 all = (0 == nation_hash_size(pv->data.v_nation_hash));
4271 gtk_list_store_set(ev->store, &iter, 0, all, -1);
4272 }
4273 buf = propval_as_string(pv);
4274 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4275 g_free(buf);
4276 break;
4277
4278 case OPID_CITY_BUILDINGS:
4279 gtk_tree_model_get(model, &iter, 1, &id, -1);
4280 if (!(0 <= id && id < B_LAST)) {
4281 return;
4282 }
4283 turn_built = present ? game.info.turn : I_NEVER;
4284 pv->data.v_built[id].turn = turn_built;
4285 buf = built_status_to_string(&pv->data.v_built[id]);
4286 gtk_list_store_set(ev->store, &iter, 0, present, 3, buf, -1);
4287 g_free(buf);
4288 buf = propval_as_string(pv);
4289 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4290 g_free(buf);
4291 break;
4292
4293 case OPID_PLAYER_NATION:
4294 gtk_tree_model_get(model, &iter, 1, &id, -1);
4295 if (!(0 <= id && id < nation_count()) || !present) {
4296 return;
4297 }
4298 old_id = nation_index(pv->data.v_nation);
4299 pv->data.v_nation = nation_by_number(id);
4300 gtk_list_store_set(ev->store, &iter, 0, TRUE, -1);
4301 gtk_tree_model_iter_nth_child(model, &iter, NULL, old_id);
4302 gtk_list_store_set(ev->store, &iter, 0, FALSE, -1);
4303 gtk_label_set_text(GTK_LABEL(ev->panel_label),
4304 nation_adjective_translation(pv->data.v_nation));
4305 pixbuf = get_flag(pv->data.v_nation);
4306 gtk_image_set_from_pixbuf(GTK_IMAGE(ev->panel_image), pixbuf);
4307 if (pixbuf) {
4308 g_object_unref(pixbuf);
4309 }
4310 break;
4311
4312 case OPID_PLAYER_GOV:
4313 gtk_tree_model_get(model, &iter, 1, &id, -1);
4314 if (!(0 <= id && id < government_count()) || !present) {
4315 return;
4316 }
4317 old_id = government_index(pv->data.v_gov);
4318 pv->data.v_gov = government_by_number(id);
4319 gtk_list_store_set(ev->store, &iter, 0, TRUE, -1);
4320 gtk_tree_model_iter_nth_child(model, &iter, NULL, old_id);
4321 gtk_list_store_set(ev->store, &iter, 0, FALSE, -1);
4322 gtk_label_set_text(GTK_LABEL(ev->panel_label),
4323 government_name_translation(pv->data.v_gov));
4324 pixbuf = sprite_get_pixbuf(get_government_sprite(tileset, pv->data.v_gov));
4325 gtk_image_set_from_pixbuf(GTK_IMAGE(ev->panel_image), pixbuf);
4326 if (pixbuf) {
4327 g_object_unref(pixbuf);
4328 }
4329 break;
4330
4331 case OPID_PLAYER_INVENTIONS:
4332 gtk_tree_model_get(model, &iter, 1, &id, -1);
4333 if (!(A_FIRST <= id && id < advance_count())) {
4334 return;
4335 }
4336 if (present) {
4337 BV_SET(pv->data.v_bv_inventions, id);
4338 } else {
4339 BV_CLR(pv->data.v_bv_inventions, id);
4340 }
4341 gtk_list_store_set(ev->store, &iter, 0, present, -1);
4342 buf = propval_as_string(pv);
4343 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4344 g_free(buf);
4345 break;
4346
4347 default:
4348 log_error("Unhandled widget toggled signal in "
4349 "extviewer_view_cell_toggled() for objprop id=%d "
4350 "name \"%s\".", propid, objprop_get_name(op));
4351 return;
4352 break;
4353 }
4354
4355 property_page_change_value(pp, op, pv);
4356}
4357
4358/************************************************************************/
4361 static void extviewer_textbuf_changed(GtkTextBuffer *textbuf,
4362 gpointer userdata)
4363{
4364 struct extviewer *ev;
4365 struct objprop *op;
4366 struct property_page *pp;
4367 enum object_property_ids propid;
4368 struct propval value = {{0,}, VALTYPE_STRING, FALSE}, *pv;
4369 GtkTextIter start, end;
4370 char *text;
4371 gchar *buf;
4372
4373 ev = userdata;
4374 if (!ev) {
4375 return;
4376 }
4377
4378 op = extviewer_get_objprop(ev);
4379 propid = objprop_get_id(op);
4380 pp = objprop_get_property_page(op);
4381
4382 gtk_text_buffer_get_start_iter(textbuf, &start);
4383 gtk_text_buffer_get_end_iter(textbuf, &end);
4384 text = gtk_text_buffer_get_text(textbuf, &start, &end, FALSE);
4385 value.data.v_const_string = text;
4386 pv = &value;
4387
4388 switch (propid) {
4389 case OPID_GAME_SCENARIO_AUTHORS:
4390 case OPID_GAME_SCENARIO_DESC:
4391 buf = propval_as_string(pv);
4392 gtk_label_set_text(GTK_LABEL(ev->panel_label), buf);
4393 g_free(buf);
4394 break;
4395 default:
4396 log_error("Unhandled widget modified signal in "
4397 "extviewer_textbuf_changed() for objprop id=%d "
4398 "name \"%s\".", propid, objprop_get_name(op));
4399 return;
4400 break;
4401 }
4402
4403 property_page_change_value(pp, op, pv);
4404 g_free(text);
4405}
4406
4407/************************************************************************/
4410 static void property_page_setup_objprops(struct property_page *pp)
4411{
4412#define ADDPROP(ARG_id, ARG_name, ARG_tooltip, ARG_flags, ARG_valtype) do { \
4413 struct objprop *MY_op = objprop_new(ARG_id, ARG_name, ARG_tooltip, \
4414 ARG_flags, ARG_valtype, pp); \
4415 objprop_hash_insert(pp->objprop_table, MY_op->id, MY_op); \
4416} while (FALSE)
4417
4418 switch (property_page_get_objtype(pp)) {
4419 case OBJTYPE_TILE:
4420 ADDPROP(OPID_TILE_IMAGE, _("Image"), NULL,
4421 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_PIXBUF);
4422 ADDPROP(OPID_TILE_TERRAIN, _("Terrain"), NULL,
4423 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_STRING);
4424 ADDPROP(OPID_TILE_RESOURCE, _("Resource"), NULL,
4425 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_STRING);
4426 ADDPROP(OPID_TILE_INDEX, _("Index"), NULL,
4427 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_INT);
4428 ADDPROP(OPID_TILE_X, Q_("?coordinate:X"), NULL,
4429 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_INT);
4430 ADDPROP(OPID_TILE_Y, Q_("?coordinate:Y"), NULL,
4431 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_INT);
4432 /* TRANS: The coordinate X in native coordinates.
4433 * The freeciv coordinate system is described in doc/HACKING. */
4434 ADDPROP(OPID_TILE_NAT_X, _("NAT X"), NULL,
4435 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_INT);
4436 /* TRANS: The coordinate Y in native coordinates.
4437 * The freeciv coordinate system is described in doc/HACKING. */
4438 ADDPROP(OPID_TILE_NAT_Y, _("NAT Y"), NULL,
4439 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_INT);
4440 ADDPROP(OPID_TILE_CONTINENT, _("Continent"), NULL,
4441 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_INT);
4442 ADDPROP(OPID_TILE_XY, Q_("?coordinates:X,Y"), NULL,
4443 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_STRING);
4444 ADDPROP(OPID_TILE_SPECIALS, _("Specials"), NULL,
4445 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE,
4446 VALTYPE_BV_SPECIAL);
4447 ADDPROP(OPID_TILE_ROADS, _("Roads"), NULL,
4448 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE,
4449 VALTYPE_BV_ROADS);
4450 ADDPROP(OPID_TILE_BASES, _("Bases"), NULL,
4451 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE,
4452 VALTYPE_BV_BASES);
4453#ifdef FREECIV_DEBUG
4454 ADDPROP(OPID_TILE_ADDRESS, _("Address"), NULL,
4455 OPF_HAS_WIDGET, VALTYPE_STRING);
4456#endif /* FREECIV_DEBUG */
4457#if 0
4458 /* Disabled entirely for now as server is not sending other
4459 * players' vision information anyway. */
4460 ADDPROP(OPID_TILE_VISION, _("Vision"), NULL,
4461 OPF_HAS_WIDGET, VALTYPE_TILE_VISION_DATA);
4462#endif
4463 /* TRANS: Tile property "Label" label in editor */
4464 ADDPROP(OPID_TILE_LABEL, Q_("?property:Label"), NULL,
4465 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_STRING);
4466 return;
4467
4468 case OBJTYPE_STARTPOS:
4469 ADDPROP(OPID_STARTPOS_IMAGE, _("Image"), NULL,
4470 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_PIXBUF);
4471 ADDPROP(OPID_STARTPOS_XY, Q_("?coordinates:X,Y"), NULL,
4472 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_STRING);
4473 ADDPROP(OPID_STARTPOS_EXCLUDE, _("Exclude Nations"), NULL,
4474 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_BOOL);
4475 ADDPROP(OPID_STARTPOS_NATIONS, _("Nations"), NULL,
4476 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE,
4477 VALTYPE_NATION_HASH);
4478 return;
4479
4480 case OBJTYPE_UNIT:
4481 ADDPROP(OPID_UNIT_IMAGE, _("Image"), NULL,
4482 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_PIXBUF);
4483#ifdef FREECIV_DEBUG
4484 ADDPROP(OPID_UNIT_ADDRESS, _("Address"), NULL,
4485 OPF_HAS_WIDGET, VALTYPE_STRING);
4486#endif /* FREECIV_DEBUG */
4487 ADDPROP(OPID_UNIT_TYPE, _("Type"), NULL,
4488 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_STRING);
4489 ADDPROP(OPID_UNIT_ID, _("ID"), NULL,
4490 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_INT);
4491 ADDPROP(OPID_UNIT_XY, Q_("?coordinates:X,Y"), NULL,
4492 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_STRING);
4493 ADDPROP(OPID_UNIT_MOVES_LEFT, _("Moves Left"), NULL,
4494 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_INT);
4495 ADDPROP(OPID_UNIT_FUEL, _("Fuel"), NULL,
4496 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_INT);
4497 ADDPROP(OPID_UNIT_MOVED, _("Moved"), NULL,
4498 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_BOOL);
4499 ADDPROP(OPID_UNIT_DONE_MOVING, _("Done Moving"), NULL,
4500 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_BOOL);
4501 /* TRANS: HP = Hit Points of a unit. */
4502 ADDPROP(OPID_UNIT_HP, _("HP"), NULL,
4503 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_INT);
4504 ADDPROP(OPID_UNIT_VETERAN, _("Veteran"), NULL,
4505 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_INT);
4506 ADDPROP(OPID_UNIT_STAY, _("Stay put"), NULL,
4507 OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_BOOL);
4508 return;
4509
4510 case OBJTYPE_CITY:
4511 ADDPROP(OPID_CITY_IMAGE, _("Image"), NULL,
4512 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_PIXBUF);
4513 ADDPROP(OPID_CITY_NAME, _("Name"), NULL,
4514 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_STRING);
4515#ifdef FREECIV_DEBUG
4516 ADDPROP(OPID_CITY_ADDRESS, _("Address"), NULL,
4517 OPF_HAS_WIDGET, VALTYPE_STRING);
4518#endif /* FREECIV_DEBUG */
4519 ADDPROP(OPID_CITY_ID, _("ID"), NULL,
4520 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_INT);
4521 ADDPROP(OPID_CITY_XY, Q_("?coordinates:X,Y"), NULL,
4522 OPF_IN_LISTVIEW | OPF_HAS_WIDGET, VALTYPE_STRING);
4523 ADDPROP(OPID_CITY_SIZE, _("Size"), NULL,
4524 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_INT);
4525 ADDPROP(OPID_CITY_HISTORY, _("History"), NULL,
4526 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_INT);
4527 ADDPROP(OPID_CITY_BUILDINGS, _("Buildings"), NULL,
4528 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE,
4529 VALTYPE_BUILT_ARRAY);
4530 ADDPROP(OPID_CITY_FOOD_STOCK, _("Food Stock"), NULL,
4531 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_INT);
4532 ADDPROP(OPID_CITY_SHIELD_STOCK, _("Shield Stock"), NULL,
4533 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_INT);
4534 return;
4535
4536 case OBJTYPE_PLAYER:
4537 ADDPROP(OPID_PLAYER_NAME, _("Name"), NULL,
4538 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE,
4539 VALTYPE_STRING);
4540#ifdef FREECIV_DEBUG
4541 ADDPROP(OPID_PLAYER_ADDRESS, _("Address"), NULL,
4542 OPF_HAS_WIDGET, VALTYPE_STRING);
4543#endif /* FREECIV_DEBUG */
4544 ADDPROP(OPID_PLAYER_NATION, _("Nation"), NULL,
4545 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE,
4546 VALTYPE_NATION);
4547 ADDPROP(OPID_PLAYER_GOV, _("Government"), NULL,
4548 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE,
4549 VALTYPE_GOV);
4550 ADDPROP(OPID_PLAYER_AGE, _("Age"), NULL,
4551 OPF_HAS_WIDGET, VALTYPE_INT);
4552 ADDPROP(OPID_PLAYER_INVENTIONS, _("Inventions"), NULL,
4553 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE,
4554 VALTYPE_INVENTIONS_ARRAY);
4555 ADDPROP(OPID_PLAYER_SCENARIO_RESERVED, _("Reserved"), NULL,
4556 OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_BOOL);
4557 ADDPROP(OPID_PLAYER_SELECT_WEIGHT, _("Select Weight"),
4558 _("How likely user is to get this player by autoselect. '-1' for default behavior."),
4559 OPF_HAS_WIDGET | OPF_EDITABLE,
4560 VALTYPE_INT);
4561 ADDPROP(OPID_PLAYER_SCIENCE, _("Science"), NULL,
4562 OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_INT);
4563 ADDPROP(OPID_PLAYER_GOLD, _("Gold"), NULL,
4564 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE,
4565 VALTYPE_INT);
4566 return;
4567
4568 case OBJTYPE_GAME:
4569 ADDPROP(OPID_GAME_SCENARIO, _("Scenario"), NULL,
4570 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE,
4571 VALTYPE_BOOL);
4572 ADDPROP(OPID_GAME_SCENARIO_NAME,
4573 _("Scenario Name"), NULL,
4574 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE,
4575 VALTYPE_STRING);
4576 ADDPROP(OPID_GAME_SCENARIO_AUTHORS,
4577 _("Scenario Authors"), NULL,
4578 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE,
4579 VALTYPE_STRING);
4580 ADDPROP(OPID_GAME_SCENARIO_DESC,
4581 _("Scenario Description"), NULL,
4582 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE,
4583 VALTYPE_STRING);
4584 ADDPROP(OPID_GAME_SCENARIO_RANDSTATE,
4585 _("Save Random Number State"), NULL,
4586 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_BOOL);
4587 ADDPROP(OPID_GAME_SCENARIO_PLAYERS,
4588 _("Save Players"), NULL,
4589 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_BOOL);
4590 ADDPROP(OPID_GAME_STARTPOS_NATIONS,
4591 _("Nation Start Positions"), NULL,
4592 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_BOOL);
4593 ADDPROP(OPID_GAME_PREVENT_CITIES,
4594 _("Prevent New Cities"), NULL,
4595 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_BOOL);
4596 ADDPROP(OPID_GAME_LAKE_FLOODING,
4597 _("Saltwater Flooding Lakes"), NULL,
4598 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_BOOL);
4599 ADDPROP(OPID_GAME_RULESET_LOCKED,
4600 _("Lock to current Ruleset"), NULL,
4601 OPF_IN_LISTVIEW | OPF_HAS_WIDGET | OPF_EDITABLE, VALTYPE_BOOL);
4602 return;
4603
4604 case NUM_OBJTYPES:
4605 break;
4606 }
4607
4608 log_error("%s(): Unhandled page object type %s (nb %d).", __FUNCTION__,
4609 objtype_get_name(property_page_get_objtype(pp)),
4610 property_page_get_objtype(pp));
4611#undef ADDPROP
4612}
4613
4614/************************************************************************/
4617 static void property_page_selection_changed(GtkTreeSelection *sel,
4618 gpointer userdata)
4619{
4620 struct property_page *pp;
4621 struct objbind *ob = NULL;
4622
4623 pp = userdata;
4624 if (!pp) {
4625 return;
4626 }
4627
4628 if (gtk_tree_selection_count_selected_rows(sel) < 1) {
4629 property_page_set_focused_objbind(pp, NULL);
4630 }
4631
4632 ob = property_page_get_focused_objbind(pp);
4633 property_page_objprop_iterate(pp, op) {
4634 objprop_refresh_widget(op, ob);
4635 } property_page_objprop_iterate_end;
4636}
4637
4638/************************************************************************/
4642 static gboolean property_page_selection_func(GtkTreeSelection *sel,
4643 GtkTreeModel *model,
4644 GtkTreePath *sel_path,
4645 gboolean currently_selected,
4646 gpointer data)
4647{
4648 struct property_page *pp;
4649 struct objbind *ob = NULL, *old_ob;
4650 GtkTreeIter iter;
4651
4652 pp = data;
4653 if (!pp || !sel_path) {
4654 return TRUE;
4655 }
4656
4657 if (!gtk_tree_model_get_iter(model, &iter, sel_path)) {
4658 return TRUE;
4659 }
4660
4661 old_ob = property_page_get_focused_objbind(pp);
4662 gtk_tree_model_get(model, &iter, 0, &ob, -1);
4663 if (currently_selected) {
4664 if (ob == old_ob) {
4665 GList *rows, *p;
4666 GtkTreePath *path;
4667 struct objbind *new_ob = NULL;
4668
4669 rows = gtk_tree_selection_get_selected_rows(sel, NULL);
4670 for (p = rows; p != NULL; p = p->next) {
4671 path = p->data;
4672 if (gtk_tree_model_get_iter(model, &iter, path)) {
4673 struct objbind *test_ob = NULL;
4674 gtk_tree_model_get(model, &iter, 0, &test_ob, -1);
4675 if (test_ob == ob) {
4676 continue;
4677 }
4678 new_ob = test_ob;
4679 break;
4680 }
4681 }
4682 g_list_foreach(rows, (GFunc) gtk_tree_path_free, NULL);
4683 g_list_free(rows);
4684
4685 property_page_set_focused_objbind(pp, new_ob);
4686 }
4687 } else {
4688 property_page_set_focused_objbind(pp, ob);
4689 }
4690
4691 return TRUE;
4692}
4693
4694/************************************************************************/
4697 static void property_page_quick_find_entry_changed(GtkWidget *entry,
4698 gpointer userdata)
4699{
4700 struct property_page *pp;
4701 const gchar *text;
4702 GtkWidget *w;
4703 GtkTreeViewColumn *col;
4704 struct property_filter *pf;
4705 bool matched;
4706
4707 pp = userdata;
4708 text = gtk_entry_buffer_get_text(gtk_entry_get_buffer(GTK_ENTRY(entry)));
4709 pf = property_filter_new(text);
4710
4711 property_page_objprop_iterate(pp, op) {
4712 if (!objprop_has_widget(op)
4713 && !objprop_show_in_listview(op)) {
4714 continue;
4715 }
4716 matched = property_filter_match(pf, op);
4717 w = objprop_get_widget(op);
4718 if (objprop_has_widget(op) && w != NULL) {
4719 gtk_widget_set_visible(w, matched);
4720 }
4721 col = objprop_get_treeview_column(op);
4722 if (objprop_show_in_listview(op) && col != NULL) {
4723 gtk_tree_view_column_set_visible(col, matched);
4724 }
4725 } property_page_objprop_iterate_end;
4726
4727 property_filter_free(pf);
4728}
4729
4730/************************************************************************/
4734static struct property_page *
4735 property_page_new(enum editor_object_type objtype,
4736 struct property_editor *pe)
4737{
4738 struct property_page *pp;
4739 GtkWidget *vgrid, *vgrid2, *hgrid, *hgrid2, *paned, *frame, *w;
4740 GtkWidget *scrollwin, *view, *label, *entry, *notebook;
4741 GtkWidget *button, *hsep;
4742 GtkTreeSelection *sel;
4743 GtkCellRenderer *cell;
4744 GtkTreeViewColumn *col;
4745 GtkSizeGroup *sizegroup;
4746 int num_columns = 0;
4747 GType *gtype_array;
4748 int col_id = 1;
4749 const char *attr_type_str, *name, *tooltip;
4750 gchar *title;
4751 int grid_row = 0;
4752 int grid2_row = 0;
4753 int grid_col = 0;
4754 int grid2_col = 0;
4755
4756 if (!(objtype < NUM_OBJTYPES)) {
4757 return NULL;
4758 }
4759
4760 pp = fc_calloc(1, sizeof(struct property_page));
4761 pp->objtype = objtype;
4762 pp->pe_parent = pe;
4763
4764 sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
4765
4766 pp->objprop_table = objprop_hash_new();
4767 property_page_setup_objprops(pp);
4768
4769 pp->objbind_table = objbind_hash_new();
4770
4771 pp->tag_table = stored_tag_hash_new();
4772
4773 property_page_objprop_iterate(pp, op) {
4774 if (objprop_show_in_listview(op)) {
4775 num_columns++;
4776 }
4777 } property_page_objprop_iterate_end;
4778
4779 /* Column zero in the store holds an objbind
4780 * pointer and is never displayed. */
4781 num_columns++;
4782 gtype_array = fc_malloc(num_columns * sizeof(GType));
4783 gtype_array[0] = G_TYPE_POINTER;
4784
4785 property_page_objprop_iterate(pp, op) {
4786 if (objprop_show_in_listview(op)) {
4787 gtype_array[col_id] = objprop_get_gtype(op);
4788 objprop_set_column_id(op, col_id);
4789 col_id++;
4790 }
4791 } property_page_objprop_iterate_end;
4792
4793 pp->object_store = gtk_list_store_newv(num_columns, gtype_array);
4794 free(gtype_array);
4795
4796 paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
4797 gtk_paned_set_position(GTK_PANED(paned), 256);
4798 pp->widget = paned;
4799
4800 /* Left side object list view. */
4801
4802 vgrid = gtk_grid_new();
4803 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
4804 GTK_ORIENTATION_VERTICAL);
4805 gtk_grid_set_row_spacing(GTK_GRID(vgrid), 4);
4806 gtk_widget_set_margin_start(vgrid, 4);
4807 gtk_widget_set_margin_end(vgrid, 4);
4808 gtk_widget_set_margin_top(vgrid, 4);
4809 gtk_widget_set_margin_bottom(vgrid, 4);
4810 gtk_paned_set_start_child(GTK_PANED(paned), vgrid);
4811
4812 scrollwin = gtk_scrolled_window_new();
4813 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(scrollwin),
4814 TRUE);
4815 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
4816 GTK_POLICY_AUTOMATIC,
4817 GTK_POLICY_AUTOMATIC);
4818 gtk_grid_attach(GTK_GRID(vgrid), scrollwin, 0, grid_row++, 1, 1);
4819
4820 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pp->object_store));
4821 gtk_widget_set_hexpand(view, TRUE);
4822 gtk_widget_set_vexpand(view, TRUE);
4823
4824 property_page_objprop_iterate(pp, op) {
4825 if (!objprop_show_in_listview(op)) {
4826 continue;
4827 }
4828
4829 attr_type_str = objprop_get_attribute_type_string(op);
4830 if (!attr_type_str) {
4831 continue;
4832 }
4833 col_id = objprop_get_column_id(op);
4834 if (col_id < 0) {
4835 continue;
4836 }
4837 name = objprop_get_name(op);
4838 if (!name) {
4839 continue;
4840 }
4841 cell = objprop_create_cell_renderer(op);
4842 if (!cell) {
4843 continue;
4844 }
4845
4846 col = gtk_tree_view_column_new_with_attributes(name, cell,
4847 attr_type_str, col_id,
4848 NULL);
4849
4850 gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
4851 gtk_tree_view_column_set_resizable(col, TRUE);
4852 gtk_tree_view_column_set_reorderable(col, TRUE);
4853 if (objprop_is_sortable(op)) {
4854 gtk_tree_view_column_set_clickable(col, TRUE);
4855 gtk_tree_view_column_set_sort_column_id(col, col_id);
4856 } else {
4857 gtk_tree_view_column_set_clickable(col, FALSE);
4858 }
4859 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
4860 objprop_set_treeview_column(op, col);
4861
4862 } property_page_objprop_iterate_end;
4863
4864 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
4865 gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
4866 g_signal_connect(sel, "changed",
4867 G_CALLBACK(property_page_selection_changed), pp);
4868 gtk_tree_selection_set_select_function(sel,
4869 property_page_selection_func, pp, NULL);
4870
4871 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrollwin), view);
4872 pp->object_view = view;
4873
4874 if (!objtype_is_conserved(objtype)) {
4875 hgrid = gtk_grid_new();
4876 gtk_grid_set_column_spacing(GTK_GRID(hgrid), 4);
4877 gtk_grid_attach(GTK_GRID(vgrid), hgrid, 0, grid_row++, 1, 1);
4878
4879 button = gtk_button_new();
4880 gtk_button_set_icon_name(GTK_BUTTON(button), "list-add");
4881 gtk_button_set_label(GTK_BUTTON(button), _("Create"));
4882 gtk_size_group_add_widget(sizegroup, button);
4883 gtk_widget_set_tooltip_text(button,
4884 _("Pressing this button will create a new object of the "
4885 "same type as the current property page and add it to "
4886 "the page. The specific type and count of the objects "
4887 "is taken from the editor tool state. So for example, "
4888 "the \"tool value\" of the unit tool and its \"count\" "
4889 "parameter affect unit creation."));
4890 g_signal_connect(button, "clicked",
4891 G_CALLBACK(property_page_create_button_clicked), pp);
4892 gtk_grid_attach(GTK_GRID(hgrid), button, grid_col++, 0, 1, 1);
4893
4894 button = gtk_button_new();
4895 gtk_button_set_icon_name(GTK_BUTTON(button), "list-remove");
4896 gtk_button_set_label(GTK_BUTTON(button), _("Destroy"));
4897 gtk_size_group_add_widget(sizegroup, button);
4898 gtk_widget_set_tooltip_text(button,
4899 _("Pressing this button will send a request to the server "
4900 "to destroy (i.e. erase) the objects selected in the object "
4901 "list."));
4902 g_signal_connect(button, "clicked",
4903 G_CALLBACK(property_page_destroy_button_clicked), pp);
4904 gtk_grid_attach(GTK_GRID(hgrid), button, grid_col++, 0, 1, 1);
4905 }
4906
4907 /* Right side properties panel. */
4908
4909 hgrid = gtk_grid_new();
4910 grid_col = 0;
4911 gtk_grid_set_column_spacing(GTK_GRID(hgrid), 4);
4912 gtk_paned_set_end_child(GTK_PANED(paned), hgrid);
4913
4914 vgrid = gtk_grid_new();
4915 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
4916 GTK_ORIENTATION_VERTICAL);
4917 gtk_grid_set_row_spacing(GTK_GRID(vgrid), 4);
4918 gtk_widget_set_margin_start(vgrid, 4);
4919 gtk_widget_set_margin_end(vgrid, 4);
4920 gtk_widget_set_margin_top(vgrid, 4);
4921 gtk_widget_set_margin_bottom(vgrid, 4);
4922 gtk_grid_attach(GTK_GRID(hgrid), vgrid, grid_col++, 0, 1, 1);
4923
4924 /* Extended property viewer to the right of the properties panel.
4925 * This needs to be created before property widgets, since some
4926 * might try to append themselves to this notebook. */
4927
4928 vgrid2 = gtk_grid_new();
4929 gtk_widget_set_hexpand(vgrid2, TRUE);
4930 gtk_widget_set_vexpand(vgrid, TRUE);
4931 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid2),
4932 GTK_ORIENTATION_VERTICAL);
4933 gtk_grid_set_row_spacing(GTK_GRID(vgrid2), 4);
4934 gtk_grid_attach(GTK_GRID(hgrid), vgrid2, grid_col++, 0, 1, 1);
4935
4936 notebook = gtk_notebook_new();
4937 gtk_widget_set_vexpand(notebook, TRUE);
4938 gtk_widget_set_size_request(notebook, 256, -1);
4939 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
4940 gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
4941 gtk_grid_attach(GTK_GRID(vgrid2), notebook, 0, grid2_row++, 1, 1);
4942 pp->extviewer_notebook = notebook;
4943
4944 hsep = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
4945 gtk_grid_attach(GTK_GRID(vgrid2), hsep, 0, grid2_row++, 1, 1);
4946
4947 hgrid2 = gtk_grid_new();
4948 gtk_widget_set_margin_start(hgrid2, 4);
4949 gtk_widget_set_margin_end(hgrid2, 4);
4950 gtk_widget_set_margin_top(hgrid2, 4);
4951 gtk_widget_set_margin_bottom(hgrid2, 4);
4952 gtk_grid_attach(GTK_GRID(vgrid2), hgrid2, 0, grid2_row++, 1, 1);
4953
4954 button = gtk_button_new_with_mnemonic(_("_Close"));
4955 gtk_size_group_add_widget(sizegroup, button);
4956 g_signal_connect_swapped(button, "clicked",
4957 G_CALLBACK(gtk_window_close), pe->widget);
4958 gtk_grid_attach(GTK_GRID(hgrid2), button, grid2_col++, 0, 1, 1);
4959
4960 /* Now create the properties panel. */
4961
4962 /* TRANS: %s is a type of object that can be edited, such as "Tile",
4963 * "Unit", "Start Position", etc. */
4964 title = g_strdup_printf(_("%s Properties"),
4965 objtype_get_name(objtype));
4966 frame = gtk_frame_new(title);
4967 g_free(title);
4968 gtk_widget_set_size_request(frame, 256, -1);
4969 gtk_grid_attach(GTK_GRID(vgrid), frame, 0, grid_row++, 1, 1);
4970
4971 scrollwin = gtk_scrolled_window_new();
4972 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(scrollwin),
4973 FALSE);
4974 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
4975 GTK_POLICY_AUTOMATIC,
4976 GTK_POLICY_AUTOMATIC);
4977 gtk_frame_set_child(GTK_FRAME(frame), scrollwin);
4978
4979 vgrid2 = gtk_grid_new();
4980 grid2_row = 0;
4981 gtk_widget_set_vexpand(vgrid2, TRUE);
4982 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid2),
4983 GTK_ORIENTATION_VERTICAL);
4984 gtk_grid_set_row_spacing(GTK_GRID(vgrid2), 4);
4985 gtk_widget_set_margin_start(vgrid2, 4);
4986 gtk_widget_set_margin_end(vgrid2, 4);
4987 gtk_widget_set_margin_top(vgrid2, 4);
4988 gtk_widget_set_margin_bottom(vgrid2, 4);
4989 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrollwin), vgrid2);
4990
4991 property_page_objprop_iterate(pp, op) {
4992 if (!objprop_has_widget(op)) {
4993 continue;
4994 }
4995 w = objprop_get_widget(op);
4996 if (!w) {
4997 continue;
4998 }
4999 gtk_grid_attach(GTK_GRID(vgrid2), w, 0, grid2_row++, 1, 1);
5000 tooltip = objprop_get_tooltip(op);
5001 if (NULL != tooltip) {
5002 gtk_widget_set_tooltip_text(w, tooltip);
5003 }
5004 } property_page_objprop_iterate_end;
5005
5006 hgrid2 = gtk_grid_new();
5007 grid2_col = 0;
5008 gtk_widget_set_margin_top(hgrid2, 4);
5009 gtk_widget_set_margin_bottom(hgrid2, 4);
5010 gtk_grid_set_column_spacing(GTK_GRID(hgrid2), 4);
5011 gtk_grid_attach(GTK_GRID(vgrid), hgrid2, 0, grid_row++, 1, 1);
5012
5013 label = gtk_label_new(_("Filter:"));
5014 gtk_grid_attach(GTK_GRID(hgrid2), label, grid2_col++, 0, 1, 1);
5015
5016 entry = gtk_entry_new();
5017 gtk_widget_set_tooltip_text(entry,
5018 _("Enter a filter string to limit which properties are shown. "
5019 "The filter is one or more text patterns separated by | "
5020 "(\"or\") or & (\"and\"). The symbol & has higher precedence "
5021 "than |. A pattern may also be negated by prefixing it with !."));
5022 g_signal_connect(entry, "changed",
5023 G_CALLBACK(property_page_quick_find_entry_changed), pp);
5024 gtk_grid_attach(GTK_GRID(hgrid2), entry, grid2_col++, 0, 1, 1);
5025
5026 hgrid2 = gtk_grid_new();
5027 grid2_col = 0;
5028 gtk_grid_set_column_spacing(GTK_GRID(hgrid2), 4);
5029 gtk_grid_attach(GTK_GRID(vgrid), hgrid2, 0, grid_row++, 1, 1);
5030
5031 button = gtk_button_new_with_mnemonic(_("_Refresh"));
5032 gtk_size_group_add_widget(sizegroup, button);
5033 gtk_widget_set_tooltip_text(button,
5034 _("Pressing this button will reset all modified properties of "
5035 "the selected objects to their current values (the values "
5036 "they have on the server)."));
5037 g_signal_connect(button, "clicked",
5038 G_CALLBACK(property_page_refresh_button_clicked), pp);
5039 gtk_grid_attach(GTK_GRID(hgrid2), button, grid2_col++, 0, 1, 1);
5040
5041 button = gtk_button_new_with_mnemonic(_("_Apply"));
5042 gtk_size_group_add_widget(sizegroup, button);
5043 gtk_widget_set_tooltip_text(button,
5044 _("Pressing this button will send all modified properties of "
5045 "the objects selected in the object list to the server. "
5046 "Modified properties' names are shown in red in the properties "
5047 "panel."));
5048 g_signal_connect(button, "clicked",
5049 G_CALLBACK(property_page_apply_button_clicked), pp);
5050 gtk_grid_attach(GTK_GRID(hgrid2), button, grid2_col++, 0, 1, 1);
5051
5052 return pp;
5053}
5054
5055/************************************************************************/
5058 static const char *property_page_get_name(const struct property_page *pp)
5059{
5060 if (!pp) {
5061 return "";
5062 }
5063 return objtype_get_name(property_page_get_objtype(pp));
5064}
5065
5066/************************************************************************/
5069static enum editor_object_type
5070 property_page_get_objtype(const struct property_page *pp)
5071{
5072 if (!pp) {
5073 return -1;
5074 }
5075 return pp->objtype;
5076}
5077
5078/************************************************************************/
5086 static GdkPixbuf *create_tile_pixbuf(const struct tile *ptile)
5087{
5088 return create_pixbuf_from_layers(ptile, NULL, NULL, LAYER_CATEGORY_TILE);
5089}
5090
5091/************************************************************************/
5098 static GdkPixbuf *create_unit_pixbuf(const struct unit *punit)
5099{
5100 return create_pixbuf_from_layers(NULL, punit, NULL, LAYER_CATEGORY_UNIT);
5101}
5102
5103/************************************************************************/
5110 static GdkPixbuf *create_city_pixbuf(const struct city *pcity)
5111{
5112 return create_pixbuf_from_layers(city_tile(pcity), NULL, pcity,
5113 LAYER_CATEGORY_CITY);
5114}
5115
5116/************************************************************************/
5124 static GdkPixbuf *create_pixbuf_from_layers(const struct tile *ptile,
5125 const struct unit *punit,
5126 const struct city *pcity,
5127 enum layer_category category)
5128{
5129 struct canvas canvas = FC_STATIC_CANVAS_INIT;
5130 int h, fh, fw, canvas_x, canvas_y;
5131 GdkPixbuf *pixbuf;
5132 cairo_t *cr;
5133
5134 fw = tileset_full_tile_width(tileset);
5135 fh = tileset_full_tile_height(tileset);
5136 h = tileset_tile_height(tileset);
5137
5138 canvas.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, fw, fh);
5139
5140 cr = cairo_create(canvas.surface);
5141 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
5142 cairo_paint(cr);
5143 cairo_destroy(cr);
5144
5145 canvas_x = 0;
5146 canvas_y = 0;
5147
5148 canvas_y += (fh - h);
5149
5150 mapview_layer_iterate(layer) {
5151 if (tileset_layer_in_category(layer, category)) {
5152 put_one_element(&canvas, 1.0, layer,
5153 ptile, NULL, NULL, punit, pcity,
5154 canvas_x, canvas_y, NULL, NULL);
5155 }
5156 } mapview_layer_iterate_end
5157 pixbuf = surface_get_pixbuf(canvas.surface, fw, fh);
5158 cairo_surface_destroy(canvas.surface);
5159
5160 return pixbuf;
5161}
5162
5163/************************************************************************/
5166 static void property_page_clear_objbinds(struct property_page *pp)
5167{
5168 if (!pp) {
5169 return;
5170 }
5171
5172 gtk_list_store_clear(pp->object_store);
5173 objbind_hash_clear(pp->objbind_table);
5174 property_page_set_focused_objbind(pp, NULL);
5175}
5176
5177/************************************************************************/
5181 static void property_page_add_objbind(struct property_page *pp,
5182 gpointer object_data)
5183{
5184 struct objbind *ob;
5185 enum editor_object_type objtype;
5186 int id;
5187
5188 if (!pp) {
5189 return;
5190 }
5191
5192 objtype = property_page_get_objtype(pp);
5193 id = objtype_get_id_from_object(objtype, object_data);
5194 if (id < 0) {
5195 return;
5196 }
5197
5198 if (objbind_hash_lookup(pp->objbind_table, id, NULL)) {
5199 /* Object already exists. */
5200 return;
5201 }
5202
5203 ob = objbind_new(objtype, object_data);
5204 if (!ob) {
5205 return;
5206 }
5207
5208 objbind_bind_properties(ob, pp);
5209
5210 objbind_hash_insert(pp->objbind_table, ob->object_id, ob);
5211}
5212
5213/************************************************************************/
5217 static void property_page_add_objbinds_from_tile(struct property_page *pp,
5218 const struct tile *ptile)
5219{
5220
5221 if (!pp || !ptile) {
5222 return;
5223 }
5224
5225 switch (property_page_get_objtype(pp)) {
5226 case OBJTYPE_TILE:
5227 property_page_add_objbind(pp, (gpointer) ptile);
5228 return;
5229
5230 case OBJTYPE_STARTPOS:
5231 {
5232 struct startpos *psp = map_startpos_get(ptile);
5233
5234 if (NULL != psp) {
5235 property_page_add_objbind(pp, map_startpos_get(ptile));
5236 }
5237 }
5238 return;
5239
5240 case OBJTYPE_UNIT:
5241 unit_list_iterate(ptile->units, punit) {
5242 property_page_add_objbind(pp, punit);
5243 } unit_list_iterate_end;
5244 return;
5245
5246 case OBJTYPE_CITY:
5247 if (tile_city(ptile)) {
5248 property_page_add_objbind(pp, tile_city(ptile));
5249 }
5250 return;
5251
5252 case OBJTYPE_PLAYER:
5253 case OBJTYPE_GAME:
5254 return;
5255
5256 case NUM_OBJTYPES:
5257 break;
5258 }
5259
5260 log_error("%s(): Unhandled page object type %s (nb %d).", __FUNCTION__,
5261 objtype_get_name(property_page_get_objtype(pp)),
5262 property_page_get_objtype(pp));
5263}
5264
5265/************************************************************************/
5271 static bool property_page_set_store_value(struct property_page *pp,
5272 struct objprop *op,
5273 struct objbind *ob,
5274 GtkTreeIter *iter)
5275{
5276 int col_id;
5277 struct propval *pv;
5278 enum value_types valtype;
5279 char buf[128], *p;
5280 GdkPixbuf *pixbuf = NULL;
5281 GtkListStore *store;
5282 gchar *buf2;
5283
5284 if (!pp || !pp->object_store || !op || !ob) {
5285 return FALSE;
5286 }
5287
5288 if (!objprop_show_in_listview(op)) {
5289 return FALSE;
5290 }
5291
5292 col_id = objprop_get_column_id(op);
5293 if (col_id < 0) {
5294 return FALSE;
5295 }
5296
5297 pv = objbind_get_value_from_object(ob, op);
5298 if (!pv) {
5299 return FALSE;
5300 }
5301
5302 valtype = objprop_get_valtype(op);
5303 store = pp->object_store;
5304
5305 switch (valtype) {
5306 case VALTYPE_NONE:
5307 break;
5308 case VALTYPE_INT:
5309 gtk_list_store_set(store, iter, col_id, pv->data.v_int, -1);
5310 break;
5311 case VALTYPE_BOOL:
5312 /* Set as translated string, not as untranslated G_TYPE_BOOLEAN */
5313 gtk_list_store_set(store, iter, col_id, propval_as_string(pv), -1);
5314 break;
5315 case VALTYPE_STRING:
5316 if (fc_strlcpy(buf, pv->data.v_string, 28) >= 28) {
5317 sz_strlcat(buf, "...");
5318 }
5319 for (p = buf; *p; p++) {
5320 if (*p == '\n' || *p == '\t' || *p == '\r') {
5321 *p = ' ';
5322 }
5323 }
5324 gtk_list_store_set(store, iter, col_id, buf, -1);
5325 break;
5326 case VALTYPE_PIXBUF:
5327 gtk_list_store_set(store, iter, col_id, pv->data.v_pixbuf, -1);
5328 break;
5329 case VALTYPE_BUILT_ARRAY:
5330 case VALTYPE_INVENTIONS_ARRAY:
5331 case VALTYPE_BV_SPECIAL:
5332 case VALTYPE_BV_ROADS:
5333 case VALTYPE_BV_BASES:
5334 case VALTYPE_NATION_HASH:
5335 buf2 = propval_as_string(pv);
5336 gtk_list_store_set(store, iter, col_id, buf2, -1);
5337 g_free(buf2);
5338 break;
5339 case VALTYPE_NATION:
5340 pixbuf = get_flag(pv->data.v_nation);
5341 gtk_list_store_set(store, iter, col_id, pixbuf, -1);
5342 if (pixbuf) {
5343 g_object_unref(pixbuf);
5344 }
5345 break;
5346 case VALTYPE_GOV:
5347 pixbuf = sprite_get_pixbuf(get_government_sprite(tileset, pv->data.v_gov));
5348 gtk_list_store_set(store, iter, col_id, pixbuf, -1);
5349 if (pixbuf) {
5350 g_object_unref(pixbuf);
5351 }
5352 break;
5353 case VALTYPE_TILE_VISION_DATA:
5354 break;
5355 }
5356
5357 propval_free(pv);
5358
5359 return TRUE;
5360}
5361
5362/************************************************************************/
5366 static void property_page_fill_widgets(struct property_page *pp)
5367{
5368 struct objbind *focused;
5369
5370 if (!pp || !pp->objbind_table) {
5371 return;
5372 }
5373
5374 if (pp->object_store) {
5375 GtkTreeIter iter;
5376 GtkTreeRowReference *rr;
5377 GtkTreeModel *model;
5378 GtkTreePath *path;
5379
5380 model = GTK_TREE_MODEL(pp->object_store);
5381
5382 property_page_objbind_iterate(pp, ob) {
5383 if (objbind_get_rowref(ob)) {
5384 continue;
5385 }
5386 gtk_list_store_append(pp->object_store, &iter);
5387 gtk_list_store_set(pp->object_store, &iter, 0, ob, -1);
5388 path = gtk_tree_model_get_path(model, &iter);
5389 rr = gtk_tree_row_reference_new(model, path);
5390 gtk_tree_path_free(path);
5391 objbind_set_rowref(ob, rr);
5392
5393 property_page_objprop_iterate(pp, op) {
5394 property_page_set_store_value(pp, op, ob, &iter);
5395 } property_page_objprop_iterate_end;
5396 } property_page_objbind_iterate_end;
5397
5398 if (gtk_tree_model_get_iter_first(model, &iter)) {
5399 GtkTreeSelection *sel;
5400 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pp->object_view));
5401 gtk_tree_selection_select_iter(sel, &iter);
5402 }
5403 }
5404
5405 focused = property_page_get_focused_objbind(pp);
5406 property_page_objprop_iterate(pp, op) {
5407 objprop_refresh_widget(op, focused);
5408 } property_page_objprop_iterate_end;
5409}
5410
5411/************************************************************************/
5415 static struct objbind *property_page_get_focused_objbind(struct property_page *pp)
5416{
5417 if (!pp) {
5418 return NULL;
5419 }
5420 return pp->focused_objbind;
5421}
5422
5423/************************************************************************/
5427 static void property_page_set_focused_objbind(struct property_page *pp,
5428 struct objbind *ob)
5429{
5430 if (!pp) {
5431 return;
5432 }
5433 pp->focused_objbind = ob;
5434}
5435
5436/************************************************************************/
5440 static struct objbind *property_page_get_objbind(struct property_page *pp,
5441 int object_id)
5442{
5443 struct objbind *ob;
5444
5445 if (!pp || !pp->objbind_table) {
5446 return NULL;
5447 }
5448
5449 objbind_hash_lookup(pp->objbind_table, object_id, &ob);
5450 return ob;
5451}
5452
5453/************************************************************************/
5457 static void property_page_load_tiles(struct property_page *pp,
5458 const struct tile_list *tiles)
5459{
5460 if (!pp || !tiles) {
5461 return;
5462 }
5463
5464 tile_list_iterate(tiles, ptile) {
5465 property_page_add_objbinds_from_tile(pp, ptile);
5466 } tile_list_iterate_end;
5467
5468 property_page_fill_widgets(pp);
5469}
5470
5471/************************************************************************/
5474 static int property_page_get_num_objbinds(const struct property_page *pp)
5475{
5476 if (!pp || !pp->objbind_table) {
5477 return 0;
5478 }
5479 return objbind_hash_size(pp->objbind_table);
5480}
5481
5482/************************************************************************/
5486 static void property_page_change_value(struct property_page *pp,
5487 struct objprop *op,
5488 struct propval *pv)
5489{
5490 GtkTreeSelection *sel;
5491 GtkTreeModel *model;
5492 GList *rows, *p;
5493 GtkTreePath *path;
5494 GtkTreeIter iter;
5495 struct objbind *ob;
5496 bool changed = FALSE;
5497
5498 if (!pp || !op || !pp->object_view) {
5499 return;
5500 }
5501
5502 if (objprop_is_readonly(op)) {
5503 return;
5504 }
5505
5506 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pp->object_view));
5507 rows = gtk_tree_selection_get_selected_rows(sel, &model);
5508
5509 for (p = rows; p != NULL; p = p->next) {
5510 path = p->data;
5511 if (gtk_tree_model_get_iter(model, &iter, path)) {
5512 gtk_tree_model_get(model, &iter, 0, &ob, -1);
5513 changed |= objbind_set_modified_value(ob, op, pv);
5514 }
5515 gtk_tree_path_free(path);
5516 }
5517 g_list_free(rows);
5518
5519 if (changed) {
5520 ob = property_page_get_focused_objbind(pp);
5521 objprop_refresh_widget(op, ob);
5522 }
5523}
5524
5525/************************************************************************/
5528 static void property_page_send_values(struct property_page *pp)
5529{
5530 GtkTreeSelection *sel;
5531 GtkTreeModel *model;
5532 GList *rows, *p;
5533 GtkTreePath *path;
5534 GtkTreeIter iter;
5535 struct objbind *ob;
5536 union packetdata packet;
5537 struct connection *my_conn = &client.conn;
5538
5539 if (!pp || !pp->object_view) {
5540 return;
5541 }
5542
5543 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pp->object_view));
5544 if (gtk_tree_selection_count_selected_rows(sel) < 1) {
5545 return;
5546 }
5547
5548 packet = property_page_new_packet(pp);
5549 if (!packet.pointers.v_pointer1) {
5550 return;
5551 }
5552
5553 rows = gtk_tree_selection_get_selected_rows(sel, &model);
5554 connection_do_buffer(my_conn);
5555 for (p = rows; p != NULL; p = p->next) {
5556 path = p->data;
5557 if (gtk_tree_model_get_iter(model, &iter, path)) {
5558 gtk_tree_model_get(model, &iter, 0, &ob, -1);
5559 if (objbind_has_modified_properties(ob)) {
5560 objbind_pack_current_values(ob, packet);
5561 property_page_objprop_iterate(pp, op) {
5562 if (objprop_is_readonly(op)) {
5563 continue;
5564 }
5565 objbind_pack_modified_value(ob, op, packet);
5566 } property_page_objprop_iterate_end;
5567 property_page_send_packet(pp, packet);
5568 }
5569 }
5570 gtk_tree_path_free(path);
5571 }
5572 connection_do_unbuffer(my_conn);
5573 g_list_free(rows);
5574
5575 property_page_free_packet(pp, packet);
5576}
5577
5578/************************************************************************/
5582 static union packetdata property_page_new_packet(struct property_page *pp)
5583{
5584 union packetdata packet;
5585
5586 packet.pointers.v_pointer2 = NULL;
5587
5588 if (!pp) {
5589 packet.pointers.v_pointer1 = NULL;
5590 return packet;
5591 }
5592
5593 switch (property_page_get_objtype(pp)) {
5594 case OBJTYPE_TILE:
5595 packet.tile = fc_calloc(1, sizeof(*packet.tile));
5596 break;
5597 case OBJTYPE_STARTPOS:
5598 packet.startpos = fc_calloc(1, sizeof(*packet.startpos));
5599 break;
5600 case OBJTYPE_UNIT:
5601 packet.unit = fc_calloc(1, sizeof(*packet.unit));
5602 break;
5603 case OBJTYPE_CITY:
5604 packet.city = fc_calloc(1, sizeof(*packet.city));
5605 break;
5606 case OBJTYPE_PLAYER:
5607 packet.player = fc_calloc(1, sizeof(*packet.player));
5608 break;
5609 case OBJTYPE_GAME:
5610 packet.game.game = fc_calloc(1, sizeof(*packet.game.game));
5611 packet.game.desc = fc_calloc(1, sizeof(*packet.game.desc));
5612 break;
5613 case NUM_OBJTYPES:
5614 break;
5615 }
5616
5617 return packet;
5618}
5619
5620/************************************************************************/
5623 static void property_page_send_packet(struct property_page *pp,
5624 union packetdata packet)
5625{
5626 struct connection *my_conn = &client.conn;
5627
5628 if (!pp || !packet.pointers.v_pointer1) {
5629 return;
5630 }
5631
5632 switch (property_page_get_objtype(pp)) {
5633 case OBJTYPE_TILE:
5634 send_packet_edit_tile(my_conn, packet.tile);
5635 return;
5636 case OBJTYPE_STARTPOS:
5637 send_packet_edit_startpos_full(my_conn, packet.startpos);
5638 return;
5639 case OBJTYPE_UNIT:
5640 send_packet_edit_unit(my_conn, packet.unit);
5641 return;
5642 case OBJTYPE_CITY:
5643 send_packet_edit_city(my_conn, packet.city);
5644 return;
5645 case OBJTYPE_PLAYER:
5646 send_packet_edit_player(my_conn, packet.player);
5647 return;
5648 case OBJTYPE_GAME:
5649 send_packet_edit_game(my_conn, packet.game.game);
5650 send_packet_edit_scenario_desc(my_conn, packet.game.desc);
5651 return;
5652 case NUM_OBJTYPES:
5653 break;
5654 }
5655
5656 log_error("%s(): Unhandled object type %s (nb %d).",
5657 __FUNCTION__, objtype_get_name(property_page_get_objtype(pp)),
5658 property_page_get_objtype(pp));
5659}
5660
5661/************************************************************************/
5664 static void property_page_free_packet(struct property_page *pp,
5665 union packetdata packet)
5666{
5667 if (!packet.pointers.v_pointer1) {
5668 return;
5669 }
5670
5671 free(packet.pointers.v_pointer1);
5672 packet.pointers.v_pointer1 = NULL;
5673
5674 if (packet.pointers.v_pointer2 != NULL) {
5675 free(packet.pointers.v_pointer2);
5676 packet.pointers.v_pointer2 = NULL;
5677 }
5678}
5679
5680/************************************************************************/
5684 static void property_page_reset_objbinds(struct property_page *pp)
5685{
5686 GtkTreeSelection *sel;
5687 GtkTreeModel *model;
5688 GtkTreeIter iter;
5689 GtkTreePath *path;
5690 GList *rows, *p;
5691 struct objbind *ob;
5692
5693 if (!pp || !pp->object_view) {
5694 return;
5695 }
5696
5697 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pp->object_view));
5698 if (gtk_tree_selection_count_selected_rows(sel) < 1) {
5699 return;
5700 }
5701
5702 rows = gtk_tree_selection_get_selected_rows(sel, &model);
5703 for (p = rows; p != NULL; p = p->next) {
5704 path = p->data;
5705 if (gtk_tree_model_get_iter(model, &iter, path)) {
5706 gtk_tree_model_get(model, &iter, 0, &ob, -1);
5707 objbind_clear_all_modified_values(ob);
5708 property_page_objprop_iterate(pp, op) {
5709 property_page_set_store_value(pp, op, ob, &iter);
5710 } property_page_objprop_iterate_end;
5711 }
5712 gtk_tree_path_free(path);
5713 }
5714 g_list_free(rows);
5715
5716 ob = property_page_get_focused_objbind(pp);
5717 property_page_objprop_iterate(pp, op) {
5718 objprop_refresh_widget(op, ob);
5719 } property_page_objprop_iterate_end;
5720}
5721
5722/************************************************************************/
5725 static void property_page_destroy_objects(struct property_page *pp)
5726{
5727 GtkTreeSelection *sel;
5728 GtkTreeModel *model;
5729 GtkTreeIter iter;
5730 GtkTreePath *path;
5731 GList *rows, *p;
5732 struct objbind *ob;
5733 struct connection *my_conn = &client.conn;
5734
5735 if (!pp || !pp->object_view) {
5736 return;
5737 }
5738
5739 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pp->object_view));
5740 if (gtk_tree_selection_count_selected_rows(sel) < 1) {
5741 return;
5742 }
5743
5744 rows = gtk_tree_selection_get_selected_rows(sel, &model);
5745 connection_do_buffer(my_conn);
5746 for (p = rows; p != NULL; p = p->next) {
5747 path = p->data;
5748 if (gtk_tree_model_get_iter(model, &iter, path)) {
5749 gtk_tree_model_get(model, &iter, 0, &ob, -1);
5750 objbind_request_destroy_object(ob);
5751 }
5752 gtk_tree_path_free(path);
5753 }
5754 connection_do_unbuffer(my_conn);
5755 g_list_free(rows);
5756}
5757
5758/************************************************************************/
5764 static void property_page_create_objects(struct property_page *pp,
5765 struct tile_list *hint_tiles)
5766{
5767 enum editor_object_type objtype;
5768 int apno, value, count, size;
5769 int tag;
5770 struct connection *my_conn = &client.conn;
5771 struct tile *ptile = NULL;
5772 struct player *pplayer;
5773
5774 if (!pp) {
5775 return;
5776 }
5777
5778 objtype = property_page_get_objtype(pp);
5779 if (objtype_is_conserved(objtype)) {
5780 return;
5781 }
5782
5783 tag = get_next_unique_tag();
5784 count = 1;
5785
5786 switch (objtype) {
5787 case OBJTYPE_STARTPOS:
5788 if (hint_tiles) {
5789 tile_list_iterate(hint_tiles, atile) {
5790 if (NULL == map_startpos_get(atile)) {
5791 ptile = atile;
5792 break;
5793 }
5794 } tile_list_iterate_end;
5795 }
5796
5797 if (NULL == ptile) {
5798 ptile = get_center_tile_mapcanvas();
5799 }
5800
5801 if (NULL == ptile) {
5802 break;
5803 }
5804
5805 dsend_packet_edit_startpos(my_conn, tile_index(ptile), FALSE, tag);
5806 break;
5807
5808 case OBJTYPE_UNIT:
5809 if (hint_tiles) {
5810 tile_list_iterate(hint_tiles, atile) {
5811 if (can_create_unit_at_tile(atile)) {
5812 ptile = atile;
5813 break;
5814 }
5815 } tile_list_iterate_end;
5816 }
5817
5818 if (!ptile) {
5819 struct unit *punit;
5820 property_page_objbind_iterate(pp, ob) {
5821 punit = objbind_get_object(ob);
5822 if (punit && can_create_unit_at_tile(unit_tile(punit))) {
5823 ptile = unit_tile(punit);
5824 break;
5825 }
5826 } property_page_objbind_iterate_end;
5827 }
5828
5829 if (!ptile) {
5830 ptile = get_center_tile_mapcanvas();
5831 }
5832
5833 if (!ptile) {
5834 break;
5835 }
5836
5837 apno = editor_tool_get_applied_player(ETT_UNIT);
5838 count = editor_tool_get_count(ETT_UNIT);
5839 value = editor_tool_get_value(ETT_UNIT);
5840 dsend_packet_edit_unit_create(my_conn, apno, tile_index(ptile),
5841 value, count, tag);
5842 break;
5843
5844 case OBJTYPE_CITY:
5845 apno = editor_tool_get_applied_player(ETT_CITY);
5846 pplayer = player_by_number(apno);
5847 if (pplayer && hint_tiles) {
5848 tile_list_iterate(hint_tiles, atile) {
5849 if (!is_enemy_unit_tile(atile, pplayer)
5850 && city_can_be_built_here(atile, NULL, FALSE)) {
5851 ptile = atile;
5852 break;
5853 }
5854 } tile_list_iterate_end;
5855 }
5856
5857 if (!ptile) {
5858 ptile = get_center_tile_mapcanvas();
5859 }
5860
5861 if (!ptile) {
5862 break;
5863 }
5864
5865 size = editor_tool_get_size(ETT_CITY);
5866 dsend_packet_edit_city_create(my_conn, apno, tile_index(ptile),
5867 size, tag);
5868 break;
5869
5870 case OBJTYPE_PLAYER:
5871 dsend_packet_edit_player_create(my_conn, tag);
5872 break;
5873
5874 case OBJTYPE_TILE:
5875 case OBJTYPE_GAME:
5876 case NUM_OBJTYPES:
5877 break;
5878 }
5879
5880 property_page_store_creation_tag(pp, tag, count);
5881}
5882
5883/************************************************************************/
5888 static void property_page_object_changed(struct property_page *pp,
5889 int object_id,
5890 bool removed)
5891{
5892 struct objbind *ob;
5893 GtkTreeRowReference *rr;
5894
5895 ob = property_page_get_objbind(pp, object_id);
5896 if (!ob) {
5897 return;
5898 }
5899
5900 rr = objbind_get_rowref(ob);
5901 if (rr && gtk_tree_row_reference_valid(rr)) {
5902 GtkTreePath *path;
5903 GtkTreeIter iter;
5904 GtkTreeModel *model;
5905
5906 model = GTK_TREE_MODEL(pp->object_store);
5907 path = gtk_tree_row_reference_get_path(rr);
5908
5909 if (gtk_tree_model_get_iter(model, &iter, path)) {
5910 if (removed) {
5911 gtk_list_store_remove(pp->object_store, &iter);
5912 } else {
5913 property_page_objprop_iterate(pp, op) {
5914 property_page_set_store_value(pp, op, ob, &iter);
5915 } property_page_objprop_iterate_end;
5916 }
5917 }
5918
5919 gtk_tree_path_free(path);
5920 }
5921
5922 if (removed) {
5923 objbind_hash_remove(pp->objbind_table, object_id);
5924 return;
5925 }
5926
5927 if (ob == property_page_get_focused_objbind(pp)) {
5928 property_page_objprop_iterate(pp, op) {
5929 objprop_refresh_widget(op, ob);
5930 } property_page_objprop_iterate_end;
5931 }
5932}
5933
5934/************************************************************************/
5940 static void property_page_object_created(struct property_page *pp,
5941 int tag, int object_id)
5942{
5943 gpointer object;
5944 enum editor_object_type objtype;
5945
5946 if (!property_page_tag_is_known(pp, tag)) {
5947 return;
5948 }
5949 property_page_remove_creation_tag(pp, tag);
5950
5951 objtype = property_page_get_objtype(pp);
5952 object = objtype_get_object_from_id(objtype, object_id);
5953
5954 if (!object) {
5955 return;
5956 }
5957
5958 property_page_add_objbind(pp, object);
5959 property_page_fill_widgets(pp);
5960}
5961
5962/************************************************************************/
5966 static void property_page_add_extviewer(struct property_page *pp,
5967 struct extviewer *ev)
5968{
5969 GtkWidget *w;
5970
5971 if (!pp || !ev) {
5972 return;
5973 }
5974
5975 w = extviewer_get_view_widget(ev);
5976 if (!w) {
5977 return;
5978 }
5979 gtk_notebook_append_page(GTK_NOTEBOOK(pp->extviewer_notebook), w, NULL);
5980}
5981
5982/************************************************************************/
5986 static void property_page_show_extviewer(struct property_page *pp,
5987 struct extviewer *ev)
5988{
5989 GtkWidget *w;
5990 GtkNotebook *notebook;
5991 int page;
5992
5993 if (!pp || !ev) {
5994 return;
5995 }
5996
5997 w = extviewer_get_view_widget(ev);
5998 if (!w) {
5999 return;
6000 }
6001
6002 notebook = GTK_NOTEBOOK(pp->extviewer_notebook);
6003 page = gtk_notebook_page_num(notebook, w);
6004 gtk_notebook_set_current_page(notebook, page);
6005}
6006
6007/************************************************************************/
6011 static void property_page_store_creation_tag(struct property_page *pp,
6012 int tag, int count)
6013{
6014 if (!pp || !pp->tag_table) {
6015 return;
6016 }
6017
6018 if (stored_tag_hash_lookup(pp->tag_table, tag, NULL)) {
6019 log_error("Attempted to insert object creation tag %d "
6020 "twice into tag table for property page %p (%d %s).",
6021 tag, pp, property_page_get_objtype(pp),
6022 property_page_get_name(pp));
6023 return;
6024 }
6025
6026 stored_tag_hash_insert(pp->tag_table, tag, count);
6027}
6028
6029/************************************************************************/
6033 static void property_page_remove_creation_tag(struct property_page *pp,
6034 int tag)
6035{
6036 int count;
6037
6038 if (!pp || !pp->tag_table) {
6039 return;
6040 }
6041
6042 if (stored_tag_hash_lookup(pp->tag_table, tag, &count)) {
6043 if (0 >= --count) {
6044 stored_tag_hash_remove(pp->tag_table, tag);
6045 }
6046 }
6047}
6048
6049/************************************************************************/
6052 static bool property_page_tag_is_known(struct property_page *pp, int tag)
6053{
6054 if (!pp || !pp->tag_table) {
6055 return FALSE;
6056 }
6057 return stored_tag_hash_lookup(pp->tag_table, tag, NULL);
6058}
6059
6060/************************************************************************/
6063 static void property_page_clear_tags(struct property_page *pp)
6064{
6065 if (!pp || !pp->tag_table) {
6066 return;
6067 }
6068 stored_tag_hash_clear(pp->tag_table);
6069}
6070
6071/************************************************************************/
6074 static void property_page_apply_button_clicked(GtkButton *button,
6075 gpointer userdata)
6076{
6077 struct property_page *pp = userdata;
6078 property_page_send_values(pp);
6079}
6080
6081/************************************************************************/
6085 static void property_page_refresh_button_clicked(GtkButton *button,
6086 gpointer userdata)
6087{
6088 struct property_page *pp = userdata;
6089 property_page_reset_objbinds(pp);
6090}
6091
6092/************************************************************************/
6095 static void property_page_create_button_clicked(GtkButton *button,
6096 gpointer userdata)
6097{
6098 struct property_page *pp = userdata, *tile_pp;
6099 struct tile_list *tiles = NULL;
6100 struct tile *ptile;
6101
6102 if (!pp) {
6103 return;
6104 }
6105
6106 tile_pp = property_editor_get_page(pp->pe_parent, OBJTYPE_TILE);
6107 tiles = tile_list_new();
6108
6109 property_page_objbind_iterate(tile_pp, ob) {
6110 ptile = objbind_get_object(ob);
6111 if (ptile) {
6112 tile_list_append(tiles, ptile);
6113 }
6114 } property_page_objbind_iterate_end;
6115
6116 property_page_create_objects(pp, tiles);
6117 tile_list_destroy(tiles);
6118}
6119
6120/************************************************************************/
6123 static void property_page_destroy_button_clicked(GtkButton *button,
6124 gpointer userdata)
6125{
6126 struct property_page *pp = userdata;
6127 property_page_destroy_objects(pp);
6128}
6129
6130/************************************************************************/
6134 static bool property_editor_add_page(struct property_editor *pe,
6135 enum editor_object_type objtype)
6136{
6137 struct property_page *pp;
6138 GtkWidget *label;
6139 const char *name;
6140
6141 if (!pe || !pe->notebook) {
6142 return FALSE;
6143 }
6144
6145 if (!(objtype < NUM_OBJTYPES)) {
6146 return FALSE;
6147 }
6148
6149 pp = property_page_new(objtype, pe);
6150 if (!pp) {
6151 return FALSE;
6152 }
6153
6154 name = property_page_get_name(pp);
6155 label = gtk_label_new(name);
6156 gtk_notebook_append_page(GTK_NOTEBOOK(pe->notebook),
6157 pp->widget, label);
6158
6159 pe->property_pages[objtype] = pp;
6160
6161 return TRUE;
6162}
6163
6164/************************************************************************/
6167static struct property_page *
6168 property_editor_get_page(struct property_editor *pe,
6169 enum editor_object_type objtype)
6170{
6171 if (!pe || !(objtype < NUM_OBJTYPES)) {
6172 return NULL;
6173 }
6174
6175 return pe->property_pages[objtype];
6176}
6177
6178/************************************************************************/
6181 static struct property_editor *property_editor_new(void)
6182{
6183 struct property_editor *pe;
6184 GtkWidget *win, *notebook, *vgrid;
6185 enum editor_object_type objtype;
6186 int grid_row = 0;
6187
6188 pe = fc_calloc(1, sizeof(*pe));
6189
6190 /* The property editor dialog window. */
6191
6192 win = gtk_window_new();
6193 gtk_window_set_title(GTK_WINDOW(win), _("Property Editor"));
6194 gtk_window_set_resizable(GTK_WINDOW(win), TRUE);
6195 gtk_window_set_default_size(GTK_WINDOW(win), 780, 560);
6196 gtk_window_set_transient_for(GTK_WINDOW(win), GTK_WINDOW(toplevel));
6197 gtk_window_set_destroy_with_parent(GTK_WINDOW(win), TRUE);
6198 gtk_widget_set_margin_start(win, 4);
6199 gtk_widget_set_margin_end(win, 4);
6200 gtk_widget_set_margin_top(win, 4);
6201 gtk_widget_set_margin_bottom(win, 4);
6202 gtk_window_set_hide_on_close(GTK_WINDOW(win), TRUE);
6203 pe->widget = win;
6204
6205 vgrid = gtk_grid_new();
6206 gtk_window_set_child(GTK_WINDOW(win), vgrid);
6207
6208 /* Property pages. */
6209
6210 notebook = gtk_notebook_new();
6211 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), TRUE);
6212 gtk_grid_attach(GTK_GRID(vgrid), notebook, 0, grid_row++, 1, 1);
6213 pe->notebook = notebook;
6214
6215 for (objtype = 0; objtype < NUM_OBJTYPES; objtype++) {
6216 property_editor_add_page(pe, objtype);
6217 }
6218
6219 return pe;
6220}
6221
6222/************************************************************************/
6225 struct property_editor *editprop_get_property_editor(void)
6226{
6227 if (!the_property_editor) {
6228 the_property_editor = property_editor_new();
6229 }
6230 return the_property_editor;
6231}
6232
6233/************************************************************************/
6236 void property_editor_load_tiles(struct property_editor *pe,
6237 const struct tile_list *tiles)
6238{
6239 struct property_page *pp;
6240 enum editor_object_type objtype;
6241 int i;
6242 const enum editor_object_type preferred[] = {
6243 OBJTYPE_CITY,
6244 OBJTYPE_UNIT,
6245 OBJTYPE_STARTPOS,
6246 OBJTYPE_TILE
6247 };
6248
6249 if (!pe || !tiles) {
6250 return;
6251 }
6252
6253 for (objtype = 0; objtype < NUM_OBJTYPES; objtype++) {
6254 pp = property_editor_get_page(pe, objtype);
6255 property_page_load_tiles(pp, tiles);
6256 }
6257
6258 for (i = 0; i < ARRAY_SIZE(preferred) - 1; i++) {
6259 pp = property_editor_get_page(pe, preferred[i]);
6260 if (property_page_get_num_objbinds(pp) > 0) {
6261 break;
6262 }
6263 }
6264 objtype = preferred[i];
6265 gtk_notebook_set_current_page(GTK_NOTEBOOK(pe->notebook), objtype);
6266}
6267
6268/************************************************************************/
6272 void property_editor_popup(struct property_editor *pe,
6273 enum editor_object_type objtype)
6274{
6275 if (pe == NULL || pe->widget == NULL) {
6276 return;
6277 }
6278
6279 gtk_widget_set_visible(pe->widget, TRUE);
6280
6281 gtk_window_present(GTK_WINDOW(pe->widget));
6282 if (objtype < NUM_OBJTYPES) {
6283 gtk_notebook_set_current_page(GTK_NOTEBOOK(pe->notebook), objtype);
6284 }
6285}
6286
6287/************************************************************************/
6290 void property_editor_popdown(struct property_editor *pe)
6291{
6292 if (pe == NULL || pe->widget == NULL) {
6293 return;
6294 }
6295
6296 gtk_widget_set_visible(pe->widget, FALSE);
6297}
6298
6299/************************************************************************/
6303 void property_editor_handle_object_changed(struct property_editor *pe,
6304 enum editor_object_type objtype,
6305 int object_id,
6306 bool remove)
6307{
6308 struct property_page *pp;
6309
6310 if (!pe) {
6311 return;
6312 }
6313
6314 if (!(objtype < NUM_OBJTYPES)) {
6315 return;
6316 }
6317
6318 pp = property_editor_get_page(pe, objtype);
6319 property_page_object_changed(pp, object_id, remove);
6320}
6321
6322/************************************************************************/
6325 void property_editor_handle_object_created(struct property_editor *pe,
6326 int tag, int object_id)
6327{
6328 enum editor_object_type objtype;
6329 struct property_page *pp;
6330
6331 for (objtype = 0; objtype < NUM_OBJTYPES; objtype++) {
6332 if (objtype_is_conserved(objtype)) {
6333 continue;
6334 }
6335 pp = property_editor_get_page(pe, objtype);
6336 property_page_object_created(pp, tag, object_id);
6337 }
6338}
6339
6340/************************************************************************/
6343 void property_editor_clear(struct property_editor *pe)
6344{
6345 enum editor_object_type objtype;
6346 struct property_page *pp;
6347
6348 if (!pe) {
6349 return;
6350 }
6351
6352 for (objtype = 0; objtype < NUM_OBJTYPES; objtype++) {
6353 pp = property_editor_get_page(pe, objtype);
6354 property_page_clear_objbinds(pp);
6355 property_page_clear_tags(pp);
6356 }
6357}
6358
6359/************************************************************************/
6363 void property_editor_reload(struct property_editor *pe,
6364 enum editor_object_type objtype)
6365{
6366 struct property_page *pp;
6367
6368 if (!pe) {
6369 return;
6370 }
6371
6372 pp = property_editor_get_page(pe, objtype);
6373 if (!pp) {
6374 return;
6375 }
6376
6377 property_page_clear_objbinds(pp);
6378
6379 switch (objtype) {
6380 case OBJTYPE_PLAYER:
6381 players_iterate(pplayer) {
6382 property_page_add_objbind(pp, pplayer);
6383 } players_iterate_end;
6384 break;
6385 case OBJTYPE_GAME:
6386 property_page_add_objbind(pp, &game);
6387 break;
6388 case OBJTYPE_TILE:
6389 case OBJTYPE_STARTPOS:
6390 case OBJTYPE_UNIT:
6391 case OBJTYPE_CITY:
6392 case NUM_OBJTYPES:
6393 break;
6394 }
6395
6396 property_page_fill_widgets(pp);
6397 gtk_notebook_set_current_page(GTK_NOTEBOOK(pe->notebook), objtype);
6398}
6399
6400/************************************************************************/
6411 static struct property_filter *property_filter_new(const char *filter)
6412{
6413 struct property_filter *pf;
6414 struct pf_conjunction *pfc;
6415 struct pf_pattern *pfp;
6416 int or_clause_count, and_clause_count;
6417 char *or_clauses[PF_MAX_CLAUSES], *and_clauses[PF_MAX_CLAUSES];
6418 const char *pattern;
6419 int i, j;
6420
6421 pf = fc_calloc(1, sizeof(*pf));
6422
6423 if (!filter || filter[0] == '\0') {
6424 return pf;
6425 }
6426
6427 or_clause_count = get_tokens(filter, or_clauses,
6428 PF_MAX_CLAUSES,
6429 PF_DISJUNCTION_SEPARATOR);
6430
6431 for (i = 0; i < or_clause_count; i++) {
6432 if (or_clauses[i][0] == '\0') {
6433 continue;
6434 }
6435 pfc = &pf->disjunction[pf->count];
6436
6437 and_clause_count = get_tokens(or_clauses[i], and_clauses,
6438 PF_MAX_CLAUSES,
6439 PF_CONJUNCTION_SEPARATOR);
6440
6441 for (j = 0; j < and_clause_count; j++) {
6442 if (and_clauses[j][0] == '\0') {
6443 continue;
6444 }
6445 pfp = &pfc->conjunction[pfc->count];
6446 pattern = and_clauses[j];
6447
6448 switch (pattern[0]) {
6449 case '!':
6450 pfp->negate = TRUE;
6451 pfp->text = fc_strdup(pattern + 1);
6452 break;
6453 default:
6454 pfp->text = fc_strdup(pattern);
6455 break;
6456 }
6457 pfc->count++;
6458 }
6459 free_tokens(and_clauses, and_clause_count);
6460 pf->count++;
6461 }
6462
6463 free_tokens(or_clauses, or_clause_count);
6464
6465 return pf;
6466}
6467
6468/************************************************************************/
6485 static bool property_filter_match(struct property_filter *pf,
6486 const struct objprop *op)
6487{
6488 struct pf_pattern *pfp;
6489 struct pf_conjunction *pfc;
6490 const char *name;
6491 bool match, or_result, and_result;
6492 int i, j;
6493
6494 if (!pf) {
6495 return TRUE;
6496 }
6497 if (!op) {
6498 return FALSE;
6499 }
6500
6501 name = objprop_get_name(op);
6502 if (!name) {
6503 return FALSE;
6504 }
6505
6506 if (pf->count < 1) {
6507 return TRUE;
6508 }
6509
6510 or_result = FALSE;
6511
6512 for (i = 0; i < pf->count; i++) {
6513 pfc = &pf->disjunction[i];
6514 and_result = TRUE;
6515 for (j = 0; j < pfc->count; j++) {
6516 pfp = &pfc->conjunction[j];
6517 match = (pfp->text[0] == '\0'
6518 || fc_strcasestr(name, pfp->text));
6519 if (pfp->negate) {
6520 match = !match;
6521 }
6522 and_result = and_result && match;
6523 if (!and_result) {
6524 break;
6525 }
6526 }
6527 or_result = or_result || and_result;
6528 if (or_result) {
6529 break;
6530 }
6531 }
6532
6533 return or_result;
6534}
6535
6536/************************************************************************/
6539 static void property_filter_free(struct property_filter *pf)
6540{
6541 struct pf_pattern *pfp;
6542 struct pf_conjunction *pfc;
6543 int i, j;
6544
6545 if (!pf) {
6546 return;
6547 }
6548
6549 for (i = 0; i < pf->count; i++) {
6550 pfc = &pf->disjunction[i];
6551 for (j = 0; j < pfc->count; j++) {
6552 pfp = &pfc->conjunction[j];
6553 if (pfp->text != NULL) {
6554 free(pfp->text);
6555 pfp->text = NULL;
6556 }
6557 }
6558 pfc->count = 0;
6559 }
6560 pf->count = 0;
6561 free(pf);
6562}
6563
6564/************************************************************************/
6567 const char *vision_layer_get_name(enum vision_layer vl)
6568{
6569 switch (vl) {
6570 case V_MAIN:
6571 /* TRANS: Vision layer name. Feel free to leave untranslated. */
6572 return _("Seen (Main)");
6573 case V_INVIS:
6574 /* TRANS: Vision layer name. Feel free to leave untranslated. */
6575 return _("Seen (Invis)");
6576 case V_SUBSURFACE:
6577 /* TRANS: Vision layer name. Feel free to leave untranslated. */
6578 return _("Seen (Subsurface)");
6579 case V_COUNT:
6580 break;
6581 }
6582
6583 log_error("%s(): Unrecognized vision layer %d.", __FUNCTION__, vl);
6584 return _("Unknown");
6585}
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:1497
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:1115
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:5663
property_page_send_values
static void property_page_send_values(struct property_page *pp)
Definition editprop.c:5507
objprop_setup_widget
static void objprop_setup_widget(struct objprop *op)
Definition editprop.c:2935
property_page_store_creation_tag
static void property_page_store_creation_tag(struct property_page *pp, int tag, int count)
Definition editprop.c:5990
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:3445
objprop_get_name
static const char * objprop_get_name(const struct objprop *op)
Definition editprop.c:2815
vision_layer_get_name
const char * vision_layer_get_name(enum vision_layer)
Definition editprop.c:6544
objbind_get_object_id
static int objbind_get_object_id(struct objbind *ob)
Definition editprop.c:1376
objprop_set_extviewer
static void objprop_set_extviewer(struct objprop *op, struct extviewer *ev)
Definition editprop.c:3422
extviewer_get_panel_widget
static GtkWidget * extviewer_get_panel_widget(struct extviewer *ev)
Definition editprop.c:3777
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:6280
propstate_new
static struct propstate * propstate_new(struct objprop *op, struct propval *pv)
Definition editprop.c:1260
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:1292
objbind_set_modified_value
static bool objbind_set_modified_value(struct objbind *ob, struct objprop *op, struct propval *pv)
Definition editprop.c:2115
objprop_create_cell_renderer
static GtkCellRenderer * objprop_create_cell_renderer(const struct objprop *op)
Definition editprop.c:2839
extviewer_clear_widgets
static void extviewer_clear_widgets(struct extviewer *ev)
Definition editprop.c:4063
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:3362
property_editor_add_page
static bool property_editor_add_page(struct property_editor *pe, enum editor_object_type objtype)
Definition editprop.c:6113
propstate_clear_value
static void propstate_clear_value(struct propstate *ps)
Definition editprop.c:1279
objbind_pack_modified_value
static void objbind_pack_modified_value(struct objbind *ob, struct objprop *op, union packetdata packet)
Definition editprop.c:2366
property_page_get_focused_objbind
static struct objbind * property_page_get_focused_objbind(struct property_page *pp)
Definition editprop.c:5394
objprop_has_widget
static bool objprop_has_widget(const struct objprop *op)
Definition editprop.c:2728
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:2199
objprop_get_extviewer
static struct extviewer * objprop_get_extviewer(struct objprop *op)
Definition editprop.c:3434
extviewer_refresh_widgets
static void extviewer_refresh_widgets(struct extviewer *ev, struct propval *pv)
Definition editprop.c:3800
property_page_get_objtype
static enum editor_object_type property_page_get_objtype(const struct property_page *pp)
Definition editprop.c:5049
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:5965
objbind_get_object
static gpointer objbind_get_object(struct objbind *ob)
Definition editprop.c:1360
property_page_get_name
static const char * property_page_get_name(const struct property_page *pp)
Definition editprop.c:5037
property_editor_handle_object_created
void property_editor_handle_object_created(struct property_editor *pe, int tag, int object_id)
Definition editprop.c:6302
objbind_property_is_modified
static bool objbind_property_is_modified(struct objbind *ob, struct objprop *op)
Definition editprop.c:2070
propstate_get_value
static struct propval * propstate_get_value(struct propstate *ps)
Definition editprop.c:1322
property_page_clear_tags
static void property_page_clear_tags(struct property_page *pp)
Definition editprop.c:6042
property_page_object_created
static void property_page_object_created(struct property_page *pp, int tag, int object_id)
Definition editprop.c:5919
property_page_tag_is_known
static bool property_page_tag_is_known(struct property_page *pp, int tag)
Definition editprop.c:6031
property_page_remove_creation_tag
static void property_page_remove_creation_tag(struct property_page *pp, int tag)
Definition editprop.c:6012
property_page_load_tiles
static void property_page_load_tiles(struct property_page *pp, const struct tile_list *tiles)
Definition editprop.c:5436
property_page_create_objects
static void property_page_create_objects(struct property_page *pp, struct tile_list *hint_tiles)
Definition editprop.c:5743
property_page_add_extviewer
static void property_page_add_extviewer(struct property_page *pp, struct extviewer *ev)
Definition editprop.c:5945
property_page_refresh_button_clicked
static void property_page_refresh_button_clicked(GtkButton *button, gpointer userdata)
Definition editprop.c:6064
property_page_set_focused_objbind
static void property_page_set_focused_objbind(struct property_page *pp, struct objbind *ob)
Definition editprop.c:5406
property_page_setup_objprops
static void property_page_setup_objprops(struct property_page *pp)
Definition editprop.c:4402
objbind_set_rowref
static void objbind_set_rowref(struct objbind *ob, GtkTreeRowReference *rr)
Definition editprop.c:2635
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:2056
objbind_get_value_from_object
static struct propval * objbind_get_value_from_object(struct objbind *ob, struct objprop *op)
Definition editprop.c:1437
propval_free
static void propval_free(struct propval *pv)
Definition editprop.c:1122
property_filter_new
static struct property_filter * property_filter_new(const char *filter)
Definition editprop.c:6388
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:5250
objtype_get_name
static const char * objtype_get_name(enum editor_object_type objtype)
Definition editprop.c:666
objbind_clear_all_modified_values
static void objbind_clear_all_modified_values(struct objbind *ob)
Definition editprop.c:2101
property_filter_match
static bool property_filter_match(struct property_filter *pf, const struct objprop *op)
Definition editprop.c:6462
property_editor_popup
void property_editor_popup(struct property_editor *pe, enum editor_object_type objtype)
Definition editprop.c:6250
property_page_destroy_button_clicked
static void property_page_destroy_button_clicked(GtkButton *button, gpointer userdata)
Definition editprop.c:6102
objbind_new
static struct objbind * objbind_new(enum editor_object_type objtype, gpointer object)
Definition editprop.c:1334
property_page_selection_func
static gboolean property_page_selection_func(GtkTreeSelection *sel, GtkTreeModel *model, GtkTreePath *path, gboolean currently_selected, gpointer data)
Definition editprop.c:4634
property_page_get_num_objbinds
static int property_page_get_num_objbinds(const struct property_page *pp)
Definition editprop.c:5453
objprop_show_in_listview
static bool objprop_show_in_listview(const struct objprop *op)
Definition editprop.c:2717
objprop_get_gtype
static GType objprop_get_gtype(const struct objprop *op)
Definition editprop.c:2673
objprop_set_treeview_column
static void objprop_set_treeview_column(struct objprop *op, GtkTreeViewColumn *col)
Definition editprop.c:2791
objbind_pack_current_values
static void objbind_pack_current_values(struct objbind *ob, union packetdata packet)
Definition editprop.c:2224
objprop_get_attribute_type_string
static const char * objprop_get_attribute_type_string(const struct objprop *op)
Definition editprop.c:2742
propval_copy
static struct propval * propval_copy(struct propval *pv)
Definition editprop.c:1040
editprop_get_property_editor
struct property_editor * editprop_get_property_editor(void)
Definition editprop.c:6203
property_editor_reload
void property_editor_reload(struct property_editor *pe, enum editor_object_type objtype)
Definition editprop.c:6340
create_unit_pixbuf
static GdkPixbuf * create_unit_pixbuf(const struct unit *punit)
Definition editprop.c:5077
extviewer_view_cell_toggled
static void extviewer_view_cell_toggled(GtkCellRendererToggle *cell, gchar *path, gpointer userdata)
Definition editprop.c:4138
property_editor_new
static struct property_editor * property_editor_new(void)
Definition editprop.c:6160
property_page_send_packet
static void property_page_send_packet(struct property_page *pp, union packetdata packet)
Definition editprop.c:5602
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:2658
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:2706
get_next_unique_tag
static int get_next_unique_tag(void)
Definition editprop.c:1029
objprop_is_sortable
static bool objprop_is_sortable(const struct objprop *op)
Definition editprop.c:2860
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:5196
objprop_get_tooltip
static const char * objprop_get_tooltip(const struct objprop *op)
Definition editprop.c:2826
objbind_get_rowref
static GtkTreeRowReference * objbind_get_rowref(struct objbind *ob)
Definition editprop.c:2647
property_filter_free
static void property_filter_free(struct property_filter *pf)
Definition editprop.c:6516
objprop_widget_spin_button_changed
static void objprop_widget_spin_button_changed(GtkSpinButton *spin, gpointer userdata)
Definition editprop.c:2901
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:3389
property_page_selection_changed
static void property_page_selection_changed(GtkTreeSelection *sel, gpointer userdata)
Definition editprop.c:4609
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:3481
propval_equal
static bool propval_equal(struct propval *pva, struct propval *pvb)
Definition editprop.c:1173
property_page_quick_find_entry_changed
static void property_page_quick_find_entry_changed(GtkWidget *entry, gpointer userdata)
Definition editprop.c:4689
objprop_refresh_widget
static void objprop_refresh_widget(struct objprop *op, struct objbind *ob)
Definition editprop.c:3112
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:6268
objbind_destroy
static void objbind_destroy(struct objbind *ob)
Definition editprop.c:2180
property_page_add_objbind
static void property_page_add_objbind(struct property_page *pp, gpointer object_data)
Definition editprop.c:5160
objbind_request_destroy_object
static void objbind_request_destroy_object(struct objbind *ob)
Definition editprop.c:1389
property_page_create_button_clicked
static void property_page_create_button_clicked(GtkButton *button, gpointer userdata)
Definition editprop.c:6074
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:5103
property_page_new_packet
static union packetdata property_page_new_packet(struct property_page *pp)
Definition editprop.c:5561
propstate_set_value
static void propstate_set_value(struct propstate *ps, struct propval *pv)
Definition editprop.c:1307
objprop_get_column_id
static int objprop_get_column_id(const struct objprop *op)
Definition editprop.c:2780
create_tile_pixbuf
static GdkPixbuf * create_tile_pixbuf(const struct tile *ptile)
Definition editprop.c:5065
extviewer_get_objprop
static struct objprop * extviewer_get_objprop(struct extviewer *ev)
Definition editprop.c:3765
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:5419
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:1875
property_page_free_packet
static void property_page_free_packet(struct property_page *pp, union packetdata packet)
Definition editprop.c:5643
create_city_pixbuf
static GdkPixbuf * create_city_pixbuf(const struct city *pcity)
Definition editprop.c:5089
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:4118
property_page_destroy_objects
static void property_page_destroy_objects(struct property_page *pp)
Definition editprop.c:5704
property_editor_load_tiles
void property_editor_load_tiles(struct property_editor *pe, const struct tile_list *tiles)
Definition editprop.c:6214
property_page_new
static struct property_page * property_page_new(enum editor_object_type objtype, struct property_editor *parent)
Definition editprop.c:4731
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:5145
property_editor_clear
void property_editor_clear(struct property_editor *pe)
Definition editprop.c:6320
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:2767
objbind_bind_properties
static void objbind_bind_properties(struct objbind *ob, struct property_page *pp)
Definition editprop.c:2210
property_page_fill_widgets
static void property_page_fill_widgets(struct property_page *pp)
Definition editprop.c:5345
objbind_has_modified_properties
static bool objbind_has_modified_properties(struct objbind *ob)
Definition editprop.c:2089
property_page_change_value
static void property_page_change_value(struct property_page *pp, struct objprop *op, struct propval *pv)
Definition editprop.c:5465
objprop_widget_toggle_button_changed
static void objprop_widget_toggle_button_changed(GtkToggleButton *button, gpointer userdata)
Definition editprop.c:2918
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:6053
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:3456
extviewer_get_view_widget
static GtkWidget * extviewer_get_view_widget(struct extviewer *ev)
Definition editprop.c:3789
objprop_get_widget
static GtkWidget * objprop_get_widget(struct objprop *op)
Definition editprop.c:3347
propval_free_data
static void propval_free_data(struct propval *pv)
Definition editprop.c:1136
extviewer_textbuf_changed
static void extviewer_textbuf_changed(GtkTextBuffer *textbuf, gpointer userdata)
Definition editprop.c:4353
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:5867
objprop_is_readonly
static bool objprop_is_readonly(const struct objprop *op)
Definition editprop.c:2874
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:2804
property_editor_get_page
static struct property_page * property_editor_get_page(struct property_editor *pe, enum editor_object_type objtype)
Definition editprop.c:6147
objbind_get_modified_value
static struct propval * objbind_get_modified_value(struct objbind *ob, struct objprop *op)
Definition editprop.c:2161
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
objprop_widget_text_changed
static void objprop_widget_text_changed(GtkEditable *text, gpointer userdata)
Definition editprop.c:2885
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:1883
startpos_number
int startpos_number(const struct startpos *psp)
Definition map.c:1633
nat_x
#define nat_x
nat_y
#define nat_y
startpos_tile
struct tile * startpos_tile(const struct startpos *psp)
Definition map.c:1676
startpos_raw_nations
const struct nation_hash * startpos_raw_nations(const struct startpos *psp)
Definition map.c:1765
startpos_pack
bool startpos_pack(const struct startpos *psp, struct packet_edit_startpos_full *packet)
Definition map.c:1706
index_to_tile
struct tile * index_to_tile(const struct civ_map *imap, int mindex)
Definition map.c:456
startpos_is_excluding
bool startpos_is_excluding(const struct startpos *psp)
Definition map.c:1753
map_startpos_by_number
struct startpos * map_startpos_by_number(int id)
Definition map.c:1624
map.h
index_to_native_pos
#define index_to_native_pos(pnat_x, pnat_y, mindex)
Definition map.h:157
index_to_map_pos
#define index_to_map_pos(pmap_x, pmap_y, mindex)
Definition map.h:233
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:319
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:78441
send_packet_edit_city
int send_packet_edit_city(struct connection *pc, const struct packet_edit_city *packet)
Definition packets_gen.c:80422
send_packet_edit_game
int send_packet_edit_game(struct connection *pc, const struct packet_edit_game *packet)
Definition packets_gen.c:82662
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:76138
dsend_packet_edit_startpos
int dsend_packet_edit_startpos(struct connection *pc, int id, bool removal, int tag)
Definition packets_gen.c:76047
send_packet_edit_player
int send_packet_edit_player(struct connection *pc, const struct packet_edit_player *packet)
Definition packets_gen.c:82034
dsend_packet_edit_player_create
int dsend_packet_edit_player_create(struct connection *pc, int tag)
Definition packets_gen.c:80600
send_packet_edit_unit
int send_packet_edit_unit(struct connection *pc, const struct packet_edit_unit *packet)
Definition packets_gen.c:78146
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:82828
dsend_packet_edit_unit_remove_by_id
int dsend_packet_edit_unit_remove_by_id(struct connection *pc, int id)
Definition packets_gen.c:77410
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:76926
dsend_packet_edit_player_remove
int dsend_packet_edit_player_remove(struct connection *pc, int id)
Definition packets_gen.c:80775
send_packet_edit_tile
int send_packet_edit_tile(struct connection *pc, const struct packet_edit_tile *packet)
Definition packets_gen.c:76582
dsend_packet_edit_city_remove
int dsend_packet_edit_city_remove(struct connection *pc, int id)
Definition packets_gen.c:78619
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:1990
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:1405
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:537
players_iterate
#define players_iterate(_pplayer)
Definition player.h:532
player_slots_iterate
#define player_slots_iterate(_pslot)
Definition player.h:523
player_slots_iterate_end
#define player_slots_iterate_end
Definition player.h:527
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:1760
packet_edit_city::shield_stock
int shield_stock
Definition packets_gen.h:1774
packet_edit_city::built
int built[B_LAST]
Definition packets_gen.h:1786
packet_edit_city::name
char name[MAX_LEN_CITYNAME]
Definition packets_gen.h:1762
packet_edit_city::history
int history
Definition packets_gen.h:1766
packet_edit_city::food_stock
int food_stock
Definition packets_gen.h:1773
packet_edit_city::size
int size
Definition packets_gen.h:1765
packet_edit_city::id
int id
Definition packets_gen.h:1761
packet_edit_game
Definition packets_gen.h:1836
packet_edit_game::ruleset_locked
bool ruleset_locked
Definition packets_gen.h:1845
packet_edit_game::scenario_players
bool scenario_players
Definition packets_gen.h:1841
packet_edit_game::lake_flooding
bool lake_flooding
Definition packets_gen.h:1844
packet_edit_game::startpos_nations
bool startpos_nations
Definition packets_gen.h:1842
packet_edit_game::scenario_name
char scenario_name[256]
Definition packets_gen.h:1838
packet_edit_game::prevent_new_cities
bool prevent_new_cities
Definition packets_gen.h:1843
packet_edit_game::scenario
bool scenario
Definition packets_gen.h:1837
packet_edit_game::scenario_authors
char scenario_authors[MAX_LEN_PACKET/3]
Definition packets_gen.h:1839
packet_edit_game::scenario_random
bool scenario_random
Definition packets_gen.h:1840
packet_edit_player
Definition packets_gen.h:1800
packet_edit_player::gold
int gold
Definition packets_gen.h:1817
packet_edit_player::scenario_reserved
bool scenario_reserved
Definition packets_gen.h:1826
packet_edit_player::nation
Nation_type_id nation
Definition packets_gen.h:1809
packet_edit_player::name
char name[MAX_LEN_NAME]
Definition packets_gen.h:1802
packet_edit_player::autoselect_weight
int autoselect_weight
Definition packets_gen.h:1815
packet_edit_player::id
int id
Definition packets_gen.h:1801
packet_edit_player::government
Government_type_id government
Definition packets_gen.h:1807
packet_edit_player::inventions
bool inventions[A_LAST+1]
Definition packets_gen.h:1824
packet_edit_player::bulbs_researched
int bulbs_researched
Definition packets_gen.h:1823
packet_edit_scenario_desc
Definition packets_gen.h:1848
packet_edit_startpos_full
Definition packets_gen.h:1694
packet_edit_startpos_full::exclude
bool exclude
Definition packets_gen.h:1696
packet_edit_startpos_full::nations
bv_startpos_nations nations
Definition packets_gen.h:1697
packet_edit_tile
Definition packets_gen.h:1700
packet_edit_tile::label
char label[MAX_LEN_NAME]
Definition packets_gen.h:1707
packet_edit_tile::extras
bv_extras extras
Definition packets_gen.h:1702
packet_edit_tile::tile
int tile
Definition packets_gen.h:1701
packet_edit_unit
Definition packets_gen.h:1729
packet_edit_unit::stay
bool stay
Definition packets_gen.h:1746
packet_edit_unit::moved
bool moved
Definition packets_gen.h:1742
packet_edit_unit::done_moving
bool done_moving
Definition packets_gen.h:1744
packet_edit_unit::moves_left
int moves_left
Definition packets_gen.h:1734
packet_edit_unit::id
int id
Definition packets_gen.h:1730
packet_edit_unit::hp
int hp
Definition packets_gen.h:1735
packet_edit_unit::fuel
int fuel
Definition packets_gen.h:1737
packet_edit_unit::veteran
int veteran
Definition packets_gen.h:1736
packet_game_info::turn
int turn
Definition packets_gen.h:241
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:61
player
Definition player.h:247
player::autoselect_weight
int autoselect_weight
Definition player.h:297
player::government
struct government * government
Definition player.h:256
player::turns_alive
int turns_alive
Definition player.h:264
player::economic
struct player_economic economic
Definition player.h:282
player::name
char name[MAX_LEN_NAME]
Definition player.h:249
player::nation
struct nation_type * nation
Definition player.h:258
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:41
terrain
Definition terrain.h:182
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:65
tile::continent
Continent_id continent
Definition tile.h:54
tileset
Definition tilespec.c:481
unit_type
Definition unittype.h:500
unit
Definition unit.h:138
unit::moves_left
int moves_left
Definition unit.h:150
unit::id
int id
Definition unit.h:145
unit::moved
bool moved
Definition unit.h:173
unit::hp
int hp
Definition unit.h:151
unit::fuel
int fuel
Definition unit.h:153
unit::stay
bool stay
Definition unit.h:205
unit::done_moving
bool done_moving
Definition unit.h:181
unit::veteran
int veteran
Definition unit.h:152
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:974
fc_strlcpy
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:791
fc_strcasestr
char * fc_strcasestr(const char *haystack, const char *needle)
Definition support.c:440
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:290
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:248
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:275
advance_iterate_end
#define advance_iterate_end
Definition tech.h:276
advance_index_iterate
#define advance_index_iterate(_start, _index)
Definition tech.h:244
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:88
tile_resource
#define tile_resource(_tile)
Definition tile.h:102
tile_list_iterate
#define tile_list_iterate(tile_list, ptile)
Definition tile.h:73
tile_terrain
#define tile_terrain(_tile)
Definition tile.h:110
TILE_XY
#define TILE_XY(ptile)
Definition tile.h:43
tile_list_iterate_end
#define tile_list_iterate_end
Definition tile.h:75
tile_extras
static const bv_extras * tile_extras(const struct tile *ptile)
Definition tile.h:120
tile_has_extra
#define tile_has_extra(ptile, pextra)
Definition tile.h:147
get_government_sprite
struct sprite * get_government_sprite(const struct tileset *t, const struct government *gov)
Definition tilespec.c:6797
tileset_small_sprite_width
int tileset_small_sprite_width(const struct tileset *t)
Definition tilespec.c:901
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:7332
tileset_small_sprite_height
int tileset_small_sprite_height(const struct tileset *t)
Definition tilespec.c:937
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
tileset_tile_width
int tileset_tile_width(const struct tileset *t)
Definition tilespec.c:753
tilespec.h
mapview_layer_iterate
#define mapview_layer_iterate(layer)
Definition tilespec.h:175
mapview_layer_iterate_end
#define mapview_layer_iterate_end
Definition tilespec.h:183
layer_category
layer_category
Definition tilespec.h:189
LAYER_CATEGORY_TILE
@ LAYER_CATEGORY_TILE
Definition tilespec.h:191
LAYER_CATEGORY_CITY
@ LAYER_CATEGORY_CITY
Definition tilespec.h:190
LAYER_CATEGORY_UNIT
@ LAYER_CATEGORY_UNIT
Definition tilespec.h:192
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::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:390
is_enemy_unit_tile
static bool is_enemy_unit_tile(const struct tile *ptile, const struct player *pplayer)
Definition unit.h:413
unit_owner
#define unit_owner(_pu)
Definition unit.h:389
is_non_allied_unit_tile
static bool is_non_allied_unit_tile(const struct tile *ptile, const struct player *pplayer)
Definition unit.h:425
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
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:836
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