'OHRRPGCE CUSTOM - Menu Editor (not to be confused with menu slices editors)
'(C) Copyright 1997-2020 James Paige, Ralph Versteegen, and the OHRRPGCE Developers
'Dual licensed under the GNU GPL v2+ and MIT Licenses. Read LICENSE.txt for terms and disclaimer of liability.

#include "config.bi"
#include "allmodex.bi"
#include "common.bi"
#include "customsubs.bi"
#include "loading.bi"
#include "cglobals.bi"
#include "scrconst.bi"
#include "sliceedit.bi"
#include "custom.bi"

'--Local SUBs
DECLARE SUB update_menu_editor_menu(byval record as integer, edmenu as MenuDef, menu as MenuDef)
DECLARE SUB update_edited_menu(menudata as MenuDef)
DECLARE SUB update_detail_menu(detail as MenuDef, menudata as MenuDef, mi as MenuDefItem)
DECLARE SUB menu_editor_keys (state as MenuState, mstate as MenuState, menudata as MenuDef, byref record as integer, menu_set as MenuSet, viewport_page as integer)
DECLARE SUB menu_editor_menu_keys (mstate as MenuState, dstate as MenuState, menudata as MenuDef, byval record as integer, viewport_page as integer)
DECLARE SUB menu_editor_detail_keys(dstate as MenuState, mstate as MenuState, detail as MenuDef, mi as MenuDefItem)
DECLARE SUB edit_menu_bits (menu as MenuDef)
DECLARE SUB edit_menu_item_bits (mi as MenuDefItem)
DECLARE SUB reposition_menu (menu as MenuDef, mstate as MenuState, viewport_page as integer)
DECLARE SUB reposition_anchor (menu as MenuDef, mstate as MenuState, viewport_page as integer)


SUB menu_editor ()

DIM menu_set as MenuSet
menu_set.menufile = workingdir & SLASH & "menus.bin"
menu_set.itemfile = workingdir & SLASH & "menuitem.bin"

DIM record as integer = 0

DIM state as MenuState 'top level
state.active = YES
state.need_update = YES
DIM mstate as MenuState  'menu being edited
mstate.active = NO
mstate.need_update = YES
DIM dstate as MenuState 'detail state
dstate.active = NO

DIM edmenu as MenuDef  'top level
WITH edmenu
 .textalign = alignLeft
 .alignhoriz = alignLeft
 .alignvert = alignTop
 .anchorhoriz = alignLeft
 .anchorvert = alignTop
 .boxstyle = 3
 .translucent = YES
 .min_chars = 38
END WITH
DIM menudata as MenuDef  'menu being edited
LoadMenuData menu_set, menudata, record
DIM detail as MenuDef  'detail editing menu
WITH detail
 .textalign = alignLeft
 .anchorhoriz = alignLeft
 .anchorvert = alignBottom
 .offset.x = -152
 .offset.y = 92
 .min_chars = 36
END WITH

DIM box_preview as string = ""

DIM viewport_page as integer = gameres_page()

setkeys YES
DO
 setwait 55
 setkeys YES
 
 IF state.active = NO THEN EXIT DO
 IF mstate.active = YES THEN
  menu_editor_menu_keys mstate, dstate, menudata, record, viewport_page
 ELSEIF dstate.active = YES THEN
  menu_editor_detail_keys dstate, mstate, detail, *menudata.items[mstate.pt]
 ELSE
  menu_editor_keys state, mstate, menudata, record, menu_set, viewport_page
 END IF
 
 IF state.need_update THEN
  state.need_update = NO
  update_menu_editor_menu record, edmenu, menudata
  init_menu_state state, edmenu
  init_menu_state mstate, menudata
 END IF
 IF dstate.need_update THEN
  dstate.need_update = NO
  update_detail_menu detail, menudata, *menudata.items[mstate.pt]
  init_menu_state dstate, detail
  WITH *menudata.items[mstate.pt]
   IF .t = mtypeTextBox THEN
    box_preview = textbox_preview_line(.sub_t)
   END IF
  END WITH
  'If any menu item data changed, the menu itself also needs updating
  mstate.need_update = YES
 END IF
 IF mstate.need_update THEN
  mstate.need_update = NO
  update_edited_menu menudata
  init_menu_state mstate, menudata
 END IF
 
 clearpage dpage
 preview_menu menudata, mstate, viewport_page, dpage

 IF mstate.active THEN
  edgeprint "ENTER to edit, Shift+Arrows to re-order", 0, pBottom, uilook(uiDisabledItem), dpage
  IF record = 0 THEN
   edgeprint "CTRL+R to reload default", 0, pBottom - 10, uilook(uiDisabledItem), dpage
  END IF
 END IF
 IF NOT mstate.active AND NOT dstate.active THEN draw_menu edmenu, state, dpage
 IF dstate.active THEN
  draw_menu detail, dstate, dpage
  IF menudata.items[mstate.pt]->t = mtypeTextBox THEN
   edgeprint box_preview, 0, pBottom, uilook(uiText), dpage
  END IF
 END IF
 
 SWAP vpage, dpage
 setvispage vpage
 dowait
