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