Crossfire Client, Branches  R11627
inventory.c
Go to the documentation of this file.
1 
2 /*
3  * Showing and manipulating your inventory and what's in a
4  * container/at your feet. (But not autopickup.)
5  */
6 
7 #ifdef WIN32
8 #include <config.h>
9 #endif
10 #include "gx11.h"
11 #include "client.h" /* LOG */
12 
13 #define bool uint8 /* Grr! Pick *something*, please! */
14 
15 extern GdkColor gdk_grey;
16 extern GdkColor gdk_black;
17 extern GtkWidget *spellinventory; /* Defined in gx11.c */
18 
19 /* *grumble* Neither of two C textbooks I checked gave an example of this. :S */
20 typedef bool (*itemfilter)(item * it);
21 
22 typedef struct {
23  item * cont; /* The container whose contents we're showing. */
24  item * move_dest; /* The container you want to move things to when you right-click on them. */
25  GtkWidget * list; /* GtkCList */
26  GtkWidget * scroll_window; /* Scrolled-window widget holding list. */
28  bool complete_rebuild:1; /* Dirty flag. */
29  bool show_weight:1;
30  bool highlight:1;
31  bool show_flags:1;
32 
33  /*
34  * Image-column (and row height...) resizes to hold biggest face;
35  * good when standing on buildings (or monsters!).
36  */
37  bool face_column_resizes:1;
38 
42 
43 /*
44  * Creation
45  */
46 
47 static GList * views;
48 
49 /* forward */
50 static void list_button_event(
51  GtkWidget *gtklist,
52  gint row, gint column,
53  GdkEventButton *event,
54  inventory_viewer * view);
55 
56 
57 static inventory_viewer * new_inventory_viewer(item * container, itemfilter filter, item * move_dest) {
58  inventory_viewer * ret;
59  GtkWidget * list;
60  GtkWidget * scroll_window;
61  GtkStyle * liststyle;
62  gchar *titles[] = {"?", "Name", "Weight"};
63 
64  scroll_window = gtk_scrolled_window_new (0,0);
65 
66  list = gtk_clist_new_with_titles(3, titles);
67 
68  g_assert(list != NULL);
69  gtk_clist_set_column_width (GTK_CLIST(list), 0, image_size);
70  gtk_clist_set_column_width (GTK_CLIST(list), 1, 150);
71  gtk_clist_set_column_width (GTK_CLIST(list), 2, 50);
72 
73  gtk_clist_set_selection_mode (GTK_CLIST(list) , GTK_SELECTION_SINGLE);
74  gtk_clist_set_row_height (GTK_CLIST(list), image_size);
75 
76  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scroll_window),
77  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
78 
79  liststyle = gtk_rc_get_style (list);
80  if (liststyle) {
81  liststyle->bg[GTK_STATE_SELECTED] = gdk_grey;
82  liststyle->fg[GTK_STATE_SELECTED] = gdk_black;
83  gtk_widget_set_style (list, liststyle);
84  }
85 
86  gtk_widget_show(list);
87 
88  gtk_container_add(GTK_CONTAINER(scroll_window), list);
89  gtk_widget_show(scroll_window);
90 
91  ret = malloc(sizeof(inventory_viewer));
92  ret->complete_rebuild = TRUE;
93  ret->list = list;
94  ret->scroll_window = scroll_window;
95  ret->cont = container;
96  ret->shows = filter;
97  ret->show_weight = TRUE;
98  ret->show_flags = TRUE;
99  ret->highlight = FALSE;
100  ret->move_dest = move_dest;
101  ret->face_column_resizes = FALSE;
102  ret->image_height = ret->image_width = image_size;
103  views = g_list_first(g_list_append(views, ret));
104 
105  gtk_clist_set_button_actions(GTK_CLIST(list),
106  1, GTK_BUTTON_SELECTS);
107  gtk_clist_set_button_actions(GTK_CLIST(list),
108  2, GTK_BUTTON_SELECTS);
109  gtk_signal_connect(GTK_OBJECT(list), "select_row",
110  GTK_SIGNAL_FUNC(list_button_event),
111  ret);
112 
113  return ret;
114 }
115 
116 
117 /* -------------------------------------------------------------------------------------- */
118 
119 /*
120  * Old way only stored *animated* item to (widget, row); here, we'll record *every*
121  * item. (And if someone wants to backport Wedel's icon-widget, make it (widget, type, location).)
122  *
123  * However, also record the animated items only for speed.
124  *
125  * TODO Test on a slower machine than the one I have right now; throw the profiler at it, figure
126  * out if this is a bottleneck, and if it is which of n different ways of storing this information
127  * is quickest.
128  */
129 
130 typedef struct {
131  item * it;
132  GList * viewers;
133 } item_delete;
134 
135 static GList * item_to_widgets = NULL;
136 static GList * animated_items = NULL;
137 
138 /*
139  * Store and retrieve
140  */
141 
142 /* TODO Ideally, this goes away and we store the list in the item, (As a
143 void pointer, of course.) However, we need to be able to check *all*
144 known items; common doesn't really support that right now. */
146  GList * p;
147  item_delete * ret = NULL;
148 
149  for (p = g_list_first(item_to_widgets); p != NULL; p = g_list_next(p) ) {
150  item_delete * record;
151 
152  record = (item_delete *)(p->data);
153 
154  if (record->it == op) {
155  return record;
156  }
157  }
158 
159  /* It's not on the list; we'll have to add one. */
160  ret = malloc(sizeof(item_delete));
161 
162  ret->it = op;
163  ret->viewers = NULL;
164 
165  item_to_widgets = g_list_first(g_list_prepend(item_to_widgets, ret));
166  g_assert(item_to_widgets != NULL);
167 
168  return ret;
169 }
170 
171 static GList * item_to_widget_retrieve_viewers(item * op) {
172  return item_to_widget_retrieve(op)->viewers;
173 }
174 
175 static void item_to_widget_store(item * op, inventory_viewer * view) {
176  item_delete * x;
177 
178  x = item_to_widget_retrieve(op);
179 
180  if (g_list_find(x->viewers, view) == NULL) {
181  x->viewers = g_list_prepend(x->viewers, view);
182  }
183  g_assert(x->viewers != NULL);
184 
185 
186  /* If it's animated, also stick it on the shortlist of animated items. */
187  if (op->animation_id > 0 && op->anim_speed) {
188  /* Only stick it on if it's not already present. :S */
189  if (g_list_find(animated_items, op) == NULL) {
190  animated_items = g_list_first(g_list_prepend(animated_items, op));
191  g_assert(animated_items != NULL);
192  }
193  }
194 }
195 
196 /*
197  * Remove
198  */
199 
200 static void remove_widget_one(gpointer item_and_widget_x, gpointer view_x) {
201  item_delete * item_and_widgets = (item_delete *)item_and_widget_x;
202 
203  item_and_widgets->viewers = g_list_remove(item_and_widgets->viewers, view_x);
204 }
205 
207  g_list_foreach(item_to_widgets, remove_widget_one, view);
208 }
209 
210 static void item_to_widget_remove_item(item * const op) {
211  item * op_mangled = op;
212  GList * search_return = NULL;
213 
214  if (item_to_widgets != NULL) {
215  GList * victim_link = NULL;
216  GList * i = NULL;
217  item_delete * victim = NULL;
218 
219  /* Look for the item_delete for this item. */
220  for (i = item_to_widgets; i != NULL; i = g_list_next(i))
221  {
222  item_delete * x = (item_delete *)(i->data);
223  if (x->it == op) {
224  victim = x;
225  victim_link = i;
226  break;
227  }
228  }
229 
230  if (victim != NULL) {
231  g_assert(victim_link != NULL);
232 
233  /* Remove the item_delete; free the widget-list first. */
234  g_list_free(victim->viewers);
235  item_to_widgets = g_list_remove_link(item_to_widgets, victim_link);
236  }
237  }
238 
239  /* Also nuke it from the animation list. (Hope g_list doesn't choke if it's not there.) */
240  /*LOG(LOG_INFO, "inventory::item_to_widget_remove_item",
241  "removing %d (%s) %p", op->tag, op->d_name, op);*/
242  animated_items = g_list_remove(animated_items, op_mangled);
243  search_return = g_list_find(animated_items, op);
244  g_assert(search_return == NULL);
245 }
246 
247 /*
248  * Animate
249  */
250 
251 static void animate_item(gpointer view_x, gpointer item_x) {
252  item * it = (item *)item_x;
253  PixmapInfo * new_face = pixmaps[it->face];
254  inventory_viewer * view = (inventory_viewer *) view_x;
255 
256  /* LOG(LOG_INFO, "inventory::animate_item", "Called"); */
257 
258  /* Don't update views that are going to be completely reconstructed anyway. */
259  if (view->complete_rebuild) return;
260 
261  gtk_clist_set_pixmap(GTK_CLIST(view->list),
262  gtk_clist_find_row_from_data(GTK_CLIST(view->list), item_x), 0,
263  (GdkPixmap*)new_face->icon_image,
264  (GdkBitmap*)new_face->icon_mask);
265 }
266 
267 static void animate_one_item(gpointer item_x, gpointer ignored) {
268  item * it = (item *)item_x;
270 
271  /* Is it animated? */
272  g_assert(it->animation_id > 0 && it->anim_speed);
273 
274  it->last_anim++;
275 
276  /* Is it time to change the face yet? */
277  if (it->last_anim < it->anim_speed) return;
278 
279  it->anim_state++;
280 
282  it->anim_state=0;
283  }
284  it->face = animations[it->animation_id].faces[it->anim_state];
285  it->last_anim=0;
286 
287  /*LOG(LOG_INFO, "inventory::animate_one_item", "Animating %p: %s to %d", op, op->d_name, op->face); */
288 
289  /* For each view the newly-updated item appears in, change its face. */
290  g_list_foreach(views, animate_item, it);
291 }
292 
293 static void animate_items(void) {
294  g_list_foreach(animated_items, animate_one_item, NULL);
295 }
296 
297 
298 static void item_changed_anim_hook(item * op) {
299  /* HACK Make sure its presence or absence in the animated-items list is correct. */
300 
301  if (op->animation_id > 0 && op->anim_speed) {
302  if (g_list_find(animated_items, op) == NULL) {
303  animated_items = g_list_prepend(animated_items, op);
304  }
305  } else {
306  animated_items = g_list_remove(animated_items, op);
307  }
308 }
309 
310 
311 /* -------------------------------------------------------------------------------------- */
312 
313 /*
314  * (Re)building
315  */
316 
317 static void highlight_item(GtkWidget * list, item * it, gint row) {
318  extern GdkColor root_color[16]; /* gx11.c; it'll probably change when Lally finishes his patch... */
319 
320  if (it->cursed || it->damned) {
321  if (!it->magical) {
322  gtk_clist_set_background (GTK_CLIST(list), row,
323  &root_color[NDI_RED]);
324  } else {
325  gtk_clist_set_background (GTK_CLIST(list), row,
326  &root_color[NDI_NAVY]);
327  }
328  }
329  else if (it->magical) {
330  gtk_clist_set_background (GTK_CLIST(list), row,
331  &root_color[NDI_BLUE]);
332  }
333 }
334 
335 #define FMT_WEIGHT(buf, buf_size, it) snprintf(buf, buf_size, "%6.1f" , it->nrof * it->weight)
336 
338  item * it;
339  char buffer[3][MAX_BUF];
340  char *columns[3];
341  gfloat scrollbar_pos; /* Copying from gx11.c, etc etc. */
342  GtkWidget * scroll_window = NULL;
343  GtkWidget * list = NULL;
344  uint16 mh = image_size, mw = image_size;
345 
346  g_assert(view != NULL);
347  g_assert(view->complete_rebuild);
348 
349  scroll_window = view->scroll_window;
350  list = view->list;
351 
352  /* GtkAdjustment doesn't give any indirect way of extracting that value. :( */
353  scrollbar_pos =
354  gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll_window))->value;
355  gtk_clist_freeze(GTK_CLIST(list));
356  gtk_clist_clear(GTK_CLIST(list));
357 
358  columns[0] = buffer[0];
359  columns[1] = buffer[1];
360 
361  for (it = view->cont->inv; it != NULL; it = it->next) {
362  PixmapInfo * pixmap = pixmaps[it->face];
363  gint row;
364 
365  if (!view->shows(it)) continue;
366 
367  if (view->face_column_resizes) {
368  if (pixmap->icon_width > mw) mw = pixmap->icon_width;
369  if (pixmap->icon_height > mh) mh = pixmap->icon_height;
370  }
371 
372  /* TODO safe_strcat! Perhaps use glib's string functions? */
373  strcpy (buffer[0]," ");
374  strcpy (buffer[1], it->d_name);
375 
376  if (view->show_flags) {
377  strcat (buffer[1], it->flags);
378  }
379 
380  if (view->show_weight && !(it->weight < 0)) {
381  FMT_WEIGHT(buffer[2], MAX_BUF, it);
382  columns[2] = buffer[2];
383  } else {
384  columns[2] = " ";
385  }
386 
387  row = gtk_clist_append(GTK_CLIST(list), columns);
388 
389  /* Set original pixmap */
390  gtk_clist_set_pixmap (GTK_CLIST (list), row, 0,
391  (GdkPixmap*)pixmap->icon_image,
392  (GdkBitmap*)pixmap->icon_mask);
393 
394  gtk_clist_set_row_data (GTK_CLIST(list), row, it);
395 
396  item_to_widget_store(it, view);
397 
398  if (view->highlight) {
399  highlight_item(list, it, row);
400  }
401  }
402 
403  if (view->face_column_resizes) {
404  if (view->image_width != mw) {
405  gtk_clist_set_column_width(GTK_CLIST(list), 0, mw);
406  view->image_width = mw;
407  }
408  if (view->image_height != mh) {
409  gtk_clist_set_row_height(GTK_CLIST(list), mh);
410  view->image_height = mh;
411  }
412  }
413 
414  /* Ok, stuff is drawn, now replace the scrollbar positioning as far as possible */
415  gtk_adjustment_set_value(
416  GTK_ADJUSTMENT(
417  gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll_window))
418  ),
419  scrollbar_pos);
420  gtk_clist_thaw(GTK_CLIST(list));
421 
422  view->complete_rebuild = FALSE;
423 }
424 
425 /*
426  * Updates and animation
427  */
428 
429 /* forward */
430 static bool view_visible(inventory_viewer * view);
431 
432 static void item_tick_per_view(gpointer data, gpointer user_data_ignored) {
433  inventory_viewer * view;
434  view = (inventory_viewer *)data;
435 
436  if (redraw_needed) {
437  /*LOG(LOG_INFO, "inventory::item_tick_per_view", "%p redraw_needed", view); */
438 
439  /* Faces have changed (gtk/image.c). Sadly, cache.c isn't more granular than this, so we
440  can only update *all* the faces. */
441 
442  /* TODO If the inventory isn't otherwise dirty, only cycle through the faces.
443  For the moment, rebuild the entire list. */
444  view->complete_rebuild = TRUE;
445 
446  /* Do not clear the flag; that's done in gx11.c::do_timeout().
447  In any case, we'd smash it for the other views. :S */
448  }
449 
450  /*
451  * HACK
452  * If visible() ever returns false, remember to manually update the widget when
453  * it becomes visible!
454  */
455  if (!view_visible(view)) return;
456 
457  if (view->complete_rebuild) {
458  /*LOG(LOG_INFO, "inventory::item_tick_per_view", "rebuild %p on timeout", view);*/
459  rebuild_our_widget(view);
460  }
461 }
462 
463 static void itemview_tick(void) {
464  animate_items();
465 
466  g_list_foreach(views, item_tick_per_view, NULL);
467 }
468 
469 /* TODO Another optimization; if an item is new (to the container),
470 we only need to dirty the views that will show the item. */
471 
472 static void item_changed_one(gpointer view_x, gpointer op_x) {
473  inventory_viewer * view = (inventory_viewer *)view_x;
474  item * it = (item *)op_x;
475 
476  /* TODO Finer-grained checking, so only the affected panels
477  complete_rebuild, and for *big* fenceposting, only add a row. */
478 
479  if (view->cont == it->env) {
480  /* TODO My brother says he can do better. */
481  view->complete_rebuild = TRUE;
482  /*LOG(LOG_INFO, "inventory::item_changed_one", "%p dirtied", view); */
483  } else {
484  /*LOG(LOG_INFO, "inventory::item_changed_one", "%p not container", view); */
485  }
486 
487 }
488 
491 
492  /*LOG(LOG_INFO, "inventory::item_event_item_changed", "Changed: %d %s %d", op->tag, op->d_name, op->face); */
493  g_list_foreach(views, item_changed_one, (gpointer)op);
494 
495  /* Update inventory list for spell writing. */
496  if (can_write_spell_on(op) && spellinventory != NULL && GTK_WIDGET_VISIBLE(spellinventory)) {
497  gint row = gtk_clist_find_row_from_data(GTK_CLIST(spellinventory), op);
498  if (row != -1)
499  gtk_clist_set_text(GTK_CLIST(spellinventory), row, 1, op->d_name);
500  }
501 
502 }
503 
504 
505 
506 static void container_clearing_one(gpointer view_x, gpointer op_x) {
507  inventory_viewer * view = (inventory_viewer *)view_x;
508  item * it = (item *)op_x;
509 
510  /* TODO We'd have to tweak for recursive-search in a tree widget, maybe. */
511  if (view->cont == it) {
512  if (!view->complete_rebuild) {
513  view->complete_rebuild = TRUE;
514  /* Wonder if at any later stage pass view? */
516  /*LOG(LOG_INFO, "inventory::container_clearing_one", "%p dirtied", view);*/
517  } else {
518  /*LOG(LOG_INFO, "inventory::container_clearing_one", "%p already dirty", view);*/
519  }
520  } else {
521  /*LOG(LOG_INFO, "inventory::container_clearing_one", "%p not container", view);*/
522  }
523 }
524 
526  /*LOG(LOG_INFO, "inventory::item_event_container_clearing", "Clearing: %d %s %d", op->tag, op->d_name, op->face); */
527  g_list_foreach(views, container_clearing_one, (gpointer)op);
528 }
529 
530 static void item_deleting_one(gpointer view_x, gpointer op_x) {
531  inventory_viewer * view = (inventory_viewer *)view_x;
532  item * it = (item *)op_x;
533 
534  if (it->env != view->cont) {
535  /*LOG(LOG_INFO, "inventory::item_deleting_one", "%p not container", view);*/
536  return;
537  }
538 
539  if (view->complete_rebuild) {
540  /*LOG(LOG_INFO, "inventory::item_deleting_one", "%p already dirty", view);*/
541  return;
542  }
543 
544  /*LOG(LOG_INFO, "inventory::item_deleting_one", "%p removing row", view);*/
545 
546  if (view->face_column_resizes) {
547  PixmapInfo * it_face = pixmaps[it->face];
548 
549  /* Special handling to shrink the image column if the 'responsible' face vanishes. */
550 
551  if (it_face->icon_width == image_size && it_face->icon_height == image_size) {
552  ; /* The column will never get smaller than image_size. */
553  } else if (it_face->icon_width < view->image_width
554  && it_face->icon_height < view->image_height) {
555  ; /* This face isn't a cause of either of the maximums. */
556  } else {
557  PixmapInfo * tmp_face;
558  item * tmp_item;
559  uint16 mw = image_size, mh = image_size;
560 
561  /* TODO Refactor with rebuild_our_widget. */
562 
563  /* it_face requires one of the dimensions to be that large.
564  See if removing it changes the requirements. */
565 
566  for (tmp_item = view->cont->inv; tmp_item != NULL; tmp_item = tmp_item->next) {
567  if (tmp_item == it) continue;
568 
569  if (!view->shows(it)) continue;
570 
571  tmp_face = pixmaps[tmp_item->face];
572 
573  if (tmp_face->icon_width > mw) mw = tmp_face->icon_width;
574  if (tmp_face->icon_height > mh) mh = tmp_face->icon_height;
575  }
576 
577  /* mw, mh hold the size requirement for every shown item bar op. */
578 
579  if (view->image_width != mw) {
580  gtk_clist_set_column_width(GTK_CLIST(view->list), 0, mw);
581  view->image_width = mw;
582  }
583  if (view->image_height != mh) {
584  gtk_clist_set_row_height(GTK_CLIST(view->list), mh);
585  view->image_height = mh;
586  }
587  }
588  }
589 
590  /* Remove the row containing the item. */
591  gtk_clist_remove(GTK_CLIST(view->list),
592  gtk_clist_find_row_from_data(GTK_CLIST(view->list), op_x)
593  );
594 }
595 
597  /*LOG(LOG_INFO, "inventory::item_event_item_deleting", "Deleting: %d %s %d", op->tag, op->d_name, op->face); */
598  g_list_foreach(views, item_deleting_one, (gpointer)op);
599  /* Among other things, prevent animating the now-Missing item. */
601 
602  if (can_write_spell_on(op) && spellinventory != NULL && GTK_WIDGET_VISIBLE(spellinventory)) {
603  gint row = gtk_clist_find_row_from_data(GTK_CLIST(spellinventory), op);
604  if (row != -1)
605  gtk_clist_remove(GTK_CLIST(spellinventory), row);
606  }
607 }
608 
609 
610 /*
611  * Configuration
612  */
613 
614 /* *Could* do these without rebuilding widget, but they almost never happen,
615  so not a problem? */
616 
617 static void inventory_viewer_set_show_weight(inventory_viewer * view, bool show_weight) {
618  if (view->show_weight == show_weight) {
619  return;
620  }
621 
622  view->complete_rebuild = TRUE;
623  view->show_weight = show_weight;
624 }
625 
626 static void inventory_viewer_set_highlight(inventory_viewer * view, bool highlight) {
627  if (view->highlight == highlight) {
628  return;
629  }
630 
631  view->complete_rebuild = TRUE;
632  view->highlight = highlight;
633 }
634 
635 static void inventory_viewer_set_show_flags(inventory_viewer * view, bool show_flags) {
636  if (view->show_flags == show_flags) {
637  return;
638  }
639 
640  view->complete_rebuild = TRUE;
641  view->show_flags = show_flags;
642 }
643 
644 static void inventory_viewer_set_container(inventory_viewer * view, item * new_cont) {
645  if (view->cont == new_cont) return;
646 
647  /*LOG(LOG_INFO, "inventory::inventory_viewer_set_container", "%p dirtied", view);*/
648  view->cont = new_cont;
649  view->complete_rebuild = TRUE;
650 }
651 
652 
653 /*
654  * Handle mouse presses in the lists
655  */
656 
657 #include "gtkproto.h" /* draw_info */
658 static void list_button_event(
659  GtkWidget *gtklist,
660  gint row, gint column,
661  GdkEventButton *event,
662  inventory_viewer * view)
663 {
664  item *it;
665  it = gtk_clist_get_row_data (GTK_CLIST(gtklist), row);
666  gtk_clist_unselect_row (GTK_CLIST(gtklist), row, 0);
667 
668  if (event->button==1) {
669  if (event->state & GDK_SHIFT_MASK)
670  toggle_locked(it);
671  else
672  client_send_examine (it->tag);
673 
674  }
675  if (event->button==2) {
676  if (event->state & GDK_SHIFT_MASK)
677  send_mark_obj(it);
678  else
679  client_send_apply (it->tag);
680  }
681  if (event->button==3) {
682  if (it->locked) {
683  draw_info ("This item is locked. To drop it, first unlock by shift+leftclicking on it.",
684  NDI_BLACK);
685  } else {
686  cpl.count = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(counttext));
687  client_send_move (view->move_dest->tag, it->tag, cpl.count);
688  if (!use_config[CONFIG_POPUPS]) { /* TODO I see no popping up here? */
689  gtk_spin_button_set_value(GTK_SPIN_BUTTON(counttext),0.0);
690  cpl.count=0;
691  }
692  }
693  }
694 }
695 
696 
697 
698 /****************************************************************************
699  *
700  * Everything below is specific to the inventory and look windows; everything
701  * above should be general.
702  *
703  * If you want to change, or especially *add*, inventory viewers, you should
704  * only need to modify things below this comment.
705  *
706  * (Viewing multiple *containers* possibly requires changes in
707  * common and the *server*...)
708  *
709  ****************************************************************************/
710 
711 /*
712  * Creation (and destruction)
713  */
714 
715 #include "pixmaps/all.xpm"
716 #include "pixmaps/hand.xpm"
717 #include "pixmaps/hand2.xpm"
718 #include "pixmaps/coin.xpm"
719 #include "pixmaps/skull.xpm"
720 #include "pixmaps/mag.xpm"
721 #include "pixmaps/nonmag.xpm"
722 #include "pixmaps/lock.xpm"
723 #include "pixmaps/unlock.xpm"
724 
725 static bool show_all(item * ignored) { return TRUE; }
726 static bool show_applied(item * it) { return it->applied; }
727 static bool show_unapplied(item * it) { return !(it->applied); }
728 static bool show_unpaid(item * it) { return it->unpaid; }
729 static bool show_cursed(item * it) { return it->cursed || it->damned; }
730 static bool show_magical(item * it) { return it->magical; }
731 static bool show_nonmagical(item * it) { return !(it->magical); }
732 static bool show_locked(item * it) { return it->locked; }
733 static bool show_unlocked(item * it) { return !(it->locked); }
734 
735 typedef struct {
736  const char *name;
737  const char *const *xpm;
739  bool highlight;
741 
742 /* TODO Dynamic!!!. */
743 #define TYPE_LISTS 9
744 
745 /* These are used to create the inventory tabs. */
747  { "all", all_xpm, show_all, TRUE },
748  { "applied", hand_xpm, show_applied, FALSE },
749  { "unapplied", hand2_xpm, show_unapplied, FALSE },
750  { "unpaid", coin_xpm, show_unpaid, FALSE },
751  { "cursed", skull_xpm, show_cursed, FALSE },
752  { "magical", mag_xpm, show_magical, FALSE },
753  { "nonmagical", nonmag_xpm, show_nonmagical, FALSE },
754  { "locked", lock_xpm, show_locked, FALSE },
755  { "unlocked", unlock_xpm, show_unlocked, TRUE }
756 };
757 
758 /* TODO Maybe I should move these two into the itemlist structs? */
759 static GList * inv_viewers = NULL;
761 /* The inventory_viewers created from the entries above that highlight,
762 plus look_viewer. */
763 static GList * highlit_inv_viewers = NULL;
764 
765 static GtkWidget * look_widget = NULL;
766 static GtkWidget * inv_notebook = NULL;
767 
768 
769 
770 /*
771  * Destroy the current views when the client is toggled between splitwindow and onewindow
772  * mode (or vice versa).
773  */
774 
775 static void add_removal_victim(gpointer view_x, gpointer victim_views_p_x) {
776  inventory_viewer * view = (inventory_viewer *)view_x;
777  GList ** victim_views_p = (GList **) victim_views_p_x;
778  if (g_list_find(*victim_views_p, view) == NULL) {
779  *victim_views_p = g_list_prepend(*victim_views_p, view);
780  }
781 }
782 
783 static void nuke_view(gpointer view_x, gpointer notused) {
784  inventory_viewer * view = (inventory_viewer *)view_x;
785  views = g_list_remove(views, view);
787  free(view);
788 }
789 
791  GList * victim_views = NULL;
792 
793  /* Eeek! Need to throw away all sorts of things. */
794 
795  /* We need to get of everything in inv_viewers, everything
796  in highlit_inv_viewers, and the look_viewer; however, we also
797  need to free them exactly once. add_removal_victim effectively
798  creates a set.*/
799  g_list_foreach(inv_viewers, add_removal_victim, &victim_views);
800  g_list_foreach(highlit_inv_viewers, add_removal_victim, &victim_views);
801  add_removal_victim(look_viewer, &victim_views);
802 
803  /* Free the views. */
804  g_list_foreach(victim_views, nuke_view, NULL);
805  g_list_free(victim_views);
806 
807  /* Zero the values; it's like the client just started. */
808  /* We presume widgets'll be taken care of by GTK widget-destroy functions. */
809  look_viewer = NULL;
810  look_widget = NULL;
811  inv_viewers = NULL;
812  inv_notebook = NULL;
813  highlit_inv_viewers = NULL;
814 }
815 
816 /*
817  * Resizing all the columns when the widget's size is changed.
818  */
819 
820 static void resize_left_widget_one(gpointer view_x, gpointer total_width_x) {
821  inventory_viewer * view = (inventory_viewer *)view_x;
822  gint total_width = GPOINTER_TO_INT(total_width_x);
823 
824  if (view == NULL) {
825  /* Weird. This is never set as a signal handler, but somehow gtk1.2
826  decides to call this with a NULL view when going to split windows.
827  */
828  return;
829  }
830 
831  gtk_clist_set_column_width(GTK_CLIST(view->list),
832  1, total_width - view->image_width);
833 
834  /*LOG(LOG_INFO, "inventory::resize_left_widget_one", "view %p image_width %d", view, view->image_width);*/
835 }
836 
837 /* I mean, the minimum width that won't cause infinite recursion is dependent on the
838 width of the scrollbar and possibly the font used in the title widgets; all that could
839 change if you switch GTK-engine-thingy, so hard-coding this value is silly. On the other
840 hand, I don't know any alternative, aside from using clist's automatic sizing features.
841 
842 ... and why in ding dong would making it smaller (70) *add* the horizontal scrollbar?
843 */
844 #define MAGIC_SAFE_WIDTH 75
845 
846 static void resize_left_widgets(GtkWidget *widget, GtkAllocation *event) {
847  static gint old_total_width = 0;
848  inventory_viewer * hack;
849  gint total_width;
850 
851  /* If GTK can unexpectedly call resize_left_widget_one() as a signal
852  handler when the inventory widgets temporarily don't exist, then we
853  might as well watch our tail here, too. */
854  if (inv_viewers == NULL) return;
855  if (look_viewer == NULL) return;
856 
857  /* HACK Extract the first inventory-viewer. */
858  hack = (inventory_viewer *)(inv_viewers->data);
859  total_width = GTK_CLIST(hack->list)->clist_window_width - MAGIC_SAFE_WIDTH;
860 
861  if (old_total_width == total_width) return;
862  old_total_width = total_width;
863 
864  g_list_foreach(inv_viewers, resize_left_widget_one, GINT_TO_POINTER(total_width));
865  resize_left_widget_one(look_viewer, GINT_TO_POINTER(total_width));
866 }
867 
868 
869 
870 /*
871  * Redrawing only the active inventory view on idle-tick..
872  */
873 
874 /* HACK Only the current inventory tab is rebuilt on each tick. */
875 static bool view_visible(inventory_viewer * view) {
876  GList * i;
877 
878  /* Bottom widget. */
879  if (view == look_viewer) return TRUE;
880 
881  /* If it's an inv_viewer, if its the visible notebook page. */
882  for(i = inv_viewers; i != NULL; i = g_list_next(i)) {
883  if (i->data == view) {
884  return view->scroll_window == gtk_notebook_get_nth_page(
885  GTK_NOTEBOOK(inv_notebook),
886  gtk_notebook_get_current_page(GTK_NOTEBOOK(inv_notebook)));
887  }
888  }
889 
890  /* assume */
891  return TRUE;
892 }
893 
894 /* As the wossname of the above, when the visible tab is changed, rebuild it if needed.
895 Tied to widgets by mod_one_widget(). */
896 static void redraw_on_show(GtkWidget * a, GdkEventVisibility * event, gpointer view_x) {
897  inventory_viewer * view = (inventory_viewer *)view_x;
898 
899  if (!view->complete_rebuild) return;
900 
901  /*{
902  char * x = "unexpected";
903 
904  if (event->state == GDK_VISIBILITY_UNOBSCURED) {
905  x = "unobscured";
906  } else if (event->state == GDK_VISIBILITY_PARTIAL) {
907  x = "partial";
908  } else if (event->state == GDK_VISIBILITY_FULLY_OBSCURED) {
909  x = "obscured";
910  }
911 
912  LOG(LOG_INFO, "inventory::redraw_on_show", "rebuilding %p (visibility changed to %s)", view, x);
913  }*/
914 
915  rebuild_our_widget(view);
916 }
917 
918 
919 
920 static GtkWidget * get_inv_widget(void) {
921  fixed_tab_init * i;
922  GtkStyle *tabstyle;
923  GdkPixmap *labelgdkpixmap;
924  GdkBitmap *labelgdkmask;
925  GtkWidget *tablabel;
926  inventory_viewer * view;
927 
928  if (inv_notebook != NULL) {
929  return inv_notebook;
930  }
931 
932  inv_notebook = gtk_notebook_new();
933  gtk_notebook_set_tab_pos (GTK_NOTEBOOK (inv_notebook), GTK_POS_TOP );
934 
935  for (i = fixed_tabs; i - fixed_tabs < TYPE_LISTS; i++) {
936  tabstyle = gtk_widget_get_style(gtkwin_root);
937 
938  labelgdkpixmap = gdk_pixmap_create_from_xpm_d(
939  gtkwin_root->window,
940  &labelgdkmask,
941  &tabstyle->bg[GTK_STATE_NORMAL],
942  (gchar **) i->xpm );
943 
944  tablabel = gtk_pixmap_new (labelgdkpixmap, labelgdkmask);
945  gtk_widget_show (tablabel);
946 
947  view = new_inventory_viewer(cpl.ob, i->filter, cpl.below); /* player to ground */
948  view->face_column_resizes = FALSE;
949 
951  highlit_inv_viewers = g_list_append(highlit_inv_viewers, view);
952 
953  inv_viewers = g_list_append(inv_viewers, view);
954 
955  gtk_notebook_append_page (GTK_NOTEBOOK (inv_notebook),
956  view->scroll_window,
957  tablabel);
958 
959  /*
960  * Attach events to make some extra behaviours...
961  */
962 
963  gtk_signal_connect(GTK_OBJECT(view->list),
964  "size-allocate",
965  (GtkSignalFunc)resize_left_widgets,
966  NULL);
967 
968  /* Since the program will automatically adjust these, any changes
969  * the user makes can get obliterated, so just don't let the user
970  * make changes.
971  */
972  gtk_clist_set_column_resizeable(GTK_CLIST(view->list), 0, FALSE);
973  gtk_clist_set_column_resizeable(GTK_CLIST(view->list), 1, FALSE);
974  gtk_clist_set_column_resizeable(GTK_CLIST(view->list), 2, FALSE);
975 
976 
977  /* Only the visible tab redraws on inventory_tick(); redraw_on_show
978  redraws dirty tabs when they *become* visible. */
979  gtk_signal_connect(GTK_OBJECT(view->list),
980  "visibility-notify-event",
981  (GtkSignalFunc)redraw_on_show,
982  view);
983 
984  gtk_widget_add_events(view->list, GDK_VISIBILITY_NOTIFY_MASK);
985  }
986 
987  gtk_widget_show(inv_notebook);
988 
989  return inv_notebook;
990 }
991 
992 
993 
994 static GtkWidget *get_look_widget(void) {
995  if (look_widget != NULL) {
996  return look_widget;
997  }
998 
999  look_viewer = new_inventory_viewer(cpl.below, show_all, cpl.ob); /* ground to player */
1000  look_viewer->highlight = TRUE;
1001  look_viewer->face_column_resizes = TRUE;
1002  highlit_inv_viewers = g_list_append(highlit_inv_viewers, look_viewer);
1003 
1004  look_widget = look_viewer->scroll_window;
1005 
1006  return look_widget;
1007 }
1008 
1009 /*
1010  * Now slap the labels on around the invwidgets.
1011  */
1012 
1014 
1015 GtkWidget *closebutton;
1016 
1017 /* forward */
1018 static void close_container_callback(item *op);
1019 
1020 
1021 void get_look_display(GtkWidget *frame)
1022 {
1023  GtkWidget *vbox1;
1024  GtkWidget *hbox1;
1025 
1026  look_list.env = cpl.below;
1027  strcpy (look_list.title, "You see:");
1028  strcpy (look_list.last_title, look_list.title);
1029  strcpy (look_list.last_weight, "0");
1030  strcpy (look_list.last_maxweight, "0");
1031  look_list.show_weight = TRUE;
1032  look_list.weight_limit = 0;
1033 
1034 
1035  vbox1 = gtk_vbox_new(FALSE, 0);/*separation here*/
1036  gtk_container_add (GTK_CONTAINER(frame), vbox1);
1037 
1038  hbox1 = gtk_hbox_new(FALSE, 2);
1039  gtk_box_pack_start (GTK_BOX(vbox1),hbox1, FALSE, FALSE, 0);
1040  gtk_widget_show (hbox1);
1041 
1042  closebutton = gtk_button_new_with_label ("Close");
1043  gtk_signal_connect_object (GTK_OBJECT (closebutton), "clicked",
1044  GTK_SIGNAL_FUNC(close_container_callback),
1045  NULL);
1046  gtk_widget_set_sensitive(closebutton, FALSE);
1047  gtk_box_pack_start (GTK_BOX(hbox1),closebutton, FALSE, FALSE, 2);
1048  gtk_widget_show (closebutton);
1049  gtk_tooltips_set_tip (tooltips, closebutton,
1050  "This will close an item if you have one open.",
1051  NULL);
1052 
1053  look_list.label = gtk_label_new ("You see:");
1054  gtk_box_pack_start (GTK_BOX(hbox1),look_list.label, TRUE, FALSE, 2);
1055  gtk_widget_show (look_list.label);
1056 
1057  look_list.weightlabel = gtk_label_new ("0");
1058  gtk_box_pack_start (GTK_BOX(hbox1),look_list.weightlabel, TRUE, FALSE, 2);
1059  gtk_widget_show (look_list.weightlabel);
1060 
1061  look_list.maxweightlabel = gtk_label_new ("0");
1062  gtk_box_pack_start (GTK_BOX(hbox1),look_list.maxweightlabel, TRUE, FALSE, 2);
1063  gtk_widget_show (look_list.maxweightlabel);
1064 
1065  gtk_box_pack_start(GTK_BOX(vbox1), get_look_widget(), TRUE, TRUE, 0);
1066 
1067  gtk_widget_show (vbox1);
1068 }
1069 
1070 /* Used for getting and dropping more than 1 of an item, and for dimension door
1071  and jumping lengths. */
1072 GtkWidget *counttext;
1073 
1074 static void count_callback(GtkWidget *widget, GtkWidget *entry)
1075 {
1076  const gchar *count_text;
1077  extern GtkWidget * gtkwin_info_text;
1078 
1079  count_text = gtk_entry_get_text(GTK_ENTRY(counttext));
1080  cpl.count = atoi (count_text);
1081  gtk_widget_grab_focus (GTK_WIDGET(gtkwin_info_text)); /* I wonder why this isn't entrytext? */
1082 }
1083 
1084 void get_inv_display(GtkWidget *frame)
1085 {
1086  GtkWidget *vbox2;
1087  GtkWidget *hbox1;
1088  GtkWidget *invlabel;
1089  GtkAdjustment *adj;
1090 
1091  strcpy (inv_list.title, "Inventory:");
1092  strcpy (inv_list.last_title, inv_list.title);
1093  strcpy (inv_list.last_weight, "0");
1094  strcpy (inv_list.last_maxweight, "0");
1095  inv_list.env = cpl.ob;
1096  inv_list.show_weight = TRUE;
1097  inv_list.weight_limit = 0;
1098 
1099  vbox2 = gtk_vbox_new(FALSE, 0); /* separation here */
1100 
1101  gtk_container_add (GTK_CONTAINER(frame), vbox2);
1102 
1103  hbox1 = gtk_hbox_new(FALSE, 2);
1104  gtk_box_pack_start (GTK_BOX(vbox2),hbox1, FALSE, FALSE, 0);
1105  gtk_widget_show (hbox1);
1106 
1107 
1108  inv_list.label = gtk_label_new ("Inventory:");
1109  gtk_box_pack_start (GTK_BOX(hbox1),inv_list.label, TRUE, FALSE, 2);
1110  gtk_widget_show (inv_list.label);
1111 
1112  inv_list.weightlabel = gtk_label_new ("0");
1113  gtk_box_pack_start (GTK_BOX(hbox1),inv_list.weightlabel, TRUE, FALSE, 2);
1114  gtk_widget_show (inv_list.weightlabel);
1115 
1116 
1117  inv_list.maxweightlabel = gtk_label_new ("0");
1118  gtk_box_pack_start (GTK_BOX(hbox1),inv_list.maxweightlabel, TRUE, FALSE, 2);
1119  gtk_widget_show (inv_list.maxweightlabel);
1120 
1121  invlabel = gtk_label_new ("Count:");
1122  gtk_box_pack_start (GTK_BOX(hbox1),invlabel, FALSE, FALSE, 5);
1123  gtk_widget_show (invlabel);
1124 
1125  adj = (GtkAdjustment *) gtk_adjustment_new (0.0, 0.0, 100000.0, 1.0,
1126  100.0, 0.0);
1127  counttext = gtk_spin_button_new (adj, 1.0, 0);
1128 
1129  gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (counttext), FALSE);
1130  gtk_widget_set_usize (counttext, 65, 0);
1131  gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (counttext),
1132  GTK_UPDATE_ALWAYS);
1133  gtk_signal_connect(GTK_OBJECT(counttext), "activate",
1134  GTK_SIGNAL_FUNC(count_callback),
1135  counttext);
1136 
1137 
1138  gtk_box_pack_start (GTK_BOX (hbox1),counttext, FALSE, FALSE, 0);
1139 
1140  gtk_widget_show (counttext);
1141  gtk_tooltips_set_tip (tooltips, counttext,
1142  "This sets the number of items you wish to pickup or drop. You can also use the keys 0-9 to set it.",
1143  NULL);
1144 
1145  gtk_box_pack_start (GTK_BOX(vbox2), get_inv_widget(), TRUE, TRUE, 0);
1146  gtk_widget_show (vbox2);
1147 }
1148 
1149 
1150 
1151 /* commandline toggle tab */
1152 
1153 void command_show (const char *params) {
1154  int i;
1155 
1156  if(params == NULL) {
1157  /* Shouldn't need to get current page, but next_page call is not wrapping
1158  * like the docs claim it should.
1159  */
1160  if (gtk_notebook_get_current_page(GTK_NOTEBOOK(inv_notebook))==TYPE_LISTS-1) {
1161  gtk_notebook_set_page(GTK_NOTEBOOK(inv_notebook), 0);
1162  } else {
1163  gtk_notebook_next_page(GTK_NOTEBOOK(inv_notebook));
1164  }
1165  return;
1166  }
1167 
1168  for (i = 0; i < TYPE_LISTS; i++) {
1169  /* Prefix match */
1170  if (!strncmp(params, fixed_tabs[i].name, strlen(params))) {
1171  gtk_notebook_set_page(GTK_NOTEBOOK(inv_notebook), i);
1172  return;
1173  }
1174  }
1175 }
1176 
1177 /*
1178  * Label updates.
1179  */
1180 
1181 
1183 {
1184  char weight[MAX_BUF];
1185  char max_weight[MAX_BUF];
1186 
1187  /* draw title and put stuff in widgets */
1188 
1189  if ( strcmp( l->title, l->last_title ) ) {
1190  strcpy(l->last_title, l->title);
1191  strcpy(weight,l->title);
1192  gtk_label_set (GTK_LABEL(l->label), weight);
1193  gtk_widget_draw (l->label, NULL);
1194  }
1195 
1196  if(l->env->weight < 0 || !l->show_weight) {
1197  strcpy(weight, " ");
1198  strcpy(max_weight, " ");
1199  }
1200  else if (!l->weight_limit) {
1201  sprintf (weight, "%6.1f",l->env->weight);
1202  strcpy (max_weight, " ");
1203  } else {
1204  sprintf (weight, "%6.1f",l->env->weight);
1205  sprintf (max_weight, "/ %4d",l->weight_limit / 1000);
1206  }
1207 
1208  if ( strcmp( weight, l->last_weight ) ) {
1209  strcpy(l->last_weight, weight);
1210  gtk_label_set (GTK_LABEL(l->weightlabel), weight);
1211  gtk_widget_draw (l->weightlabel, NULL);
1212  }
1213  if ( strcmp( max_weight, l->last_maxweight ) ) {
1214  strcpy(l->last_maxweight, max_weight);
1215  gtk_label_set (GTK_LABEL(l->maxweightlabel), max_weight);
1216  gtk_widget_draw (l->maxweightlabel, NULL);
1217  }
1218 
1219  l->env->inv_updated = FALSE;
1220 }
1221 
1222 /*
1223  * update_list_labels() redraws inventory and look window labels when necessary
1224  *
1225  * (Maybe somewhat more often; look_list doesn't always have a weight shown, possibly.)
1226  */
1227 static void update_lists_labels(void)
1228 {
1229  if (inv_list.env->inv_updated) {
1230  update_list_labels (&inv_list);
1231  }
1232 
1233  if (look_list.env->inv_updated) {
1234  update_list_labels (&look_list);
1235  }
1236 
1237 }
1238 
1239 
1240 
1241 /*
1242  * Events
1243  */
1244 
1246 {
1247  inv_list.weight_limit = wlim;
1248  update_list_labels(&inv_list);
1249 }
1250 
1251 /* toggle weight */
1252 
1253 static void set_show_weight_inv_one(gpointer view_x, gpointer new_setting) {
1254  inventory_viewer * view = (inventory_viewer *)view_x;
1255  inventory_viewer_set_show_weight(view, GPOINTER_TO_INT(new_setting));
1256 }
1257 
1258 void set_show_weight (const char *s)
1259 {
1260  if (s == NULL || *s == 0 || strncmp ("inventory", s, strlen(s)) == 0) {
1261  inv_list.show_weight = ! inv_list.show_weight; /* toggle */
1262  update_list_labels (&inv_list);
1263  g_list_foreach(inv_viewers, set_show_weight_inv_one, GINT_TO_POINTER((int)inv_list.show_weight));
1264  } else if (strncmp ("look", s, strlen(s)) == 0) {
1265  look_list.show_weight = ! look_list.show_weight; /* toggle */
1266  update_list_labels (&look_list);
1267  inventory_viewer_set_show_weight(look_viewer, look_list.show_weight);
1268  }
1269 }
1270 
1271 
1272 
1273 /* toggle flags */
1274 
1275 static void set_flags_one(gpointer view_x, gpointer show_flags) {
1276  inventory_viewer * view = (inventory_viewer *)view_x;
1277  inventory_viewer_set_show_flags(view, GPOINTER_TO_INT(show_flags));
1278 }
1279 
1280 static void set_inv_flags(bool show_flags) {
1281  g_list_foreach(inv_viewers, set_flags_one, GINT_TO_POINTER((int)show_flags));
1282 }
1283 
1284 static void set_look_flags(bool show_flags) {
1285  inventory_viewer_set_show_flags(look_viewer, show_flags);
1286 }
1287 
1288 void itemlist_set_show_icon(itemlist * l, int new_setting) {
1289  if (l->show_icon == new_setting) return;
1290 
1291  /* HACK */
1292  if (l == &inv_list) {
1293  set_inv_flags(!new_setting);
1294  } else if (l == &look_list) {
1295  set_look_flags(!new_setting);
1296  } else {
1297  g_assert(l == &inv_list || l == &look_list);
1298  }
1299 
1300  l->show_icon = new_setting;
1301 }
1302 
1303 void set_show_icon (const char *s)
1304 {
1305  if (s == NULL || *s == 0 || strncmp ("inventory", s, strlen(s)) == 0) {
1306  itemlist_set_show_icon(&inv_list, !inv_list.show_icon); /* toggle */
1307  } else if (strncmp ("look", s, strlen(s)) == 0) {
1308  itemlist_set_show_icon(&look_list, !look_list.show_icon); /* toggle */
1309  }
1310 }
1311 
1312 
1313 /* when containers are opened and shut */
1314 
1315 static void set_look_list_env_one(gpointer view_x, gpointer new_look_x) {
1316  inventory_viewer * view = (inventory_viewer *)view_x;
1317  item * new_look = (item *)new_look_x;
1318 
1319  view->move_dest = new_look;
1320 }
1321 
1322 /* Also called on disconnect. */
1324  if (look_list.env == op) return;
1325 
1326  look_list.env = op;
1327 
1328  inventory_viewer_set_container(look_viewer, op);
1329 
1330  g_list_foreach(inv_viewers, set_look_list_env_one, op);
1331 }
1332 
1333 
1334 void open_container (item *op) {
1335  set_look_list_env(op);
1336  sprintf (look_list.title, "%s:", op->d_name);
1337  gtk_widget_set_sensitive(closebutton, TRUE);
1338 
1339  update_list_labels (&look_list);
1340 }
1341 
1343 {
1344  if (look_list.env != cpl.below) {
1346  client_send_apply (look_list.env->tag);
1348  strcpy (look_list.title, "You see:");
1349  gtk_widget_set_sensitive(closebutton, FALSE);
1350  update_list_labels (&look_list);
1351  }
1352 }
1353 
1354 /* This is basically the same as above, but is used for the callback
1355  * of the close button. As such, it has to always send the apply.
1356  * However, since its a callback, its not like we can just easily
1357  * pass additional parameters.
1358  */
1360 {
1361  if (look_list.env != cpl.below) {
1362  client_send_apply (look_list.env->tag);
1364  strcpy (look_list.title, "You see:");
1365  gtk_widget_set_sensitive(closebutton, FALSE);
1366 
1367  update_list_labels (&look_list);
1368  }
1369 }
1370 
1371 /* --- */
1372 
1373 /* Called by gx11::do_timeout(). */
1374 void inventory_tick(void) {
1376  itemview_tick();
1377 }
sint16 image_height
Definition: inventory.c:40
char last_weight[MAX_BUF]
Definition: gx11.h:89
static GList * views
Definition: inventory.c:47
GtkWidget * scroll_window
Definition: inventory.c:26
float weight
Definition: item.h:56
Animations animations[MAXANIM]
Definition: commands.c:419
static void redraw_on_show(GtkWidget *a, GdkEventVisibility *event, gpointer view_x)
Definition: inventory.c:896
static GtkWidget * list
Definition: gx11.c:2982
static void set_look_list_env_one(gpointer view_x, gpointer new_look_x)
Definition: inventory.c:1315
static GList * inv_viewers
Definition: inventory.c:759
static void close_container_callback(item *op)
Definition: inventory.c:1359
signed short sint16
Definition: client-types.h:80
GtkWidget * label
Definition: gx11.h:92
static void set_show_weight_inv_one(gpointer view_x, gpointer new_setting)
Definition: inventory.c:1253
static void item_tick_per_view(gpointer data, gpointer user_data_ignored)
Definition: inventory.c:432
static void highlight_item(GtkWidget *list, item *it, gint row)
Definition: inventory.c:317
uint32 count
Definition: client.h:295
static GList * animated_items
Definition: inventory.c:136
int can_write_spell_on(item *it)
Definition: item.c:752
void item_event_item_changed(item *op)
Definition: inventory.c:489
#define TYPE_LISTS
Definition: inventory.c:743
GtkTooltips * tooltips
Definition: gx11.c:252
void set_look_list_env(item *op)
Definition: inventory.c:1323
void set_show_icon(const char *s)
Definition: inventory.c:1303
static bool show_unapplied(item *it)
Definition: inventory.c:727
#define CONFIG_POPUPS
Definition: client.h:160
void command_show(const char *params)
Definition: inventory.c:1153
static void set_flags_one(gpointer view_x, gpointer show_flags)
Definition: inventory.c:1275
static GtkWidget * get_look_widget(void)
Definition: inventory.c:994
static XEvent event
Definition: x11.c:193
static GtkWidget * get_inv_widget(void)
Definition: inventory.c:920
static GList * highlit_inv_viewers
Definition: inventory.c:763
char flags[NAME_LEN]
Definition: item.h:53
uint8 anim_speed
Definition: item.h:59
char last_maxweight[MAX_BUF]
Definition: gx11.h:90
item * ob
Definition: client.h:272
static void item_to_widget_remove_widget(inventory_viewer *view)
Definition: inventory.c:206
struct item_struct * env
Definition: item.h:48
uint16 icon_height
Definition: gx11.h:62
snd_pcm_hw_params_t * params
Definition: alsa9.c:111
static inventory_viewer * new_inventory_viewer(item *container, itemfilter filter, item *move_dest)
Definition: inventory.c:57
#define CONFIG_APPLY_CONTAINER
Definition: client.h:179
void inventory_tick(void)
Definition: inventory.c:1374
static GList * item_to_widgets
Definition: inventory.c:135
static void set_inv_flags(bool show_flags)
Definition: inventory.c:1280
static inventory_viewer * look_viewer
Definition: inventory.c:760
struct item_struct * next
Definition: item.h:46
void update_list_labels(itemlist *l)
Definition: inventory.c:1182
static void resize_left_widgets(GtkWidget *widget, GtkAllocation *event)
Definition: inventory.c:846
static void item_to_widget_remove_item(item *const op)
Definition: inventory.c:210
static bool show_unlocked(item *it)
Definition: inventory.c:733
char last_title[MAX_BUF]
Definition: gx11.h:88
void item_event_item_deleting(item *op)
Definition: inventory.c:596
static void item_changed_one(gpointer view_x, gpointer op_x)
Definition: inventory.c:472
GtkWidget * list
Definition: inventory.c:25
itemlist look_list
Definition: inventory.c:1013
itemfilter shows
Definition: inventory.c:27
uint16 inv_updated
Definition: item.h:70
static void inventory_viewer_set_show_flags(inventory_viewer *view, bool show_flags)
Definition: inventory.c:635
uint8 redraw_needed
Definition: gx11.c:205
GtkWidget * closebutton
Definition: inventory.c:1015
static bool show_unpaid(item *it)
Definition: inventory.c:728
PixmapInfo * pixmaps[MAXPIXMAPNUM]
Definition: gx11.c:118
static item_delete * item_to_widget_retrieve(item *op)
Definition: inventory.c:145
uint16 icon_width
Definition: gx11.h:62
static void set_look_flags(bool show_flags)
Definition: inventory.c:1284
static void count_callback(GtkWidget *widget, GtkWidget *entry)
Definition: inventory.c:1074
static void item_to_widget_store(item *op, inventory_viewer *view)
Definition: inventory.c:175
GtkWidget * gtkwin_info_text
Definition: gx11.c:279
static void update_lists_labels(void)
Definition: inventory.c:1227
uint16 applied
Definition: item.h:67
void client_send_apply(int tag)
Definition: player.c:80
#define NDI_RED
Definition: newclient.h:204
void set_show_weight(const char *s)
Definition: inventory.c:1258
#define TRUE
Definition: client-types.h:71
static GList * item_to_widget_retrieve_viewers(item *op)
Definition: inventory.c:171
static void container_clearing_one(gpointer view_x, gpointer op_x)
Definition: inventory.c:506
sint16 image_width
Definition: inventory.c:39
static void animate_items(void)
Definition: inventory.c:293
static bool view_visible(inventory_viewer *view)
Definition: inventory.c:875
static void list_button_event(GtkWidget *gtklist, gint row, gint column, GdkEventButton *event, inventory_viewer *view)
Definition: inventory.c:658
void set_weight_limit(uint32 wlim)
Definition: inventory.c:1245
void close_container(item *op)
Definition: inventory.c:1342
uint16 locked
Definition: item.h:66
GtkWidget * counttext
Definition: inventory.c:1072
sint16 use_config[CONFIG_NUMS]
Definition: init.c:50
const char * name
Definition: inventory.c:736
char d_name[NAME_LEN]
Definition: item.h:50
void * icon_image
Definition: gx11.h:61
uint16 animation_id
Definition: item.h:58
static void rebuild_our_widget(inventory_viewer *view)
Definition: inventory.c:337
item * below
Definition: client.h:273
Client_Player cpl
Definition: client.c:77
itemfilter filter
Definition: inventory.c:738
void item_event_container_clearing(item *op)
Definition: inventory.c:525
GList * viewers
Definition: inventory.c:132
sint32 tag
Definition: item.h:54
item * env
Definition: gx11.h:86
void client_send_move(int loc, int tag, int nrof)
Definition: player.c:92
static void remove_widget_one(gpointer item_and_widget_x, gpointer view_x)
Definition: inventory.c:200
GtkWidget * gtkwin_root
Definition: gx11.c:278
static bool show_locked(item *it)
Definition: inventory.c:732
char * name
Definition: image.c:61
uint8 show_weight
Definition: gx11.h:97
static void inventory_viewer_set_show_weight(inventory_viewer *view, bool show_weight)
Definition: inventory.c:617
uint16 magical
Definition: item.h:62
#define NDI_NAVY
Definition: newclient.h:203
static bool show_nonmagical(item *it)
Definition: inventory.c:731
GtkWidget * maxweightlabel
Definition: gx11.h:94
item * move_dest
Definition: inventory.c:24
#define MAGIC_SAFE_WIDTH
Definition: inventory.c:844
unsigned short uint16
Definition: client-types.h:79
static bool show_cursed(item *it)
Definition: inventory.c:729
uint32 weight_limit
Definition: gx11.h:99
void send_mark_obj(item *op)
Definition: item.c:590
itemlist inv_list
Definition: inventory.c:1013
void toggle_locked(item *op)
Definition: item.c:573
GdkColor root_color[16]
Definition: gx11.c:244
static void resize_left_widget_one(gpointer view_x, gpointer total_width_x)
Definition: inventory.c:820
#define MAX_BUF
Definition: client-types.h:128
void inventory_splitwin_toggling(void)
Definition: inventory.c:790
uint16 unpaid
Definition: item.h:65
GdkColor gdk_black
Definition: gx11.c:240
static GtkWidget * look_widget
Definition: inventory.c:765
uint8 anim_state
Definition: item.h:60
GtkWidget * spellinventory
Definition: gx11.c:2984
static fixed_tab_init fixed_tabs[TYPE_LISTS]
Definition: inventory.c:746
bool(* itemfilter)(item *it)
Definition: inventory.c:20
void get_look_display(GtkWidget *frame)
Definition: inventory.c:1021
unsigned int uint32
Definition: client-types.h:77
static void animate_item(gpointer view_x, gpointer item_x)
Definition: inventory.c:251
#define bool
Definition: inventory.c:13
item * it
Definition: inventory.c:131
static GtkWidget * inv_notebook
Definition: inventory.c:766
bool face_column_resizes
Definition: inventory.c:37
GtkWidget * weightlabel
Definition: gx11.h:93
static void inventory_viewer_set_container(inventory_viewer *view, item *new_cont)
Definition: inventory.c:644
static void item_deleting_one(gpointer view_x, gpointer op_x)
Definition: inventory.c:530
Pixmap pixmap
Definition: xutil.c:67
void client_send_examine(int tag)
Definition: player.c:85
const char *const * xpm
Definition: inventory.c:737
uint8 show_icon
Definition: gx11.h:96
void draw_info(const char *str, int color)
Definition: gx11.c:1773
uint16 last_anim
Definition: item.h:61
static void item_changed_anim_hook(item *op)
Definition: inventory.c:298
static bool show_applied(item *it)
Definition: inventory.c:726
void open_container(item *op)
Definition: inventory.c:1334
static void nuke_view(gpointer view_x, gpointer notused)
Definition: inventory.c:783
static bool show_all(item *ignored)
Definition: inventory.c:725
uint16 damned
Definition: item.h:64
#define NDI_BLACK
Definition: newclient.h:201
static bool show_magical(item *it)
Definition: inventory.c:730
struct item_struct * inv
Definition: item.h:49
#define FMT_WEIGHT(buf, buf_size, it)
Definition: inventory.c:335
#define FALSE
Definition: client-types.h:68
uint8 num_animations
Definition: client.h:73
void get_inv_display(GtkWidget *frame)
Definition: inventory.c:1084
static void itemview_tick(void)
Definition: inventory.c:463
int image_size
Definition: gx11.c:116
Definition: gx11.h:85
char title[MAX_BUF]
Definition: gx11.h:87
static void animate_one_item(gpointer item_x, gpointer ignored)
Definition: inventory.c:267
uint16 cursed
Definition: item.h:63
bool complete_rebuild
Definition: inventory.c:28
static void add_removal_victim(gpointer view_x, gpointer victim_views_p_x)
Definition: inventory.c:775
sint16 face
Definition: item.h:57
static void inventory_viewer_set_highlight(inventory_viewer *view, bool highlight)
Definition: inventory.c:626
GdkColor gdk_grey
Definition: gx11.c:239
void itemlist_set_show_icon(itemlist *l, int new_setting)
Definition: inventory.c:1288
#define NDI_BLUE
Definition: newclient.h:206
uint16 * faces
Definition: client.h:79
void * icon_mask
Definition: gx11.h:61