LOOP
SaveMenuData menu_set, menudata, record
freepage viewport_page

END SUB

SUB menu_editor_keys (state as MenuState, mstate as MenuState, menudata as MenuDef, byref record as integer, menu_set as MenuSet, viewport_page as integer)
 IF keyval(ccCancel) > 1 THEN state.active = NO
 IF keyval(scF1) > 1 THEN show_help "menu_editor_main"
 
 usemenu state
 
 SELECT CASE state.pt
  CASE 0
   IF enter_space_click(state) THEN
    state.active = NO
   END IF
  CASE 1
   DIM saverecord as integer = record
   IF intgrabber_with_addset(record, 0, gen(genMaxMenu), 32767, "menu") THEN
    IF record > gen(genMaxMenu) THEN gen(genMaxMenu) = record
    SaveMenuData menu_set, menudata, saverecord
    LoadMenuData menu_set, menudata, record
    state.need_update = YES
    mstate.need_update = YES
   END IF
  CASE 2
   IF strgrabber(menudata.name, 20) THEN state.need_update = YES
  CASE 3
   IF enter_space_click(state) THEN
    mstate.active = YES
    mstate.need_update = YES
    menudata.edit_mode = YES
    append_menu_item menudata, "[NEW MENU ITEM]"
   END IF
  CASE 4
   IF intgrabber(menudata.boxstyle, 0, 14) THEN state.need_update = YES
  CASE 5
   IF intgrabber(menudata.textcolor, LowColorCode(), 255) THEN state.need_update = YES
   IF enter_space_click(state) THEN
    menudata.textcolor = color_browser_256(menudata.textcolor)
    state.need_update = YES
   END IF
  CASE 6
   IF intgrabber(menudata.disabled_textcolor, LowColorCode(), 255) THEN state.need_update = YES
   IF enter_space_click(state) THEN
    menudata.disabled_textcolor = color_browser_256(menudata.disabled_textcolor)
    state.need_update = YES
   END IF
  CASE 7
   IF intgrabber(menudata.maxrows, 0, 100) THEN state.need_update = YES
  CASE 8
   IF enter_space_click(state) THEN
    edit_menu_bits menudata
    state.need_update = YES
   END IF
  CASE 9
   IF enter_space_click(state) THEN
    reposition_menu menudata, mstate, viewport_page
   END IF
  CASE 10
   IF enter_space_click(state) THEN
    reposition_anchor menudata, mstate, viewport_page
   END IF
  CASE 11 ' text align
   DIM temp as integer = menudata.textalign  'byte to integer
   IF intgrabber(temp, alignLeft, alignRight) THEN state.need_update = YES
   menudata.textalign = temp
  CASE 12 ' Minimum width in chars
   IF intgrabber(menudata.min_chars, 0, 200) THEN state.need_update = YES
  CASE 13 ' Maximum width in chars
   IF intgrabber(menudata.max_chars, 0, 200) THEN state.need_update = YES
  CASE 14 ' border size
   IF intgrabber(menudata.bordersize, -100, 100) THEN state.need_update = YES
  CASE 15 ' item spacing
   IF intgrabber(menudata.itemspacing, -10, 100) THEN state.need_update = YES
  CASE 16: ' on-close script
   IF enter_space_click(state) THEN
    scriptbrowse menudata.on_close, plottrigger, "menu on-close plotscript"
    state.need_update = YES
   END IF
   IF scrintgrabber(menudata.on_close, 0, 0, ccLeft, ccRight, 1, plottrigger) THEN state.need_update = YES
  CASE 17: ' esc menu
   IF zintgrabber(menudata.esc_menu, -1, gen(genMaxMenu)) THEN state.need_update = YES
 END SELECT
