'OHRRPGCE - Game/Custom general menu code
'(C) Copyright 1997-2023 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.

#ifndef MENUS_BI
#define MENUS_BI

#include "udts.bi"
#include "uiconst.bi"

' Default placement (top-left) of editor menus
CONST pMenuX = 4
CONST pMenuY = 4
' Default placement of info/help line (called the "tooltip" in many menus)
CONST pInfoX = pLeft + 4
CONST pInfoY = pBottom - 2
' Something in the bottom-right or top-right corner
CONST pInfoRight = pRight - 4

'' Generic MenuState Stuff
DECLARE SUB init_menu_state OVERLOAD (byref state as MenuState, menu() as SimpleMenuItem, menuopts as MenuOptions = MenuOptions())
DECLARE SUB init_menu_state OVERLOAD (byref state as MenuState, byval menu as BasicMenuItem vector, menuopts as MenuOptions = MenuOptions())
DECLARE SUB init_menu_state OVERLOAD (byref state as MenuState, menu() as string, menuopts as MenuOptions = MenuOptions())
DECLARE SUB append_simplemenu_item (byref menu as SimpleMenuItem vector, caption as zstring ptr, byval unselectable as bool = NO, byval col as integer = 0, byval dat as integer = 0, byval where as integer = -1)
DECLARE SUB correct_menu_state (state as MenuState)
DECLARE SUB correct_menu_state_top (state as MenuState)
DECLARE FUNCTION usemenu OVERLOAD (state as MenuState, byval deckey as KBScancode = ccUp, byval inckey as KBScancode = ccDown) as bool
DECLARE FUNCTION usemenu OVERLOAD (byref pt as integer, byref top as integer, byval first as integer, byval last as integer, byval size as integer, byval deckey as KBScancode = ccUp, byval inckey as KBScancode = ccDown) as bool
DECLARE FUNCTION usemenu OVERLOAD (state as MenuState, byval menudata as BasicMenuItem vector, byval deckey as KBScancode = ccUp, byval inckey as KBScancode = ccDown) as bool
DECLARE FUNCTION usemenu OVERLOAD (state as MenuState, menu as MenuDef, byval deckey as KBScancode = ccUp, byval inckey as KBScancode = ccDown) as bool
DECLARE FUNCTION usemenu OVERLOAD (state as MenuState, selectable() as bool, byval deckey as KBScancode = ccUp, byval inckey as KBScancode = ccDown) as bool
DECLARE SUB usemenu_mouse_only (state as MenuState)
DECLARE FUNCTION default_menu_controls(state as MenuState, escval as integer = -1) as integer
DECLARE FUNCTION scrollmenu (state as MenuState, byval deckey as KBScancode = ccUp, byval inckey as KBScancode = ccDown) as bool
DECLARE SUB standard_to_basic_menu (menu() as string, byref state as MenuState, byref basicmenu as BasicMenuItem vector, byval shaded as bool ptr = NULL)
DECLARE SUB standardmenu OVERLOAD (menu() as string, state as MenuState, x as RelPos = pMenuX, y as RelPos = pMenuY, page as integer, menuopts as MenuOptions = MenuOptions())
DECLARE SUB standardmenu OVERLOAD (menu() as string, state as MenuState, shaded() as bool, x as RelPos = pMenuX, y as RelPos = pMenuY, page as integer, menuopts as MenuOptions = MenuOptions())
DECLARE SUB standardmenu OVERLOAD (byval menu as BasicMenuItem vector, state as MenuState, x as RelPos = pMenuX, y as RelPos = pMenuY, page as integer, menuopts as MenuOptions = MenuOptions())
DECLARE SUB calc_menustate_size OVERLOAD (byref state as MenuState)
DECLARE SUB calc_menustate_size OVERLOAD (byref state as MenuState, menu as MenuDef, page as integer)
DECLARE SUB calc_menu_rect OVERLOAD (state as MenuState, menuopts as MenuOptions, xy as RelPosXY, page as integer = -1, menu as BasicMenuItem vector = NULL)
DECLARE SUB calc_menu_rect OVERLOAD (state as MenuState, menu as MenuDef, byval page as integer)
DECLARE FUNCTION menu_item_color(state as MenuState, itemno as integer, disabled as bool = NO, unselectable as bool = NO, c_normal as integer = 0, c_disabled as integer = 0, def_normal as integer = -uiMenuItem-1, def_disabled as integer = -uiDisabledItem-1) as integer


'' Mouse support
DECLARE FUNCTION standardmenu_item_rect OVERLOAD (state as MenuState, menutext as string, index as integer) as RectType
DECLARE FUNCTION standardmenu_item_rect OVERLOAD (menu as BasicMenuItem vector, state as MenuState) as RectType
DECLARE FUNCTION find_menu_item_at_point (state as MenuState, pos as XYPair) as integer
DECLARE FUNCTION mouse_update_hover (state as MenuState) as bool
DECLARE SUB mouse_update_selection (state as MenuState)
DECLARE SUB mouse_scroll_menu(byref state as MenuState)
DECLARE SUB mouse_drag_menu(byref state as MenuState, byval button as MouseButton=mouseLeft, byval threshold as integer=10, byval magnify as double=1.0)
DECLARE FUNCTION menutext_hit_tester(menutext as string, state as MenuState, index as integer, pos as XYPair) as bool
DECLARE FUNCTION stringmenu_hit_tester(state as MenuState, index as integer, pos as XYPair) as bool

