1 /* NetHack may be freely redistributed. See license for details. */
2
3 #include "vulture_sdl.h" /* XXX this must be the first include,
4 no idea why but it won't compile otherwise */
5
6 extern "C" {
7 #include "hack.h"
8
9 extern int take_off();
10 extern int select_off(struct obj *);
11 extern long takeoff_mask;
12 extern const char *disrobing;
13 }
14
15 #include "vulture_gra.h"
16 #include "vulture_txt.h"
17 #include "vulture_win.h"
18 #include "vulture_mou.h"
19 #include "vulture_tile.h"
20
21 #include "inventory.h"
22 #include "objitemwin.h"
23 #include "objheaderwin.h"
24 #include "contextmenu.h"
25 #include "button.h"
26
27
28 #define META(c) (0x80 | (c))
29 #define CTRL(c) (0x1f & (c))
30
31
inventory(window * p,std::list<menuitem> & menuitems,int how,int id)32 inventory::inventory(window *p, std::list<menuitem> &menuitems, int how, int id) :
33 menuwin(p, menuitems, how), nhid(id)
34 {
35 v_type = V_WINTYPE_OBJWIN;
36
37 ow_ncols = ow_vcols = ow_firstcol = ow_vrows = 0;
38 ow_lasttoggled = NULL;
39 }
40
41
draw()42 bool inventory::draw()
43 {
44 std::string stored_caption;
45 char label[32];
46 int ix ,iy, iw, ih, labelwidth;
47
48 /* draw the window, but prevent draw_mainwin from drawing the caption */
49 stored_caption = caption;
50 caption.clear();
51
52 mainwin::draw();
53
54 caption = stored_caption;
55
56 ix = abs_x + border_left;
57 iy = abs_y + border_top;
58 iw = w - border_left - border_right;
59 ih = h - border_top - border_bottom;
60
61 int headline_height = vulture_get_lineheight(V_FONT_HEADLINE);
62 int headline_width = vulture_text_length(V_FONT_HEADLINE, caption);
63
64 vulture_fill_rect(ix, iy, ix + iw - 1, iy + headline_height * 2, CLR32_BLACK_A50);
65
66 vulture_line(ix, iy, ix + iw - 1, iy, CLR32_GRAY20);
67 vulture_line(ix, iy + headline_height * 2, ix + iw - 1,
68 iy + headline_height * 2, CLR32_GRAY20);
69
70 vulture_put_text_shadow(V_FONT_HEADLINE, caption, vulture_screen, ix+(iw-headline_width)/2,
71 iy+headline_height/2+2, CLR32_WHITE, CLR32_GRAY20);
72
73 if (ow_ncols > ow_vcols) {
74
75 if ( ow_firstcol + 1 == ow_firstcol + ow_vcols )
76 snprintf(label, 32, "Page %d of %d", ow_firstcol + 1, ow_ncols);
77 else
78 snprintf(label, 32, "Pages %d to %d of %d", ow_firstcol + 1, ow_firstcol + ow_vcols, ow_ncols);
79
80 labelwidth = vulture_text_length(V_FONT_MENU, label);
81
82 vulture_put_text_shadow(V_FONT_MENU, label, vulture_screen, x+(w-labelwidth)/2,
83 y+h-21, CLR32_BLACK, CLR32_GRAY20);
84 }
85
86 return 1;
87 }
88
89
update_invscroll(int newpos)90 void inventory::update_invscroll(int newpos)
91 {
92 window * winelem;
93 int itemcount = 0;
94 int itemcol;
95 int leftoffset = border_left;
96 int topoffset = border_top;
97
98 topoffset += vulture_get_lineheight(V_FONT_HEADLINE) * 2 + 2;
99
100 if (newpos + ow_vcols > ow_ncols)
101 newpos = ow_ncols - ow_vcols;
102 else if (newpos < 0)
103 newpos = 0;
104
105 ow_firstcol = newpos;
106
107
108 for (winelem = first_child; winelem; winelem = winelem->sib_next) {
109 if (winelem->v_type == V_WINTYPE_OBJITEM ||
110 winelem->v_type == V_WINTYPE_OBJITEMHEADER) {
111 itemcol = (itemcount / ow_vrows);
112
113 winelem->x = (itemcol - newpos) * (V_LISTITEM_WIDTH + 4) + leftoffset;
114 winelem->y = (itemcount % ow_vrows) * V_LISTITEM_HEIGHT + topoffset;
115
116 winelem->visible = (itemcol >= newpos && itemcol < newpos + ow_vcols);
117
118 itemcount++;
119 }
120
121 else if (winelem->v_type == V_WINTYPE_BUTTON) {
122 if (winelem->menu_id == V_INV_PREVPAGE)
123 winelem->visible = (newpos != 0);
124 else if (winelem->menu_id == V_INV_NEXTPAGE)
125 winelem->visible = (newpos + ow_vcols < ow_ncols);
126 }
127 }
128 }
129
130
context_menu(objitemwin * target)131 eventresult inventory::context_menu(objitemwin *target)
132 {
133 int action = 0, key = 0;
134 contextmenu *menu;
135
136 menu = new contextmenu(ROOTWIN);
137 menu->add_item("Apply", V_INVACTION_APPLY);
138
139 if (!target->obj->owornmask)
140 {
141 /* if you can wear it there's no way you can eat or drink it */
142 if (target->obj->oclass == POTION_CLASS)
143 menu->add_item("Drink", V_INVACTION_DRINK);
144 menu->add_item("Eat", V_INVACTION_EAT);
145 }
146
147 menu->add_item("Read", V_INVACTION_READ);
148
149 if (target->obj->oclass == WAND_CLASS)
150 menu->add_item("Zap", V_INVACTION_ZAP);
151
152 /* you could already be wearing it, then you can't wear it again */
153 if (!target->obj->owornmask && target->obj->oclass != WAND_CLASS) {
154 if (target->obj->oclass != RING_CLASS && target->obj->oclass != AMULET_CLASS)
155 menu->add_item("Wear", V_INVACTION_WEAR);
156
157 if (target->obj->oclass != ARMOR_CLASS)
158 menu->add_item("Put on", V_INVACTION_PUT_ON);
159 }
160
161 menu->add_item("Wield", V_INVACTION_WIELD);
162 menu->add_item("Quiver", V_INVACTION_QUIVER);
163
164 if (target->obj->owornmask)
165 menu->add_item("Remove", V_INVACTION_REMOVE);
166
167 if (!target->obj->owornmask)
168 menu->add_item("Drop", V_INVACTION_DROP);
169
170 if (!objects[target->obj->otyp].oc_name_known)
171 menu->add_item("Name", V_INVACTION_NAME);
172
173 menu->layout();
174 vulture_event_dispatcher(&action, V_RESPOND_INT, menu);
175
176 delete menu;
177
178
179 if (action) {
180 vulture_eventstack_add('i', -1, -1, V_RESPOND_POSKEY);
181
182 switch (action)
183 {
184 case V_INVACTION_APPLY: key = 'a'; break;
185 case V_INVACTION_DRINK: key = 'q'; break;
186 case V_INVACTION_EAT: key = 'e'; break;
187 case V_INVACTION_READ: key = 'r'; break;
188 case V_INVACTION_ZAP: key = 'z'; break;
189 case V_INVACTION_WEAR: key = 'W'; break;
190 case V_INVACTION_PUT_ON:key = 'P'; break;
191 case V_INVACTION_WIELD: key = 'w'; break;
192 case V_INVACTION_QUIVER: key = 'Q'; break;
193 case V_INVACTION_REMOVE:
194 /* we call a bunch of functions in do_wear.c directly here;
195 * we can do so safely because take_off() directly accounts for
196 * elapsed turns */
197 select_off(target->obj); /* sets takoff_mask */
198 if (takeoff_mask)
199 {
200 /* default activity for armor and/or accessories,
201 * possibly combined with weapons */
202 disrobing = "disrobing";
203
204 /* specific activity when handling weapons only */
205 if (!(takeoff_mask & ~(W_WEP|W_SWAPWEP|W_QUIVER)))
206 disrobing = "disarming";
207
208 (void) take_off();
209 }
210 /* having performed an action we need to return to the main game loop
211 * so that thing like AC and vision (because of helmets & amulets of ESP)
212 * get recalculated.
213 * However we do not want to perform any more actions or cause messages
214 * to be printed. CTRL+r (redraw) is a suitable NOP */
215 key = CTRL('r');
216 return V_EVENT_HANDLED_FINAL;
217
218 case V_INVACTION_NAME:
219 vulture_eventstack_add(target->menu_id, -1, -1, V_RESPOND_ANY);
220 vulture_eventstack_add('n', -1,-1, V_RESPOND_ANY);
221 vulture_eventstack_add(META('n'), -1, -1, V_RESPOND_POSKEY);
222 return V_EVENT_HANDLED_FINAL;
223
224 case V_INVACTION_DROP: key = 'd'; break;
225 }
226
227 vulture_eventstack_add(target->menu_id, -1, -1, V_RESPOND_CHARACTER);
228 vulture_eventstack_add(key, -1, -1, V_RESPOND_POSKEY);
229
230 return V_EVENT_HANDLED_FINAL;
231 }
232
233 return V_EVENT_HANDLED_NOREDRAW;
234 }
235
236
237
handle_mousemotion_event(window * target,void * result,int xrel,int yrel,int state)238 eventresult inventory::handle_mousemotion_event(window* target, void* result, int xrel,
239 int yrel, int state)
240 {
241 vulture_set_mcursor(V_CURSOR_NORMAL);
242 return V_EVENT_HANDLED_NOREDRAW;
243 }
244
245
handle_mousebuttonup_event(window * target,void * result,int mouse_x,int mouse_y,int button,int state)246 eventresult inventory::handle_mousebuttonup_event(window* target, void* result,
247 int mouse_x, int mouse_y, int button, int state)
248 {
249 point mouse = vulture_get_mouse_pos();
250 window *winelem;
251 objitemwin *oitem;
252
253 if (select_how == PICK_NONE) {
254 /* close the window if the user clicks outside it */
255 if (this == target && (mouse.x < abs_x || mouse.y < abs_y ||
256 mouse.x > abs_x + w || mouse.y > abs_y + h))
257 return V_EVENT_HANDLED_FINAL;
258
259 /* left clicks on object items do nothing */
260 if (button == SDL_BUTTON_LEFT &&
261 target != this && target->v_type == V_WINTYPE_OBJITEM)
262 return V_EVENT_HANDLED_NOREDRAW;
263
264 /* right clicks on object items open a context menu */
265 else if (button == SDL_BUTTON_RIGHT && target->v_type == V_WINTYPE_OBJITEM)
266 return context_menu(static_cast<objitemwin*>(target));
267 }
268
269 if (button == SDL_BUTTON_WHEELUP) {
270 if (ow_firstcol > 0) {
271 /* scroll inventory backwards */
272 update_invscroll(ow_firstcol - 1);
273 need_redraw = 1;
274 return V_EVENT_HANDLED_REDRAW;
275 }
276 return V_EVENT_HANDLED_NOREDRAW;
277 }
278
279 else if (button == SDL_BUTTON_WHEELDOWN) {
280 if (ow_firstcol + ow_vcols < ow_ncols) {
281 /* scroll inventory forwards */
282 update_invscroll(ow_firstcol + 1);
283 need_redraw = 1;
284 return V_EVENT_HANDLED_REDRAW;
285 }
286 return V_EVENT_HANDLED_NOREDRAW;
287 }
288
289 else if (button == SDL_BUTTON_LEFT) {
290 if (this == target)
291 return V_EVENT_HANDLED_NOREDRAW;
292
293 if (target->v_type == V_WINTYPE_BUTTON) {
294 switch (target->menu_id)
295 {
296 case V_MENU_ACCEPT:
297 case V_MENU_CANCEL:
298 case V_INV_CLOSE:
299 *(int*)result = target->menu_id;
300 return V_EVENT_HANDLED_FINAL;
301
302 case V_INV_PREVPAGE:
303 update_invscroll(ow_firstcol - 1);
304 need_redraw = 1;
305 return V_EVENT_HANDLED_REDRAW;
306
307 case V_INV_NEXTPAGE:
308 update_invscroll(ow_firstcol + 1);
309 need_redraw = 1;
310 return V_EVENT_HANDLED_REDRAW;
311 }
312 }
313
314 /* select a range of items from target (clicked item) to handler->pd.ow_lasttoggled (previously clicked item) */
315 if (target->v_type == V_WINTYPE_OBJITEM && (SDL_GetModState() & KMOD_LSHIFT) &&
316 select_how != PICK_ONE && ow_lasttoggled) {
317 int selectme = 0;
318 for (winelem = first_child; winelem; winelem = winelem->sib_next) {
319 if (winelem == target || winelem == ow_lasttoggled) {
320 selectme = !selectme;
321 oitem = static_cast<objitemwin*>(winelem);
322 oitem->item->selected = 1;
323 oitem->item->count = -1;
324 }
325
326 if (selectme && winelem->v_type == V_WINTYPE_OBJITEM) {
327 oitem = static_cast<objitemwin*>(winelem);
328 oitem->item->selected = 1;
329 oitem->item->count = -1;
330 }
331 }
332
333 ow_lasttoggled->last_toggled = 0;
334 ow_lasttoggled = static_cast<objitemwin*>(target);
335 static_cast<objitemwin*>(target)->last_toggled = 1;
336
337 need_redraw = 1;
338 return V_EVENT_HANDLED_REDRAW;
339 }
340 else if (target->v_type == V_WINTYPE_OBJITEM) {
341 select_option(static_cast<objitemwin*>(target), -1);
342
343 if (ow_lasttoggled)
344 ow_lasttoggled->last_toggled = false;
345 ow_lasttoggled = static_cast<objitemwin*>(target);
346 ow_lasttoggled->last_toggled = true;
347
348 if (select_how == PICK_ONE) {
349 *(int*)result = V_MENU_ACCEPT;
350 return V_EVENT_HANDLED_FINAL;
351 }
352
353 need_redraw = 1;
354 return V_EVENT_HANDLED_REDRAW;
355 }
356 }
357
358 return V_EVENT_HANDLED_NOREDRAW;
359 }
360
361
handle_keydown_event(window * target,void * result,int sym,int mod,int unicode)362 eventresult inventory::handle_keydown_event(window* target, void* result, int sym, int mod, int unicode)
363 {
364 window *winelem;
365 int itemcount, colno, key;
366
367 need_redraw = 1;
368 key = unicode;
369 switch (sym) {
370 case SDLK_RETURN:
371 case SDLK_KP_ENTER:
372 *(int*)result = V_MENU_ACCEPT;
373 return V_EVENT_HANDLED_FINAL;
374
375 case SDLK_SPACE:
376 case SDLK_ESCAPE:
377 *(int*)result = (select_how == PICK_NONE) ? V_MENU_ACCEPT : V_MENU_CANCEL;
378 return V_EVENT_HANDLED_FINAL;
379
380 /* handle menu control keys */
381 case SDLK_HOME: key = MENU_FIRST_PAGE; /* '^' */ break;
382 case SDLK_END: key = MENU_LAST_PAGE; /* '|' */ break;
383
384 /* scroll via arrow keys */
385 case SDLK_PAGEDOWN:
386 case SDLK_KP2:
387 case SDLK_DOWN:
388 case SDLK_RIGHT:
389 update_invscroll(ow_firstcol + 1);
390 return V_EVENT_HANDLED_REDRAW;
391
392 case SDLK_PAGEUP:
393 case SDLK_KP8:
394 case SDLK_UP:
395 case SDLK_LEFT:
396 update_invscroll(ow_firstcol - 1);
397 return V_EVENT_HANDLED_REDRAW;
398
399 case SDLK_BACKSPACE:
400 if (ow_lasttoggled)
401 ow_lasttoggled->item->count = ow_lasttoggled->item->count / 10;
402 return V_EVENT_HANDLED_REDRAW;
403
404 default: break;
405 }
406
407 if (!key)
408 /* a function or modifier key, but not one we recognize, was pressed */
409 return V_EVENT_HANDLED_NOREDRAW;
410
411 switch (key) {
412 case MENU_PREVIOUS_PAGE:
413 update_invscroll(ow_firstcol - 1);
414 return V_EVENT_HANDLED_REDRAW;
415
416 case MENU_NEXT_PAGE:
417 update_invscroll(ow_firstcol + 1);
418 return V_EVENT_HANDLED_REDRAW;
419
420 case MENU_FIRST_PAGE:
421 update_invscroll(0);
422 return V_EVENT_HANDLED_REDRAW;
423
424 case MENU_LAST_PAGE:
425 update_invscroll(999999);
426 return V_EVENT_HANDLED_REDRAW;
427
428
429 case MENU_SELECT_ALL:
430 case MENU_UNSELECT_ALL:
431 /* invalid for single selection menus */
432 if (select_how != PICK_ANY)
433 return V_EVENT_HANDLED_NOREDRAW;
434
435 for (winelem = first_child; winelem; winelem = winelem->sib_next) {
436 if (winelem->v_type == V_WINTYPE_OBJITEM) {
437 static_cast<objitemwin*>(winelem)->item->selected =
438 (key == MENU_SELECT_ALL);
439 static_cast<objitemwin*>(winelem)->item->count = -1;
440 }
441 }
442 return V_EVENT_HANDLED_REDRAW;
443
444
445 case MENU_INVERT_ALL:
446 /* invalid for single selection menus */
447 if (select_how != PICK_ANY)
448 return V_EVENT_HANDLED_NOREDRAW;
449
450 for (winelem = first_child; winelem; winelem = winelem->sib_next) {
451 if (winelem->v_type == V_WINTYPE_OBJITEM) {
452 static_cast<objitemwin*>(winelem)->item->selected =
453 !static_cast<objitemwin*>(winelem)->item->selected;
454 static_cast<objitemwin*>(winelem)->item->count = -1;
455 }
456 }
457 return V_EVENT_HANDLED_REDRAW;
458
459
460 case MENU_SELECT_PAGE:
461 case MENU_UNSELECT_PAGE:
462 /* invalid for single selection menus */
463 if (select_how != PICK_ANY)
464 return V_EVENT_HANDLED_NOREDRAW;
465
466 for (winelem = first_child; winelem; winelem = winelem->sib_next) {
467 if (winelem->v_type == V_WINTYPE_OBJITEM && winelem->visible) {
468 static_cast<objitemwin*>(winelem)->item->selected = (key == MENU_SELECT_PAGE);
469 static_cast<objitemwin*>(winelem)->item->count = -1;
470 }
471 }
472 return V_EVENT_HANDLED_REDRAW;
473
474
475 case MENU_INVERT_PAGE:
476 /* invalid for single selection menus */
477 if (select_how != PICK_ANY)
478 return V_EVENT_HANDLED_NOREDRAW;
479
480 for (winelem = first_child; winelem; winelem = winelem->sib_next) {
481 if (winelem->v_type == V_WINTYPE_OBJITEM && winelem->visible) {
482 static_cast<objitemwin*>(winelem)->item->selected =
483 !static_cast<objitemwin*>(winelem)->item->selected;
484 static_cast<objitemwin*>(winelem)->item->count = -1;
485 }
486 }
487 return V_EVENT_HANDLED_REDRAW;
488
489
490 case MENU_SEARCH:
491 char str_to_find[512];
492 str_to_find[0] = '\0';
493 if (vulture_get_input(-1, -1, "What are you looking for?", str_to_find) != -1)
494 {
495 itemcount = 0;
496 for (winelem = first_child; winelem; winelem = winelem->sib_next) {
497 itemcount++;
498 if (winelem->caption.find(str_to_find)) {
499 colno = itemcount / ow_vrows;
500 update_invscroll(colno);
501 break;
502 }
503 }
504
505 if (ow_lasttoggled)
506 ow_lasttoggled->last_toggled = false;
507 ow_lasttoggled = static_cast<objitemwin*>(winelem);
508 if (ow_lasttoggled)
509 ow_lasttoggled->last_toggled = true;
510 }
511 return V_EVENT_HANDLED_REDRAW;
512
513 default:
514 if (select_how == PICK_NONE)
515 return V_EVENT_HANDLED_FINAL;
516
517 /* numbers are part of a count */
518 if (key >= '0' && key <= '9' && ow_lasttoggled &&
519 ow_lasttoggled->item->count < 1000000) {
520 if (ow_lasttoggled->item->count == -1)
521 ow_lasttoggled->item->count = 0;
522 ow_lasttoggled->item->count = ow_lasttoggled->item->count * 10 + (key - '0');
523
524 return V_EVENT_HANDLED_REDRAW;
525 }
526
527 /* try to match the key to an accelerator */
528 std::vector<window *> targets_found( find_accel( key ) );
529 for ( std::vector<window *>::iterator target = targets_found.begin();
530 target != targets_found.end();
531 ++target )
532 {
533 select_option(static_cast<objitemwin*>(*target), -1);
534 if (select_how == PICK_ONE) {
535 *(int*)result = V_MENU_ACCEPT;
536 return V_EVENT_HANDLED_FINAL;
537 }
538
539 if (ow_lasttoggled)
540 ow_lasttoggled->last_toggled = 0;
541 ow_lasttoggled = static_cast<objitemwin*>(*target);
542 ow_lasttoggled->last_toggled = 1;
543
544
545 /* if the selected element isn't visible bring it into view */
546 if (!(*target)->visible) {
547 itemcount = 0;
548 for (winelem = first_child; winelem && winelem != *target;
549 winelem = winelem->sib_next)
550 itemcount++;
551
552 colno = itemcount / ow_vrows;
553 update_invscroll(colno);
554 }
555 }
556
557 if ( targets_found.size() > 0 ) {
558 return V_EVENT_HANDLED_REDRAW;
559 }
560
561 break;
562 }
563
564 return V_EVENT_HANDLED_NOREDRAW;
565 }
566
567
handle_resize_event(window * target,void * result,int res_w,int res_h)568 eventresult inventory::handle_resize_event(window* target, void* result, int res_w, int res_h)
569 {
570 if (visible) {
571 /* hide_window takes care of the background */
572 hide();
573
574 /* resize */
575 layout();
576
577 /* redraw */
578 visible = 1;
579 need_redraw = 1;
580 return V_EVENT_HANDLED_REDRAW;
581 }
582
583 return V_EVENT_HANDLED_NOREDRAW;
584 }
585
586
layout()587 void inventory::layout()
588 {
589 window *winelem;
590 button *btn;
591 struct obj * invitem;
592
593 int itemcount = 0;
594 int ncols, nrows;
595 int maxitems_per_col, maxitems_per_row;
596 int textheight;
597
598 /* remove all child windows - they get (re-)created here */
599 while (first_child)
600 delete first_child;
601
602 if (caption.empty())
603 caption = "Inventory";
604
605 int leftoffset = border_left;
606 int topoffset = border_top;
607 int rightoffset = border_right;
608 int bottomoffset = 60; /* guesstimate for bottom border + page arrows + minimal spacing */
609
610 textheight = vulture_get_lineheight(V_FONT_LARGE);
611 topoffset += textheight*2 + 2;
612
613 if (select_how != PICK_NONE)
614 bottomoffset += (textheight + 14);
615
616 for (item_iterator i = items.begin(); i != items.end(); ++i) {
617 if (!i->identifier)
618 new objheaderwin(this, i->str);
619 else
620 new objitemwin(this, &(*i), i->str, i->accelerator, i->group_accelerator,
621 i->glyph, i->preselected, select_how == PICK_ANY);
622 itemcount++;
623
624 }
625
626 /* how many items will fit on the screen vertically */
627 maxitems_per_col = (parent->h - topoffset - bottomoffset) / V_LISTITEM_HEIGHT;
628
629 maxitems_per_row = (parent->w - 2*leftoffset - 10) / (V_LISTITEM_WIDTH + 4);
630
631 /* calc number of rows to contain itemcount items */
632 ncols = itemcount / maxitems_per_col + (itemcount % maxitems_per_col != 0 ? 1 : 0);
633
634 /* distribute items evenly among the rows */
635 nrows = itemcount / ncols + (itemcount % ncols != 0 ? 1 : 0);
636
637 /* if there are more columns than can be displayed, prefer to maximize
638 * space usage over even distribution of the items */
639 if (ncols > maxitems_per_row)
640 nrows = maxitems_per_col;
641
642 ow_vcols = ncols > maxitems_per_row ? maxitems_per_row : ncols;
643 ow_vrows = nrows > maxitems_per_col ? maxitems_per_col : nrows;
644 ow_ncols = ncols;
645
646 ow_firstcol = 0;
647
648 itemcount = 0;
649 for (winelem = first_child; winelem; winelem = winelem->sib_next) {
650 if (winelem->v_type == V_WINTYPE_OBJITEM ||
651 winelem->v_type == V_WINTYPE_OBJITEMHEADER) {
652 winelem->x = (itemcount / ow_vrows) * (V_LISTITEM_WIDTH + 4) + leftoffset;
653 winelem->y = (itemcount % ow_vrows) * V_LISTITEM_HEIGHT + topoffset;
654 winelem->visible = ((itemcount / ow_vrows) < ow_vcols);
655
656 /* find the objects associated with the items */
657 if (winelem->v_type == V_WINTYPE_OBJITEM) {
658 /* nethack may have been nice and passed an object pointer in menu_id_v
659 * Unforunately, we need this ugly hack to try to discern between
660 * chars, small ints and pointers */
661 if (winelem->menu_id_v > (void*)0x10000)
662 static_cast<objitemwin*>(winelem)->obj = (struct obj *)winelem->menu_id_v;
663 else if (nhid == WIN_INVEN) {
664 invitem = invent;
665 while (invitem && invitem->invlet != winelem->accelerator)
666 invitem = invitem->nobj;
667 static_cast<objitemwin*>(winelem)->obj = invitem;
668 }
669 }
670
671 itemcount++;
672 }
673 }
674
675 w = ow_vcols * (V_LISTITEM_WIDTH + 4) - 4 + leftoffset + rightoffset;
676 h = ow_vrows * V_LISTITEM_HEIGHT + topoffset + border_bottom;
677
678 if (ncols > ow_vcols) {
679 h += 25;
680
681 btn = new button(this, "", V_INV_PREVPAGE, '\0');
682 btn->x = leftoffset;
683 btn->y = h - border_bottom - 23;
684 btn->w = 100;
685 btn->h = 24;
686 btn->image = vulture_get_img_src(0, 0, vulture_winelem.invarrow_left->w,
687 vulture_winelem.invarrow_left->h, vulture_winelem.invarrow_left);
688 btn->visible = 0;
689
690 btn = new button(this, "", V_INV_NEXTPAGE, '\0');
691 btn->x = w - rightoffset - 101;
692 btn->y = h - border_bottom - 23;
693 btn->w = 100;
694 btn->h = 24;
695 btn->image = vulture_get_img_src(0, 0, vulture_winelem.invarrow_right->w,
696 vulture_winelem.invarrow_right->h, vulture_winelem.invarrow_right);
697 btn->visible = 1;
698 }
699
700 if (select_how != PICK_NONE) {
701 int btn1_width = 0;
702 if ( select_how == PICK_ANY )
703 btn1_width = vulture_text_length(V_FONT_MENU, "Accept") + 14;
704 int btn2_width = vulture_text_length(V_FONT_MENU, "Cancel") + 14;
705 int max_width = (btn1_width > btn2_width) ? btn1_width : btn2_width;
706 int total_width = max_width;
707
708 h += textheight + 14;
709
710 if ( select_how == PICK_ANY )
711 {
712 total_width += max_width + 10;
713 btn = new button(this, "Accept", V_MENU_ACCEPT, '\0');
714 btn->h = textheight + 10;
715 btn->y = h - border_bottom - (textheight + 12);
716 btn->w = max_width;
717 btn->x = (w - rightoffset - leftoffset - total_width) / 2 + leftoffset;
718 }
719
720 btn = new button(this, "Cancel", V_MENU_CANCEL, '\0');
721 btn->h = textheight + 10;
722 btn->y = h - border_bottom - (textheight + 12);
723 btn->w = max_width;
724 btn->x = (w - rightoffset - leftoffset - total_width) / 2 + leftoffset;
725 if ( select_how == PICK_ANY )
726 btn->x += max_width + 10;
727 } else {
728 btn = new button(this, "", V_INV_CLOSE, '\0');
729 btn->visible = 1;
730 btn->x = w - border_right - 28;
731 btn->y = border_top + 2;
732 btn->w = 26;
733 btn->h = 26;
734 btn->image = vulture_get_img_src(0, 0, vulture_winelem.closebutton->w,
735 vulture_winelem.closebutton->h, vulture_winelem.closebutton);
736 }
737
738 x = (parent->w - w) / 2;
739 y = (parent->h - h) / 2;
740
741 abs_x = parent->x + x;
742 abs_y = parent->y + y;
743
744 }
745