END SUB

SUB menu_editor_menu_keys (mstate as MenuState, dstate as MenuState, menudata as MenuDef, byval record as integer, viewport_page as integer)
 DIM i as integer
 DIM elem as integer

 'Fix the top left corner of the menustate for the menu we are editing so it will match the preview's viewport
 mstate.rect.topleft = (vpages(vpage)->size - vpages(viewport_page)->size) + menudata.rect.topleft + XY(8+menudata.bordersize,8+menudata.bordersize)

 IF keyval(ccCancel) > 1 ORELSE menu_click_outside_with_page(menudata, viewport_page) THEN
  mstate.active = NO
  menudata.edit_mode = NO
  mstate.need_update = YES
  'remove [NEW MENU ITEM]
  remove_menu_item menudata, menudata.last
  EXIT SUB
 END IF
 IF keyval(scF1) > 1 THEN show_help "menu_editor_items"

 usemenu mstate
 IF mstate.pt >= 0 AND mstate.pt < menudata.numitems THEN
 WITH *menudata.items[mstate.pt]
  IF NOT (menudata.edit_mode = YES AND .trueorder.next = NULL) THEN  'not the last item, "NEW MENU ITEM"
   IF strgrabber(.caption, 38) THEN
    'Space should not enter the menu
   ELSEIF enter_space_click(mstate) THEN
    mstate.active = NO
    dstate.active = YES
    dstate.need_update = YES
   END IF
   IF keyval(scDelete) > 1 THEN
    IF yesno("Delete this menu item?", NO) THEN
     remove_menu_item menudata, mstate.pt
     mstate.need_update = YES
    END IF
   END IF
   IF keyval(scShift) > 0 THEN
    IF keyval(ccUp) > 1 AND mstate.pt < mstate.last - 1 THEN ' just went up
     'NOTE: Cursor will have already moved because of usemenu call above
     swap_menu_items menudata, mstate.pt, menudata, mstate.pt + 1
     mstate.need_update = YES
    END IF
    IF keyval(ccDown) > 1 AND mstate.pt > mstate.first THEN ' just went down
     'NOTE: Cursor will have already moved because of usemenu call above
     swap_menu_items menudata, mstate.pt, menudata, mstate.pt - 1
     mstate.need_update = YES
    END IF
   END IF
  ELSE
   IF menudata.edit_mode = YES THEN
    'Selecting the item that appends new items
    IF enter_space_click(mstate) THEN
     menudata.last->caption = ""
     append_menu_item menudata, "[NEW MENU ITEM]"
     mstate.active = NO
     mstate.need_update = YES
     dstate.active = YES
     dstate.need_update = YES
    END IF
   END IF
  END IF
 END WITH
 END IF' above block only runs with a valid mstate.pt

 IF record = 0 THEN
  IF keyval(scCtrl) > 0 AND keyval(scR) > 1 THEN
   IF yesno("Reload the default main menu?") THEN
    ClearMenuData menudata
    create_default_menu menudata
    append_menu_item menudata, "[NEW MENU ITEM]"
    mstate.need_update = YES
   END IF
  END IF
 END IF
 
END SUB

