Crossfire Client, Trunk
inventory.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, see the
9  * 'LICENSE' and 'COPYING' files.
10  *
11  * The authors can be reached via e-mail to crossfire-devel@real-time.com
12  */
13 
19 #include "client.h"
20 
21 #include <gtk/gtk.h>
22 
23 #include "image.h"
24 #include "main.h"
25 #include "gtk2proto.h"
26 
27 #include "../../pixmaps/all.xpm"
28 #include "../../pixmaps/coin.xpm"
29 #include "../../pixmaps/hand.xpm"
30 #include "../../pixmaps/hand2.xpm"
31 #include "../../pixmaps/lock.xpm"
32 #include "../../pixmaps/mag.xpm"
33 #include "../../pixmaps/nonmag.xpm"
34 #include "../../pixmaps/skull.xpm"
35 #include "../../pixmaps/unlock.xpm"
36 #include "../../pixmaps/unidentified.xpm"
37 
38 GtkWidget *treeview_look;
39 
41 static const GdkColor applied_color = {0, 50000, 50000, 50000};
42 
43 static GtkTreeStore *store_look;
44 static GtkWidget *encumbrance_current;
45 static GtkWidget *encumbrance_max;
46 static GtkWidget *inv_notebook;
47 static GtkWidget *inv_table;
48 
49 static double weight_limit;
50 
51 /*
52  * Hopefully, large enough. Trying to do this with g_malloc gets more
53  * complicated because position of elements within the array are important, so
54  * a simple g_realloc won't work.
55  */
56 #define MAX_INV 2000
57 static GtkWidget *inv_table_children[MAX_INV];
58 
59 #define INV_TABLE_AT(x, y, cols) inv_table_children[cols*y + x]
60 
61 /* Different styles we recognize */
62 enum Styles {
64 };
65 
66 /* The name of these styles in the rc file */
67 static const char *Style_Names[Style_Last] = {
68  "inv_magical", "inv_cursed", "inv_unpaid", "inv_locked", "inv_applied"
69 };
70 
71 /* Actual styles as loaded. May be null if no style found. */
72 static GtkStyle *inv_styles[Style_Last];
73 
74 /*
75  * The basic idea of the NoteBook_Info structure is to hold everything we need
76  * to know about the different inventory notebooks in a module fashion -
77  * instead of hardcoding values, they can be held in the array.
78  */
79 #define NUM_INV_LISTS 11
80 #define INV_SHOW_ITEM 0x1
81 #define INV_SHOW_COLOR 0x2
82 
89 };
90 
91 static int num_inv_notebook_pages = 0;
92 
93 typedef struct {
94  const char *name;
95  const char *tooltip;
96  const char *const *xpm;
97  int(*show_func) (item *it);
101  enum display_type type;
102  GtkWidget *treeview;
103 } Notebook_Info;
104 
105 static GtkTreeStore *treestore;
107 /* Prototypes for static functions */
108 static void on_switch_page(GtkNotebook *notebook, gpointer *page,
109  guint page_num, gpointer user_data);
110 
111 static int show_all(item *it) {
112  return INV_SHOW_ITEM | INV_SHOW_COLOR;
113 }
114 
115 static int show_applied(item *it) {
116  return (it->applied ? INV_SHOW_ITEM : 0);
117 }
118 
119 static int show_unapplied(item *it) {
120  return (it->applied ? 0 : INV_SHOW_ITEM);
121 }
122 
123 static int show_unpaid(item *it) {
124  return (it->unpaid ? INV_SHOW_ITEM : 0);
125 }
126 
127 static int show_cursed(item *it) {
128  return ((it->cursed | it->damned) ? INV_SHOW_ITEM : 0);
129 }
130 
131 static int show_magical(item *it) {
132  return (it->magical ? INV_SHOW_ITEM : 0);
133 }
134 
135 static int show_nonmagical(item *it) {
136  return (it->magical ? 0 : INV_SHOW_ITEM);
137 }
138 
139 static int show_locked(item *it) {
140  return (it->locked ? (INV_SHOW_ITEM | INV_SHOW_COLOR) : 0);
141 }
142 
143 static int show_unlocked(item *it) {
144  // Show open containers, even if locked, to make moving items easier.
145  return ((it->locked && !it->open) ? 0 : (INV_SHOW_ITEM | INV_SHOW_COLOR));
146 }
147 
148 static int show_unidentified(item *it) {
149  return ((it->flagsval & F_UNIDENTIFIED) ? INV_SHOW_ITEM : 0);
150 }
151 
153  {"all", "All", all_xpm, show_all, INV_TREE},
154  {"applied", "Applied", hand_xpm, show_applied, INV_TREE},
155  {"unapplied", "Unapplied", hand2_xpm, show_unapplied, INV_TREE},
156  {"unpaid", "Unpaid", coin_xpm, show_unpaid, INV_TREE},
157  {"cursed", "Cursed", skull_xpm, show_cursed, INV_TREE},
158  {"magical", "Magical", mag_xpm, show_magical, INV_TREE},
159  {"nonmagical", "Non-magical", nonmag_xpm, show_nonmagical, INV_TREE},
160  {"locked", "Locked", lock_xpm, show_locked, INV_TREE},
161  {"unlocked", "Unlocked", unlock_xpm, show_unlocked, INV_TREE},
162  {"unidentified", "Unidentified", unidentified_xpm, show_unidentified, INV_TREE},
163  {"icons", "Icon View", NULL, show_all, INV_TABLE}
164 };
165 
173 };
174 
180 enum item_env {
182 };
183 
194 static int get_item_env(item *it) {
195  if (it->env == cpl.ob) {
196  return ITEM_INVENTORY;
197  }
198  if (it->env == cpl.below) {
199  return ITEM_GROUND;
200  }
201  if (it->env == NULL) {
202  return 0;
203  }
204  return (ITEM_IN_CONTAINER | get_item_env(it->env));
205 }
206 
207 static void list_item_drop(item *tmp);
208 
209 static void ma_examine(GtkWidget *widget, item *tmp) {
210  client_send_examine(tmp->tag);
211 }
212 
213 static void ma_apply(GtkWidget *widget, item *tmp) {
214  client_send_apply(tmp->tag);
215 }
216 
217 static void ma_mark(GtkWidget *widget, item *tmp) {
218  send_mark_obj(tmp);
219 }
220 
221 static void ma_lock(GtkWidget *widget, item *tmp) {
222  toggle_locked(tmp);
223 }
224 
225 static void ma_drop(GtkWidget *widget, item *tmp) {
226  list_item_drop(tmp);
227 }
228 
229 static void show_item_menu(GdkEventButton *event, item *tmp) {
230  GtkWidget *menu = gtk_menu_new();
231  GtkWidget *mi_examine = gtk_menu_item_new_with_mnemonic("_Examine");
232  GtkWidget *mi_apply = gtk_menu_item_new_with_mnemonic("_Apply");
233  GtkWidget *mi_mark = gtk_menu_item_new_with_mnemonic("_Mark");
234  GtkWidget *mi_lock;
235  if (tmp->locked) {
236  mi_lock = gtk_menu_item_new_with_mnemonic("Un_lock");
237  } else {
238  mi_lock = gtk_menu_item_new_with_mnemonic("_Lock");
239  }
240  GtkWidget *mi_drop;
241  gchar *drop_action = tmp->env == cpl.ob ? "_Drop" : "_Pick Up";
242  if (cpl.count != 0) {
243  gchar *drop_label;
244  drop_label = g_strdup_printf("%s %d", drop_action, cpl.count);
245  mi_drop = gtk_menu_item_new_with_mnemonic(drop_label);
246  g_free(drop_label);
247  } else {
248  mi_drop = gtk_menu_item_new_with_mnemonic(drop_action);
249  }
250 
251  gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi_examine);
252  gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi_apply);
253  if (tmp->env == cpl.ob) {
254  // In player's inventory
255  gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi_mark);
256  gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi_lock);
257  }
258  gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi_drop);
259  g_signal_connect(mi_examine, "activate", G_CALLBACK(ma_examine), tmp);
260  g_signal_connect(mi_apply, "activate", G_CALLBACK(ma_apply), tmp);
261  g_signal_connect(mi_mark, "activate", G_CALLBACK(ma_mark), tmp);
262  g_signal_connect(mi_lock, "activate", G_CALLBACK(ma_lock), tmp);
263  g_signal_connect(mi_drop, "activate", G_CALLBACK(ma_drop), tmp);
264  gtk_widget_show_all(menu);
265  gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);
266 }
267 
273 static void list_item_action(GdkEventButton *event, item *tmp) {
274  /* It'd sure be nice if these weren't hardcoded values for button and
275  * shift presses.
276  */
277  if (event->button == 1) { // primary/left mouse button
278  if (event->state & GDK_SHIFT_MASK) {
279  toggle_locked(tmp);
280  } else {
282  show_item_menu(event, tmp);
283  } else {
284  client_send_examine(tmp->tag);
285  }
286  }
287  } else if (event->button == 2) { // middle mouse button
288  /* Some mice do not have a functioning middle mouse button,
289  * so all the actions here are duplicated elsewhere
290  */
291  if (event->state & GDK_SHIFT_MASK) {
292  send_mark_obj(tmp);
293  } else {
294  client_send_apply(tmp->tag);
295  }
296  } else if (event->button == 3) { // secondary/right mouse button
297  if (event->state & GDK_SHIFT_MASK) {
298  client_send_apply(tmp->tag);
299  } else if (event->state & GDK_CONTROL_MASK) {
300  send_mark_obj(tmp);
301  } else {
302  list_item_drop(tmp);
303  }
304  }
305 }
306 
307 static void list_item_drop(item *tmp) {
308  int env;
309 
310  /* We need to know where this item is in fact is */
311  env = get_item_env(tmp);
312 
313  if (tmp->locked) {
315  "This item is locked. To drop it, first unlock by shift+leftclicking on it.");
316  } else {
317  guint32 dest;
318  /*
319  * Figure out where to move the item to. If it is on the ground,
320  * it is moving to the players inventory. If it is in a container,
321  * it is also moving to players inventory. If it is in the players
322  * inventory (not a container) and the player has an open container
323  * in his inventory, move the object to the container (not ground).
324  * Otherwise, it is moving to the ground (dest=0). Have to look at
325  * the item environment, because what list is no longer accurate.
326  */
327  if (env & (ITEM_GROUND | ITEM_IN_CONTAINER)) {
328  dest = cpl.ob->tag;
329  } else if (env == ITEM_INVENTORY && cpl.container &&
332  dest = cpl.container->tag;
333  } else {
334  dest = 0;
335  }
336 
337  client_send_move(dest, tmp->tag, cpl.count);
338  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbutton_count), 0.0);
339  cpl.count = 0;
340  }
341 }
342 
357 static gboolean list_selection_func(GtkTreeSelection *selection,
358  GtkTreeModel *model, GtkTreePath *path,
359  gboolean path_currently_selected, gpointer userdata) {
360  GtkTreeIter iter;
361  GdkEventButton *event;
362 
363  /* Get the current event so we can know if shift is pressed */
364  event = (GdkEventButton*)gtk_get_current_event();
365  if (!event) {
366  LOG(LOG_ERROR, "inventory.c::list_selection_func", "Unable to get event structure\n");
367  return FALSE;
368  }
369 
370  if (gtk_tree_model_get_iter(model, &iter, path)) {
371  item *tmp;
372 
373  gtk_tree_model_get(model, &iter, LIST_OBJECT, &tmp, -1);
374 
375  if (!tmp) {
376  LOG(LOG_ERROR, "inventory.c::list_selection_func", "Unable to get item structure\n");
377  return FALSE;
378  }
379  list_item_action(event, tmp);
380  }
381  /*
382  * Don't want the row toggled - our code above handles what we need to do,
383  * so return false.
384  */
385  return FALSE;
386 }
387 
397 static void list_row_collapse(GtkTreeView *treeview, GtkTreeIter *iter,
398  GtkTreePath *path, gpointer user_data) {
399  GtkTreeModel *model;
400  item *tmp;
401 
402  model = gtk_tree_view_get_model(treeview);
403 
404  gtk_tree_model_get(GTK_TREE_MODEL(model), iter, LIST_OBJECT, &tmp, -1);
405  client_send_apply(tmp->tag);
406 }
407 
412 static void setup_list_columns(GtkWidget *treeview) {
413  GtkCellRenderer *renderer;
414  GtkTreeViewColumn *column;
415  GtkTreeSelection *selection;
416 
417 #if 0
418  /*
419  * This is a hack to hide the expander column. We do this because access
420  * via containers need to be handled by the apply/unapply mechanism -
421  * otherwise, I think it will be confusing - people 'closing' the container
422  * with the expander arrow and still having things go into/out of the
423  * container. Unfortunat
424  */
425  renderer = gtk_cell_renderer_text_new();
426  column = gtk_tree_view_column_new_with_attributes("", renderer,
427  "text", LIST_NONE,
428  NULL);
429  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
430  gtk_tree_view_column_set_visible(column, FALSE);
431  gtk_tree_view_set_expander_column(GTK_TREE_VIEW(treeview), column);
432 #endif
433 
434  renderer = gtk_cell_renderer_pixbuf_new();
435  /*
436  * Setting the xalign to 0.0 IMO makes the display better. Gtk
437  * automatically resizes the column to make space based on image size,
438  * however, it isn't really aggressive on shrinking it. IMO, it looks
439  * better for the image to always be at the far left - without this
440  * alignment, the image is centered which IMO doesn't always look good.
441  */
442  g_object_set(G_OBJECT(renderer), "xalign", 0.0, NULL);
443  column = gtk_tree_view_column_new_with_attributes("?", renderer,
444  "pixbuf", LIST_ICON, NULL);
445 
446  /* gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);*/
447  gtk_tree_view_column_set_min_width(column, image_size);
448  gtk_tree_view_column_set_sort_column_id(column, LIST_TYPE);
449  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
450 
451  renderer = gtk_cell_renderer_text_new();
452  column = gtk_tree_view_column_new_with_attributes("Name", renderer,
453  "text", LIST_NAME, NULL);
454  gtk_tree_view_column_set_expand(column, TRUE);
455  gtk_tree_view_column_set_sort_column_id(column, LIST_BASENAME);
456 
457  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
458  gtk_tree_view_column_add_attribute(column, renderer, "background-gdk", LIST_BACKGROUND);
459  gtk_tree_view_column_add_attribute(column, renderer, "foreground-gdk", LIST_FOREGROUND);
460  gtk_tree_view_column_add_attribute(column, renderer, "font-desc", LIST_FONT);
461  gtk_tree_view_set_expander_column(GTK_TREE_VIEW(treeview), column);
462  gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
463 
464  renderer = gtk_cell_renderer_text_new();
465  column = gtk_tree_view_column_new_with_attributes("Weight", renderer,
466  "text", LIST_WEIGHT, NULL);
467  /*
468  * At 50, the title was always truncated on some systems. 64 is the
469  * minimum on those systems for it to be possible to avoid truncation at
470  * all. Truncating the title looks cheesy, especially since heavy items
471  * (100+) need the width of the field anyway. If weight pushed off the
472  * edge is a problem, it would be just better to let the user resize or
473  * find a way to allow rendering with a smaller font.
474  */
475  gtk_tree_view_column_set_min_width(column, 64);
476  gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
477 
478  gtk_tree_view_column_set_sort_column_id(column, LIST_WEIGHT);
479  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
480  gtk_tree_view_column_add_attribute(column, renderer, "background-gdk", LIST_BACKGROUND);
481  gtk_tree_view_column_add_attribute(column, renderer, "foreground-gdk", LIST_FOREGROUND);
482  gtk_tree_view_column_add_attribute(column, renderer, "font-desc", LIST_FONT);
483  /*
484  * Really, we never really do selections - clicking on an object causes a
485  * reaction right then. So grab press before the selection and just negate
486  * the selection - that's more efficient than unselection the item after it
487  * was selected.
488  */
489  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
490 
491  gtk_tree_selection_set_select_function(selection, list_selection_func, NULL, NULL);
492 }
493 
502  int i;
503  GtkStyle *tmp_style;
504  static int has_init = 0;
505 
506  for (i = 0; i < Style_Last; i++) {
507  if (has_init && inv_styles[i]) {
508  g_object_unref(inv_styles[i]);
509  }
510  tmp_style = gtk_rc_get_style_by_paths(gtk_settings_get_default(), NULL, Style_Names[i],
511  G_TYPE_NONE);
512  if (tmp_style) {
513  inv_styles[i] = g_object_ref(tmp_style);
514  } else {
515  LOG(LOG_INFO, "inventory.c::inventory_get_styles", "Unable to find style for %s",
516  Style_Names[i]);
517  inv_styles[i] = NULL;
518  }
519  }
520  has_init = 1;
521 }
522 
528 void inventory_init(GtkWidget *window_root) {
529  int i;
530 
531  /*inventory_get_styles();*/
532 
533  inv_notebook = GTK_WIDGET(gtk_builder_get_object(window_xml,
534  "notebook_inv"));
535  treeview_look = GTK_WIDGET(gtk_builder_get_object(window_xml,
536  "treeview_look"));
537  encumbrance_current = GTK_WIDGET(gtk_builder_get_object(window_xml,
538  "label_stat_encumbrance_current"));
539  encumbrance_max = GTK_WIDGET(gtk_builder_get_object(window_xml,
540  "label_stat_encumbrance_max"));
541  inv_table = GTK_WIDGET(gtk_builder_get_object(window_xml,
542  "inv_table"));
543 
544  g_signal_connect((gpointer)inv_notebook, "switch_page",
545  (GCallback)on_switch_page, NULL);
546  g_signal_connect((gpointer) treeview_look, "row_collapsed",
547  (GCallback) list_row_collapse, NULL);
548 
549  memset(inv_table_children, 0, sizeof (GtkWidget *) * MAX_INV);
550 
551  treestore = gtk_tree_store_new(LIST_NUM_COLUMNS,
552  G_TYPE_STRING,
553  G_TYPE_OBJECT,
554  G_TYPE_STRING,
555  G_TYPE_STRING,
556  G_TYPE_POINTER,
557  GDK_TYPE_COLOR,
558  G_TYPE_INT,
559  G_TYPE_STRING,
560  GDK_TYPE_COLOR,
561  PANGO_TYPE_FONT_DESCRIPTION);
562 
563  store_look = gtk_tree_store_new(LIST_NUM_COLUMNS,
564  G_TYPE_STRING,
565  G_TYPE_OBJECT,
566  G_TYPE_STRING,
567  G_TYPE_STRING,
568  G_TYPE_POINTER,
569  GDK_TYPE_COLOR,
570  G_TYPE_INT,
571  G_TYPE_STRING,
572  GDK_TYPE_COLOR,
573  PANGO_TYPE_FONT_DESCRIPTION);
574 
575  gtk_tree_view_set_model(GTK_TREE_VIEW(treeview_look), GTK_TREE_MODEL(store_look));
577  /*
578  * Glade doesn't let us fully realize a treeview widget - we still need to
579  * to do a bunch of customization just like we do for the look window
580  * above. If we have to do all that work, might as well just put it in the
581  * for loop below vs setting up half realized widgets within layout that we
582  * then need to finish setting up. However, that said, we want to be able
583  * to set up other notebooks within layout for perhaps a true list of just
584  * icons. So we presume that any tabs that exist must already be all set
585  * up. We prepend our tabs to the existing tab - this makes the position
586  * of the array of noteboks correspond to actual data in the tabs.
587  */
588  for (i = 0; i < NUM_INV_LISTS; i++) {
589  GtkWidget *swindow, *image;
590 
591  if (inv_notebooks[i].type == INV_TREE) {
592  swindow = gtk_scrolled_window_new(NULL, NULL);
593  gtk_widget_show(swindow);
594  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swindow),
595  GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
596  image = gtk_image_new_from_pixbuf(
597  gdk_pixbuf_new_from_xpm_data((const char**) inv_notebooks[i].xpm));
598 
599  if (inv_notebooks[i].tooltip) {
600  GtkWidget *eb;
601 
602  eb = gtk_event_box_new();
603  gtk_widget_show(eb);
604 
605  gtk_container_add(GTK_CONTAINER(eb), image);
606  gtk_widget_show(image);
607 
608  image = eb;
609  gtk_widget_set_tooltip_text(image, inv_notebooks[i].tooltip);
610  }
611 
612  gtk_notebook_insert_page(GTK_NOTEBOOK(inv_notebook), swindow, image, i);
613 
614  inv_notebooks[i].treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(
615  treestore));
616 
617  g_signal_connect((gpointer) inv_notebooks[i].treeview, "row_collapsed",
618  G_CALLBACK(list_row_collapse), NULL);
619 
620  setup_list_columns(inv_notebooks[i].treeview);
621  gtk_widget_show(inv_notebooks[i].treeview);
622  gtk_container_add(GTK_CONTAINER(swindow), inv_notebooks[i].treeview);
623  }
624  }
625  num_inv_notebook_pages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(inv_notebook));
626 
627  /* Make sure we are on the first page */
628  gtk_notebook_set_current_page(GTK_NOTEBOOK(inv_notebook), 0);
629 
630  /* If all the data is set up properly, these should match */
632  LOG(LOG_ERROR, "inventory.c::inventory_init",
633  "num_inv_notebook_pages (%d) does not match NUM_INV_LISTS(%d)\n",
635  }
636 
637 }
638 
648 }
649 
654 void open_container(item *op) {
655 }
656 
661 void command_show(const char *params) {
662  if (!params) {
663  /*
664  * Shouldn't need to get current page, but next_page call is not
665  * wrapping like the docs claim it should.
666  */
667  if (gtk_notebook_get_current_page(GTK_NOTEBOOK(inv_notebook)) ==
669  gtk_notebook_set_current_page(GTK_NOTEBOOK(inv_notebook), 0);
670  } else {
671  gtk_notebook_next_page(GTK_NOTEBOOK(inv_notebook));
672  }
673  } else {
674  char buf[MAX_BUF];
675 
676  for (int i = 0; i < NUM_INV_LISTS; i++) {
677  if (!strncmp(params, inv_notebooks[i].name, strlen(params))) {
678  gtk_notebook_set_current_page(GTK_NOTEBOOK(inv_notebook), i);
679  return;
680  }
681  }
682  snprintf(buf, sizeof (buf), "Unknown notebook page %s\n", params);
684  }
685 }
686 
693 void set_weight_limit(guint32 wlim) {
694  weight_limit = wlim / 1000.0;
695 }
696 
702 static GtkStyle *get_row_style(item *it) {
703  int style;
704 
705  /* Note that this ordering is documented in the sample rc file.
706  * it would be nice if this precedence could be more easily
707  * setable by the end user.
708  */
709  if (it->unpaid) {
710  style = Style_Unpaid;
711  } else if (it->cursed || it->damned) {
712  style = Style_Cursed;
713  } else if (it->magical) {
714  style = Style_Magical;
715  } else if (it->applied) {
716  style = Style_Applied;
717  } else if (it->locked) {
718  style = Style_Locked;
719  } else {
720  return NULL; /* No matching style */
721  }
722 
723  return inv_styles[style];
724 }
725 
726 /***************************************************************************
727  * Below are the actual guts for drawing the inventory and look windows.
728  * Some quick notes:
729  * 1) The gtk2 widgets (treeview/treemodel) seem noticably slower than the
730  * older clist widgets in gtk1. This is beyond the code below - just
731  * scrolling the window, which is all done internally by gtk, is
732  * quite slow. Seems especially bad when using the scrollwheel.
733  * 2) documentation suggests the detaching the treemodel and re-attaching
734  * it after insertions would be faster. The problem is that this causes
735  * loss of positioning for the scrollbar. Eg, you eat a food in the middle
736  * of your inventory, and then inventory resets to the top of the inventory.
737  * 3) it'd probably be much more efficient if the code could know what changes
738  * are taking place, instead of rebuilding the tree model each time. For
739  * example, if the only thing that changed is the number of of the object,
740  * we can just update the name and weight, and not rebuild the entire list.
741  * This may be doable in the code below by getting data from the tree store
742  * and comparing it against what we want to show - however, figuring out
743  * insertions and removals are more difficult.
744  */
745 
746 static void remove_object_from_store(item* it, GtkTreeStore* store) {
747  GtkTreeIter iter;
748  gboolean valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
749  while (valid) {
750  item* curr_item;
751  gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, LIST_OBJECT, &curr_item, -1);
752  if (curr_item == it) {
753  gtk_tree_store_remove(store, &iter);
754  break;
755  }
756  valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
757  }
758 }
759 
761  switch (get_item_env(it)) {
762  case ITEM_INVENTORY:
764  cpl.ob->inv_updated = 1;
765  break;
766  case ITEM_GROUND:
768  cpl.below->inv_updated = 1;
769  break;
770  }
771 }
772 
774 }
775 
777 }
778 
792 static void add_object_to_store(item *it, GtkTreeStore *store,
793  GtkTreeIter *new, GtkTreeIter *parent, int color) {
794  char buf[256], buf1[256];
795  GdkColor *foreground = NULL, *background = NULL;
796  PangoFontDescription *font = NULL;
797  GtkStyle *row_style;
798 
799  if (it->weight < 0) {
800  strcpy(buf, " ");
801  } else {
802  snprintf(buf, sizeof (buf), "%6.1f", it->nrof * it->weight);
803  }
804  snprintf(buf1, 255, "%s %s", it->d_name, it->flags);
805  if (color) {
806  row_style = get_row_style(it);
807  if (row_style) {
808  /*
809  * Even if the user doesn't define these, we should still get get
810  * defaults from the system.
811  */
812  foreground = &row_style->text[GTK_STATE_NORMAL];
813  background = &row_style->base[GTK_STATE_NORMAL];
814  font = row_style->font_desc;
815  }
816  }
817 
818  gtk_tree_store_append(store, new, parent); /* Acquire an iterator */
819  gtk_tree_store_set(store, new,
820  LIST_ICON, (GdkPixbuf*) pixmaps[it->face]->icon_image,
821  LIST_NAME, buf1,
822  LIST_WEIGHT, buf,
823  LIST_BACKGROUND, background,
824  LIST_FOREGROUND, foreground,
825  LIST_FONT, font,
826  LIST_OBJECT, it,
827  LIST_TYPE, it->type,
828  LIST_BASENAME, it->s_name,
829  -1);
830 }
831 
836  item *tmp;
837  GtkTreeIter iter;
838  /*
839  * List drawing is actually fairly inefficient - we only know globally if
840  * the objects has changed, but have no idea what specific object has
841  * changed. As such, we are forced to basicly redraw the entire list each
842  * time this is called.
843  */
844  gtk_tree_store_clear(store_look);
845 
846  for (tmp = cpl.below->inv; tmp; tmp = tmp->next) {
847  add_object_to_store(tmp, store_look, &iter, NULL, 1);
848 
849  if ((cpl.container == tmp) && tmp->open) {
850  item *tmp2;
851  GtkTreeIter iter1;
852  GtkTreePath *path;
853 
854  for (tmp2 = tmp->inv; tmp2; tmp2 = tmp2->next) {
855  add_object_to_store(tmp2, store_look, &iter1, &iter, 1);
856  }
857  path = gtk_tree_model_get_path(GTK_TREE_MODEL(store_look), &iter);
858  gtk_tree_view_expand_row(GTK_TREE_VIEW(treeview_look), path, FALSE);
859  gtk_tree_path_free(path);
860  }
861  }
862 }
863 
870 static void draw_inv_list(int tab) {
871  item *tmp;
872  GtkTreeIter iter;
873  int rowflag;
874 
875  /*
876  * List drawing is actually fairly inefficient - we only know globally if
877  * the objects has changed, but have no idea what specific object has
878  * changed. As such, we are forced to basicly redraw the entire list each
879  * time this is called.
880  */
881  gtk_tree_store_clear(treestore);
882 
883  for (tmp = cpl.ob->inv; tmp; tmp = tmp->next) {
884  rowflag = inv_notebooks[tab].show_func(tmp);
885  if (!(rowflag & INV_SHOW_ITEM)) {
886  continue;
887  }
888 
889  add_object_to_store(tmp, treestore, &iter, NULL, rowflag & INV_SHOW_COLOR);
890 
891  if ((cpl.container == tmp) && tmp->open) {
892  item *tmp2;
893  GtkTreeIter iter1;
894  GtkTreePath *path;
895 
896  for (tmp2 = tmp->inv; tmp2; tmp2 = tmp2->next) {
897  /*
898  * Wonder if we really want this logic for objects in
899  * containers? my thought is yes - being able to see all
900  * cursed objects in the container could be quite useful.
901  * Unfortunately, that doesn't quite work as intended, because
902  * we will only get here if the container object is being
903  * displayed. Since container objects can't be cursed, can't
904  * use that as a filter.
905  */
906  /*
907  rowflag = inv_notebooks[tab].show_func(tmp2);
908  */
909  if (!(rowflag & INV_SHOW_ITEM)) {
910  continue;
911  }
912  add_object_to_store(tmp2, treestore, &iter1, &iter,
913  rowflag & INV_SHOW_COLOR);
914  }
915  path = gtk_tree_model_get_path(GTK_TREE_MODEL(treestore), &iter);
916  gtk_tree_view_expand_row(GTK_TREE_VIEW(inv_notebooks[tab].treeview), path, FALSE);
917  gtk_tree_path_free(path);
918  }
919  }
920 }
921 
930  GtkWidget *widget, GdkEventButton *event, gpointer user_data) {
931  list_item_action(event, (item*) user_data);
932  return TRUE;
933 }
934 
935 static void draw_inv_table_icon(GdkWindow *dst, const void *image) {
936  cairo_t *cr = gdk_cairo_create(dst);
937 
938  gdk_window_clear(dst);
939  gdk_cairo_set_source_pixbuf(cr, (GdkPixbuf *) image, 0, 0);
940  cairo_paint(cr);
941  cairo_destroy(cr);
942 }
943 
951 static gboolean drawingarea_inventory_table_expose_event(GtkWidget *widget,
952  GdkEventExpose *event, gpointer user_data) {
953  if (cpl.ob->inv_updated != 0) {
954  // Delay drawing until inventory is fully updated. This avoids drawing
955  // previously added items that may now be removed, leading to a heap
956  // use-after-free.
957  return TRUE;
958  }
959 
960  /*
961  * Can get cases when switching tabs that we get an expose event before the
962  * list is updated - if so, don't draw stuff we don't have faces for.
963  */
964  item* tmp = (item*)user_data;
965  if (tmp->face) {
966  draw_inv_table_icon(gtk_widget_get_window(widget), pixmaps[tmp->face]->icon_image);
967  }
968 
969  return TRUE;
970 }
971 
978 static void draw_inv_table(int animate) {
979  int x, y, rows, columns, num_items, i;
980  static int max_drawn = 0;
981  item *tmp;
982  char buf[256];
983  gulong handler;
984 
985  num_items = 0;
986  for (tmp = cpl.ob->inv; tmp; tmp = tmp->next) {
987  num_items++;
988  }
989 
990  if (num_items > MAX_INV) {
991  LOG(LOG_ERROR, "draw_inv_table", "Too many items in inventory!");
992  return;
993  }
994 
995  GtkAllocation size;
996  gtk_widget_get_allocation(inv_table, &size);
997 
998  columns = size.width / image_size;
999  rows = size.height / image_size;
1000 
1001  if (columns < 1) {
1002  // size.width is occasionally very small after a player applies a bed
1003  // to reality and the character selection window comes on. This causes
1004  // columns = 0 and a divide by zero a few lines later.
1005  return;
1006  }
1007 
1008  if (num_items > columns * rows) {
1009  rows = num_items / columns;
1010  if (num_items % columns) {
1011  rows++;
1012  }
1013  }
1014 
1015  gtk_table_resize(GTK_TABLE(inv_table), rows, columns);
1016 
1017  x = 0;
1018  y = 0;
1019  for (tmp = cpl.ob->inv; tmp; tmp = tmp->next) {
1020  if (INV_TABLE_AT(x, y, columns) == NULL) {
1021  INV_TABLE_AT(x, y, columns) = gtk_drawing_area_new();
1022  gtk_widget_set_size_request(INV_TABLE_AT(x, y, columns), image_size,
1023  image_size);
1024 
1025  gtk_table_attach(GTK_TABLE(inv_table), INV_TABLE_AT(x, y, columns),
1026  x, x + 1, y, y + 1, GTK_FILL, GTK_FILL, 0, 0);
1027  }
1028  if (animate) {
1029  /* This is an object with animations */
1030  if (tmp->animation_id > 0 && tmp->anim_speed) {
1031  tmp->last_anim++;
1032 
1033  /* Time to change the face for this one */
1034  if (tmp->last_anim >= tmp->anim_speed) {
1035  tmp->anim_state++;
1036  if (tmp->anim_state >= animations[tmp->animation_id].num_animations) {
1037  tmp->anim_state = 0;
1038  }
1039  tmp->face = animations[tmp->animation_id].faces[tmp->anim_state];
1040  tmp->last_anim = 0;
1041 
1043  gtk_widget_get_window(INV_TABLE_AT(x, y, columns)),
1044  pixmaps[tmp->face]->icon_image);
1045  }
1046  }
1047  /* On animation run, so don't do any of the remaining logic */
1048  } else {
1049  /*
1050  * Need to clear out the old signals, since the signals are
1051  * effectively stacked - you can have 6 signal handlers tied to the
1052  * same function.
1053  */
1054  handler = g_signal_handler_find((gpointer) INV_TABLE_AT(x, y, columns),
1055  G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
1057  NULL);
1058 
1059  if (handler) {
1060  g_signal_handler_disconnect((gpointer) INV_TABLE_AT(x, y, columns), handler);
1061  }
1062 
1063  handler = g_signal_handler_find((gpointer) INV_TABLE_AT(x, y, columns),
1064  G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
1066  NULL);
1067  if (handler) {
1068  g_signal_handler_disconnect((gpointer) INV_TABLE_AT(x, y, columns), handler);
1069  }
1070  /*
1071  * Not positive precisely what events are needed, but some events
1072  * beyond just the button press are necessary for the tooltips to
1073  * work.
1074  */
1075  gtk_widget_add_events(INV_TABLE_AT(x, y, columns), GDK_ALL_EVENTS_MASK);
1076 
1077  g_signal_connect((gpointer) INV_TABLE_AT(x, y, columns), "button_press_event",
1079  tmp);
1080 
1081  g_signal_connect((gpointer) INV_TABLE_AT(x, y, columns), "expose_event",
1083  tmp);
1084 
1085  /* Draw the inventory icon image to the table. */
1086  draw_inv_table_icon(gtk_widget_get_window(INV_TABLE_AT(x, y, columns)),
1087  pixmaps[tmp->face]->icon_image);
1088 
1089  // Draw an extra indicator if the item is applied.
1090  if (tmp->applied) {
1091  gtk_widget_modify_bg(INV_TABLE_AT(x, y, columns),
1092  GTK_STATE_NORMAL, &applied_color);
1093  } else {
1094  gtk_widget_modify_bg(INV_TABLE_AT(x, y, columns),
1095  GTK_STATE_NORMAL, NULL);
1096  }
1097 
1098  gtk_widget_show(INV_TABLE_AT(x, y, columns));
1099  /*
1100  * Use tooltips to provide additional detail about the icons.
1101  * Looking at the code, the tooltip widget will take care of
1102  * removing the old tooltip, freeing strings, etc.
1103  */
1104  snprintf(buf, 255, "%s %s", tmp->d_name, tmp->flags);
1105  gtk_widget_set_tooltip_text(INV_TABLE_AT(x, y, columns), buf);
1106  }
1107  x++;
1108  if (x == columns) {
1109  x = 0;
1110  y++;
1111  }
1112 
1113  }
1114  /* Don't need to do the logic below if only doing animation run */
1115  if (animate) {
1116  return;
1117  }
1118  /*
1119  * Need to disconnect the callback functions cells we did not draw.
1120  * otherwise, we get errors on objects that are drawn.
1121  */
1122  for (i = num_items; i <= max_drawn; i++) {
1123  if (INV_TABLE_AT(x, y, columns)) {
1124  gtk_widget_destroy(INV_TABLE_AT(x, y, columns));
1125  INV_TABLE_AT(x, y, columns) = NULL;
1126  }
1127  x++;
1128  if (x == columns) {
1129  x = 0;
1130  y++;
1131  }
1132  }
1133  max_drawn = num_items;
1134 
1135  gtk_widget_show(inv_table);
1136 }
1137 
1144 static void draw_inv(int tab) {
1145  char buf[256];
1146 
1147  snprintf(buf, sizeof (buf), "%6.1f", cpl.ob->weight);
1148  gtk_label_set_text(GTK_LABEL(encumbrance_current), buf);
1149  snprintf(buf, sizeof (buf), "%6.1f", weight_limit);
1150  gtk_label_set_text(GTK_LABEL(encumbrance_max), buf);
1151 
1152  if (inv_notebooks[tab].type == INV_TREE) {
1153  draw_inv_list(tab);
1154  } else if (inv_notebooks[tab].type == INV_TABLE) {
1155  draw_inv_table(0);
1156  }
1157 }
1158 
1162 void draw_lists() {
1163  /*
1164  * There are some extra complications with container handling and timing.
1165  * For example, we draw the window before we get a list of the container,
1166  * and then the container contents are not drawn - this can be handled by
1167  * looking at container->inv_updated.
1168  */
1170  cpl.container->env->inv_updated = 1;
1171  cpl.container->inv_updated = 0;
1172  }
1173  if (cpl.ob->inv_updated) {
1174  draw_inv(gtk_notebook_get_current_page(GTK_NOTEBOOK(inv_notebook)));
1175  cpl.ob->inv_updated = 0;
1176  }
1177  if (cpl.below->inv_updated) {
1178  draw_look_list();
1179  cpl.below->inv_updated = 0;
1180  }
1181 }
1182 
1195 static void on_switch_page(GtkNotebook *notebook, gpointer *page,
1196  guint page_num, gpointer user_data) {
1197  guint oldpage;
1198 
1199  oldpage = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
1200  if (oldpage != page_num && inv_notebooks[oldpage].type == INV_TREE) {
1201  gtk_tree_store_clear(treestore);
1202  }
1203  cpl.ob->inv_updated = 1;
1204 }
1205 
1209 static void animate_inventory() {
1210  gboolean valid;
1211  GtkTreeIter iter;
1212  item *tmp;
1213  int page;
1214  GtkTreeStore *store;
1215 
1216  page = gtk_notebook_get_current_page(GTK_NOTEBOOK(inv_notebook));
1217 
1218  /* Still need to do logic for the table view. */
1219  if (inv_notebooks[page].type == INV_TABLE) {
1220  draw_inv_table(1);
1221  return;
1222  }
1223 
1224  store = treestore;
1225 
1226  /* Get the first iter in the list */
1227  valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
1228 
1229  while (valid) {
1230  gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
1231  LIST_OBJECT, &tmp,
1232  -1);
1233 
1234  /* This is an object with animations */
1235  if (tmp->animation_id > 0 && tmp->anim_speed &&
1236  animations[tmp->animation_id].faces != NULL) {
1237  tmp->last_anim++;
1238 
1239  /* Time to change the face for this one */
1240  if (tmp->last_anim >= tmp->anim_speed) {
1241  tmp->anim_state++;
1242  if (tmp->anim_state >= animations[tmp->animation_id].num_animations) {
1243  tmp->anim_state = 0;
1244  }
1245  tmp->face = animations[tmp->animation_id].faces[tmp->anim_state];
1246  tmp->last_anim = 0;
1247 
1248  /* Update image in the tree store */
1249  gtk_tree_store_set(store, &iter,
1250  LIST_ICON, (GdkPixbuf*) pixmaps[tmp->face]->icon_image,
1251  -1);
1252  }
1253  }
1254  valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1255  }
1256 }
1257 
1261 static void animate_look() {
1262  gboolean valid;
1263  GtkTreeIter iter;
1264  item *tmp;
1265 
1266  /* Get the first iter in the list */
1267  valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store_look), &iter);
1268 
1269  while (valid) {
1270  gtk_tree_model_get(GTK_TREE_MODEL(store_look), &iter,
1271  LIST_OBJECT, &tmp,
1272  -1);
1273 
1274  /* This is an object with animations */
1275  if (tmp->animation_id > 0 && tmp->anim_speed) {
1276  tmp->last_anim++;
1277 
1278  /* Time to change the face for this one */
1279  if (tmp->last_anim >= tmp->anim_speed) {
1280  tmp->anim_state++;
1281  if (tmp->anim_state >= animations[tmp->animation_id].num_animations) {
1282  tmp->anim_state = 0;
1283  }
1284  tmp->face = animations[tmp->animation_id].faces[tmp->anim_state];
1285  tmp->last_anim = 0;
1286 
1287  /* Update image in the tree store */
1288  gtk_tree_store_set(store_look, &iter,
1289  LIST_ICON, (GdkPixbuf*) pixmaps[tmp->face]->icon_image,
1290  -1);
1291  }
1292  }
1293  valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store_look), &iter);
1294  }
1295 }
1296 
1303  animate_look();
1304 }
LIST_TYPE
@ LIST_TYPE
Definition: inventory.c:171
LOG_INFO
@ LOG_INFO
Minor, non-harmful issues.
Definition: client.h:436
show_applied
static int show_applied(item *it)
Definition: inventory.c:115
draw_look_list
void draw_look_list()
Draws the objects beneath the player.
Definition: inventory.c:835
show_unpaid
static int show_unpaid(item *it)
Definition: inventory.c:123
MSG_TYPE_CLIENT
#define MSG_TYPE_CLIENT
Client originated Messages.
Definition: newclient.h:390
close_container
void close_container(item *op)
Open and close_container are now no-ops - since these are now drawn inline as treestores,...
Definition: inventory.c:647
show_cursed
static int show_cursed(item *it)
Definition: inventory.c:127
item_struct::inv
struct item_struct * inv
Definition: item.h:54
client_send_move
void client_send_move(int loc, int tag, int nrof)
Request to move 'nrof' objects with 'tag' to 'loc'.
Definition: player.c:93
item_struct::animation_id
guint16 animation_id
Definition: item.h:63
LIST_OBJECT
@ LIST_OBJECT
Definition: inventory.c:171
LIST_NONE
@ LIST_NONE
Definition: inventory.c:171
get_item_env
static int get_item_env(item *it)
Returns information on the environment of the item, using the return values below.
Definition: inventory.c:194
animate_look
static void animate_look()
Definition: inventory.c:1261
draw_lists
void draw_lists()
Redraws inventory and look windows when necessary.
Definition: inventory.c:1162
list_property
list_property
Definition: inventory.c:170
Styles
Styles
Definition: inventory.c:62
inventory_init
void inventory_init(GtkWidget *window_root)
Set up the inventory viewer.
Definition: inventory.c:528
LIST_BACKGROUND
@ LIST_BACKGROUND
Definition: inventory.c:171
Notebook_Info
Definition: inventory.c:93
item_event_item_changed
void item_event_item_changed(item *it)
Definition: inventory.c:776
LIST_FOREGROUND
@ LIST_FOREGROUND
Definition: inventory.c:172
item_struct::flagsval
guint32 flagsval
Definition: item.h:81
item_struct::env
struct item_struct * env
Definition: item.h:53
Notebook_Info::tooltip
const char * tooltip
Tooltip for menu.
Definition: inventory.c:95
setup_list_columns
static void setup_list_columns(GtkWidget *treeview)
Definition: inventory.c:412
item_struct::applied
guint16 applied
Definition: item.h:73
ma_drop
static void ma_drop(GtkWidget *widget, item *tmp)
Definition: inventory.c:225
inv_notebook
static GtkWidget * inv_notebook
Definition: inventory.c:46
list_row_collapse
static void list_row_collapse(GtkTreeView *treeview, GtkTreeIter *iter, GtkTreePath *path, gpointer user_data)
If the player collapses the row with the little icon, we have to unapply the object for things to wor...
Definition: inventory.c:397
Notebook_Info::name
const char * name
Name of this page, for the show command.
Definition: inventory.c:94
pixmaps
PixmapInfo * pixmaps[MAXPIXMAPNUM]
Definition: image.c:34
item_struct::damned
guint16 damned
Definition: item.h:69
Animations::num_animations
guint8 num_animations
Number of animations.
Definition: client.h:101
weight_limit
static double weight_limit
Definition: inventory.c:49
send_mark_obj
void send_mark_obj(item *op)
Definition: item.c:548
Style_Last
@ Style_Last
Definition: inventory.c:63
INV_SHOW_ITEM
#define INV_SHOW_ITEM
Definition: inventory.c:80
treeview_look
GtkWidget * treeview_look
Definition: inventory.c:38
draw_inv_table
static void draw_inv_table(int animate)
Draws the table of image icons.
Definition: inventory.c:978
NDI_RED
#define NDI_RED
Definition: newclient.h:227
item_struct::last_anim
guint16 last_anim
Definition: item.h:66
ITEM_GROUND
@ ITEM_GROUND
Definition: inventory.c:181
Notebook_Info::treeview
GtkWidget * treeview
treeview widget for this tab
Definition: inventory.c:102
item_struct::nrof
guint32 nrof
Definition: item.h:60
ITEM_INVENTORY
@ ITEM_INVENTORY
Definition: inventory.c:181
MSG_TYPE_CLIENT_ERROR
#define MSG_TYPE_CLIENT_ERROR
Bad things happening.
Definition: newclient.h:641
ma_lock
static void ma_lock(GtkWidget *widget, item *tmp)
Definition: inventory.c:221
spinbutton_count
GtkWidget * spinbutton_count
Definition: keys.c:62
Style_Magical
@ Style_Magical
Definition: inventory.c:63
LIST_FONT
@ LIST_FONT
Definition: inventory.c:172
item_env
item_env
Definition: inventory.c:180
inventory_tick
void inventory_tick()
This is called periodically from main.c - basically a timeout, used to animate the inventory.
Definition: inventory.c:1301
Player_Struct::container
item * container
open container
Definition: client.h:339
set_weight_limit
void set_weight_limit(guint32 wlim)
No reason to divide by 1000 everytime we do the display, so do it once and store it here.
Definition: inventory.c:693
LIST_NAME
@ LIST_NAME
Definition: inventory.c:171
MAX_INV
#define MAX_INV
Definition: inventory.c:56
MAX_BUF
#define MAX_BUF
Definition: client.h:40
inv_table_children
static GtkWidget * inv_table_children[MAX_INV]
Definition: inventory.c:57
applied_color
static const GdkColor applied_color
Color to use to indicate that an item is applied.
Definition: inventory.c:41
list_item_drop
static void list_item_drop(item *tmp)
Definition: inventory.c:307
inv_table
static GtkWidget * inv_table
Definition: inventory.c:47
LIST_BASENAME
@ LIST_BASENAME
Definition: inventory.c:172
item_event_container_clearing
void item_event_container_clearing(item *container)
Definition: inventory.c:773
store_look
static GtkTreeStore * store_look
Definition: inventory.c:43
item_struct::open
guint16 open
Definition: item.h:74
item_struct::face
gint16 face
Definition: item.h:62
drawingarea_inventory_table_button_press_event
static gboolean drawingarea_inventory_table_button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
Definition: inventory.c:929
Notebook_Info::xpm
const char *const * xpm
Icon to draw for the notebook selector.
Definition: inventory.c:96
Player_Struct::ob
item * ob
Player object.
Definition: client.h:336
treestore
static GtkTreeStore * treestore
store of data for treeview
Definition: inventory.c:105
Style_Cursed
@ Style_Cursed
Definition: inventory.c:63
Style_Unpaid
@ Style_Unpaid
Definition: inventory.c:63
gtk2proto.h
num_inv_notebook_pages
static int num_inv_notebook_pages
Definition: inventory.c:91
item_struct::unpaid
guint16 unpaid
Definition: item.h:71
list_selection_func
static gboolean list_selection_func(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer userdata)
Used when a button is pressed on the inventory or look list.
Definition: inventory.c:357
ma_examine
static void ma_examine(GtkWidget *widget, item *tmp)
Definition: inventory.c:209
Style_Applied
@ Style_Applied
Definition: inventory.c:63
F_UNIDENTIFIED
#define F_UNIDENTIFIED
Definition: newclient.h:257
LOG
void LOG(LogLevel level, const char *origin, const char *format,...)
Log messages of a certain importance to stderr.
Definition: misc.c:111
add_object_to_store
static void add_object_to_store(item *it, GtkTreeStore *store, GtkTreeIter *new, GtkTreeIter *parent, int color)
Adds a row to the treestore.
Definition: inventory.c:792
LIST_NUM_COLUMNS
@ LIST_NUM_COLUMNS
Definition: inventory.c:172
display_type
display_type
Definition: inventory.c:87
item_struct::flags
char flags[NAME_LEN]
Definition: item.h:58
draw_ext_info
void draw_ext_info(int orig_color, int type, int subtype, const char *message)
A message processor that accepts messages along with meta information color and type.
Definition: info.c:915
list_item_action
static void list_item_action(GdkEventButton *event, item *tmp)
Definition: inventory.c:273
NDI_BLACK
#define NDI_BLACK
Definition: newclient.h:224
image.h
LIST_ICON
@ LIST_ICON
Definition: inventory.c:171
show_item_menu
static void show_item_menu(GdkEventButton *event, item *tmp)
Definition: inventory.c:229
inventory_get_styles
void inventory_get_styles()
Gets the style information for the inventory windows.
Definition: inventory.c:501
draw_inv_table_icon
static void draw_inv_table_icon(GdkWindow *dst, const void *image)
Definition: inventory.c:935
item_struct::cursed
guint16 cursed
Definition: item.h:68
INV_SHOW_COLOR
#define INV_SHOW_COLOR
Definition: inventory.c:81
item_struct::magical
guint16 magical
Definition: item.h:67
item_struct::next
struct item_struct * next
Definition: item.h:51
image_size
int image_size
Definition: image.c:30
show_all
static int show_all(item *it)
Definition: inventory.c:111
item_struct::anim_speed
guint8 anim_speed
Definition: item.h:64
CONFIG_INV_MENU
#define CONFIG_INV_MENU
Definition: client.h:216
NUM_INV_LISTS
#define NUM_INV_LISTS
Definition: inventory.c:79
item_struct
Definition: item.h:50
item_struct::type
guint16 type
Definition: item.h:82
open_container
void open_container(item *op)
Definition: inventory.c:654
item_struct::tag
gint32 tag
Definition: item.h:59
INV_TREE
@ INV_TREE
Definition: inventory.c:88
Style_Locked
@ Style_Locked
Definition: inventory.c:63
LOG_ERROR
@ LOG_ERROR
Warning that something definitely didn't work.
Definition: client.h:438
Animations::faces
guint16 * faces
Definition: client.h:108
inv_notebooks
static Notebook_Info inv_notebooks[NUM_INV_LISTS]
Definition: inventory.c:152
draw_inv
static void draw_inv(int tab)
Draws the inventory and updates the encumbrance statistics display in the client.
Definition: inventory.c:1144
client_send_apply
void client_send_apply(int tag)
Definition: player.c:82
main.h
LIST_WEIGHT
@ LIST_WEIGHT
Definition: inventory.c:171
cpl
Client_Player cpl
Player object.
Definition: client.c:69
ITEM_IN_CONTAINER
@ ITEM_IN_CONTAINER
Definition: inventory.c:181
show_unapplied
static int show_unapplied(item *it)
Definition: inventory.c:119
has_init
static int has_init
Definition: account.c:88
Player_Struct::below
item * below
Items below the player (pl.below->inv)
Definition: client.h:337
show_locked
static int show_locked(item *it)
Definition: inventory.c:139
encumbrance_current
static GtkWidget * encumbrance_current
Definition: inventory.c:44
draw_inv_list
static void draw_inv_list(int tab)
Draws the inventory window.
Definition: inventory.c:870
remove_object_from_store
static void remove_object_from_store(item *it, GtkTreeStore *store)
Definition: inventory.c:746
item_event_item_deleting
void item_event_item_deleting(item *it)
Definition: inventory.c:760
MSG_TYPE_CLIENT_NOTICE
#define MSG_TYPE_CLIENT_NOTICE
Non-critical note to player.
Definition: newclient.h:638
PixmapInfo::icon_image
GdkPixbuf * icon_image
Definition: image.h:46
ma_mark
static void ma_mark(GtkWidget *widget, item *tmp)
Definition: inventory.c:217
item_struct::s_name
char s_name[NAME_LEN]
Definition: item.h:56
item_struct::inv_updated
guint16 inv_updated
Definition: item.h:77
INV_TABLE
@ INV_TABLE
Definition: inventory.c:88
Player_Struct::count
guint32 count
Repeat count on command.
Definition: client.h:359
show_unlocked
static int show_unlocked(item *it)
Definition: inventory.c:143
use_config
gint16 use_config[CONFIG_NUMS]
Definition: client.h:244
Notebook_Info::show_func
int(* show_func)(item *it)
Function that takes an item and returns INV_SHOW_* above on whether to show this item and if it shoul...
Definition: inventory.c:97
animate_inventory
static void animate_inventory()
Definition: inventory.c:1209
drawingarea_inventory_table_expose_event
static gboolean drawingarea_inventory_table_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
Definition: inventory.c:951
on_switch_page
static void on_switch_page(GtkNotebook *notebook, gpointer *page, guint page_num, gpointer user_data)
People are likely go to the different tabs much less often than their inventory changes.
Definition: inventory.c:1195
item_struct::d_name
char d_name[NAME_LEN]
Definition: item.h:55
animations
Animations animations[MAXANIM]
Definition: commands.c:1155
item_struct::weight
float weight
Definition: item.h:61
show_nonmagical
static int show_nonmagical(item *it)
Definition: inventory.c:135
window_root
GtkWidget * window_root
In main.c.
Definition: main.c:105
show_unidentified
static int show_unidentified(item *it)
Definition: inventory.c:148
command_show
void command_show(const char *params)
Definition: inventory.c:661
encumbrance_max
static GtkWidget * encumbrance_max
Definition: inventory.c:45
Style_Names
static const char * Style_Names[Style_Last]
Definition: inventory.c:67
item_struct::locked
guint16 locked
Definition: item.h:72
item_struct::anim_state
guint8 anim_state
Definition: item.h:65
get_row_style
static GtkStyle * get_row_style(item *it)
Definition: inventory.c:702
toggle_locked
void toggle_locked(item *op)
Definition: item.c:530
ma_apply
static void ma_apply(GtkWidget *widget, item *tmp)
Definition: inventory.c:213
client.h
inv_styles
static GtkStyle * inv_styles[Style_Last]
Definition: inventory.c:72
INV_TABLE_AT
#define INV_TABLE_AT(x, y, cols)
Definition: inventory.c:59
client_send_examine
void client_send_examine(int tag)
Definition: player.c:86
show_magical
static int show_magical(item *it)
Definition: inventory.c:131
window_xml
GtkBuilder * window_xml
Definition: main.c:104