Changeset 542

Show
Ignore:
Timestamp:
08/24/07 07:20:46 (1 year ago)
Author:
ajps
Message:

Split out ui-event and ui-menu from ui.c, partly in preparation for other ui-* files. Indulge in some renaming and recommenting of some data structures and things, e.g. event_type becomes ui_event_data, hopefully to distinguish it better from the game event stuff.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/Makefile.src

    r541 r542  
    6363        trap.o \ 
    6464        ui.o \ 
     65        ui-event.o \ 
     66        ui-menu.o \ 
    6567        util.o  \ 
    6668        variable.o \ 
  • trunk/src/birth.c

    r505 r542  
    1111#include "angband.h" 
    1212#include "cmds.h" 
    13  
     13#include "ui-menu.h" 
    1414 
    1515 
     
    800800/* Display a gender */ 
    801801static void display_gender(menu_type *menu, int oid, bool cursor, 
    802                                                        int row, int col, int width) 
     802                           int row, int col, int width) 
    803803{ 
    804804        byte attr = curs_attrs[CURS_KNOWN][0 != cursor]; 
     
    814814/* RACE */ 
    815815static void display_race(menu_type *menu, int oid, bool cursor, 
    816                                                int row, int col, int width) 
     816                        int row, int col, int width) 
    817817{ 
    818818        byte attr = curs_attrs[CURS_KNOWN][0 != cursor]; 
     
    828828/* CLASS */ 
    829829static void display_class(menu_type *menu, int oid, bool cursor, 
    830                                                        int row, int col, int width) 
     830                          int row, int col, int width) 
    831831{ 
    832832        byte attr = curs_attrs[0 != (rp_ptr->choice & (1L << oid))][0 != cursor]; 
     
    842842/* ROLLER */ 
    843843static void display_roller(menu_type *menu, int oid, bool cursor, 
    844                                                        int row, int col, int width) 
     844                           int row, int col, int width) 
    845845{ 
    846846        byte attr = curs_attrs[CURS_KNOWN][0 != cursor]; 
     
    953953        while (i < (int)N_ELEMENTS(menu_defs)) 
    954954        { 
    955                 event_type cx; 
     955                ui_event_data cx; 
    956956                int cursor = *values[i]; 
    957957 
  • trunk/src/cmd0.c

    r526 r542  
    1818#include "angband.h" 
    1919#include "cmds.h" 
    20  
     20#include "ui-menu.h" 
    2121 
    2222/* 
     
    463463        region area = { 23, 4, 37, 13 }; 
    464464 
    465         event_type evt; 
     465        ui_event_data evt; 
    466466        int cursor = 0; 
    467467        command_type *selection = selection_p; 
     
    528528        region area = { 21, 5, 37, 6 }; 
    529529 
    530         event_type evt; 
     530        ui_event_data evt; 
    531531        int cursor = 0; 
    532532        command_type chosen_command = { NULL, 0, NULL }; 
  • trunk/src/cmd4.c

    r532 r542  
    2020#include "option.h" 
    2121#include "ui.h" 
    22  
     22#include "ui-menu.h" 
    2323 
    2424 
     
    204204                                byte attr_top, char char_left); 
    205205 
    206 static bool visual_mode_command(event_type ke, bool *visual_list_ptr,  
     206static bool visual_mode_command(ui_event_data ke, bool *visual_list_ptr,  
    207207                                int height, int width,  
    208208                                byte *attr_top_ptr, char *char_left_ptr,  
     
    479479        o_funcs.is_visual = FALSE; 
    480480 
    481         menu_init(&group_menu, MN_SCROLL, MN_STRING, &group_region); 
     481        menu_init(&group_menu, MN_SCROLL, MN_STRINGS, &group_region); 
    482482        menu_init2(&object_menu, find_menu_skin(MN_SCROLL), &object_iter, &object_region); 
    483483 
     
    488488        while ((!flag) && (grp_cnt)) 
    489489        { 
    490                 event_type ke, ke0; 
     490                ui_event_data ke, ke0; 
    491491 
    492492                if (redraw) 
     
    777777 *  Do visual mode command -- Change symbols 
    778778 */ 
    779 static bool visual_mode_command(event_type ke, bool *visual_list_ptr,  
     779static bool visual_mode_command(ui_event_data ke, bool *visual_list_ptr,  
    780780                                int height, int width,  
    781781                                byte *attr_top_ptr, char *char_left_ptr,  
     
    19321932void do_cmd_change_name(void) 
    19331933{ 
    1934         event_type ke; 
     1934        ui_event_data ke; 
    19351935 
    19361936        int mode = 0; 
     
    20402040void do_cmd_messages(void) 
    20412041{ 
    2042         event_type ke; 
     2042        ui_event_data ke; 
    20432043 
    20442044        int i, j, n, q; 
     
    23382338        while (TRUE) 
    23392339        { 
    2340                 event_type cx; 
     2340                ui_event_data cx; 
    23412341 
    23422342                cx = menu_select(menu, &cursor_pos, EVT_MOVE); 
     
    23762376        int x = 0; 
    23772377 
    2378         event_type ke; 
     2378        ui_event_data ke; 
    23792379 
    23802380        u32b new_flags[ANGBAND_TERM_MAX]; 
     
    29872987 */ 
    29882988 
    2989 static event_action macro_actions[] = 
     2989static menu_action macro_actions[] = 
    29902990{ 
    29912991        {LOAD_PREF, "Load a user pref file", 0}, 
     
    30313031        while (1) 
    30323032        { 
    3033                 event_type c; 
     3033                ui_event_data c; 
    30343034                int evt; 
    30353035 
     
    35043504} 
    35053505 
    3506 event_action visual_menu_items [] = 
     3506menu_action visual_menu_items [] = 
    35073507{ 
    35083508        { LOAD_PREF, "Load a user pref file", 0, 0}, 
     
    35363536        while (1) 
    35373537        { 
    3538                 event_type key; 
     3538                ui_event_data key; 
    35393539                int evt = -1; 
    35403540                clear_from(0); 
     
    36823682 
    36833683 
    3684 static event_action color_events [] = 
     3684static menu_action color_events [] = 
    36853685{ 
    36863686        {LOAD_PREF, "Load a user pref file", 0, 0}, 
     
    37103710        while (1) 
    37113711        { 
    3712                 event_type key; 
     3712                ui_event_data key; 
    37133713                int evt; 
    37143714                clear_from(0); 
     
    39513951 */ 
    39523952 
    3953 static event_action option_actions [] =  
     3953static menu_action option_actions [] =  
    39543954{ 
    39553955        {'1', "Interface options", do_cmd_options_aux, (void*)0},  
     
    40154015{ 
    40164016        int cursor = 0; 
    4017         event_type c = EVENT_EMPTY; 
     4017        ui_event_data c = EVENT_EMPTY; 
    40184018 
    40194019        screen_save(); 
     
    40724072        int cursor = 0; 
    40734073        int i; 
    4074         event_type c = EVENT_EMPTY; 
     4074        ui_event_data c = EVENT_EMPTY; 
    40754075        region knowledge_region = { 0, 0, -1, 11 }; 
    40764076 
     
    41584158        menu->menu_data = macro_actions; 
    41594159        menu->count = N_ELEMENTS(macro_actions); 
    4160         menu_init(menu, MN_SCROLL, MN_EVT, &SCREEN_REGION); 
     4160        menu_init(menu, MN_SCROLL, MN_ACTIONS, &SCREEN_REGION); 
    41614161 
    41624162        /* visuals menu */ 
     
    41694169        menu->menu_data = visual_menu_items; 
    41704170        menu->count = N_ELEMENTS(visual_menu_items); 
    4171         menu_init(menu, MN_SCROLL, MN_EVT, &SCREEN_REGION); 
     4171        menu_init(menu, MN_SCROLL, MN_ACTIONS, &SCREEN_REGION); 
    41724172 
    41734173        /* colors menu */ 
     
    41804180        menu->menu_data = color_events; 
    41814181        menu->count = N_ELEMENTS(color_events); 
    4182         menu_init(menu, MN_SCROLL, MN_EVT, &SCREEN_REGION); 
     4182        menu_init(menu, MN_SCROLL, MN_ACTIONS, &SCREEN_REGION); 
    41834183 
    41844184        /* knowledge menu */ 
     
    41894189        menu->menu_data = knowledge_actions; 
    41904190        menu->count = N_ELEMENTS(knowledge_actions), 
    4191         menu_init(menu, MN_SCROLL, MN_ACT, &SCREEN_REGION); 
     4191        menu_init(menu, MN_SCROLL, MN_ITEMS, &SCREEN_REGION); 
    41924192 
    41934193        /* initialize other static variables */ 
  • trunk/src/externs.h

    r538 r542  
    630630/* typeutils.c */ 
    631631void display_panel(const data_panel *panel, int count, 
    632                                        bool left_adj, const region *bounds); 
     632                   bool left_adj, const region *bounds); 
    633633 
    634634/* util.c */ 
     
    643643extern void flush_fail(void); 
    644644extern char inkey(void); 
    645 extern event_type inkey_ex(void); 
     645extern ui_event_data inkey_ex(void); 
    646646extern char anykey(void); 
    647647extern void bell(cptr reason); 
     
    670670extern bool get_check(cptr prompt); 
    671671extern bool get_com(cptr prompt, char *command); 
    672 extern bool get_com_ex(cptr prompt, event_type *command); 
     672extern bool get_com_ex(cptr prompt, ui_event_data *command); 
    673673extern void grid_data_as_text(grid_data *g, byte *ap, char *cp, byte *tap, char *tcp); 
    674674extern void pause_line(int row); 
  • trunk/src/main-ros.c

    r507 r542  
    297297 
    298298/* V, post3.0.7, has conflicting types for these we have to #define around */ 
    299 #undef event_type 
    300299#undef menu_flags 
    301300#undef menu_item 
  • trunk/src/main-win.c

    r538 r542  
    24472447{ 
    24482448        term_data *td = &data[0]; 
    2449         event_type ch; 
     2449        ui_event_data ch; 
    24502450 
    24512451        /* Only in graphics mode since the fonts can't be scaled */ 
  • trunk/src/squelch.c

    r399 r542  
    1919#include "angband.h" 
    2020#include "cmds.h" 
    21  
     21#include "ui-menu.h" 
    2222 
    2323/* 
     
    604604        menu_iter menu_f = { 0, 0, 0, quality_subdisplay, quality_subaction }; 
    605605        region area = { 24, 5, 26, SQUELCH_MAX }; 
    606         event_type evt; 
     606        ui_event_data evt; 
    607607        int cursor; 
    608608 
     
    643643        menu_iter menu_f = { 0, 0, 0, quality_display, quality_action }; 
    644644        region area = { 1, 5, -1, -1 }; 
    645         event_type evt = EVENT_EMPTY; 
     645        ui_event_data evt = EVENT_EMPTY; 
    646646        int cursor = 0; 
    647647 
     
    724724        menu_iter menu_f = { 0, 0, 0, sval_display, sval_action }; 
    725725        region area = { 1, 5, -1, -1 }; 
    726         event_type evt = { EVT_NONE, 0, 0, 0, 0 }; 
     726        ui_event_data evt = { EVT_NONE, 0, 0, 0, 0 }; 
    727727        int cursor = 0; 
    728728 
     
    916916{ 
    917917        int cursor = 0; 
    918         event_type c = EVENT_EMPTY; 
     918        ui_event_data c = EVENT_EMPTY; 
    919919        const char cmd_keys[] = { ARROW_LEFT, ARROW_RIGHT, '\0' }; 
    920920 
  • trunk/src/store.c

    r531 r542  
    1919#include "angband.h" 
    2020#include "cmds.h" 
    21  
     21#include "ui-menu.h" 
    2222 
    2323/*** Constants and definitions ***/ 
     
    26602660 
    26612661        menu_type menu; 
    2662         event_type evt = EVENT_EMPTY; 
     2662        ui_event_data evt = EVENT_EMPTY; 
    26632663        int cursor = 0; 
    26642664 
  • trunk/src/types.h

    r531 r542  
    936936        s16b command_dir;               /* Gives direction of current command */ 
    937937        int  command_inv;               /* Gives item of current command */ 
    938         event_type command_cmd_ex; /* Gives additional information of current command */ 
     938        ui_event_data command_cmd_ex; /* Gives additional information of current command */ 
    939939 
    940940        s16b command_see;               /* See "cmd1.c" */ 
     
    11031103}; 
    11041104 
     1105/* ============= Defines a visual grouping ============ */ 
     1106typedef struct 
     1107{ 
     1108        byte tval; 
     1109        cptr name; 
     1110} grouper; 
     1111 
    11051112/* Information for object auto-inscribe */ 
    11061113struct autoinscription 
  • trunk/src/ui.c

    r489 r542  
    11/* 
    22 * File: ui.c 
    3  * Purpose: Generic menu interaction functions 
     3 * Purpose: Generic ui functions 
    44 * 
    55 * Copyright (c) 2007 Pete Mack and others. 
     
    1717 */ 
    1818#include "angband.h" 
    19  
    20 /* 
    21  * Implementation of Extremely Basic Event Model. 
    22  * Limits: 
    23  *   all events are of the concrete type event_type (see z-util.h),  
    24  *   which are supposed to model simple UI actions: 
    25  *      - < escape > 
    26  *      - keystroke 
    27  *      - mousepress 
    28  *      - select menu element 
    29  *      - move menu cursor 
    30  *      - back to parent (hierarchical menu escape) 
    31  * 
    32  * There are 3 basic event-related classes: 
    33  * The event_type. 
    34  * Concrete event, with at most 32 distinct types. 
    35  * 
    36  * The event_listener observer for key events 
    37  * 
    38  * The event_target   The registrar for event_listeners. 
    39  * For convenience, the event target is also an event_listener. 
    40  */ 
    41  
    42 /* Some useful constants */ 
    43 const char default_choice[] = 
    44         "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 
    45  
    46 const char lower_case[] = "abcdefghijklmnopqrstuvwxyz"; 
    47 const char upper_case[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
    48  
    49 int jumpscroll = 0; 
    50 int menu_width = 23; 
    51  
    52 /* forward declarations */ 
    53 static void display_menu_row(menu_type *menu, int pos, int top, 
    54                                                          bool cursor, int row, int col, int width); 
    5519 
    5620/* =================== GEOMETRY ================= */ 
     
    7337} 
    7438 
    75 bool region_inside(const region *loc, const event_type *key) 
     39bool region_inside(const region *loc, const ui_event_data *key) 
    7640{ 
    7741        if ((loc->col > key->mousex) || (loc->col + loc->width <= key->mousex)) 
     
    8347        return TRUE; 
    8448} 
    85  
    86 /* ======================= EVENTS ======================== */ 
    87  
    88 /* List of event listeners--Helper class for event_target and the event loop */ 
    89 struct listener_list 
    90 { 
    91         event_listener *listener; 
    92         struct listener_list *next; 
    93 }; 
    94  
    95  
    96 void stop_event_loop() 
    97 { 
    98         event_type stop = { EVT_STOP, 0, 0, 0, 0 }; 
    99  
    100         /* Stop right away! */ 
    101         Term_event_push(&stop); 
    102 } 
    103  
    104 /* 
    105  * Primitive event loop. 
    106  *  - target = the event target 
    107  *  - forever - if false, stop at first unhandled event. Otherwise, stop only 
    108  *    for STOP events 
    109  *  - start - optional initial event that allows you to prime the loop without 
    110  *    pushing the event queue. 
    111  *  Returns: 
    112  *    EVT_STOP - the loop was halted. 
    113  *    EVT_AGAIN - start was not handled, and forever is false 
    114  *    The first unhandled event - forever is false. 
    115  */ 
    116 event_type run_event_loop(event_target * target, bool forever, const event_type *start) 
    117 { 
    118         event_type ke = EVENT_EMPTY; 
    119         bool handled = TRUE; 
    120  
    121         while (forever || handled) 
    122         { 
    123                 listener_list *list = target->observers; 
    124                 handled = FALSE; 
    125  
    126                 if (start) ke = *start; 
    127                 else ke = inkey_ex(); 
    128  
    129                 if (ke.type == EVT_STOP) 
    130                         break; 
    131  
    132                 if (ke.type & target->self.events.evt_flags) 
    133                         handled = target->self.handler(target->self.object, &ke); 
    134  
    135                 if (!target->is_modal) 
    136                 { 
    137                         while (list && !handled) 
    138                         { 
    139                                 if (ke.type & list->listener->events.evt_flags) 
    140                                         handled = list->listener->handler(list->listener->object, &ke); 
    141  
    142                                 list = list->next; 
    143                         } 
    144                 } 
    145  
    146                 if (handled) start = NULL; 
    147         } 
    148  
    149         if (start) 
    150         { 
    151                 ke.type = EVT_AGAIN; 
    152                 ke.key = '\xff'; 
    153         } 
    154  
    155         return ke; 
    156 } 
    157  
    158 void add_listener(event_target * target, event_listener * observer) 
    159 { 
    160         listener_list *link; 
    161  
    162         link = ZNEW(listener_list); 
    163         link->listener = observer; 
    164         link->next = target->observers; 
    165         target->observers = link; 
    166 } 
    167  
    168 void remove_listener(event_target * target, event_listener * observer) 
    169 { 
    170         listener_list *cur = target->observers; 
    171         listener_list **prev = &target->observers; 
    172  
    173         while (cur) 
    174         { 
    175                 if (cur->listener == observer) 
    176                 { 
    177                         *prev = cur->next; 
    178                         FREE(cur); 
    179                         break; 
    180                 } 
    181         } 
    182  
    183         bell("remove_listener: no such observer"); 
    184 } 
    185  
    186  
    187  
    188 /* ======================= MN_EVT HELPER FUNCTIONS ====================== */ 
    189  
    190 /* Display an event, with possible preference overrides */ 
    191 static void display_event_aux(event_action *event, int menu_id, byte color, int row, int col, int wid) 
    192 { 
    193         /* TODO: add preference support */ 
    194         /* TODO: wizard mode should show more data */ 
    195         Term_erase(col, row, wid); 
    196  
    197         if (event->name) 
    198                 Term_putstr(col, row, wid, color, event->name); 
    199 } 
    200  
    201 static void display_event(menu_type *menu, int oid, bool cursor, int row, int col, int width) 
    202 { 
    203         event_action *evts = (event_action *)menu->menu_data; 
    204         byte color = curs_attrs[CURS_KNOWN][0 != cursor]; 
    205  
    206         display_event_aux(&evts[oid], menu->target.self.object_id, color, row, col, 
    207                                           width); 
    208 } 
    209  
    210 /* act on selection only */ 
    211 /* Return: true if handled. */ 
    212 static bool handle_menu_item_event(char cmd, void *db, int oid) 
    213 { 
    214         event_action *evt = &((event_action *)db)[oid]; 
    215  
    216         if (cmd == '\xff' && evt->action) 
    217         { 
    218                 evt->action(evt->data, evt->name); 
    219                 return TRUE; 
    220         } 
    221         else if (cmd == '\xff') 
    222         { 
    223                 return TRUE; 
    224         } 
    225  
    226         return FALSE; 
    227 } 
    228  
    229 static int valid_menu_event(menu_type *menu, int oid) 
    230 { 
    231         event_action *evts = (event_action *)menu->menu_data; 
    232         return (NULL != evts[oid].name); 
    233 } 
    234  
    235 /* Virtual function table for action_events */ 
    236 static const menu_iter menu_iter_event = 
    237 { 
    238         MN_EVT, 
    239         0, 
    240         valid_menu_event, 
    241         display_event, 
    242         handle_menu_item_event 
    243 }; 
    244  
    245  
    246 /*======================= MN_ACT HELPER FUNCTIONS ====================== */ 
    247  
    248 static char tag_menu_item(menu_type *menu, int oid) 
    249 { 
    250         menu_item *items = (menu_item *)menu->menu_data; 
    251         return items[oid].sel; 
    252 } 
    253  
    254 static void display_menu_item(menu_type *menu, int oid, bool cursor, int row, int col, int width) 
    255 { 
    256         menu_item *items = (menu_item *)menu->menu_data; 
    257         byte color = curs_attrs[!(items[oid].flags & (MN_GRAYED))][0 != cursor]; 
    258  
    259         display_event_aux(&items[oid].evt, menu->target.self.object_id, color, row, 
    260                                           col, width); 
    261 } 
    262  
    263 /* act on selection only */ 
    264 static bool handle_menu_item(char cmd, void *db, int oid) 
    265 { 
    266         if (cmd == '\xff') 
    267         { 
    268                 menu_item *item = &((menu_item *)db)[oid]; 
    269  
    270                 if (item->flags & MN_DISABLED) 
    271                         return TRUE; 
    272                 if (item->evt.action) 
    273                         item->evt.action(item->evt.data, item->evt.name); 
    274                 if (item->flags & MN_SELECTABLE) 
    275                         item->flags ^= MN_SELECTED; 
    276  
    277                 return TRUE; 
    278         } 
    279  
    280         return FALSE; 
    281 } 
    282  
    283 static int valid_menu_item(menu_type *menu, int oid) 
    284 { 
    285         menu_item *items = (menu_item *)menu->menu_data; 
    286  
    287         if (items[oid].flags & MN_HIDDEN) 
    288                 return 2; 
    289  
    290         return (NULL != items[oid].evt.name); 
    291 } 
    292  
    293 /* Virtual function table for menu items */ 
    294 static const menu_iter menu_iter_item = 
    295 { 
    296         MN_ACT, 
    297         tag_menu_item, 
    298         valid_menu_item, 
    299         display_menu_item, 
    300         handle_menu_item 
    301 }; 
    302  
    303 /* Simple strings - display and selection only */ 
    304 static void display_string(menu_type *menu, int oid, bool cursor, 
    305                int row, int col, int width) 
    306 { 
    307         const char **items = (const char **)menu->menu_data; 
    308         byte color = curs_attrs[CURS_KNOWN][0 != cursor]; 
    309         Term_putstr(col, row, width, color, items[oid]); 
    310 } 
    311  
    312 /* Virtual function table for displaying arrays of strings */ 
    313 static const menu_iter menu_iter_string = 
    314 { MN_STRING, 0, 0, display_string, 0 }; 
    315  
    316  
    317  
    318  
    319 /* ================== SKINS ============== */ 
    320  
    321  
    322 /* Scrolling menu */ 
    323 /* Find the position of a cursor given a screen address */ 
    324 static int scrolling_get_cursor(int row, int col, int n, int top, region *loc) 
    325 { 
    326         int cursor = row - loc->row + top; 
    327         if (cursor >= n) cursor = n - 1; 
    328  
    329         return cursor; 
    330 } 
    331  
    332  
    333 /* Display current view of a skin */ 
    334 static void display_scrolling(menu_type *menu, int cursor, int *top, region *loc) 
    335 { 
    336         int col = loc->col; 
    337         int row = loc->row; 
    338         int rows_per_page = loc->page_rows; 
    339         int n = menu->filter_count; 
    340         int i; 
    341  
    342         /* Keep a certain distance from the top when possible */ 
    343         if ((cursor <= *top) && (*top > 0)) 
    344                 *top = cursor - jumpscroll - 1; 
    345  
    346         /* Keep a certain distance from the bottom when possible */ 
    347         if (cursor >= *top + (rows_per_page - 1)) 
    348                 *top = cursor - (rows_per_page - 1) + 1 + jumpscroll; 
    349  
    350         /* Limit the top to legal places */ 
    351         *top = MIN(*top, n - rows_per_page); 
    352         *top = MAX(*top, 0); 
    353  
    354  
    355         for (i = 0; i < rows_per_page && i < n; i++) 
    356         { 
    357                 bool is_curs = (i == cursor - *top); 
    358                 display_menu_row(menu, i + *top, *top, is_curs, row + i, col, 
    359                                                  loc->width); 
    360         } 
    361  
    362         if (menu->cursor >= 0) 
    363                 Term_gotoxy(col, row + cursor - *top); 
    364 } 
    365  
    366 static char scroll_get_tag(menu_type *menu, int pos) 
    367 { 
    368         if (menu->selections) 
    369                 return menu->selections[pos - menu->top]; 
    370  
    371         return 0; 
    372 } 
    373  
    374 /* Virtual function table for scrollable menu skin */ 
    375 static const menu_skin scroll_skin = 
    376 { 
    377         MN_SCROLL, 
    378         scrolling_get_cursor, 
    379         display_scrolling, 
    380         scroll_get_tag 
    381 }; 
    382  
    383  
    384 /* Multi-column menu */ 
    385 /* Find the position of a cursor given a screen address */ 
    386 static int columns_get_cursor(int row, int col, int n, int top, region *loc) 
    387 { 
    388         int rows_per_page = loc->page_rows; 
    389         int colw = loc->width / (n + rows_per_page - 1) / rows_per_page; 
    390         int cursor = row + rows_per_page * (col - loc->col) / colw; 
    391  
    392         if (cursor < 0) cursor = 0;     /* assert: This should never happen */ 
    393         if (cursor >= n) cursor = n - 1; 
    394  
    395         return cursor; 
    396 } 
    397  
    398 void display_columns(menu_type *menu, int cursor, int *top, region *loc) 
    399 { 
    400         int c, r; 
    401         int w, h; 
    402         int n = menu->filter_count; 
    403         int col = loc->col; 
    404         int row = loc->row; 
    405         int rows_per_page = loc->page_rows; 
    406         int cols = (n + rows_per_page - 1) / rows_per_page; 
    407         int colw = menu_width; 
    408  
    409         Term_get_size(&w, &h); 
    410  
    411         if ((colw * cols) > (w - col)) 
    412                 colw = (w - col) / cols; 
    413  
    414         for (c = 0; c < cols; c++) 
    415         { 
    416                 for (r = 0; r < rows_per_page; r++) 
    417                 { 
    418                         int pos = c * rows_per_page + r; 
    419                         bool is_cursor = (pos == cursor); 
    420                         display_menu_row(menu, pos, 0, is_cursor, row + r, col + c * colw, 
    421                                                          colw); 
    422                 } 
    423         } 
    424 } 
    425  
    426 static char column_get_tag(menu_type *menu, int pos) 
    427 { 
    428         if (menu->selections) 
    429                 return menu->selections[pos]; 
    430  
    431         return 0; 
    432 } 
    433  
    434 /* Virtual function table for multi-column menu skin */ 
    435 static const menu_skin column_skin = 
    436 { 
    437         MN_COLUMNS, 
    438         columns_get_cursor, 
    439         display_columns, 
    440         column_get_tag 
    441 }; 
    442  
    443 /* ================== IMPLICIT MENU FOR KEY SELECTION ================== */ 
    444  
    445 static void display_nothing(menu_type *menu, int cursor, int *top, region *loc) 
    446 { 
    447 } 
    448  
    449 static int no_cursor(int row, int col, int n, int top, region *loc) 
    450 { 
    451         return -1; 
    452 } 
    453  
    454 static const menu_skin key_select_skin = 
    455 { 
    456         MN_KEY_ONLY, 
    457         no_cursor, 
    458         display_nothing, 
    459 }; 
    460  
    461  
    462 /* ================== GENERIC HELPER FUNCTIONS ============== */ 
    463  
    464 static bool is_valid_row(menu_type *menu, int cursor) 
    465 { 
    466         int oid = cursor; 
    467  
    468         if (cursor < 0 || cursor >= menu->filter_count) 
    469                 return FALSE; 
    470  
    471         if (menu->object_list) 
    472                 oid = menu->object_list[cursor]; 
    473  
    474         if (!menu->row_funcs->valid_row) 
    475                 return TRUE; 
    476  
    477         return menu->row_funcs->valid_row(menu, oid); 
    478 } 
    479  
    480 /*  
    481  * Return a new position in the menu based on the key 
    482  * pressed and the flags and various handler functions. 
    483  */ 
    484 static int get_cursor_key(menu_type *menu, int top, char key) 
    485 { 
    486         int i; 
    487         int n = menu->filter_count; 
    488  
    489         if (menu->flags & MN_CASELESS_TAGS) 
    490                 key = toupper((unsigned char) key); 
    491  
    492         if (menu->flags & MN_NO_TAGS) 
    493         { 
    494                 return -1; 
    495         } 
    496         else if (menu->flags & MN_REL_TAGS) 
    497         { 
    498                 for (i = 0; i < n; i++) 
    499                 { 
    500                         char c = menu->skin->get_tag(menu, i); 
    501  
    502                         if ((menu->flags & MN_CASELESS_TAGS) && c) 
    503                                 c = toupper((unsigned char) c); 
    504  
    505                         if (c && c == key) 
    506                                 return i + menu->top; 
    507                 } 
    508         } 
    509         else if (!(menu->flags & MN_PVT_TAGS) && menu->selections) 
    510         { 
    511                 for (i = 0; menu->selections[i]; i++) 
    512                 { 
    513                         char c = menu->selections[i]; 
    514  
    515                         if (menu->flags & MN_CASELESS_TAGS) 
    516                                 c = toupper((unsigned char) c); 
    517  
    518                         if (c == key) 
    519                                 return i; 
    520                 } 
    521         } 
    522         else if (menu->row_funcs->get_tag) 
    523         { 
    524                 for (i = 0; i < n; i++) 
    525                 { 
    526                         int oid = menu->object_list ? menu->object_list[i] : i; 
    527                         char c = menu->row_funcs->get_tag(menu, oid); 
    528  
    529                         if ((menu->flags & MN_CASELESS_TAGS) && c) 
    530                                 c = toupper((unsigned char) c); 
    531  
    532                         if (c && c == key) 
    533                                 return i; 
    534                 } 
    535         } 
    536  
    537         return -1; 
    538 } 
    539  
    540 /* 
    541  * Event handler wrapper function 
    542  * Filters unhandled keys & conditions  
    543  */ 
    544 static bool handle_menu_key(char cmd, menu_type *menu, int cursor) 
    545 { 
    546         int oid = cursor; 
    547         int flags = menu->flags; 
    548  
    549         if (menu->object_list) oid = menu->object_list[cursor]; 
    550         if (flags & MN_NO_ACT) return FALSE; 
    551  
    552         if (cmd == ESCAPE) return FALSE; 
    553         if (!cmd == '\xff' && (!menu->cmd_keys || !strchr(menu->cmd_keys, cmd))) 
    554                 return FALSE; 
    555  
    556         if (menu->row_funcs->row_handler && 
    557                 menu->row_funcs->row_handler(cmd, (void *)menu->menu_data, oid)) 
    558         { 
    559                 event_type ke; 
    560                 ke.type = EVT_SELECT; 
    561                 ke.key = cmd; 
    562                 ke.index = cursor; 
    563                 Term_event_push(&ke); 
    564                 return TRUE; 
    565         } 
    566  
    567         return FALSE; 
    568 } 
    569  
    570 /* Modal display of menu */ 
    571 static void display_menu_row(menu_type *menu, int pos, int top, 
    572                              bool cursor, int row, int col, int width) 
    573 { 
    574         int flags = menu->flags; 
    575         char sel = 0; 
    576         int oid = pos; 
    577  
    578         if (menu->object_list) 
    579                 oid = menu->object_list[oid]; 
    580  
    581         if (menu->row_funcs->valid_row && menu->row_funcs->valid_row(menu, oid) == 2) 
    582                 return; 
    583  
    584         if (!(flags & MN_NO_TAGS)) 
    585         { 
    586                 if (flags & MN_REL_TAGS) 
    587                         sel = menu->skin->get_tag(menu, pos); 
    588                 else if (menu->selections && !(flags & MN_PVT_TAGS)) 
    589                         sel = menu->selections[pos]; 
    590                 else if (menu->row_funcs->get_tag) 
    591                         sel = menu->row_funcs->get_tag(menu, oid); 
    592         } 
    593  
    594         if (sel) 
    595         { 
    596                 /* TODO: CHECK FOR VALID */ 
    597                 byte color = curs_attrs[CURS_KNOWN][0 != (cursor)]; 
    598                 Term_putstr(col, row, 3, color, format("%c) ", sel)); 
    599                 col += 3; 
    600                 width -= 3; 
    601         } 
    602  
    603         menu->row_funcs->display_row(menu, oid, cursor, row, col, width); 
    604 } 
    605  
    606 void menu_refresh(menu_type *menu) 
    607 { 
    608         region *loc = &menu->boundary; 
    609         int oid = menu->cursor; 
    610  
    611         if (menu->object_list && menu->cursor >= 0) 
    612                 oid = menu->object_list[oid]; 
    613  
    614         region_erase(&menu->boundary); 
    615  
    616         if (menu->title) 
    617                 Term_putstr(loc->col, loc->row, loc->width, TERM_WHITE, menu->title); 
    618  
    619         if (menu->prompt) 
    620                 Term_putstr(loc->col, loc->row + loc->page_rows - 1, loc->width, 
    621                                         TERM_WHITE, menu->prompt); 
    622  
    623         if (menu->browse_hook && oid >= 0) 
    624                 menu->browse_hook(oid, (void*) menu->menu_data, loc); 
    625  
    626         menu->skin->display_list(menu, menu->cursor, &menu->top, &menu->active); 
    627 } 
    628  
    629 /* The menu event loop */ 
    630 static bool menu_handle_event(menu_type *menu, const event_type *in) 
    631 { 
    632         int n = menu->filter_count; 
    633         int *cursor = &menu->cursor; 
    634         event_type out; 
    635  
    636         out.key = '\xff'; 
    637  
    638         if (menu->target.observers) 
    639         { 
    640                 /* TODO: need a panel dispatcher here, not a generic target */ 
    641                 event_target t = { { 0, 0, 0, 0, { 0 } }, FALSE, 0 /* menu->target.observers */}; 
    642                 t.observers = menu->target.observers; 
    643