1 /*****************************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
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)
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 *****************************************************************************/
15 #include <fc_config.h>
32 #include "client_main.h"
36 #include "unitselect_common.h"
38 /* client/gui-gtk-2.0 */
40 #include "gui_stuff.h"
43 #include "unitselect.h"
45 /* Activate this to get more columns (see below) */
48 enum usdlg_column_types
{
54 enum usdlg_row_types
{
61 /* Basic data (Unit, description, count) */
62 #define USDLG_COLUMNS_DEFAULT 3
63 /* Additional data; shown if DEBUG_USDLG */
64 #define USDLG_COL_UTID USDLG_COLUMNS_DEFAULT + 0 /* Unit type ID */
65 #define USDLG_COL_UID USDLG_COLUMNS_DEFAULT + 1 /* Unit ID */
66 #define USDLG_COL_LOCATION USDLG_COLUMNS_DEFAULT + 2 /* Unit location */
67 #define USDLG_COL_ACTIVITY USDLG_COLUMNS_DEFAULT + 3 /* Unit activity */
68 #define USDLG_COL_ROW_TYPE USDLG_COLUMNS_DEFAULT + 4 /* Row type */
69 #define USDLG_COLUMNS_DEBUG USDLG_COLUMNS_DEFAULT + 5
70 /* Layout options; never shown */
71 #define USDLG_COL_STYLE USDLG_COLUMNS_DEBUG + 0
72 #define USDLG_COL_WEIGHT USDLG_COLUMNS_DEBUG + 1
73 #define USDLG_COLUMNS_ALL USDLG_COLUMNS_DEBUG + 2
76 #define USDLG_COLUMNS_SHOW USDLG_COLUMNS_DEBUG
78 #define USDLG_COLUMNS_SHOW USDLG_COLUMNS_DEFAULT
81 enum usdlg_column_types usdlg_col_types
[USDLG_COLUMNS_ALL
] = {
82 COL_PIXBUF
, /* Unit */
83 COL_TEXT
, /* Description */
85 COL_INT
, /* Debug: unit type */
86 COL_INT
, /* Debug: unit ID */
87 COL_INT
, /* Debug: location */
88 COL_INT
, /* Debug: activity */
89 COL_INT
, /* Debug: row type */
90 COL_INT
, /* Layout: style */
91 COL_INT
/* Layout: width */
94 static const char *usdlg_col_titles
[USDLG_COLUMNS_ALL
] = {
98 "[Unittype]", /* Only for debug, no translation! */
117 struct unit_select_dialog
{
136 GtkWidget
*cmd
[USDLG_CMD_LAST
];
137 } tabs
[SELLOC_COUNT
];
140 /* The unit selection dialog; should only be used in usdlg_get(). */
141 static struct unit_select_dialog
*unit_select_dlg
= NULL
;
143 static struct unit_select_dialog
*usdlg_get(bool create
);
144 static struct unit_select_dialog
*usdlg_create(void);
145 static void usdlg_destroy(void);
146 static void usdlg_destroy_callback(GtkObject
*object
, gpointer data
);
147 static void usdlg_tile(struct unit_select_dialog
*pdialog
,
149 static void usdlg_refresh(struct unit_select_dialog
*pdialog
);
151 static void usdlg_tab_select(struct unit_select_dialog
*pdialog
,
153 enum unit_select_location_mode loc
);
154 static GtkTreeStore
*usdlg_tab_store_new(void);
155 static bool usdlg_tab_update(struct unit_select_dialog
*pdialog
,
156 struct usdata_hash
*ushash
,
157 enum unit_select_location_mode loc
);
158 static void usdlg_tab_append_utype(GtkTreeStore
*store
,
159 enum unit_select_location_mode loc
,
160 struct unit_type
*putype
,
162 static void usdlg_tab_append_activity(GtkTreeStore
*store
,
163 enum unit_select_location_mode loc
,
164 const struct unit_type
*putype
,
165 enum unit_activity act
,
166 int count
, GtkTreeIter
*it
,
167 GtkTreeIter
*parent
);
168 static void usdlg_tab_append_units(struct unit_select_dialog
*pdialog
,
169 enum unit_select_location_mode loc
,
170 enum unit_activity act
,
171 const struct unit
*punit
,
172 bool transported
, GtkTreeIter
*it
,
173 GtkTreeIter
*parent
);
175 static void usdlg_cmd_ready(GtkObject
*object
, gpointer data
);
176 static void usdlg_cmd_sentry(GtkObject
*object
, gpointer data
);
177 static void usdlg_cmd_select(GtkObject
*object
, gpointer data
);
178 static void usdlg_cmd_deselect(GtkObject
*object
, gpointer data
);
179 static void usdlg_cmd_exec(GtkObject
*object
, gpointer mode_data
,
181 static void usdlg_cmd_exec_unit(struct unit
*punit
, enum usdlg_cmd cmd
);
182 static void usdlg_cmd_center(GtkObject
*object
, gpointer data
);
183 static void usdlg_cmd_focus(GtkObject
*object
, gpointer data
);
184 static void usdlg_cmd_focus_real(GtkTreeView
*view
);
185 static void usdlg_cmd_row_activated(GtkTreeView
*view
, GtkTreePath
*path
,
186 GtkTreeViewColumn
*col
, gpointer data
);
187 static void usdlg_cmd_cursor_changed(GtkTreeView
*view
, gpointer data
);
190 /*****************************************************************************
191 Popup the unit selection dialog.
192 *****************************************************************************/
193 void unit_select_dialog_popup_main(struct tile
*ptile
, bool create
)
195 struct unit_select_dialog
*pdialog
;
197 /* Create the dialog if it is requested. */
198 pdialog
= usdlg_get(create
);
200 /* Present the unit selection dialog if it exists. */
203 gtk_widget_show_all(GTK_WIDGET(pdialog
->shell
));
205 usdlg_tile(pdialog
, ptile
);
206 /* Refresh data and hide unused tabs. */
207 usdlg_refresh(pdialog
);
211 /*****************************************************************************
212 Popdown the unit selection dialog.
213 *****************************************************************************/
214 void unit_select_dialog_popdown(void)
219 /*****************************************************************************
220 Get the current unit selection dialog. Create it if needed and 'create' is
222 *****************************************************************************/
223 static struct unit_select_dialog
*usdlg_get(bool create
)
225 if (unit_select_dlg
) {
226 /* Return existing dialog. */
227 return unit_select_dlg
;
229 /* Create new dialog. */
230 unit_select_dlg
= usdlg_create();
231 return unit_select_dlg
;
238 /*****************************************************************************
239 Create a new unit selection dialog.
240 *****************************************************************************/
241 static struct unit_select_dialog
*usdlg_create(void)
243 GtkWidget
*hbox
, *vbox
;
244 GtkWidget
*close_cmd
;
245 struct unit_select_dialog
*pdialog
;
247 /* Create a container for the dialog. */
248 pdialog
= fc_calloc(1, sizeof(*pdialog
));
250 /* No tile defined. */
251 pdialog
->ptile
= NULL
;
253 /* Create the dialog. */
254 pdialog
->shell
= gtk_dialog_new_with_buttons(_("Unit selection"), NULL
, 0,
256 setup_dialog(pdialog
->shell
, toplevel
);
257 g_signal_connect(pdialog
->shell
, "destroy",
258 G_CALLBACK(usdlg_destroy_callback
), pdialog
);
259 gtk_window_set_position(GTK_WINDOW(pdialog
->shell
), GTK_WIN_POS_MOUSE
);
260 gtk_widget_realize(pdialog
->shell
);
262 vbox
= GTK_DIALOG(pdialog
->shell
)->vbox
;
263 hbox
= gtk_hbox_new(TRUE
, 0);
264 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, FALSE
, 0);
267 pdialog
->notebook
= gtk_notebook_new();
268 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(pdialog
->notebook
),
270 gtk_box_pack_start(GTK_BOX(vbox
), pdialog
->notebook
, TRUE
, TRUE
, 0);
273 usdlg_tab_select(pdialog
, _("_Units"), SELLOC_UNITS
);
274 usdlg_tab_select(pdialog
, _("_Tile"), SELLOC_TILE
);
275 usdlg_tab_select(pdialog
, _("C_ontinent"), SELLOC_CONT
);
276 usdlg_tab_select(pdialog
, _("_Land"), SELLOC_LAND
);
277 usdlg_tab_select(pdialog
, _("_Sea"), SELLOC_SEA
);
278 usdlg_tab_select(pdialog
, _("_Both"), SELLOC_BOTH
);
279 usdlg_tab_select(pdialog
, _("_World"), SELLOC_WORLD
);
282 close_cmd
= gtk_dialog_add_button(GTK_DIALOG(pdialog
->shell
),
283 GTK_STOCK_CLOSE
, GTK_RESPONSE_CLOSE
);
284 gtk_dialog_set_default_response(GTK_DIALOG(pdialog
->shell
),
286 g_signal_connect(close_cmd
, "clicked",
287 G_CALLBACK(usdlg_destroy_callback
), pdialog
);
292 /*****************************************************************************
293 Destroy a unit selection dialog.
294 *****************************************************************************/
295 static void usdlg_destroy(void)
297 if (unit_select_dlg
) {
298 gtk_widget_destroy(GTK_WIDGET(unit_select_dlg
->shell
));
299 free(unit_select_dlg
);
301 unit_select_dlg
= NULL
;
304 /*****************************************************************************
305 Callback for the destruction of the dialog.
306 *****************************************************************************/
307 static void usdlg_destroy_callback(GtkObject
*object
, gpointer data
)
312 /*****************************************************************************
313 Set the reference tile.
314 *****************************************************************************/
315 static void usdlg_tile(struct unit_select_dialog
*pdialog
,
322 /* Check for a valid tile. */
324 pdialog
->ptile
= ptile
;
325 } else if (pdialog
->ptile
== NULL
) {
326 struct unit
*punit
= head_of_units_in_focus();
329 pdialog
->ptile
= unit_tile(punit
);
330 center_tile_mapcanvas(pdialog
->ptile
);
332 pdialog
->ptile
= get_center_tile_mapcanvas();
337 /*****************************************************************************
339 *****************************************************************************/
340 static void usdlg_refresh(struct unit_select_dialog
*pdialog
)
342 struct usdata_hash
*ushash
= NULL
;
343 enum unit_select_location_mode loc
;
349 /* Sort units into the hash. */
350 ushash
= usdlg_data_new(pdialog
->ptile
);
351 /* Update all tabs. */
352 for (loc
= unit_select_location_mode_begin();
353 loc
!= unit_select_location_mode_end();
354 loc
= unit_select_location_mode_next(loc
)) {
355 bool show
= usdlg_tab_update(pdialog
, ushash
, loc
);
358 gtk_widget_hide(pdialog
->tabs
[loc
].page
);
360 gtk_widget_show(pdialog
->tabs
[loc
].page
);
362 if (pdialog
->tabs
[loc
].path
) {
363 gtk_tree_view_expand_row(GTK_TREE_VIEW(pdialog
->tabs
[loc
].view
),
364 pdialog
->tabs
[loc
].path
,FALSE
);
365 gtk_tree_view_set_cursor(GTK_TREE_VIEW(pdialog
->tabs
[loc
].view
),
366 pdialog
->tabs
[loc
].path
, NULL
, FALSE
);
367 gtk_tree_path_free(pdialog
->tabs
[loc
].path
);
368 pdialog
->tabs
[loc
].path
= NULL
;
372 /* Destroy the hash. */
373 usdlg_data_destroy(ushash
);
376 /*****************************************************************************
377 +--------------------------------+
378 | +-----------------+----------+ |
379 | | (unit list) | select | |
384 | +-----------------+----------+ |
387 +--------------------------------+
388 *****************************************************************************/
389 static void usdlg_tab_select(struct unit_select_dialog
*pdialog
,
391 enum unit_select_location_mode loc
)
393 GtkWidget
*page
, *label
, *hbox
, *vbox
, *bbox
, *view
, *sw
;
395 static bool titles_done
;
398 page
= gtk_vbox_new(FALSE
, 0);
399 gtk_container_set_border_width(GTK_CONTAINER(page
), 8);
400 pdialog
->tabs
[loc
].page
= page
;
402 label
= gtk_label_new_with_mnemonic(title
);
403 gtk_notebook_append_page(GTK_NOTEBOOK(pdialog
->notebook
), page
, label
);
405 hbox
= gtk_hbox_new(FALSE
, 0);
406 gtk_box_pack_start(GTK_BOX(page
), hbox
, TRUE
, TRUE
, 0);
408 store
= usdlg_tab_store_new();
409 pdialog
->tabs
[loc
].store
= store
;
411 view
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
412 pdialog
->tabs
[loc
].view
= view
;
413 g_object_unref(store
);
415 g_signal_connect(view
, "row-activated", G_CALLBACK(usdlg_cmd_row_activated
),
417 g_signal_connect(view
, "cursor-changed",
418 G_CALLBACK(usdlg_cmd_cursor_changed
), (gpointer
*)loc
);
420 /* Translate titles. */
421 intl_slist(ARRAY_SIZE(usdlg_col_titles
), usdlg_col_titles
, &titles_done
);
423 for (i
= 0; i
< USDLG_COLUMNS_SHOW
; i
++) {
424 GtkTreeViewColumn
*column
= NULL
;
425 GtkCellRenderer
*renderer
= NULL
;
427 switch (usdlg_col_types
[i
]) {
429 renderer
= gtk_cell_renderer_pixbuf_new();
430 column
= gtk_tree_view_column_new_with_attributes(
431 usdlg_col_titles
[i
], renderer
, "pixbuf", i
, NULL
);
432 gtk_tree_view_column_set_expand(column
, FALSE
);
435 renderer
= gtk_cell_renderer_text_new();
436 column
= gtk_tree_view_column_new_with_attributes(
437 usdlg_col_titles
[i
], renderer
, "text", i
,
438 "style", USDLG_COL_STYLE
, "weight", USDLG_COL_WEIGHT
, NULL
);
439 gtk_tree_view_column_set_expand(column
, TRUE
);
442 renderer
= gtk_cell_renderer_text_new();
443 column
= gtk_tree_view_column_new_with_attributes(
444 usdlg_col_titles
[i
], renderer
, "text", i
,
445 "style", USDLG_COL_STYLE
, "weight", USDLG_COL_WEIGHT
, NULL
);
446 g_object_set(renderer
, "xalign", 1.0, NULL
);
447 gtk_tree_view_column_set_alignment(column
, 1.0);
448 gtk_tree_view_column_set_expand(column
, FALSE
);
452 fc_assert_ret(column
!= NULL
);
453 gtk_tree_view_append_column(GTK_TREE_VIEW(view
), column
);
456 sw
= gtk_scrolled_window_new(NULL
, NULL
);
457 gtk_widget_set_size_request(sw
, -1, 300);
458 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw
),
459 GTK_SHADOW_ETCHED_IN
);
460 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
),
461 GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
);
462 gtk_container_add(GTK_CONTAINER(sw
), view
);
463 gtk_box_pack_start(GTK_BOX(hbox
), sw
, TRUE
, TRUE
, 0);
465 vbox
= gtk_vbox_new(FALSE
, 10);
466 gtk_box_pack_start(GTK_BOX(hbox
), vbox
, FALSE
, TRUE
, 0);
468 /* button box 1: ready, sentry */
469 bbox
= gtk_vbox_new(FALSE
, 0);
470 gtk_box_pack_start(GTK_BOX(vbox
), bbox
, FALSE
, TRUE
, 0);
472 pdialog
->tabs
[loc
].cmd
[USDLG_CMD_READY
]
473 = gtk_button_new_with_mnemonic(_("Ready"));
474 gtk_box_pack_start(GTK_BOX(bbox
), pdialog
->tabs
[loc
].cmd
[USDLG_CMD_READY
],
476 g_signal_connect(pdialog
->tabs
[loc
].cmd
[USDLG_CMD_READY
], "clicked",
477 G_CALLBACK(usdlg_cmd_ready
), (gpointer
*)loc
);
478 gtk_widget_set_sensitive(
479 GTK_WIDGET(pdialog
->tabs
[loc
].cmd
[USDLG_CMD_READY
]), FALSE
);
481 pdialog
->tabs
[loc
].cmd
[USDLG_CMD_SENTRY
]
482 = gtk_button_new_with_mnemonic(_("Sentry"));
483 gtk_box_pack_start(GTK_BOX(bbox
), pdialog
->tabs
[loc
].cmd
[USDLG_CMD_SENTRY
],
485 g_signal_connect(pdialog
->tabs
[loc
].cmd
[USDLG_CMD_SENTRY
], "clicked",
486 G_CALLBACK(usdlg_cmd_sentry
), (gpointer
*)loc
);
487 gtk_widget_set_sensitive(
488 GTK_WIDGET(pdialog
->tabs
[loc
].cmd
[USDLG_CMD_SENTRY
]), FALSE
);
490 /* button box 2: select, deselect */
491 bbox
= gtk_vbox_new(FALSE
, 0);
492 gtk_box_pack_start(GTK_BOX(vbox
), bbox
, FALSE
, TRUE
, 0);
494 pdialog
->tabs
[loc
].cmd
[USDLG_CMD_SELECT
]
495 = gtk_button_new_with_mnemonic(_("_Select"));
496 gtk_box_pack_start(GTK_BOX(bbox
), pdialog
->tabs
[loc
].cmd
[USDLG_CMD_SELECT
],
498 g_signal_connect(pdialog
->tabs
[loc
].cmd
[USDLG_CMD_SELECT
], "clicked",
499 G_CALLBACK(usdlg_cmd_select
), (gpointer
*)loc
);
500 gtk_widget_set_sensitive(
501 GTK_WIDGET(pdialog
->tabs
[loc
].cmd
[USDLG_CMD_SELECT
]), FALSE
);
503 pdialog
->tabs
[loc
].cmd
[USDLG_CMD_DESELECT
]
504 = gtk_button_new_with_mnemonic(_("_Deselect"));
505 gtk_box_pack_start(GTK_BOX(bbox
),
506 pdialog
->tabs
[loc
].cmd
[USDLG_CMD_DESELECT
], FALSE
, TRUE
,
508 g_signal_connect(pdialog
->tabs
[loc
].cmd
[USDLG_CMD_DESELECT
], "clicked",
509 G_CALLBACK(usdlg_cmd_deselect
), (gpointer
*)loc
);
510 gtk_widget_set_sensitive(
511 GTK_WIDGET(pdialog
->tabs
[loc
].cmd
[USDLG_CMD_DESELECT
]), FALSE
);
513 /* button box 3: center, focus */
514 bbox
= gtk_vbox_new(FALSE
, 0);
515 gtk_box_pack_start(GTK_BOX(vbox
), bbox
, FALSE
, TRUE
, 0);
517 pdialog
->tabs
[loc
].cmd
[USDLG_CMD_CENTER
]
518 = gtk_button_new_with_mnemonic(_("C_enter"));
519 gtk_box_pack_start(GTK_BOX(bbox
), pdialog
->tabs
[loc
].cmd
[USDLG_CMD_CENTER
],
521 g_signal_connect(pdialog
->tabs
[loc
].cmd
[USDLG_CMD_CENTER
], "clicked",
522 G_CALLBACK(usdlg_cmd_center
), (gpointer
*)loc
);
523 gtk_widget_set_sensitive(
524 GTK_WIDGET(pdialog
->tabs
[loc
].cmd
[USDLG_CMD_CENTER
]), FALSE
);
526 pdialog
->tabs
[loc
].cmd
[USDLG_CMD_FOCUS
]
527 = gtk_button_new_with_mnemonic(_("_Focus"));
528 gtk_box_pack_start(GTK_BOX(bbox
), pdialog
->tabs
[loc
].cmd
[USDLG_CMD_FOCUS
],
530 g_signal_connect(pdialog
->tabs
[loc
].cmd
[USDLG_CMD_FOCUS
], "clicked",
531 G_CALLBACK(usdlg_cmd_focus
), (gpointer
*)loc
);
532 gtk_widget_set_sensitive(
533 GTK_WIDGET(pdialog
->tabs
[loc
].cmd
[USDLG_CMD_FOCUS
]), FALSE
);
536 /*****************************************************************************
537 Create a player dialog store.
538 *****************************************************************************/
539 static GtkTreeStore
*usdlg_tab_store_new(void)
542 GType model_types
[USDLG_COLUMNS_ALL
];
545 for (i
= 0; i
< USDLG_COLUMNS_ALL
; i
++) {
546 switch (usdlg_col_types
[i
]) {
548 model_types
[i
] = GDK_TYPE_PIXBUF
;
551 model_types
[i
] = G_TYPE_STRING
;
554 model_types
[i
] = G_TYPE_INT
;
559 store
= gtk_tree_store_newv(i
, model_types
);
564 /*****************************************************************************
565 Update on tab of the dialog.
566 *****************************************************************************/
567 static bool usdlg_tab_update(struct unit_select_dialog
*pdialog
,
568 struct usdata_hash
*ushash
,
569 enum unit_select_location_mode loc
)
574 fc_assert_ret_val(ushash
, FALSE
);
575 fc_assert_ret_val(pdialog
!= NULL
, FALSE
);
577 store
= pdialog
->tabs
[loc
].store
;
579 /* clear current store. */
580 gtk_tree_store_clear(GTK_TREE_STORE(store
));
582 /* Iterate over all unit types. */
583 if (loc
== SELLOC_UNITS
) {
584 /* Special case - show all units on this tile in their transports. */
585 unit_type_iterate(utype
) {
588 usdata_hash_lookup(ushash
, utype_index(utype
), &data
);
594 activity_type_iterate(act
) {
595 if (unit_list_size(data
->units
[loc
][act
]) == 0) {
599 unit_list_iterate(data
->units
[loc
][act
], punit
) {
602 usdlg_tab_append_units(pdialog
, loc
, act
, punit
, FALSE
,
604 } unit_list_iterate_end
;
608 } activity_type_iterate_end
;
609 } unit_type_iterate_end
;
611 unit_type_iterate(utype
) {
614 GtkTreeIter it_utype
;
618 usdata_hash_lookup(ushash
, utype_index(utype
), &data
);
624 activity_type_iterate(act
) {
627 if (unit_list_size(data
->units
[loc
][act
]) == 0) {
631 /* Level 1: Display unit type. */
633 usdlg_tab_append_utype(GTK_TREE_STORE(store
), loc
, data
->utype
,
638 /* Level 2: Display unit activities. */
639 usdlg_tab_append_activity(GTK_TREE_STORE(store
), loc
, data
->utype
,
640 act
, unit_list_size(data
->units
[loc
][act
]),
643 /* Level 3: Display all units with this activitiy
644 * (and transported units in further level(s)). */
645 unit_list_iterate(data
->units
[loc
][act
], punit
) {
648 usdlg_tab_append_units(pdialog
, loc
, act
, punit
, FALSE
,
650 } unit_list_iterate_end
;
652 count
+= unit_list_size(data
->units
[loc
][act
]);
654 /* Update sum of units with this type. */
655 gtk_tree_store_set(GTK_TREE_STORE(store
), &it_utype
, 2, count
, -1);
657 /* Expand to the activities. */
659 = gtk_tree_model_get_path(GTK_TREE_MODEL(pdialog
->tabs
[loc
].store
),
661 gtk_tree_view_expand_row(GTK_TREE_VIEW(pdialog
->tabs
[loc
].view
), path
,
663 gtk_tree_path_free(path
);
667 } activity_type_iterate_end
;
668 } unit_type_iterate_end
;
674 /*****************************************************************************
675 Append the data for one unit type.
676 *****************************************************************************/
677 static void usdlg_tab_append_utype(GtkTreeStore
*store
,
678 enum unit_select_location_mode loc
,
679 struct unit_type
*putype
,
685 fc_assert_ret(store
!= NULL
);
686 fc_assert_ret(putype
!= NULL
);
689 gtk_tree_store_append(GTK_TREE_STORE(store
), it
, NULL
);
692 pix
= gdk_pixbuf_new(GDK_COLORSPACE_RGB
, TRUE
, 8,
693 tileset_full_tile_width(tileset
),
694 tileset_full_tile_height(tileset
));
697 struct canvas canvas_store
;
699 canvas_store
.type
= CANVAS_PIXBUF
;
700 canvas_store
.v
.pixbuf
= pix
;
702 gdk_pixbuf_fill(pix
, 0x00000000);
703 put_unittype(putype
, &canvas_store
, 1.0, 0, 0);
706 /* The name of the unit. */
707 fc_snprintf(buf
, sizeof(buf
), "%s", utype_name_translation(putype
));
709 /* Add it to the tree. */
710 gtk_tree_store_set(GTK_TREE_STORE(store
), it
,
711 0, pix
, /* Unit pixmap */
713 2, -1, /* will be set later */ /* Number of units */
714 3, utype_index(putype
), /* Unit type ID */
715 /* 4: not set */ /* Unit ID */
716 5, loc
, /* Unit location */
717 /* 6: not set */ /* Unit activity */
718 7, ROW_UNITTYPE
, /* Row type */
719 8, PANGO_STYLE_NORMAL
, /* Style */
720 9, PANGO_WEIGHT_BOLD
, /* Weight */
725 /*****************************************************************************
726 Append the unit activity.
727 *****************************************************************************/
728 static void usdlg_tab_append_activity(GtkTreeStore
*store
,
729 enum unit_select_location_mode loc
,
730 const struct unit_type
*putype
,
731 enum unit_activity act
,
732 int count
, GtkTreeIter
*it
,
737 fc_assert_ret(store
!= NULL
);
738 fc_assert_ret(putype
!= NULL
);
741 gtk_tree_store_append(GTK_TREE_STORE(store
), it
, parent
);
744 fc_snprintf(buf
, sizeof(buf
), "%s", get_activity_text(act
));
746 /* Add it to the tree. */
747 gtk_tree_store_set(GTK_TREE_STORE(store
), it
,
748 /* 0: not set */ /* Unit pixmap */
750 2, count
, /* Number of units */
751 3, utype_index(putype
), /* Unit type ID */
752 /* 4: not set */ /* Unit ID */
753 5, loc
, /* Unit location */
754 6, act
, /* Unit activity */
755 7, ROW_ACTIVITY
, /* Row type */
756 8, PANGO_STYLE_NORMAL
, /* Style */
757 9, PANGO_WEIGHT_NORMAL
, /* Weight */
761 /*****************************************************************************
762 Append units (recursively).
763 *****************************************************************************/
764 static void usdlg_tab_append_units(struct unit_select_dialog
*pdialog
,
765 enum unit_select_location_mode loc
,
766 enum unit_activity act
,
767 const struct unit
*punit
,
768 bool transported
, GtkTreeIter
*it
,
771 char buf
[248] = "", buf2
[248] = "";
774 enum usdlg_row_types row
= ROW_UNIT
;
775 int style
= PANGO_STYLE_NORMAL
;
776 int weight
= PANGO_WEIGHT_NORMAL
;
779 fc_assert_ret(pdialog
!= NULL
);
780 fc_assert_ret(punit
!= NULL
);
782 store
= pdialog
->tabs
[loc
].store
;
786 gtk_tree_store_append(GTK_TREE_STORE(store
), it
, parent
);
789 pix
= gdk_pixbuf_new(GDK_COLORSPACE_RGB
, TRUE
, 8,
790 tileset_full_tile_width(tileset
),
791 tileset_full_tile_height(tileset
));
794 struct canvas canvas_store
;
796 canvas_store
.type
= CANVAS_PIXBUF
;
797 canvas_store
.v
.pixbuf
= pix
;
799 gdk_pixbuf_fill(pix
, 0x00000000);
800 put_unit(punit
, &canvas_store
, 1.0, 0, 0);
803 phome
= game_city_by_number(punit
->homecity
);
805 fc_snprintf(buf2
, sizeof(buf2
), "%s", city_name_get(phome
));
806 } else if (unit_owner(punit
) == client_player()
807 || client_is_global_observer()) {
808 /* TRANS: used in place of unit home city name */
809 sz_strlcpy(buf2
, _("no home city"));
811 /* TRANS: used in place of unit home city name */
812 sz_strlcpy(buf2
, _("unknown"));
815 /* Strings only used in debug builds, don't bother with i18n */
816 fc_snprintf(buf
, sizeof(buf
), "%s [Unit ID %d]\n(%s)\nCoordinates: (%d,%d)",
817 unit_name_translation(punit
), punit
->id
, buf2
,
818 TILE_XY(unit_tile(punit
)));
820 struct unit
*ptrans
= unit_transport_get(punit
);
823 cat_snprintf(buf
, sizeof(buf
), "\nTransported by unit ID %d",
827 #else /* FREECIV_DEBUG */
828 /* TRANS: unit type and home city, e.g. "Transport\n(New Orleans)" */
829 fc_snprintf(buf
, sizeof(buf
), _("%s\n(%s)"), unit_name_translation(punit
),
831 #endif /* FREECIV_DEBUG */
834 weight
= PANGO_WEIGHT_NORMAL
;
835 style
= PANGO_STYLE_ITALIC
;
836 row
= ROW_UNIT_TRANSPORTED
;
839 /* Add it to the tree. */
840 gtk_tree_store_set(GTK_TREE_STORE(store
), it
,
841 0, pix
, /* Unit pixmap */
843 2, 1, /* Number of units */
844 3, utype_index(unit_type_get(punit
)), /* Unit type ID */
845 4, punit
->id
, /* Unit ID */
846 5, loc
, /* Unit location */
847 6, act
, /* Unit activity */
848 7, row
, /* Row type */
849 8, style
, /* Style */
850 9, weight
, /* Weight */
854 if (get_transporter_occupancy(punit
) > 0) {
855 unit_list_iterate(unit_transport_cargo(punit
), pcargo
) {
856 GtkTreeIter it_cargo
;
858 usdlg_tab_append_units(pdialog
, loc
, act
, pcargo
, TRUE
, &it_cargo
, it
);
859 } unit_list_iterate_end
;
862 if (!transported
&& unit_is_in_focus(punit
)) {
863 pdialog
->tabs
[loc
].path
864 = gtk_tree_model_get_path(GTK_TREE_MODEL(store
), it
);
868 /*****************************************************************************
869 Callback for the ready button.
870 *****************************************************************************/
871 static void usdlg_cmd_ready(GtkObject
*object
, gpointer data
)
873 usdlg_cmd_exec(object
, data
, USDLG_CMD_READY
);
876 /*****************************************************************************
877 Callback for the sentry button.
878 *****************************************************************************/
879 static void usdlg_cmd_sentry(GtkObject
*object
, gpointer data
)
881 usdlg_cmd_exec(object
, data
, USDLG_CMD_SENTRY
);
884 /*****************************************************************************
885 Callback for the select button.
886 *****************************************************************************/
887 static void usdlg_cmd_select(GtkObject
*object
, gpointer data
)
889 usdlg_cmd_exec(object
, data
, USDLG_CMD_SELECT
);
892 /*****************************************************************************
893 Callback for the deselect button.
894 *****************************************************************************/
895 static void usdlg_cmd_deselect(GtkObject
*object
, gpointer data
)
897 usdlg_cmd_exec(object
, data
, USDLG_CMD_DESELECT
);
900 /*****************************************************************************
901 Main function for the callbacks.
902 *****************************************************************************/
903 static void usdlg_cmd_exec(GtkObject
*object
, gpointer mode_data
,
906 enum unit_select_location_mode loc_mode
= (enum unit_select_location_mode
) mode_data
;
908 GtkTreeSelection
*selection
;
912 struct unit_select_dialog
*pdialog
= usdlg_get(FALSE
);
914 fc_assert_ret(pdialog
!= NULL
);
915 fc_assert_ret(unit_select_location_mode_is_valid(loc_mode
));
917 if (!can_client_change_view() || !can_client_control()) {
921 view
= GTK_TREE_VIEW(pdialog
->tabs
[loc_mode
].view
);
922 selection
= gtk_tree_view_get_selection(view
);
924 if (!gtk_tree_selection_get_selected(selection
, &model
, &it
)) {
925 log_debug("No selection");
928 gtk_tree_model_get(model
, &it
, USDLG_COL_ROW_TYPE
, &row
, -1);
934 struct usdata_hash
*ushash
;
937 gtk_tree_model_get(model
, &it
, USDLG_COL_LOCATION
, &loc
,
938 USDLG_COL_UTID
, &utid
, -1);
940 /* We can't be sure that all units still exists - recalc the data. */
941 ushash
= usdlg_data_new(pdialog
->ptile
);
943 usdata_hash_lookup(ushash
, utid
, &data
);
945 activity_type_iterate(act
) {
946 if (unit_list_size(data
->units
[loc
][act
]) == 0) {
950 unit_list_iterate(data
->units
[loc
][act
], punit
) {
951 usdlg_cmd_exec_unit(punit
, cmd
);
952 } unit_list_iterate_end
;
953 } activity_type_iterate_end
;
956 /* Destroy the hash. */
957 usdlg_data_destroy(ushash
);
963 struct usdata_hash
*ushash
;
966 gtk_tree_model_get(model
, &it
, USDLG_COL_ACTIVITY
, &act
,
967 USDLG_COL_LOCATION
, &loc
, USDLG_COL_UTID
, &utid
, -1);
969 /* We can't be sure that all units still exists - recalc the data. */
970 ushash
= usdlg_data_new(pdialog
->ptile
);
972 usdata_hash_lookup(ushash
, utid
, &data
);
974 && unit_list_size(data
->units
[loc
][act
]) != 0) {
975 unit_list_iterate(data
->units
[loc
][act
], punit
) {
976 usdlg_cmd_exec_unit(punit
, cmd
);
977 } unit_list_iterate_end
;
980 /* Destroy the hash. */
981 usdlg_data_destroy(ushash
);
985 case ROW_UNIT_TRANSPORTED
:
990 gtk_tree_model_get(model
, &it
, USDLG_COL_UID
, &uid
, -1);
992 punit
= game_unit_by_number(uid
);
995 log_debug("Unit vanished (Unit ID %d)!", uid
);
999 usdlg_cmd_exec_unit(punit
, cmd
);
1005 unit_focus_update();
1006 /* Refresh dialog. */
1007 usdlg_refresh(pdialog
);
1010 /*****************************************************************************
1011 Update one unit (select/deselect/ready/sentry).
1012 *****************************************************************************/
1013 static void usdlg_cmd_exec_unit(struct unit
*punit
, enum usdlg_cmd cmd
)
1015 fc_assert_ret(punit
);
1018 case USDLG_CMD_SELECT
:
1019 if (!unit_is_in_focus(punit
)) {
1020 unit_focus_add(punit
);
1023 case USDLG_CMD_DESELECT
:
1024 if (unit_is_in_focus(punit
)) {
1025 unit_focus_remove(punit
);
1028 case USDLG_CMD_READY
:
1029 if (punit
->activity
!= ACTIVITY_IDLE
) {
1030 request_new_unit_activity(punit
, ACTIVITY_IDLE
);
1033 case USDLG_CMD_SENTRY
:
1034 if (punit
->activity
!= ACTIVITY_SENTRY
) {
1035 request_new_unit_activity(punit
, ACTIVITY_SENTRY
);
1038 case USDLG_CMD_CENTER
:
1039 case USDLG_CMD_FOCUS
:
1040 /* Nothing here. It is done in its own functions. */
1042 case USDLG_CMD_LAST
:
1043 /* Should never happen. */
1044 fc_assert_ret(cmd
!= USDLG_CMD_LAST
);
1049 /*****************************************************************************
1050 Callback for the center button.
1051 *****************************************************************************/
1052 static void usdlg_cmd_center(GtkObject
*object
, gpointer data
)
1054 enum unit_select_location_mode loc
= (enum unit_select_location_mode
) data
;
1056 GtkTreeSelection
*selection
;
1057 GtkTreeModel
*model
;
1060 struct unit_select_dialog
*pdialog
= usdlg_get(FALSE
);
1062 fc_assert_ret(pdialog
!= NULL
);
1063 fc_assert_ret(unit_select_location_mode_is_valid(loc
));
1065 view
= GTK_TREE_VIEW(pdialog
->tabs
[loc
].view
);
1066 selection
= gtk_tree_view_get_selection(view
);
1068 if (!gtk_tree_selection_get_selected(selection
, &model
, &it
)) {
1069 log_debug("No selection");
1072 gtk_tree_model_get(model
, &it
, USDLG_COL_ROW_TYPE
, &row
, -1);
1074 if (row
== ROW_UNIT
|| row
== ROW_UNIT_TRANSPORTED
) {
1078 gtk_tree_model_get(model
, &it
, USDLG_COL_UID
, &uid
, -1);
1080 punit
= player_unit_by_number(client_player(), uid
);
1082 center_tile_mapcanvas(unit_tile(punit
));
1087 /*****************************************************************************
1088 Callback for the focus button.
1089 *****************************************************************************/
1090 static void usdlg_cmd_focus(GtkObject
*object
, gpointer data
)
1092 enum unit_select_location_mode loc
= (enum unit_select_location_mode
) data
;
1093 struct unit_select_dialog
*pdialog
= usdlg_get(FALSE
);
1095 fc_assert_ret(pdialog
!= NULL
);
1096 fc_assert_ret(unit_select_location_mode_is_valid(loc
));
1098 usdlg_cmd_focus_real(GTK_TREE_VIEW(pdialog
->tabs
[loc
].view
));
1101 /*****************************************************************************
1102 Callback if a row is activated.
1103 *****************************************************************************/
1104 static void usdlg_cmd_row_activated(GtkTreeView
*view
, GtkTreePath
*path
,
1105 GtkTreeViewColumn
*col
, gpointer data
)
1107 usdlg_cmd_focus_real(view
);
1110 /*****************************************************************************
1111 Focus to the currently selected unit.
1112 *****************************************************************************/
1113 static void usdlg_cmd_focus_real(GtkTreeView
*view
)
1115 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(view
);
1116 GtkTreeModel
*model
;
1120 if (!can_client_change_view() || !can_client_control()) {
1124 if (!gtk_tree_selection_get_selected(selection
, &model
, &it
)) {
1125 log_debug("No selection");
1128 gtk_tree_model_get(model
, &it
, USDLG_COL_ROW_TYPE
, &row
, -1);
1130 if (row
== ROW_UNIT
|| row
== ROW_UNIT_TRANSPORTED
) {
1134 gtk_tree_model_get(model
, &it
, USDLG_COL_UID
, &uid
, -1);
1136 punit
= player_unit_by_number(client_player(), uid
);
1137 if (punit
&& unit_owner(punit
) == client_player()) {
1138 unit_focus_set(punit
);
1144 /*****************************************************************************
1145 Callback if the row is changed.
1146 *****************************************************************************/
1147 static void usdlg_cmd_cursor_changed(GtkTreeView
*view
, gpointer data
)
1149 enum unit_select_location_mode loc
= (enum unit_select_location_mode
) data
;
1150 GtkTreeSelection
*selection
;
1151 GtkTreeModel
*model
;
1154 struct unit_select_dialog
*pdialog
= usdlg_get(FALSE
);
1156 bool cmd_status
[USDLG_CMD_LAST
];
1159 fc_assert_ret(pdialog
!= NULL
);
1160 fc_assert_ret(unit_select_location_mode_is_valid(loc
));
1162 selection
= gtk_tree_view_get_selection(view
);
1163 if (!gtk_tree_selection_get_selected(selection
, &model
, &it
)) {
1164 log_debug("No selection");
1167 gtk_tree_model_get(model
, &it
, USDLG_COL_ROW_TYPE
, &row
, USDLG_COL_UID
,
1173 /* Button status for rows unittype and activity:
1178 * deselect TRUE FALSE
1179 * center FALSE FALSE
1180 * focus FALSE FALSE */
1181 if (can_client_change_view() && can_client_control()) {
1182 cmd_status
[USDLG_CMD_READY
] = TRUE
;
1183 cmd_status
[USDLG_CMD_SENTRY
] = TRUE
;
1184 cmd_status
[USDLG_CMD_SELECT
] = TRUE
;
1185 cmd_status
[USDLG_CMD_DESELECT
] = TRUE
;
1187 cmd_status
[USDLG_CMD_READY
] = FALSE
;
1188 cmd_status
[USDLG_CMD_SENTRY
] = FALSE
;
1189 cmd_status
[USDLG_CMD_SELECT
] = FALSE
;
1190 cmd_status
[USDLG_CMD_DESELECT
] = FALSE
;
1193 cmd_status
[USDLG_CMD_CENTER
] = FALSE
;
1194 cmd_status
[USDLG_CMD_FOCUS
] = FALSE
;
1197 case ROW_UNIT_TRANSPORTED
:
1198 /* Button status for rows unit and unit (transported):
1201 * sentry !SENTRY FALSE
1202 * select !FOCUS FALSE
1203 * deselect FOCUS FALSE
1205 * focus !FOCUS FALSE */
1206 punit
= player_unit_by_number(client_player(), uid
);
1208 if (punit
&& can_client_change_view() && can_client_control()) {
1209 if (punit
->activity
== ACTIVITY_IDLE
) {
1210 cmd_status
[USDLG_CMD_READY
] = FALSE
;
1212 cmd_status
[USDLG_CMD_READY
] = TRUE
;
1215 if (punit
->activity
== ACTIVITY_SENTRY
) {
1216 cmd_status
[USDLG_CMD_SENTRY
] = FALSE
;
1218 cmd_status
[USDLG_CMD_SENTRY
] = TRUE
;
1221 if (!unit_is_in_focus(punit
)) {
1222 cmd_status
[USDLG_CMD_SELECT
] = TRUE
;
1223 cmd_status
[USDLG_CMD_DESELECT
] = FALSE
;
1224 cmd_status
[USDLG_CMD_FOCUS
] = TRUE
;
1226 cmd_status
[USDLG_CMD_SELECT
] = FALSE
;
1227 cmd_status
[USDLG_CMD_DESELECT
] = TRUE
;
1228 cmd_status
[USDLG_CMD_FOCUS
] = FALSE
;
1231 cmd_status
[USDLG_CMD_READY
] = FALSE
;
1232 cmd_status
[USDLG_CMD_SENTRY
] = FALSE
;
1234 cmd_status
[USDLG_CMD_SELECT
] = FALSE
;
1235 cmd_status
[USDLG_CMD_DESELECT
] = FALSE
;
1237 cmd_status
[USDLG_CMD_FOCUS
] = FALSE
;
1240 cmd_status
[USDLG_CMD_CENTER
] = TRUE
;
1244 /* Set widget status. */
1245 for (cmd_id
= 0; cmd_id
< USDLG_CMD_LAST
; cmd_id
++) {
1246 gtk_widget_set_sensitive(GTK_WIDGET(pdialog
->tabs
[loc
].cmd
[cmd_id
]),
1247 cmd_status
[cmd_id
]);