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

Freeciv-3.3

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