SUB menu_editor_detail_keys(dstate as MenuState, mstate as MenuState, detail as MenuDef, mi as MenuDefItem)
 DIM max as integer

 IF keyval(ccCancel) > 1 ORELSE menu_click_outside(detail) THEN
  dstate.active = NO
  mstate.active = YES
  EXIT SUB
 END IF
 IF keyval(scF1) > 1 THEN show_help "menu_editor_item_details"

 usemenu dstate

 DIM editaction as integer = detail.items[dstate.pt]->sub_t
 SELECT CASE editaction
  CASE 0: 'go back
   IF enter_space_click(dstate) THEN
    dstate.active = NO
    mstate.active = YES
    EXIT SUB
   END IF
  CASE 1: 'caption
   IF strgrabber(mi.caption, 38) THEN
    dstate.need_update = YES
   END IF
  CASE 2: 'type
   IF intgrabber(mi.t, 0, mtypeLAST) THEN
    mi.sub_t = 0
    dstate.need_update = YES
   END IF
  CASE 3: 'subtype
   SELECT CASE mi.t
    CASE mtypeLabel
     max = lbLAST
    CASE mtypeSpecial
     max = spLAST
    CASE mtypeMenu
     max = gen(genMaxMenu)
    CASE mtypeTextBox
     max = gen(genMaxTextBox)
   END SELECT
   IF mi.t = mtypeScript THEN
    IF scrintgrabber(mi.sub_t, 0, 0, ccLeft, ccRight, 1, plottrigger) THEN dstate.need_update = YES
    IF enter_space_click(dstate) THEN
     scriptbrowse mi.sub_t, plottrigger, "Menu Item Script"
     dstate.need_update = YES
    END IF
   ELSEIF mi.t = mtypeTextBox THEN
    IF textboxgrabber(mi.sub_t, dstate) THEN dstate.need_update = YES
   ELSE
    IF intgrabber(mi.sub_t, 0, max) THEN dstate.need_update = YES
   END IF
  CASE 4: 'conditional tag1
   IF tag_grabber(mi.tag1, dstate) THEN dstate.need_update = YES
  CASE 5: 'conditional tag2
   IF tag_grabber(mi.tag2, dstate) THEN dstate.need_update = YES
  CASE 6: 'set tag
   IF tag_set_grabber(mi.settag, dstate) THEN dstate.need_update = YES
  CASE 7: 'toggle tag
   IF tag_id_grabber(mi.togtag, dstate) THEN dstate.need_update = YES
  CASE 8: ' bitsets
   IF enter_space_click(dstate) THEN
    edit_menu_item_bits mi
    dstate.need_update = YES
   END IF
  CASE 9 TO 11: 'extra data
   'Currently, menu items stored in menuitem.bin always have 3 extra data
   DIM value as integer = mi.extra(editaction - 9)
   IF intgrabber(value, -32768, 32767) THEN
    mi.extra(editaction - 9) = value
    dstate.need_update = YES
   END IF
  CASE 12: 'color
   IF intgrabber(mi.col, LowColorCode(), 255) THEN dstate.need_update = YES
   IF enter_space_click(dstate) THEN
    mi.col = color_browser_256(mi.col)
    dstate.need_update = YES
   END IF
  CASE 13: 'disabled color
   IF intgrabber(mi.disabled_col, LowColorCode(), 255) THEN dstate.need_update = YES
   IF enter_space_click(dstate) THEN
    mi.disabled_col = color_browser_256(mi.disabled_col)
    dstate.need_update = YES
   END IF

 END SELECT

END SUB

SUB update_menu_editor_menu(byval record as integer, edmenu as MenuDef, menu as MenuDef)
 DIM cap as string
 DeleteMenuItems edmenu
 
 append_menu_item edmenu, "Previous Menu"
 
 cap = "Menu " & record
 IF record = 0 THEN cap = cap & " (MAIN MENU)"
 append_menu_item edmenu, cap
 
 append_menu_item edmenu, "Name: " & menu.name
 append_menu_item edmenu, "Edit items..."
 append_menu_item edmenu, "Box style: " & menu.boxstyle
 append_menu_item edmenu, "Text color: " & slice_color_caption(menu.textcolor, "Default UI color")
 append_menu_item edmenu, "Disabled color: " & slice_color_caption(menu.disabled_textcolor, "Default UI color")
 append_menu_item edmenu, "Max rows to display: " & zero_default(menu.maxrows)
 append_menu_item edmenu, "Edit bitsets..."
 append_menu_item edmenu, "Reposition menu..."
 append_menu_item edmenu, "Change anchor point..."
 append_menu_item edmenu, "Text align: " & HorizCaptions(menu.textalign)
 append_menu_item edmenu, "Minimum width: " & zero_default(menu.min_chars, "Automatic")
 append_menu_item edmenu, "Maximum width: " & zero_default(menu.max_chars, "None")
 append_menu_item edmenu, "Border size: " & zero_default(menu.bordersize)
 append_menu_item edmenu, "Item spacing: " & zero_default(menu.itemspacing)
 append_menu_item edmenu, "On-close script: " & scriptname(menu.on_close)
 IF menu.esc_menu = 0 THEN
  cap = "just closes this menu"
 ELSE
  cap = "switch to menu " & menu.esc_menu - 1 & " " & getmenuname(menu.esc_menu - 1)
 END IF
 IF menu.no_close THEN cap = "disabled by bitset"
 append_menu_item edmenu, "Cancel button: " & cap
