Qt client - remove right click menu from end turn sidebar
[freeciv.git] / client / gui-gtk-2.0 / messagewin.c
blobd8fef77a7158d9011bdb36f74cf2343dbf7ff1ff
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)
6 any later version.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
22 #include <gtk/gtk.h>
24 /* utility */
25 #include "fcintl.h"
26 #include "log.h"
28 /* common */
29 #include "events.h"
30 #include "game.h"
31 #include "map.h"
32 #include "player.h"
34 /* client */
35 #include "options.h"
37 /* client/gui-gtk-2.0 */
38 #include "chatline.h"
39 #include "citydlg.h"
40 #include "gui_main.h"
41 #include "gui_stuff.h"
42 #include "mapview.h"
44 #include "messagewin.h"
47 struct meswin_dialog {
48 struct gui_dialog *shell;
49 GtkTreeView *tree_view;
52 /* Those values must match meswin_dialog_store_new(). */
53 enum meswin_columns {
54 MESWIN_COL_ICON,
55 MESWIN_COL_MESSAGE,
57 /* Not visible. */
58 MESWIN_COL_WEIGHT,
59 MESWIN_COL_STYLE,
60 MESWIN_COL_ID,
62 MESWIN_COL_NUM
65 enum meswin_responses {
66 MESWIN_RES_GOTO = 1,
67 MESWIN_RES_POPUP_CITY
70 static struct meswin_dialog meswin = { NULL, };
72 /****************************************************************************
73 Create a tree model for the message window.
74 ****************************************************************************/
75 static GtkListStore *meswin_dialog_store_new(void)
77 return gtk_list_store_new(MESWIN_COL_NUM,
78 GDK_TYPE_PIXBUF, /* MESWIN_COL_ICON */
79 G_TYPE_STRING, /* MESWIN_COL_MESSAGE */
80 G_TYPE_INT, /* MESWIN_COL_WEIGHT */
81 G_TYPE_INT, /* MESWIN_COL_STYLE */
82 G_TYPE_INT); /* MESWIN_COL_ID */
85 /****************************************************************************
86 Get the pango attributes for the visited state.
87 ****************************************************************************/
88 static void meswin_dialog_visited_get_attr(bool visited, gint *weight,
89 gint *style)
91 if (NULL != weight) {
92 *weight = (visited ? PANGO_WEIGHT_NORMAL : PANGO_WEIGHT_BOLD);
94 if (NULL != style) {
95 *style = (visited ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
99 /****************************************************************************
100 Set the visited state of the store.
101 ****************************************************************************/
102 static void meswin_dialog_set_visited(GtkTreeModel *model,
103 GtkTreeIter *iter, bool visited)
105 gint row, weight, style;
107 gtk_tree_model_get(model, iter, MESWIN_COL_ID, &row, -1);
108 meswin_dialog_visited_get_attr(visited, &weight, &style);
109 gtk_list_store_set(GTK_LIST_STORE(model), iter,
110 MESWIN_COL_WEIGHT, weight,
111 MESWIN_COL_STYLE, style,
112 -1);
113 meswin_set_visited_state(row, visited);
116 /****************************************************************************
117 Refresh a message window dialog.
118 ****************************************************************************/
119 static void meswin_dialog_refresh(struct meswin_dialog *pdialog)
121 GtkTreeSelection *selection;
122 GtkTreeModel *model;
123 GtkListStore *store;
124 GtkTreeIter iter;
125 const struct message *pmsg;
126 gint weight, style;
127 int selected, i, num;
128 bool need_alert = FALSE;
130 fc_assert_ret(NULL != pdialog);
132 /* Save the selection. */
133 selection = gtk_tree_view_get_selection(pdialog->tree_view);
134 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
135 gtk_tree_model_get(model, &iter, MESWIN_COL_ID, &selected, -1);
136 } else {
137 selected = -1;
140 model = gtk_tree_view_get_model(pdialog->tree_view);
141 store = GTK_LIST_STORE(model);
142 num = meswin_get_num_messages();
144 gtk_list_store_clear(store);
145 for (i = 0; i < num; i++) {
146 GdkPixbuf *pb;
147 struct sprite *icon;
148 int x0, y0, x1, y1, w, h;
150 pmsg = meswin_get_message(i);
152 if (gui_options.gui_gtk2_new_messages_go_to_top) {
153 gtk_list_store_prepend(store, &iter);
154 } else {
155 gtk_list_store_append(store, &iter);
158 icon = get_event_sprite(tileset, pmsg->event);
159 sprite_get_bounding_box(icon, &x0, &y0, &x1, &y1);
160 w = (x1 - x0) + 1;
161 h = (y1 - y0) + 1;
162 pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, w, h);
163 gdk_pixbuf_copy_area(sprite_get_pixbuf(icon), x0, y0, w, h,
164 pb, 0, 0);
166 meswin_dialog_visited_get_attr(pmsg->visited, &weight, &style);
167 gtk_list_store_set(store, &iter,
168 MESWIN_COL_ICON, pb,
169 MESWIN_COL_MESSAGE, pmsg->descr,
170 MESWIN_COL_WEIGHT, weight,
171 MESWIN_COL_STYLE, style,
172 MESWIN_COL_ID, i,
173 -1);
174 g_object_unref(pb);
175 if (i == selected) {
176 /* Restore the selection. */
177 gtk_tree_selection_select_iter(selection, &iter);
180 if (!pmsg->visited) {
181 need_alert = TRUE;
185 if (need_alert) {
186 gui_dialog_alert(pdialog->shell);
190 /**************************************************************************
191 Selection changed callback.
192 **************************************************************************/
193 static void meswin_dialog_selection_callback(GtkTreeSelection *selection,
194 gpointer data)
196 struct meswin_dialog *pdialog = data;
197 const struct message *pmsg;
198 GtkTreeModel *model;
199 GtkTreeIter iter;
200 gint row;
202 if (!gtk_tree_selection_get_selected(selection, &model, &iter)) {
203 return;
206 gtk_tree_model_get(model, &iter, MESWIN_COL_ID, &row, -1);
207 pmsg = meswin_get_message(row);
209 gui_dialog_set_response_sensitive(pdialog->shell, MESWIN_RES_GOTO,
210 NULL != pmsg && pmsg->location_ok);
211 gui_dialog_set_response_sensitive(pdialog->shell, MESWIN_RES_POPUP_CITY,
212 NULL != pmsg && pmsg->city_ok);
215 /**************************************************************************
216 A row has been activated by the user.
217 **************************************************************************/
218 static void meswin_dialog_row_activated_callback(GtkTreeView *view,
219 GtkTreePath *path,
220 GtkTreeViewColumn *col,
221 gpointer data)
223 GtkTreeModel *model = gtk_tree_view_get_model(view);
224 GtkTreeIter iter;
225 gint row;
227 if (!gtk_tree_model_get_iter(model, &iter, path)) {
228 return;
231 gtk_tree_model_get(model, &iter, MESWIN_COL_ID, &row, -1);
233 if (NULL != meswin_get_message(row)) {
234 meswin_double_click(row);
235 meswin_dialog_set_visited(model, &iter, TRUE);
239 /****************************************************************************
240 Mouse button press handler for the message window treeview. We only
241 care about right clicks on a row; this action centers on the tile
242 associated with the event at that row (if applicable).
243 ****************************************************************************/
244 static gboolean meswin_dialog_button_press_callback(GtkWidget *widget,
245 GdkEventButton *ev,
246 gpointer data)
248 GtkTreePath *path = NULL;
249 GtkTreeModel *model;
250 GtkTreeIter iter;
251 gint row;
253 fc_assert_ret_val(GTK_IS_TREE_VIEW(widget), FALSE);
255 if (GDK_BUTTON_PRESS != ev->type || 3 != ev->button) {
256 return FALSE;
259 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), ev->x, ev->y,
260 &path, NULL, NULL, NULL)) {
261 return TRUE;
264 model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
265 if (gtk_tree_model_get_iter(model, &iter, path)) {
266 gtk_tree_model_get(model, &iter, MESWIN_COL_ID, &row, -1);
267 meswin_goto(row);
269 gtk_tree_path_free(path);
271 return TRUE;
274 /**************************************************************************
275 Dialog response callback.
276 **************************************************************************/
277 static void meswin_dialog_response_callback(struct gui_dialog *pgui_dialog,
278 int response, gpointer data)
280 struct meswin_dialog *pdialog = data;
281 GtkTreeSelection *selection;
282 GtkTreeModel *model;
283 GtkTreeIter iter;
284 gint row;
286 switch (response) {
287 case MESWIN_RES_GOTO:
288 case MESWIN_RES_POPUP_CITY:
289 break;
290 default:
291 gui_dialog_destroy(pgui_dialog);
292 return;
295 selection = gtk_tree_view_get_selection(pdialog->tree_view);
296 if (!gtk_tree_selection_get_selected(selection, &model, &iter)) {
297 return;
300 gtk_tree_model_get(model, &iter, MESWIN_COL_ID, &row, -1);
302 switch (response) {
303 case MESWIN_RES_GOTO:
304 meswin_goto(row);
305 break;
306 case MESWIN_RES_POPUP_CITY:
307 meswin_popup_city(row);
308 break;
310 meswin_dialog_set_visited(model, &iter, TRUE);
313 /****************************************************************************
314 Initilialize a message window dialog.
315 ****************************************************************************/
316 static void meswin_dialog_init(struct meswin_dialog *pdialog)
318 GtkWidget *view, *sw, *cmd, *notebook;
319 GtkBox *vbox;
320 GtkListStore *store;
321 GtkTreeSelection *selection;
322 GtkCellRenderer *renderer;
323 GtkTreeViewColumn *col;
325 fc_assert_ret(NULL != pdialog);
327 if (gui_options.gui_gtk2_message_chat_location == GUI_GTK_MSGCHAT_SPLIT) {
328 notebook = right_notebook;
329 } else {
330 notebook = bottom_notebook;
333 gui_dialog_new(&pdialog->shell, GTK_NOTEBOOK(notebook), pdialog, TRUE);
334 gui_dialog_set_title(pdialog->shell, _("Messages"));
335 vbox = GTK_BOX(pdialog->shell->vbox);
337 sw = gtk_scrolled_window_new(NULL, NULL);
338 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
339 GTK_SHADOW_ETCHED_IN);
340 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
341 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
342 gtk_box_pack_start(vbox, sw, TRUE, TRUE, 0);
344 store = meswin_dialog_store_new();
345 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
346 g_object_unref(store);
347 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(view));
348 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
349 g_signal_connect(view, "row_activated",
350 G_CALLBACK(meswin_dialog_row_activated_callback), NULL);
351 g_signal_connect(view, "button-press-event",
352 G_CALLBACK(meswin_dialog_button_press_callback), NULL);
353 pdialog->tree_view = GTK_TREE_VIEW(view);
355 renderer = gtk_cell_renderer_pixbuf_new();
356 col = gtk_tree_view_column_new_with_attributes(NULL, renderer,
357 "pixbuf", MESWIN_COL_ICON, NULL);
358 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
359 gtk_tree_view_column_set_visible(col, !gui_options.gui_gtk2_small_display_layout);
361 renderer = gtk_cell_renderer_text_new();
362 col = gtk_tree_view_column_new_with_attributes(NULL, renderer,
363 "text", MESWIN_COL_MESSAGE,
364 "weight", MESWIN_COL_WEIGHT,
365 "style", MESWIN_COL_STYLE,
366 NULL);
367 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
368 gtk_container_add(GTK_CONTAINER(sw), view);
370 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
371 g_signal_connect(selection, "changed",
372 G_CALLBACK(meswin_dialog_selection_callback), pdialog);
374 if (gui_options.gui_gtk2_show_message_window_buttons) {
375 cmd = gui_dialog_add_stockbutton(pdialog->shell, GTK_STOCK_JUMP_TO,
376 _("Goto _Location"), MESWIN_RES_GOTO);
377 gtk_widget_set_sensitive(cmd, FALSE);
379 cmd = gui_dialog_add_stockbutton(pdialog->shell, GTK_STOCK_ZOOM_IN,
380 _("I_nspect City"),
381 MESWIN_RES_POPUP_CITY);
382 gtk_widget_set_sensitive(cmd, FALSE);
385 gui_dialog_add_button(pdialog->shell, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
386 gui_dialog_response_set_callback(pdialog->shell,
387 meswin_dialog_response_callback);
388 gui_dialog_set_default_size(pdialog->shell, 520, 300);
390 meswin_dialog_refresh(pdialog);
391 gui_dialog_show_all(pdialog->shell);
394 /****************************************************************************
395 Closes a message window dialog.
396 ****************************************************************************/
397 static void meswin_dialog_free(struct meswin_dialog *pdialog)
399 fc_assert_ret(NULL != pdialog);
401 gui_dialog_destroy(pdialog->shell);
402 fc_assert(NULL == pdialog->shell);
404 memset(pdialog, 0, sizeof(*pdialog));
407 /****************************************************************************
408 Popup the dialog inside the main-window, and optionally raise it.
409 ****************************************************************************/
410 void meswin_dialog_popup(bool raise)
412 if (NULL == meswin.shell) {
413 meswin_dialog_init(&meswin);
416 gui_dialog_present(meswin.shell);
417 if (raise) {
418 gui_dialog_raise(meswin.shell);
422 /****************************************************************************
423 Closes the message window dialog.
424 ****************************************************************************/
425 void meswin_dialog_popdown(void)
427 if (NULL != meswin.shell) {
428 meswin_dialog_free(&meswin);
429 fc_assert(NULL == meswin.shell);
433 /****************************************************************************
434 Return TRUE iff the message window is open.
435 ****************************************************************************/
436 bool meswin_dialog_is_open(void)
438 return (NULL != meswin.shell);
441 /****************************************************************************
442 Update the message window dialog.
443 ****************************************************************************/
444 void real_meswin_dialog_update(void)
446 if (NULL != meswin.shell) {
447 meswin_dialog_refresh(&meswin);