'' Selection by typing
DECLARE FUNCTION select_by_typing (selectst as SelectTypeState, byval allow_numbers as bool = YES) as bool
DECLARE SUB select_clear (selectst as SelectTypeState)
DECLARE SUB highlight_menu_typing_selection OVERLOAD (menu() as string, menu_display() as string, selectst as SelectTypeState, state as MenuState)
DECLARE SUB highlight_menu_typing_selection OVERLOAD (byref menu as BasicMenuItem vector, byref menu_display as BasicMenuItem vector, selectst as SelectTypeState, state as MenuState)
DECLARE FUNCTION highlight_menu_typing_selection_string(z as string, selectst as SelectTypeState) as string
DECLARE SUB select_on_word_boundary_excluding OVERLOAD (menu() as string, selectst as SelectTypeState, state as MenuState, excludeword as string)
DECLARE SUB select_on_word_boundary_excluding OVERLOAD (byval menu as BasicMenuItem vector, selectst as SelectTypeState, state as MenuState, excludeword as string)
DECLARE SUB select_on_word_boundary OVERLOAD (menu() as string, selectst as SelectTypeState, state as MenuState)
DECLARE SUB select_on_word_boundary OVERLOAD (byval menu as BasicMenuItem vector, selectst as SelectTypeState, state as MenuState)
DECLARE SUB select_instr(menu() as string, selectst as SelectTypeState, state as MenuState)

'' MenuDef
DECLARE SUB ClearMenuData(dat as MenuDef)
DECLARE SUB InitLikeStandardMenu(menu as MenuDef)
DECLARE SUB DeleteMenuItems(menu as MenuDef)
DECLARE SUB SortMenuItems(menu as MenuDef)
DECLARE FUNCTION getmenuname(byval record as integer) as string
DECLARE SUB init_menu_state OVERLOAD (byref state as MenuState, menu as MenuDef)
DECLARE SUB sort_menu_and_select_selectable_item(menu as MenuDef, state as MenuState)
DECLARE FUNCTION append_menu_item(byref menu as MenuDef, caption as zstring ptr, byval t as integer=mtypeLabel, byval sub_t as integer=0, byval dataptr as any ptr=0) as integer
DECLARE SUB remove_menu_item OVERLOAD (byref menu as MenuDef, byval mi as MenuDefItem ptr)
DECLARE SUB remove_menu_item OVERLOAD (byref menu as MenuDef, byval mislot as integer)
DECLARE SUB swap_menu_items(byref menu1 as MenuDef, byval mislot1 as integer, byref menu2 as MenuDef, byval mislot2 as integer)

'' Saving/Loading/(De)serializing MenuDefs
DECLARE SUB LoadMenuData(menu_set as MenuSet, dat as MenuDef, byval record as integer, byval ignore_items as integer=NO)
DECLARE SUB SaveMenuData(menu_set as MenuSet, dat as MenuDef, byval record as integer)
DECLARE SUB MenuBitsToArray (menu as MenuDef, bits() as integer)
DECLARE SUB MenuBitsFromArray (menu as MenuDef, bits() as integer)
DECLARE SUB MenuItemBitsToArray (mi as MenuDefItem, bits() as integer)
DECLARE SUB MenuItemBitsFromArray (mi as MenuDefItem, bits() as integer)
DECLARE FUNCTION read_menu_int (menu as MenuDef, byval intoffset_plus1 as integer) as integer
DECLARE SUB write_menu_int (menu as MenuDef, byval intoffset_plus1 as integer, byval n as integer)
DECLARE FUNCTION read_menu_item_int (mi as MenuDefItem, byval intoffset as integer) as integer
DECLARE SUB write_menu_item_int (mi as MenuDefItem, byval intoffset as integer, byval n as integer)

'' Drawing MenuDefs
DECLARE SUB draw_menu (menu as MenuDef, state as MenuState, byval page as integer)
DECLARE SUB update_menu_captions (menu as MenuDef)
DECLARE FUNCTION menudef_item_rect (menu as MenuDef, state as MenuState, menutext as string, index as integer) as RectType
DECLARE FUNCTION anchor_point(byval anchor as AlignType, byval size as integer) as integer
DECLARE FUNCTION count_visible_menu_items (menu as MenuDef) as integer

DECLARE FUNCTION get_menu_item_caption (mi as MenuDefItem, menu as MenuDef) as string
DECLARE FUNCTION get_special_menu_caption(byval subtype as integer) as string
DECLARE FUNCTION get_menu_item_editing_annotation (mi as MenuDefItem) as string
DECLARE FUNCTION menu_item_is_activatable(mi as MenuDefItem) as bool