END SUB

'Update the user-defined menu itself, for tags.
'Note: MenuDefItem.disabled and .unselectable are not saved to disk, hence they can be safely modified.
SUB update_edited_menu(menudata as MenuDef)
 FOR idx as integer = 0 TO menudata.numitems - 1
  WITH *menudata.items[idx]
   .disabled = NO
   IF .t = mtypeLabel AND .sub_t = lbDisabled THEN .disabled = YES
   'Check only for tags conditions set to 'Never'
   IF .tag1 = 1 OR .tag2 = 1 THEN .disabled = YES
   'Make sure menu items don't disappear, or we can't edit them!
   '(This is NOT saved)
   .override_hide = menudata.edit_mode
  END WITH
 NEXT
END SUB

SUB update_detail_menu(detail as MenuDef, menudata as MenuDef, mi as MenuDefItem)
 DIM i as integer
 DIM cap as string
 DIM index as integer
 DeleteMenuItems detail

 ' Set .sub_t of each menu item to indicate what menu_editor_detail_keys should do

 append_menu_item detail, "Go Back", , 0
 
 cap = mi.caption
 IF LEN(cap) = 0 THEN cap = "[DEFAULT]"
 append_menu_item detail, "Caption: " & cap, , 1
 
 append_menu_item detail, "Type", , 2
 WITH *detail.last
  SELECT CASE mi.t
   CASE mtypeLabel
    .caption = "Type: " & mi.t & " Label"
   CASE mtypeSpecial
    .caption = "Type: " & mi.t & " Special screen"
   CASE mtypeMenu
    .caption = "Type: " & mi.t & " Go to Menu"
   CASE mtypeTextBox
    .caption = "Type: " & mi.t & " Show text box"
   CASE mtypeScript
    .caption = "Type: " & mi.t & " Run script"
  END SELECT
 END WITH
 
 append_menu_item detail, "Subtype: " & mi.sub_t, , 3
 WITH *detail.last
  SELECT CASE mi.t
   CASE mtypeLabel
    SELECT CASE mi.sub_t
     CASE lbSelectable:   .caption &= " Selectable"
     CASE lbDisabled:     .caption &= " Disabled"
     CASE lbUnselectable: .caption &= " Can't be selected"
    END SELECT
   CASE mtypeSpecial
    .caption = .caption & " " & get_special_menu_caption(mi.sub_t)
   CASE mtypeMenu
    .caption = .caption & " " & getmenuname(mi.sub_t)
   CASE mtypeScript
    .caption = "Subtype: " & scriptname(mi.sub_t)
    IF mi.sub_t THEN
     ' Indicate which script arguments are passed
     ' (It's safe to call append_menu_item, because WITH saves a reference to *detail.last)
     DIM argsinfo as string = "Args: "
     IF menudata.allow_gameplay THEN
      '0 is passed instead of the menu item handle if it would be invalid
      argsinfo &= IIF(mi.close_when_activated, "0, ", "handle, ")
     ELSE
      'Sadly, for back-compatibility, leave out the handle instead of passing zero.
     END IF
     argsinfo &= "extra0, extra1, extra2"
     append_menu_item detail, argsinfo, , -1   'sub_t: does nothing
     detail.last->disabled = YES
     detail.last->unselectable = YES  'Does nothing, yet
    END IF
   CASE ELSE
    .caption = "Subtype: " & mi.sub_t
  END SELECT
  .caption &= get_menu_item_editing_annotation(mi)
 END WITH

 append_menu_item detail, "Color: " & slice_color_caption(mi.col, "Default"), , 12
 append_menu_item detail, "Disabled color: " & slice_color_caption(mi.disabled_col, "Default"), , 13

 append_menu_item detail, tag_condition_caption(mi.tag1, "Enable if tag", "Always"), , 4
 append_menu_item detail, tag_condition_caption(mi.tag2, " and also tag", "Always"), , 5
 IF menu_item_is_activatable(mi) THEN
  append_menu_item detail, tag_set_caption(mi.settag, "Set tag"), , 6
  append_menu_item detail, tag_toggle_caption(mi.togtag), , 7
 END IF
 append_menu_item detail, "Edit Bitsets...", , 8
 FOR i = 0 TO 2
  append_menu_item detail, "Extra data " & i & ": " & mi.extra(i), , 9 + i
 NEXT i
