From: PatR Date: Mon, 15 Feb 2016 08:59:33 +0000 (-0800) Subject: X11 extended command menu scrolling X-Git-Tag: NetHack-3.6.1_RC01~921 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8d2a74b5b03b2fb7b44367ef04b470ba23933dca;p=nethack X11 extended command menu scrolling When the extended command menu auto-scrolls as the player types in characters, scroll so that all matching entries come into view rather than just the first one. For example, it someone types 'w', instead of just highlighting and showing "wipe", it will highlight "wipe" (because that has become the default response when is used) but also show "wiz-this", "wiz-that", and "wmode". It actually shows one extra entry beyond the last matching one--so you can see that there aren't any more ambiguous choices--except for 'w' where "wmode" is the very last extended command. Previously, on subsequent popups of the extended command menu, the scrollbar's slider was left drawn in the position it was in during the previous time even though menu content wasn't scrolled. Now it's forced back to the top (non-scrolled) position when that menu is popped up. --- diff --git a/win/X11/winmisc.c b/win/X11/winmisc.c index 114d8b3d6..23253f4a3 100644 --- a/win/X11/winmisc.c +++ b/win/X11/winmisc.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 winmisc.c $NHDT-Date: 1455415590 2016/02/14 02:06:30 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.23 $ */ +/* NetHack 3.6 winmisc.c $NHDT-Date: 1455526714 2016/02/15 08:58:34 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.24 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -76,6 +76,7 @@ static void FDECL(extend_dismiss, (Widget, XtPointer, XtPointer)); static void FDECL(extend_help, (Widget, XtPointer, XtPointer)); static void FDECL(popup_delete, (Widget, XEvent *, String *, Cardinal *)); static void NDECL(ec_dismiss); +static void FDECL(ec_scroll_to_view, (int)); static void NDECL(init_extended_commands_popup); static Widget FDECL(make_menu, (const char *, const char *, const char *, const char *, XtCallbackProc, const char *, @@ -592,6 +593,7 @@ X11_get_ext_cmd() init_extended_commands_popup(); extended_cmd_selected = -1; /* reset selected value */ + ec_scroll_to_view(-1); /* force scroll bar to top */ positionpopup(extended_command_popup, FALSE); /* center on cursor */ nh_XtPopup(extended_command_popup, (int) XtGrabExclusive, @@ -716,39 +718,87 @@ ec_dismiss() exit_x_event = TRUE; /* leave event loop */ } -void -ec_scroll_to_view() +/* scroll the extended command menu if necessary + so that choices extended_cmd_selected through ec_indx will be visible */ +static void +ec_scroll_to_view(ec_indx) +int ec_indx; /* might be greater than extended_cmd_selected */ { - Arg args[3]; - Cardinal num_args; - Position y, h; /* ext cmd label y and height */ Widget viewport, scrollbar, tmpw; + Arg args[5]; + Cardinal num_args; + Position lo_y, hi_y; /* ext cmd label y */ float s_shown, s_top; /* scrollbar pos */ float s_min, s_max; - Position vh; /* viewport height */ + Dimension h, hh, wh, vh; /* widget and viewport heights */ + Dimension border_width; + int distance; + boolean force_top = (ec_indx < 0); - if (extended_cmd_selected < 0) - return; + /* + * If the extended command menu needs to be scrolled in order to move + * either the highlighted entry (extended_cmd_selected) or the target + * entry (ec_indx) into view, we want to make both end up visible. + * [Highligthed one is the first matching entry when the user types + * something, such as "adjust" after typing 'a', and will be chosen + * by pressing . Target entry is one past the last matching + * entry (or last matching entry itself if at end of command list), + * showing the user the other potential matches so far.] + * + * If that's not possible (maybe menu has been resized so that it's + * too small), the highlighted entry takes precedence and the target + * will be decremented until close enough to fit. + */ - /* get selected ext command label y position and height */ - num_args = 0; - XtSetArg(args[num_args], XtNy, &y); num_args++; - XtSetArg(args[num_args], XtNheight, &h); num_args++; - XtGetValues(extended_commands[extended_cmd_selected], args, num_args); + if (force_top) + ec_indx = 0; /* get viewport and scrollbar widgets */ - tmpw = extended_commands[extended_cmd_selected]; + tmpw = extended_commands[ec_indx]; viewport = XtParent(tmpw); do { - tmpw = XtParent(tmpw); scrollbar = XtNameToWidget(tmpw, "*vertical"); - } while (!scrollbar && tmpw); + if (scrollbar) + break; + tmpw = XtParent(tmpw); + } while (tmpw); if (scrollbar && viewport) { - /* get viewport height */ + /* get selected ext command label y position and height */ num_args = 0; - XtSetArg(args[num_args], XtNheight, &vh); num_args++; - XtGetValues(viewport, args, num_args); + XtSetArg(args[num_args], XtNy, &hi_y); num_args++; + XtSetArg(args[num_args], XtNheight, &h); num_args++; + XtSetArg(args[num_args], nhStr(XtNborderWidth), &border_width); + num_args++; + XtSetArg(args[num_args], nhStr(XtNdefaultDistance), &distance); + num_args++; + XtGetValues(extended_commands[ec_indx], args, num_args); + if (distance < 1 || distance > 32766) /* defaultDistance is weird */ + distance = 4; + /* vertical distance between top of one command widget and the next */ + hh = h + distance + 2 * border_width; + /* location of the highlighted entry, if any */ + if (extended_cmd_selected >= 0) { + XtSetArg(args[0], XtNy, &lo_y); + XtGetValues(extended_commands[extended_cmd_selected], args, ONE); + } else + lo_y = hi_y; + + /* get menu widget and viewport heights */ + XtSetArg(args[0], XtNheight, &wh); + XtGetValues(tmpw, args, ONE); + XtSetArg(args[0], XtNheight, &vh); + XtGetValues(viewport, args, ONE); + + /* widget might be too small if it has been resized or + there are a very large number of ambiguous choices */ + if (hi_y - lo_y > wh) { + ec_indx = extended_cmd_selected; + if (wh > hh) + ec_indx += (wh / hh); + XtSetArg(args[0], XtNy, &hi_y); + XtGetValues(extended_commands[ec_indx], args, num_args); + } /* get scrollbar "height" and "top" position; floats between 0-1 */ num_args = 0; @@ -760,11 +810,14 @@ ec_scroll_to_view() s_max = (s_top + s_shown) * vh; /* scroll if outside the view */ - if ((int)y <= (int)s_min) { - s_min = (float)(y / (float)vh); + if (force_top) { + s_min = 0.0; + XtCallCallbacks(scrollbar, XtNjumpProc, &s_min); + } else if ((int) lo_y <= (int) s_min) { + s_min = (float) (lo_y / (float) vh); XtCallCallbacks(scrollbar, XtNjumpProc, &s_min); - } else if ((int)(y + h) >= (int)s_max) { - s_min = (float)((y+h) / (float)vh) - s_shown; + } else if ((int) (hi_y + h) >= (int) s_max) { + s_min = (float) ((hi_y + h) / (float) vh) - s_shown; XtCallCallbacks(scrollbar, XtNjumpProc, &s_min); } } @@ -856,7 +909,17 @@ Cardinal *num_params; extended_cmd_selected = i; swap_fg_bg(extended_commands[extended_cmd_selected]); } - ec_scroll_to_view(); + /* advance to one past last matching entry, so that all + ambiguous choices, plus one to show thare aren't any + more such, will scroll into view */ + do { + if (!extcmdlist[i + 1].ef_txt + || *extcmdlist[i + 1].ef_txt == '?') + break; /* end of list */ + ++i; + } while (!strncmp(ec_chars, extcmdlist[i].ef_txt, ec_nchars)); + + ec_scroll_to_view(i); return; } } @@ -977,7 +1040,7 @@ Widget *formp; /* return */ XtSetArg(args[num_args], nhStr(XtNdefaultDistance), &distance); num_args++; XtSetArg(args[num_args], nhStr(XtNborderWidth), &border_width); num_args++; XtGetValues(view, args, num_args); - if (!distance) + if (distance < 1 || distance > 32766) distance = 4; /*