'' Scrollbars!
DECLARE SUB draw_scrollbar OVERLOAD (state as MenuState, menu as MenuDef, page as integer, align as AlignType = alignRight)
DECLARE SUB draw_scrollbar OVERLOAD (state as MenuState, rect as RectType, boxstyle as integer=0, page as integer, align as AlignType = alignRight)
DECLARE SUB draw_fullscreen_scrollbar(state as MenuState, boxstyle as integer=0, page as integer, align as AlignType = alignRight)


' Some day this may be a universal menu class.
' In the meantime, just use a simple menu() as string, but probably
' should switch to BasicMenuItem at a minimum
TYPE ModularMenu EXTENDS Object
 running as bool         'Whether inside run()

 'These arrays contain data for each menu item
 menu(any) as string
 selectable(any) as bool 'Optional: whether selectable
 shaded(any) as bool     'Optional: whether a header (actually whether greyed-out, but eduiHeading by default
 itemtypes(any) as integer  'Optional: menu item data (meaning defined by subclass)
 itemids(any) as integer  'Optional: menu item data (meaning defined by subclass)

 tooltip as string       'Shown at the bottom of the screen
 title as string         'Shown at the top, like the multichoice() prompt
 state as MenuState
 selectst as SelectTypeState
 can_use_strgrabber as bool 'Whether you can use strgrabber (false when selecting-by-typing)
 using_strgrabber as bool 'Set this true in each_tick() to disable select-by-typing
 want_exit as bool        'True in each_tick if user is trying to exit. Set this true in each_tick to force exit
 menuopts as MenuOptions
 floating as bool        'Appears in the center of the screen, like notification, instead of fullscreen
 use_selectable as bool  'Set to true to make use of selectable() (TODO: get rid of this horrible setting, somehow)
 usemenu_ret as bool     'The return value of usemenu for this tick
 helpkey as string
 holdscreen as integer   '0 if none

 ' Add an item to the menu
 ' Virtual because you might want to set more per-item data
 DECLARE VIRTUAL SUB add_item (itemtype as integer = 0, id as integer = -1, text as string = "", canselect as bool = YES, heading as bool = NO, disabled as bool = NO)

 ' Wrap and split 'text' into multiple items
 DECLARE SUB add_wrapped_items(itemtype as integer = 0, id as integer = -1, text as string = "", canselect as bool = YES, heading as bool = NO, disabled as bool = NO)

 ' Add a blank line
 DECLARE SUB add_spacer()

 ' Add a header to the menu
 DECLARE SUB header(text as string)

 ' Delete all menu items
 DECLARE SUB clear_menu()

 ' Whether should call try_exit()
 DECLARE FUNCTION exit_condition() as bool

 ' Called to create/update 'menu()' and 'state' if state.need_update is true. Also called once at start.
 ' Should correctly set state.last
 DECLARE VIRTUAL SUB update()

 ' Called each tick. Can either call update() itself or set state.need_update=YES
 ' Set want_exit = YES to exit the menu
 DECLARE VIRTUAL SUB each_tick()

 ' Called when user tries to leave the menu
 ' Return YES to exit the menu
 DECLARE VIRTUAL FUNCTION try_exit() as bool

 ' Called before drawing the menu to draw any extra stuff
 DECLARE VIRTUAL SUB draw_underlays()

 ' Called after drawing the menu (and tooltip) to draw any extra stuff
 DECLARE VIRTUAL SUB draw_overlays()

 ' Generally you shouldn't need to override this.
 DECLARE VIRTUAL SUB draw()

 DECLARE SUB run()

 PRIVATE:

 DECLARE SUB update_wrapper()
END TYPE

' I don't think we'll use this in Game. Reduce executable size.
#IFDEF IS_CUSTOM

' Displays a stack of dropdown/popup-style MenuDef menus, each one opening next to the previous menu item
TYPE MenuStack
  menus(any) as MenuDef
  states(any) as MenuState
  helpkey as string
  open_at_mouse as bool

  DECLARE SUB open_menu()
  DECLARE SUB open_menu_at(itemrect as RectType)
  DECLARE FUNCTION add_item(text as string, t as integer = 0, sub_t as integer = 0, dataptr as any ptr = 0) byref as MenuDefItem
  DECLARE SUB finish_open()
  DECLARE SUB close_menu()

  DECLARE FUNCTION is_open() as bool
  DECLARE FUNCTION is_active() as bool
  DECLARE FUNCTION controls() as bool
  DECLARE FUNCTION activate() as bool
  DECLARE FUNCTION cur_menu() as MenuDef ptr
  DECLARE FUNCTION cur_item() as MenuDefItem ptr
  DECLARE SUB draw(page as integer)
END TYPE

#ENDIF


'' Global variables
EXTERN force_use_mouse as integer

#endif