END SUB


SUB edit_menu_bits (menu as MenuDef)
 DIM bitname(11) as string
 DIM bits(0) as integer
 
 bitname(0) = "Translucent box"
 bitname(1) = "Never show scrollbar"
 bitname(2) = "Allow gameplay & scripts"
 bitname(3) = "Suspend player even if gameplay allowed"
 bitname(4) = "No box"
 bitname(5) = "Disable player closing menu"
 bitname(6) = "Disable player control of menu"
 bitname(7) = "Prevent main menu activation"
 bitname(8) = "Advance text box when menu closes"
 bitname(9) = "Highlight selection background"
 bitname(10) = "Remember selection when reopening"
 bitname(11) = "Clamp to screen bounds"

 MenuBitsToArray menu, bits()
 editbitset bits(), 0, bitname(), "menu_editor_bitsets"
 MenuBitsFromArray menu, bits()
END SUB

SUB edit_menu_item_bits (mi as MenuDefItem)
 DIM bitname(2) as string
 DIM bits(0) as integer

 bitname(0) = "Hide if disabled"
 IF menu_item_is_activatable(mi) THEN
  bitname(1) = "Close menu when activated"
 END IF
 bitname(2) = "Don't run on-close script"

 MenuItemBitsToArray mi, bits()
 editbitset bits(), 0, bitname(), "menu_editor_item_bitsets"
 MenuItemBitsFromArray mi, bits()  
END SUB

SUB reposition_menu (menu as MenuDef, mstate as MenuState, viewport_page as integer)
 setkeys
 DO
  setwait 55
  setkeys

  IF keyval(ccCancel) > 1 THEN EXIT DO
  IF keyval(scF1) > 1 THEN show_help "reposition_menu"

  DIM speed as integer = IIF(keyval(scShift), 12, 1)
  DIM delay as integer = IIF(keyval(scShift), 55, 90)
  WITH menu.offset
   IF slowkey(ccUp, delay)  THEN .y -= speed
   IF slowkey(ccDown, delay)  THEN .y += speed
   IF slowkey(ccLeft, delay)  THEN .x -= speed
   IF slowkey(ccRight, delay)  THEN .x += speed
  END WITH

  clearpage dpage
  preview_menu menu, mstate, viewport_page, dpage
  edgeprint "Offset=" & menu.offset, 0, 0, uilook(uiMenuItem), dpage
  edgeprint "Arrows to re-position, SHIFT for speed, ESC to exit", 0, pBottom, uilook(uiMenuItem), dpage

  SWAP vpage, dpage
  setvispage vpage
  dowait
 LOOP
END SUB

SUB reposition_anchor (menu as MenuDef, mstate as MenuState, viewport_page as integer)
 DIM tog as integer = 0
 DIM x as integer
 DIM y as integer
 setkeys
 DO
  setwait 55
  setkeys
  tog = tog XOR 1
 
  IF keyval(ccCancel) > 1 THEN EXIT DO
  IF keyval(scF1) > 1 THEN show_help "reposition_anchor"
  
  WITH menu
   IF keyval(ccUp) > 1 THEN .anchorvert = bound(.anchorvert - 1, alignTop, alignBottom)
   IF keyval(ccDown) > 1 THEN .anchorvert = bound(.anchorvert + 1, alignTop, alignBottom)
   IF keyval(ccLeft) > 1 THEN .anchorhoriz = bound(.anchorhoriz - 1, alignLeft, alignRight)
   IF keyval(ccRight) > 1 THEN .anchorhoriz = bound(.anchorhoriz + 1, alignLeft, alignRight)
  END WITH
 
  clearpage dpage
  preview_menu menu, mstate, viewport_page
  WITH menu
   x = .rect.x - 2 + anchor_point(.anchorhoriz, .rect.wide)
   y = .rect.y - 2 + anchor_point(.anchorvert, .rect.high)
   rectangle x, y, 5, 5, 2 + tog, viewport_page
  END WITH
  draw_viewport_page viewport_page, dpage

  edgeprint "Arrows to re-position, ESC to exit", 0, pBottom, uilook(uiMenuItem), dpage
  
  SWAP vpage, dpage
  setvispage vpage
  dowait
 LOOP
END SUB
