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  item *tmp;
954 
955  if (cpl.ob->inv_updated != 0) {
956  // Delay drawing until inventory is fully updated. This avoids drawing
957  // previously added items that may now be removed, leading to a heap
958  // use-after-free.
959  return TRUE;
960  }
961 
962  tmp = (item*) user_data;
963 
964  /*
965  * Can get cases when switching tabs that we get an expose event before the
966  * list is updated - if so, don't draw stuff we don't have faces for.
967  */
968  if (tmp->face) {
969  draw_inv_table_icon(gtk_widget_get_window(widget), pixmaps[tmp->face]->icon_image);
970  }
971 
972  return TRUE;
973 }
974 
981 static void draw_inv_table(int animate) {
982  int x, y, rows, columns, num_items, i;
983  static int max_drawn = 0;
984  item *tmp;
985  char buf[256];
986  gulong handler;
987 
988  num_items = 0;
989  for (tmp = cpl.ob->inv; tmp; tmp = tmp->next) {
990  num_items++;
991  }
992 
993  if (num_items > MAX_INV) {
994  LOG(LOG_ERROR, "draw_inv_table", "Too many items in inventory!");
995  return;
996  }
997 
998  GtkAllocation size;
999  gtk_widget_get_allocation(inv_table, &size);
1000 
1001  columns = size.width / image_size;
1002  rows = size.height / image_size;
1003 
1004  if (columns < 1) {
1005  // size.width is occasionally very small after a player applies a bed
1006  // to reality and the character selection window comes on. This causes
1007  // columns = 0 and a divide by zero a few lines later.
1008  return;
1009  }
1010 
1011  if (num_items > columns * rows) {
1012  rows = num_items / columns;
1013  if (num_items % columns) {
1014  rows++;
1015  }
1016  }
1017 
1018  gtk_table_resize(GTK_TABLE(inv_table), rows, columns);
1019 
1020  x = 0;
1021  y = 0;
1022  for (tmp = cpl.ob->inv; tmp; tmp = tmp->next) {
1023  if (INV_TABLE_AT(x, y, columns) == NULL) {
1024  INV_TABLE_AT(x, y, columns) = gtk_drawing_area_new();
1025  gtk_widget_set_size_request(INV_TABLE_AT(x, y, columns), image_size,
1026  image_size);
1027 
1028  gtk_table_attach(GTK_TABLE(inv_table), INV_TABLE_AT(x, y, columns),
1029  x, x + 1, y, y + 1, GTK_FILL, GTK_FILL, 0, 0);
1030  }
1031  if (animate) {
1032  /* This is an object with animations */
1033  if (tmp->animation_id > 0 && tmp->anim_speed) {
1034  tmp->last_anim++;
1035 
1036  /* Time to change the face for this one */
1037  if (tmp->last_anim >= tmp->anim_speed) {
1038  tmp->anim_state++;
1039  if (tmp->anim_state >= animations[tmp->animation_id].num_animations) {
1040  tmp->anim_state = 0;
1041  }
1042  tmp->face = animations[tmp->animation_id].faces[tmp->anim_state];
1043  tmp->last_anim = 0;
1044 
1046  gtk_widget_get_window(INV_TABLE_AT(x, y, columns)),
1047  pixmaps[tmp->face]->icon_image);
1048  }
1049  }
1050  /* On animation run, so don't do any of the remaining logic */
1051  } else {
1052  /*
1053  * Need to clear out the old signals, since the signals are
1054  * effectively stacked - you can have 6 signal handlers tied to the
1055  * same function.
1056  */
1057  handler = g_signal_handler_find((gpointer) INV_TABLE_AT(x, y, columns),
1058  G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
1060  NULL);
1061 
1062  if (handler) {
1063  g_signal_handler_disconnect((gpointer) INV_TABLE_AT(x, y, columns), handler);
1064  }
1065 
1066  handler = g_signal_handler_find((gpointer) INV_TABLE_AT(x, y, columns),
1067  G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
1069  NULL);
1070  if (handler) {
1071  g_signal_handler_disconnect((gpointer) INV_TABLE_AT(x, y, columns), handler);
1072  }
1073  /*
1074  * Not positive precisely what events are needed, but some events
1075  * beyond just the button press are necessary for the tooltips to
1076  * work.
1077  */
1078  gtk_widget_add_events(INV_TABLE_AT(x, y, columns), GDK_ALL_EVENTS_MASK);
1079 
1080  g_signal_connect((gpointer) INV_TABLE_AT(x, y, columns), "button_press_event",
1082  tmp);
1083 
1084  g_signal_connect((gpointer) INV_TABLE_AT(x, y, columns), "expose_event",
1086  tmp);
1087 
1088  /* Draw the inventory icon image to the table. */
1089  draw_inv_table_icon(gtk_widget_get_window(INV_TABLE_AT(x, y, columns)),
1090  pixmaps[tmp->face]->icon_image);
1091 
1092  // Draw an extra indicator if the item is applied.
1093  if (tmp->applied) {
1094  gtk_widget_modify_bg(INV_TABLE_AT(x, y, columns),
1095  GTK_STATE_NORMAL, &applied_color);
1096  } else {
1097  gtk_widget_modify_bg(INV_TABLE_AT(x, y, columns),
1098  GTK_STATE_NORMAL, NULL);
1099  }
1100 
1101  gtk_widget_show(INV_TABLE_AT(x, y, columns));
1102  /*
1103  * Use tooltips to provide additional detail about the icons.
1104  * Looking at the code, the tooltip widget will take care of
1105  * removing the old tooltip, freeing strings, etc.
1106  */
1107  snprintf(buf, 255, "%s %s", tmp->d_name, tmp->flags);
1108  gtk_widget_set_tooltip_text(INV_TABLE_AT(x, y, columns), buf);
1109  }
1110  x++;
1111  if (x == columns) {
1112  x = 0;
1113  y++;
1114  }
1115 
1116  }
1117  /* Don't need to do the logic below if only doing animation run */
1118  if (animate) {
1119  return;
1120  }
1121  /*
1122  * Need to disconnect the callback functions cells we did not draw.
1123  * otherwise, we get errors on objects that are drawn.
1124  */
1125  for (i = num_items; i <= max_drawn; i++) {
1126  if (INV_TABLE_AT(x, y, columns)) {
1127  gtk_widget_destroy(INV_TABLE_AT(x, y, columns));
1128  INV_TABLE_AT(x, y, columns) = NULL;
1129  }
1130  x++;
1131  if (x == columns) {
1132  x = 0;
1133  y++;
1134  }
1135  }
1136  max_drawn = num_items;
1137 
1138  gtk_widget_show(inv_table);
1139 }
1140 
1147 static void draw_inv(int tab) {
1148  char buf[256];
1149 
1150  snprintf(buf, sizeof (buf), "%6.1f", cpl.ob->weight);
1151  gtk_label_set_text(GTK_LABEL(encumbrance_current), buf);
1152  snprintf(buf, sizeof (buf), "%6.1f", weight_limit);
1153  gtk_label_set_text(GTK_LABEL(encumbrance_max), buf);
1154 
1155  if (inv_notebooks[tab].type == INV_TREE) {
1156  draw_inv_list(tab);
1157  } else if (inv_notebooks[tab].type == INV_TABLE) {
1158  draw_inv_table(0);
1159  }
1160 }
1161 
1165 void draw_lists() {
1166  /*
1167  * There are some extra complications with container handling and timing.
1168  * For example, we draw the window before we get a list of the container,
1169  * and then the container contents are not drawn - this can be handled by
1170  * looking at container->inv_updated.
1171  */
1173  cpl.container->env->inv_updated = 1;
1174  cpl.container->inv_updated = 0;
1175  }
1176  if (cpl.ob->inv_updated) {
1177  draw_inv(gtk_notebook_get_current_page(GTK_NOTEBOOK(inv_notebook)));
1178  cpl.ob->inv_updated = 0;
1179  }
1180  if (cpl.below->inv_updated) {
1181  draw_look_list();
1182  cpl.below->inv_updated = 0;
1183  }
1184 }
1185 
1198 static void on_switch_page(GtkNotebook *notebook, gpointer *page,
1199  guint page_num, gpointer user_data) {
1200  guint oldpage;
1201 
1202  oldpage = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
1203  if (oldpage != page_num && inv_notebooks[oldpage].type == INV_TREE) {
1204  gtk_tree_store_clear(treestore);
1205  }
1206  cpl.ob->inv_updated = 1;
1207 }
1208 
1212 static void animate_inventory() {
1213  gboolean valid;
1214  GtkTreeIter iter;
1215  item *tmp;
1216  int page;
1217  GtkTreeStore *store;
1218 
1219  page = gtk_notebook_get_current_page(GTK_NOTEBOOK(inv_notebook));
1220 
1221  /* Still need to do logic for the table view. */
1222  if (inv_notebooks[page].type == INV_TABLE) {
1223  draw_inv_table(1);
1224  return;
1225  }
1226 
1227  store = treestore;
1228 
1229  /* Get the first iter in the list */
1230  valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
1231 
1232  while (valid) {
1233  gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
1234  LIST_OBJECT, &tmp,
1235  -1);
1236 
1237  /* This is an object with animations */
1238  if (tmp->animation_id > 0 && tmp->anim_speed &&
1239  animations[tmp->animation_id].faces != NULL) {
1240  tmp->last_anim++;
1241 
1242  /* Time to change the face for this one */
1243  if (tmp->last_anim >= tmp->anim_speed) {
1244  tmp->anim_state++;
1245  if (tmp->anim_state >= animations[tmp->animation_id].num_animations) {
1246  tmp->anim_state = 0;
1247  }
1248  tmp->face = animations[tmp->animation_id].faces[tmp->anim_state];
1249  tmp->last_anim = 0;
1250 
1251  /* Update image in the tree store */
1252  gtk_tree_store_set(store, &iter,
1253  LIST_ICON, (GdkPixbuf*) pixmaps[tmp->face]->icon_image,
1254  -1);
1255  }
1256  }
1257  valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1258  }
1259 }
1260 
1264 static void animate_look() {
1265  gboolean valid;
1266  GtkTreeIter iter;
1267  item *tmp;
1268 
1269  /* Get the first iter in the list */
1270  valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store_look), &iter);
1271 
1272  while (valid) {
1273  gtk_tree_model_get(GTK_TREE_MODEL(store_look), &iter,
1274  LIST_OBJECT, &tmp,
1275  -1);
1276 
1277  /* This is an object with animations */
1278  if (tmp->animation_id > 0 && tmp->anim_speed) {
1279  tmp->last_anim++;
1280 
1281  /* Time to change the face for this one */
1282  if (tmp->last_anim >= tmp->anim_speed) {
1283  tmp->anim_state++;
1284  if (tmp->anim_state >= animations[tmp->animation_id].num_animations) {
1285  tmp->anim_state = 0;
1286  }
1287  tmp->face = animations[tmp->animation_id].faces[tmp->anim_state];
1288  tmp->last_anim = 0;
1289 
1290  /* Update image in the tree store */
1291  gtk_tree_store_set(store_look, &iter,
1292  LIST_ICON, (GdkPixbuf*) pixmaps[tmp->face]->icon_image,
1293  -1);
1294  }
1295  }
1296  valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store_look), &iter);
1297  }
1298 }
1299 
1306  animate_look();
1307 }
LIST_TYPE
@ LIST_TYPE
Definition: inventory.c:171
LOG_INFO
@ LOG_INFO
Minor, non-harmful issues.
Definition: client.h:434
show_applied
static int show_applied(item *it)
Definition: inventory.c:115
draw_look_list
void draw_look_list()
Definition: inventory.c:835
show_unpaid
static int show_unpaid(item *it)
Definition: inventory.c:123
MSG_TYPE_CLIENT
#define MSG_TYPE_CLIENT
Definition: newclient.h:387
close_container
void close_container(item *op)
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)
Definition: player.c:97
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)
Definition: inventory.c:194
animate_look
static void animate_look()
Definition: inventory.c:1264
draw_lists
void draw_lists()
Definition: inventory.c:1165
list_property
list_property
Definition: inventory.c:170
Styles
Styles
Definition: inventory.c:62
inventory_init
void inventory_init(GtkWidget *window_root)
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
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)
Definition: inventory.c:397
Notebook_Info::name
const char * name
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
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)
Definition: inventory.c:981
NDI_RED
#define NDI_RED
Definition: newclient.h:224
item_struct::last_anim
guint16 last_anim
Definition: item.h:66
ITEM_GROUND
@ ITEM_GROUND
Definition: inventory.c:181
Notebook_Info::treeview
GtkWidget * treeview
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
Definition: newclient.h:638
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()
Definition: inventory.c:1304
Player_Struct::container
item * container
Definition: client.h:337
set_weight_limit
void set_weight_limit(guint32 wlim)
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
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
Definition: inventory.c:96
Player_Struct::ob
item * ob
Definition: client.h:334
treestore
static GtkTreeStore * treestore
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)
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:254
LOG
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:111
add_object_to_store
static void add_object_to_store(item *it, GtkTreeStore *store, GtkTreeIter *new, GtkTreeIter *parent, int color)
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)
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:221
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()
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:436
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)
Definition: inventory.c:1147
client_send_apply
void client_send_apply(int tag)
Definition: player.c:86
main.h
LIST_WEIGHT
@ LIST_WEIGHT
Definition: inventory.c:171
cpl
Client_Player cpl
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
Definition: client.h:335
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)
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
Definition: newclient.h:635
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
Definition: client.h:357
show_unlocked
static int show_unlocked(item *it)
Definition: inventory.c:143
use_config
gint16 use_config[CONFIG_NUMS]
Definition: client.h:242
Notebook_Info::show_func
int(* show_func)(item *it)
Definition: inventory.c:97
animate_inventory
static void animate_inventory()
Definition: inventory.c:1212
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)
Definition: inventory.c:1198
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
Definition: main.c:103
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:90
show_magical
static int show_magical(item *it)
Definition: inventory.c:131
window_xml
GtkBuilder * window_xml
Definition: main.c:102