Vdo_grid_list_tween_done = true
local Input_tracker
local Grid_mouse_input_tracker
local Scrollbar_input_tracker
local GRID_BUTTON_SPACING = 3
local GRID_BUTTON_SIZE = 150
local MOVE_UP = -2
local MOVE_DOWN = 2
local MOVE_LEFT = -1
local MOVE_RIGHT = 1
local SCALE_STD_RES_GRID_BUTTON = .67 --.9
local ANCHOR_SCROLLBAR_BUFFER = 28
local ANCHOR_TITLE_SPACE = 32
local SIZE_GRID_BUTTON = 59
function vdo_grid_list_init()
end
function vdo_grid_list_cleanup()
end
-- Inherited from Vdo_base_object
Vdo_grid_list = Vdo_base_object:new_base()
function Vdo_grid_list:init()
-- Hide the initial button
vint_set_property(vint_object_find("grid_base"), "visible", false)
vint_set_property(vint_object_find("grid_layered"), "visible", false)
vint_set_property(vint_object_find("grid_check"), "visible", false)
vint_set_property(vint_object_find("grid_canceled"), "visible", false)
vint_set_property(vint_object_find("grid_anchor"), "visible", false)
vint_set_property(vint_object_find("grid_title"), "visible", false)
self.scrollbar = Vdo_scrollbar:new("grid_scrollbar", self.handle, self.doc_handle)
self.group = Vdo_base_object:new("grid_group", self.handle, self.doc_handle)
self.bg = Vdo_base_object:new("grid_list_bg",self.handle, self.doc_handle)
self.highlight_name = Vdo_base_object:new("grid_highlight_name", self.handle, self.doc_handle)
self.input_enabled = false
self.scrollbar:set_visible(false)
Vdo_grid_list_tween_done = true
local highlight = Vdo_hint_button:new( "grid_hint_button", self.handle, self.doc_handle)
highlight:set_button(CTRL_MENU_BUTTON_A)
if game_is_active_input_gamepad() == false then
highlight:set_visible(false)
end
local list_anim = Vdo_anim_object:new("grid_group_anim", self.handle, self.doc_handle)
list_anim:stop()
Input_tracker = Vdo_input_tracker:new()
--clone title and add it to grid here
local base_title_grp = Vdo_base_object:new("grid_title_grp", self.handle, self.doc_handle)
base_title_grp:set_visible(false)
self.draw_called = false
self.title_added = false
self.update_start_row = true
if game_get_platform() == "PC" then
Grid_mouse_input_tracker = Vdo_input_tracker:new()
Scrollbar_input_tracker = Vdo_input_tracker:new()
end
end
-- Deletes the internal data and destroys the button clones
function Vdo_grid_list:cleanup()
if self.draw_called then
for i, button in pairs(self.buttons) do
button:object_destroy()
end
self.draw_called = false
end
if self.title_added then
for i = 1, #self.titles do
self.titles[i]:object_destroy()
end
self.title_added = false
end
if Grid_mouse_input_tracker ~= nil then
--Grid_mouse_input_tracker:remove_all()
Grid_mouse_input_tracker:subscribe(false)
-- Not unsubscribing from the scrollbar here is intentional
-- If you do, it prevents the mouse from dragging the scrollbar correctly
end
self.data = nil
end
function Vdo_grid_list:draw_items(input_data, current_option, max_width, max_height, button_w, button_h, hint_button_offset, current_category, outline_scale, background_enabled, show_current_button_bool, grid_spacing, set_size)
max_width = max_width or 999
max_height = max_height or 999
if self.draw_called == false then
self.update_start_row = true
end
-- Nuke the shit out of whatever was previously here
self:cleanup()
local data = {}
-- Most grids to not contain categories... but we're going to make all the data fit this format (ie. an extra layer of tables) because
-- it greatly simplifies the script. We just won't draw the header for grids that only have one category.
if input_data[1].category_name == nil then
data[1] = input_data
current_category = 1
data[1].category_name = "filler cat name"
else
data = input_data
end
-- Set up tables to manage handles and data for this object
self.draw_called = true
self.buttons = {}
self.data = data
self.open = false
self.max_width = max_width
self.max_height = max_height
self.button_w = button_w or GRID_BUTTON_SIZE
self.button_h = button_h or GRID_BUTTON_SIZE
self.hint_button_offset = hint_button_offset
self.outline_scale = outline_scale
self.background_enabled = background_enabled
self.show_current_button_bool = show_current_button_bool
self.grid_spacing = grid_spacing or GRID_BUTTON_SPACING
self.set_size = set_size
self.titles = {}
self.rows = 0
self.num_buttons = 0
self.cat_rows = {}
self.cat_buttons = {}
local curr_row = 1
self.num_categories = #data
-- Set up handle for base button
local base_button
-- Check which button to use
if data[1][1].is_layered then
base_button = Vdo_grid_button_layered:new("grid_layered", self.handle, self.doc_handle)
elseif data[1][1].is_checked ~= nil then
base_button = Vdo_grid_button_check:new("grid_check", self.handle, self.doc_handle)
elseif data[1][1].is_canceled_type then
base_button = Vdo_grid_button_canceled:new("grid_canceled", self.handle, self.doc_handle)
else
base_button = Vdo_grid_button:new("grid_base", self.handle, self.doc_handle)
end
if base_button.handle == 0 then
return
end
--get the x and y of the button
base_button:set_property("anchor", -1 * self.button_w, -1 * self.button_h)
base_button.x, base_button.y = base_button:get_property("anchor")
--adjust for negative grid padding
if self.grid_spacing < 0 then
base_button:set_anchor(base_button.x + (self.grid_spacing * -2), base_button.y + (self.grid_spacing * -2))
base_button.x, base_button.y = base_button:get_property("anchor")
end
-- Set initial category
if current_category == nil or current_category < 1 or current_category > self.num_categories then
current_category = 1
end
self.current_cat = current_category
-- We need to go through all the categories and add up the rows, and find which row number our
-- current choice is in
local header_offset = 0
if self.num_categories > 1 then
header_offset = 1
end
local adjusted_height = (self.max_height * (self.button_h + self.grid_spacing)) + (self.grid_spacing * 2)
local adjusted_width = (self.button_w + self.grid_spacing) * self.max_width + (self.grid_spacing * 2)
--adjust background for negative grid spacing
if self.grid_spacing < 0 then
adjusted_width = (self.button_w + self.grid_spacing) * self.max_width + (self.grid_spacing * 2) + (self.grid_spacing * -4)
adjusted_height = (self.max_height * (self.button_h + self.grid_spacing)) + (self.grid_spacing * 2) + (self.grid_spacing * -4)
end
--set background size and anchor
if self.background_enabled == nil then
self.background_enabled = true
end
self.bg:set_visible(self.background_enabled)
element_set_actual_size(self.bg.handle, adjusted_width, adjusted_height )
self.bg:set_anchor((self.button_w + self.grid_spacing) * -0.5, (self.button_h + self.grid_spacing) * -0.5)
local bg_x, bg_y = self.bg:get_anchor()
for i = 1, #data do
self.cat_buttons[i] = #data[i]
self.num_buttons = self.num_buttons + self.cat_buttons[i]
-- see if this category holds our current highlighted item
if i == self.current_cat then
-- Set initial cursor position
if current_option == nil or current_option < 1 or current_option > self.cat_buttons[i] then
current_option = 1
end
curr_row = self.rows + header_offset + ceil(current_option / self.max_width)
end
self.cat_rows[i] = header_offset + ceil(self.cat_buttons[i]/max_width)
self.rows = self.rows + self.cat_rows[i]
end
--set the curent button to the passed in variable for the current option (as long as it's not nil)
if self.data[self.current_cat][current_option] ~= nil then
self.current_idx = current_option
end
--if we have less rows than the max visible set the max visible to the number of rows
if self.rows < self.max_height then
self.max_height = self.rows
end
local start_row
if self.update_start_row then
-- calculate the first row we should display
start_row = curr_row - floor(self.max_height / 2)
if start_row < 1 then
start_row = 1
end
if start_row + self.max_height - 1 > self.rows then
start_row = self.rows - self.max_height + 1
end
self.start_row = start_row
else
-- If self.update_start_row is false, use self.start_row since then the starting row was already set
start_row = self.start_row
end
local new_x = base_button.x
local new_y = base_button.y
--loop through the visible rows and populate our table of buttons
local data_index
local cat_index
local grid_index = 1
local draw_header = false
if self.num_categories > 1 then
local row_count = 0
for i = 1,self.num_categories do
if start_row <= row_count + self.cat_rows[i] then
cat_index = i
if start_row - row_count == 1 then
-- the first row to draw is a header row
draw_header = true
data_index = ((start_row - row_count - 1) * self.max_width) + 1
else
-- -2 to account for indexing starting at 1, and 1 row for category header
data_index = ((start_row - row_count - 2) * self.max_width) + 1
end
-- found category, stop loop
break
end
row_count = row_count + self.cat_rows[i]
end
else
cat_index = 1
data_index = ((start_row - 1) * self.max_width) + 1
end
local title_count = 0
for i = 1,self.max_height do
-- are we on a category header row?
-- BTW, I can't believe lua doesn't have a continue operation...
if draw_header then
draw_header = false
-- draw the category header
title_count = title_count + 1
self:add_subtitle(self.data[cat_index].category_name, title_count, new_y)
else
--only use grid spacing after the first row
--if i > 1 then
new_y = base_button.y + ((self.button_h + self.grid_spacing) * (i))
--else
-- new_y = 0--base_button.y
--end
--loop through the columns
for j = 1, max_width do
--check so that we don't run out of valid data
if data_index > self.num_buttons then
break
end
--only use grid spacing after the first column
--if j == 1 then
-- new_x = 0--base_button.x
--else
new_x = base_button.x + ((self.button_w + self.grid_spacing) * j)
--end
if self.data[1][1].is_layered then
self.buttons[grid_index] = Vdo_grid_button_layered:clone(base_button.handle)
elseif self.data[1][1].is_checked ~= nil then
self.buttons[grid_index] = Vdo_grid_button_check:clone(base_button.handle)
elseif self.data[1][1].is_canceled_type ~= nil then
self.buttons[grid_index] = Vdo_grid_button_canceled:clone(base_button.handle)
else
self.buttons[grid_index] = Vdo_grid_button:clone(base_button.handle)
end
self.buttons[grid_index]:set_visible(true)
local button = self.buttons[grid_index]
local button_data = data[cat_index][data_index]
-- Set the button icon
-- check for dual icons
if button_data.dual_wield == true then
button:set_icon(button_data.icon, true)
else
self:set_icon(button, button_data)
end
-- Set the button toggle text
if button_data.label ~= nil then
button:set_text(button_data.label)
else
button:set_text_crc(button_data.label_crc)
end
-- Only color it if it's not a layered button
if self.data[1][1].is_layered == nil or self.data[1][1].is_layered == false then
button:set_color(button_data.color.red, button_data.color.green, button_data.color.blue)
end
-- If it's canceled_type button, then set whether it starts disabled
if self.data[1][1].is_canceled_type then
button:set_cancel(button_data.disabled)
end
--debug_print("vint", "cat_index = "..cat_index..", grid_index = "..grid_index..", data_index = "..data_index.."\n")
if self.data[cat_index][data_index].is_checked == true then
button:set_checkbox(1,self.highlight_color)
end
-- Make the button visible
button:set_visible(true)
button:set_property("anchor", new_x, new_y)
if set_size == true then
button:set_size(button_w,button_h)
if vint_is_std_res() == true then
button:set_scale(SCALE_STD_RES_GRID_BUTTON, SCALE_STD_RES_GRID_BUTTON)
end
end
--check to see if we want unhighlighted buttons greyed out, used for radio station select
if self.tint_current_button == true then
local grey = 100
button:set_color(grey/255,grey/255,grey/255)
end
-- if this is the highlighted choice, save for easy reference
if cat_index == self.current_cat and data_index == self.current_idx then
self.current_button = button
end
self.prev_title = button_data.title
data_index = data_index + 1
grid_index = grid_index + 1
-- have we reached the end of the category?
if self.num_categories > 1 and data_index > self.cat_buttons[cat_index] then
data_index = 1
cat_index = cat_index + 1
draw_header = true
break
end
end
end
end
if self.rows > self.max_height then
self.scrollbar:set_anchor(bg_x + adjusted_width + GRID_BUTTON_SPACING, bg_y)
if game_get_platform() == "PC" then
local adjusted_total_height = (self.rows * (self.button_h + self.grid_spacing)) + (self.grid_spacing * 2)
self.scrollbar:set_size(SCROLLBAR_WIDTH, adjusted_height, adjusted_total_height)
-- If self.update_start_row was false, then the scrollbar's value is already being set.
if self.update_start_row then
self.scrollbar:set_value(self.rows - (self.max_height - 1), self.start_row)
end
else
self.scrollbar:set_size(SCROLLBAR_WIDTH, adjusted_height)
self.scrollbar:set_value(self.rows, curr_row)
end
self.scrollbar:set_property("visible",true)
else
self.scrollbar:set_property("visible",false)
end
--position name for highlighted item
self.highlight_name:set_anchor(bg_x, bg_y + adjusted_height + GRID_BUTTON_SPACING, 1)
-- Highlight current button
local highlight_button = Vdo_grid_button:new("grid_top_button", self.handle, self.doc_handle)
local highlight_button_outline = Vdo_grid_button:new("grid_top_button_outline", self.handle, self.doc_handle)
local highlight_button_layered = Vdo_grid_button:new("grid_top_button_layered", self.handle, self.doc_handle)
local highlight_button_outline_layered = Vdo_grid_button:new("grid_top_button_outline_layered", self.handle, self.doc_handle)
local highlight_button_check = Vdo_grid_button_check:new("grid_top_button_check", self.handle, self.doc_handle)
local highlight_button_canceled = Vdo_grid_button_canceled:new("grid_top_button_canceled", self.handle, self.doc_handle)
highlight_button:set_visible(false)
highlight_button_outline:set_visible(false)
highlight_button_layered:set_visible(false)
highlight_button_outline_layered:set_visible(false)
highlight_button_check:set_visible(false)
highlight_button_canceled:set_visible(false)
-- Make sure current_button was set to a valid button, otherwise set it to the first button
if self.current_button.handle < 1 then
self.current_button = self.buttons[1]
end
self.current_button:set_visible(true)
if self.data[1][1].is_layered then
highlight_button = Vdo_grid_button_layered:new("grid_top_button_layered", self.handle, self.doc_handle)
highlight_button_outline = Vdo_grid_button_layered:new("grid_top_button_outline_layered", self.handle, self.doc_handle)
highlight_button_outline:set_visible(true)
elseif self.data[1][1].is_checked ~= nil then
highlight_button = Vdo_grid_button_check:new("grid_top_button_check", self.handle, self.doc_handle)
highlight_button_outline = Vdo_grid_button_check:new("grid_top_button_check", self.handle, self.doc_handle)
--highlight_button:set_checkbox(1,self.highlight_color)
elseif self.data[1][1].is_canceled_type ~= nil then
highlight_button = Vdo_grid_button_canceled:new("grid_top_button_canceled", self.handle, self.doc_handle)
highlight_button_outline = Vdo_grid_button_canceled:new("grid_top_button_canceled", self.handle, self.doc_handle)
else
highlight_button = Vdo_grid_button:new("grid_top_button", self.handle, self.doc_handle)
highlight_button_outline = Vdo_grid_button:new("grid_top_button_outline", self.handle, self.doc_handle)
highlight_button_outline:set_visible(true)
end
-- Hide button underneath for checked buttons
if self.data[self.current_cat][current_option].is_checked ~= nil then
self.current_button:set_visible(false)
end
-- check to see if we want to show the icon behind the highlight, used on radio station select
-- after the first draw save the status in self.show_current_button
if self.show_current_button_bool ~= nil then
--self.show_current_button = show_current_button
self.current_button:set_visible(show_current_button_bool)
end
local button_data = self.data[self.current_cat][self.current_idx]
--set the size of the highlight
self:set_highlight_size(button_data.dual_wield)
highlight_button:set_visible(true)
if outline_scale ~= nil then
highlight_button_outline:set_scale(outline_scale, outline_scale)
end
if self.data[1][1].is_layered == nil or self.data[1][1].is_layered == false then
highlight_button:set_color(button_data.color.red, button_data.color.green, button_data.color.blue)
end
--do we have a check box type button?
--if so set the highlight color if highlight color is valid
if self.highlight_color ~= nil and self.data[1][1].is_checked ~= nil then
highlight_button:set_highlight_color(self.highlight_color)
end
--Set the button icon
self:set_icon(highlight_button, button_data)
self:set_icon(highlight_button_outline, button_data)
-- set hightlight anchor position
local button_x,button_y = self.current_button:get_property("anchor")
local highlight = Vdo_base_object:new( "grid_highlight", self.handle, self.doc_handle)
highlight:set_property( "anchor", button_x, button_y)
highlight:set_visible(true)
--don't play highlight anim if index is the same
--if old_idx ~= self.current_idx then
local highlight_anim = Vdo_anim_object:new("highlight_anim", self.handle, self.doc_handle)
highlight_anim:play()
--end
local hint_button = Vdo_base_object:new("grid_hint_button", self.handle, self.doc_handle)
local highlight_scale_twn = Vdo_tween_object:new("grid_highlight_scale_twn", self.handle, self.doc_handle)
if hint_button_offset == nil then
-- Reposition hint button to bottom right corner of highlighted button
local highlight_width, highlight_height = highlight_button:get_screen_size()
local highlight_scale_x, highlight_scale_y = highlight_scale_twn:get_end_value()
hint_button:set_anchor(button_x + (highlight_width * highlight_scale_x * .5) - 35, button_y + (highlight_height * highlight_scale_y * .5) - 35)
else
hint_button:set_anchor(button_x + hint_button_offset, button_y + hint_button_offset)
end
-- Set highlighted item name
local highlight_label = self.data[self.current_cat][self.current_idx].label
local highlight_label_crc = self.data[self.current_cat][self.current_idx].label_crc
if highlight_label ~= nil then
self.highlight_name:set_text(highlight_label)
else
self.highlight_name:set_text_crc(highlight_label_crc)
end
-- align grid list to the top right of the button for easier placement in the doc
--local first_btn_width, first_btn_height = self.buttons[1]:get_screen_size()
self.group:set_anchor((self.button_w - SIZE_GRID_BUTTON) * 0.5, (self.button_h - SIZE_GRID_BUTTON)* 0.5)
--disable the clip/mask for now
--local grid_clip = Vdo_base_object:new("grid_clip")
--grid_clip:set_property("clip_enabled", false)
self.update_start_row = true
end
function Vdo_grid_list:move_cursor(direction, do_not_redraw, is_index_set)
if not self.draw_called then
return
end
local num_rows = ceil(self.cat_buttons[self.current_cat] / self.max_width)
-- Don't update the start row when using the mouse to select something
if direction == 0 then
self.update_start_row = false
end
--check if we have more than one row or category
if self.num_categories == 1 and num_rows <= 1 and (direction == MOVE_UP or direction == MOVE_DOWN) then
return
--check if we have one item
elseif self.num_categories == 1 and self.num_buttons <= 1 then
return
else
--check if we can process input
if Vdo_grid_list_tween_done then
-- Clear out old highlight
for idx, button in pairs(self.buttons) do
button:set_highlight(false)
end
-- apply movement
local move_offset
if direction == MOVE_UP then
move_offset = - self.max_width
elseif direction == MOVE_DOWN then
move_offset = self.max_width
else
move_offset = direction
end
local old_idx = self.current_idx
local prev_row = ceil(self.current_idx / self.max_width)
-- apply movement
self.current_idx = self.current_idx + move_offset
local new_row = ceil(self.current_idx / self.max_width)
-- do we need a header row?
local offset = 1
if self.num_categories > 1 then
offset = 2
end
local num_buttons = self.cat_buttons[self.current_cat]
local last_row_len = num_buttons - ((self.cat_rows[self.current_cat] - offset) * self.max_width)
if is_index_set then
-- if the index was set from mouse_move, update only the highlight since the grid's contents have not changed
self:update_highlight(self.hint_button_offset)
else
-- handle all wrapping
if direction == MOVE_RIGHT then
-- row wrap
if new_row ~= prev_row then
self.current_idx = self.current_idx - self.max_width
end
-- last short row wrap
if self.current_idx > num_buttons then
self.current_idx = self.current_idx - last_row_len
end
elseif direction == MOVE_LEFT then
-- row wrap
if new_row ~= prev_row then
self.current_idx = self.current_idx + self.max_width
end
-- last short row wrap
if self.current_idx > num_buttons then
self.current_idx = self.current_idx - (self.max_width - last_row_len)
end
elseif direction == MOVE_UP then
-- top of grid wrap
if self.current_idx < 1 then
-- go to previous category
self.current_cat = self.current_cat - 1
if self.current_cat < 1 then
self.current_cat = self.num_categories
end
-- We now need to calculate the index in the new category to use
self.current_idx = ((old_idx - 1) % self.max_width) + 1 + ((num_rows - 1) * self.max_width)
if self.current_idx > self.cat_buttons[self.current_cat] then
self.current_idx = self.current_idx - self.max_width
if self.current_idx > self.cat_buttons[self.current_cat] or self.current_idx < 1 then
self.current_idx = self.cat_buttons[self.current_cat]
end
end
end
elseif direction == MOVE_DOWN then
-- end of grid wrap
if self.current_idx > num_buttons then
-- go to next category
self.current_cat = self.current_cat + 1
if self.current_cat > self.num_categories then
self.current_cat = 1
end
-- We now need to calculate the index in the new category to use
self.current_idx = ((old_idx - 1) % self.max_width) + 1
if self.current_idx > self.cat_buttons[self.current_cat] then
self.current_idx = self.cat_buttons[self.current_cat]
end
end
end
--redraw the list
if do_not_redraw ~= true then
--input_data, current_option, max_width, max_height, button_w, button_h, hint_button_offset, current_category, outline_scale, background_enabled, show_current_button, grid_padding, set_size
self:draw_items(self.data, self.current_idx, self.max_width, self.max_height, self.button_w, self.button_h, self.hint_button_offset, self.current_cat, self.outline_scale, self.background_enabled, self.show_current_button_bool, self.grid_spacing, self.set_size)
self:update_mouse_inputs()
end
end
end
--check if we should play scrolling audio
if direction ~= 0 or is_index_set then
if self.num_buttons > 1 then
game_UI_audio_play("UI_Reward_Store_Menu_Navigation")
end
end
end
end
function Vdo_grid_list:get_selection()
if not self.draw_called then
return
end
return self.current_idx
end
-- Gets an optional ID value if one is saved
function Vdo_grid_list:get_id()
if not self.draw_called then
return
end
return self.data[self.current_cat][self.current_idx].id
end
function Vdo_grid_list:get_data_from_id(id)
for i, category in pairs (self.data) do
for j, entry in pairs (category) do
if entry.id == id then
return entry
end
end
end
end
function Vdo_grid_list:button_a()
if not self.draw_called then
return
end
--check if we can process input
if not Vdo_grid_list_tween_done then
return
end
self:toggle_checked()
end
function Vdo_grid_list:button_b()
if not self.draw_called then
return
end
end
function Vdo_grid_list:toggle_checked()
local current_idx = self.current_idx
local current_cat = self.current_cat
local current_data = self.data[current_cat][current_idx]
if current_data.is_checked then
local current_button = self.buttons[current_idx]
if current_data.checked ~= nil then
if current_data.locked == false or current_data.locked == nil then
if current_data.checked == true then
current_data.checked = false
else
current_data.checked = true
end
end
end
current_button:set_check_box(current_data.checked,current_data.locked)
elseif current_data.is_canceled_type then
local new_disabled_state = not current_data.disabled
current_data.disabled = new_disabled_state
local current_button = self.buttons[current_idx]
local highlight_button = Vdo_grid_button_canceled:new("grid_top_button_canceled", self.handle, self.doc_handle)
current_button:set_cancel(new_disabled_state)
highlight_button:set_cancel(new_disabled_state)
end
end
function Vdo_grid_list:return_data()
if not self.draw_called then
return
end
return self.data
end
function Vdo_grid_list:return_selected_data()
if not self.draw_called then
return
end
return self.data[self.current_cat][self.current_idx]
end
function Vdo_grid_list:return_selected_index()
if not self.draw_called then
return
end
return self.current_idx
end
function Vdo_grid_list:return_selected_cat()
if not self.draw_called then
return
end
return self.current_cat
end
function Vdo_grid_list:is_tween_done()
return Vdo_grid_list_tween_done
end
function vdo_grid_list_scroll_done(tween_h, event_name)
-- remove this callback
remove_tween_end_callback( vint_object_find("grid_group_anchor_tween") )
Vdo_grid_list_tween_done = true
end
function Vdo_grid_list:nav_enable(is_on, callback_action, callback_nav)
if is_on then
-- Subscribe to the button presses we need
Input_tracker:add_input("select", callback_action, 150)
Input_tracker:add_input("back", callback_action, 150)
Input_tracker:add_input("nav_up", callback_nav, 150)
Input_tracker:add_input("nav_down", callback_nav, 150)
Input_tracker:add_input("nav_left", callback_nav, 150)
Input_tracker:add_input("nav_right", callback_nav, 150)
Input_tracker:subscribe(true)
--self:set_visible(true)
-- Subscribe to the mouse inputs we need
if Grid_mouse_input_tracker ~= nil then
self:add_mouse_inputs(callback_action, callback_nav, Grid_mouse_input_tracker)
Grid_mouse_input_tracker:subscribe(true)
Scrollbar_input_tracker:subscribe(true)
end
if self.store_input_tracker then
self.store_input_tracker:subscribe(false)
end
else
-- Remove the button presses we needed
Input_tracker:remove_input("select")
Input_tracker:remove_input("back")
Input_tracker:remove_input("nav_up")
Input_tracker:remove_input("nav_down")
Input_tracker:remove_input("nav_left")
Input_tracker:remove_input("nav_right")
Input_tracker:subscribe(false)
--self:set_visible(false)
if Grid_mouse_input_tracker ~= nil then
Grid_mouse_input_tracker:remove_all()
Scrollbar_input_tracker:remove_all()
end
if self.store_input_tracker and self.input_enabled then
self.store_input_tracker:subscribe(true)
end
end
self.input_enabled = is_on
end
function Vdo_grid_list:set_highlight_color(color)
self.scrollbar:set_highlight_color(color)
self.highlight_name:set_color(color.R, color.G, color.B)
self.highlight_color = color
end
function Vdo_grid_list:show_grid(is_visible)
--self:set_visible(is_visible)
end
function Vdo_grid_list:add_subtitle(title_name, title_index, y_pos)
--clone title and add it to grid here
local base_title_grp = Vdo_base_object:new("grid_title_grp", self.handle, self.doc_handle)
self.titles[title_index] = Vdo_base_object:clone(base_title_grp.handle)
self.titles[title_index].title = Vdo_base_object:new("grid_title",self.titles[title_index].handle, self.doc_handle)
self.titles[title_index].line = Vdo_base_object:new("grid_title_line",self.titles[title_index].handle, self.doc_handle)
self.titles[title_index].title:set_text(title_name)
self.titles[title_index].title:set_visible(true)
local text_width, text_height = self.titles[title_index].title:get_screen_size()
local bg_width, bg_height = self.bg:get_screen_size()
self.titles[title_index].line:set_anchor(text_width + 10, text_height * 0.5)
self.titles[title_index].line:set_screen_size(bg_width - (text_width + 30), 3)
self.titles[title_index].line:set_visible(true)
self.titles[title_index].line:set_alpha(1)
self.titles[title_index]:set_anchor(self.button_w * -0.5 + 10, y_pos + self.button_h)
self.titles[title_index]:set_visible(true)
self.title_added = true
end
function Vdo_grid_list:set_icon(button, button_data)
if button_data.is_layered then
button:set_icon(button_data)
else
if nil ~= button_data.icon then
button:set_icon(button_data.icon)
elseif nil ~= button_data.icon_crc then
button:set_icon_crc(button_data.icon_crc)
end
end
if button_data.is_canceled_type then
button:set_cancel(button_data.disabled)
end
if button_data.is_checked then
button:set_checkbox(1, self.highlight_color)
end
end
function Vdo_grid_list:set_highlight_size(dual_is_visible)
local highlight_button
if self.data[1][1].is_layered then
highlight_button = Vdo_grid_button_layered:new("grid_top_button_layered", self.handle)
elseif self.data[1][1].is_checked ~= nil then
highlight_button = Vdo_grid_button_check:new("grid_top_button_check", self.handle)
elseif self.data[1][1].is_canceled_type ~= nil then
highlight_button = Vdo_grid_button_canceled:new("grid_top_button_canceled", self.handle)
else
highlight_button = Vdo_grid_button:new("grid_top_button", self.handle)
end
-- highlight_button:set_size(self.button_w, self.button_h)
--highlight_button:set_scale(self.outline_scale, self.outline_scale)
if dual_is_visible == true then
highlight_button:set_highlight(true, true)
else
highlight_button:set_highlight(true)
end
end
-- Only updates the highlighted button based on the current index without redrawing the entire list
-- This function's code copies the highlight button code in draw_items
--
function Vdo_grid_list:update_highlight(hint_button_offset)
-- Highlight current button
local highlight_button = Vdo_grid_button_layered:new("grid_top_button", self.handle, self.doc_handle)
local highlight_button_outline = Vdo_grid_button_layered:new("grid_top_button_outline", self.handle, self.doc_handle)
local highlight_button_layered = Vdo_grid_button_layered:new("grid_top_button_layered", self.handle, self.doc_handle)
local highlight_button_outline_layered = Vdo_grid_button_layered:new("grid_top_button_outline_layered", self.handle, self.doc_handle)
local highlight_button_check = Vdo_grid_button_check:new("grid_top_button_check", self.handle, self.doc_handle)
local highlight_button_canceled = Vdo_grid_button_canceled:new("grid_top_button_canceled", self.handle, self.doc_handle)
highlight_button:set_visible(false)
highlight_button_outline:set_visible(false)
highlight_button_layered:set_visible(false)
highlight_button_outline_layered:set_visible(false)
highlight_button_check:set_visible(false)
highlight_button_canceled:set_visible(false)
-- Get the current button based on the current index
local grid_index = self.current_idx - ((self.start_row - 1) * self.max_width)
self.current_button = self.buttons[grid_index]
self.current_button:set_visible(true)
if self.data[1][1].is_layered then
highlight_button = Vdo_grid_button_layered:new("grid_top_button_layered", self.handle, self.doc_handle)
highlight_button_outline = Vdo_grid_button_layered:new("grid_top_button_outline_layered", self.handle, self.doc_handle)
highlight_button_outline:set_visible(true)
elseif self.data[1][1].is_checked ~= nil then
highlight_button = Vdo_grid_button_check:new("grid_top_button_check", self.handle, self.doc_handle)
elseif self.data[1][1].is_canceled_type ~= nil then
highlight_button = Vdo_grid_button_canceled:new("grid_top_button_canceled", self.handle, self.doc_handle)
else
highlight_button = Vdo_grid_button:new("grid_top_button", self.handle, self.doc_handle)
highlight_button_outline = Vdo_grid_button:new("grid_top_button_outline", self.handle, self.doc_handle)
highlight_button_outline:set_visible(true)
end
-- Hide button underneath for checked buttons
if self.data[self.current_cat][self.current_idx].is_checked ~= nil then
self.current_button:set_visible(false)
--hide check for highlight
--self.current_button:set_checkbox(-1)
end
local dual_is_visible = self.data[self.current_cat][self.current_idx].dual_wield
--set the size of the highlight
self:set_highlight_size(dual_is_visible)
highlight_button:set_visible(true)
local val = self.data[self.current_cat][self.current_idx]
if self.data[1][1].is_layered == nil or self.data[1][1].is_layered == false then
highlight_button:set_color(val.color.red, val.color.green, val.color.blue)
end
if self.highlight_color ~= nil then
highlight_button:set_highlight_color(self.highlight_color)
end
--Set the button icon
self:set_icon(highlight_button, val)
self:set_icon(highlight_button_outline, val)
-- set hightlight anchor position
local button_x,button_y = self.current_button:get_property("anchor")
local highlight = Vdo_base_object:new( "grid_highlight", self.handle, self.doc_handle)
highlight:set_property( "anchor", button_x, button_y)
highlight:set_visible(true)
--don't play highlight anim if index is the same
--if old_idx ~= self.current_idx then
local highlight_anim = Vdo_anim_object:new("highlight_anim", self.handle, self.doc_handle)
highlight_anim:play()
--end
local hint_button = Vdo_base_object:new("grid_hint_button", self.handle, self.doc_handle)
local highlight_scale_twn = Vdo_tween_object:new("grid_highlight_scale_twn", self.handle, self.doc_handle)
if hint_button_offset == nil then
-- Reposition hint button to bottom right corner of highlighted button
local highlight_width, highlight_height = highlight_button:get_screen_size()
local highlight_scale_x, highlight_scale_y = highlight_scale_twn:get_end_value()
hint_button:set_anchor(button_x + (highlight_width * highlight_scale_x * .5) - 35, button_y + (highlight_height * highlight_scale_y * .5) - 35)
else
hint_button:set_anchor(button_x + hint_button_offset, button_y + hint_button_offset)
end
-- Set highlighted item name
local highlight_label = self.data[self.current_cat][self.current_idx].label
local highlight_label_crc = self.data[self.current_cat][self.current_idx].label_crc
if highlight_label ~= nil then
self.highlight_name:set_text(highlight_label)
else
self.highlight_name:set_text_crc(highlight_label_crc)
end
self.group:set_anchor((self.button_w - SIZE_GRID_BUTTON) * 0.5, (self.button_h - SIZE_GRID_BUTTON)* 0.5)
end
-- =====================================
-- Mouse Specific Functions
-- =====================================
-- Returns the data index of the button selected based on the target handle.
-- Returns 0 (invalid index) if no button was found
--
function Vdo_grid_list:get_data_index(target_handle)
if not self.draw_called then
debug_print("vint", "Vdo_grid_list:get_selection called() with invalid document handle")
return
end
for idx, button in pairs(self.buttons) do
if button.handle == target_handle then
if self.rows > self.max_height then
if self.num_categories > 1 then
-- This should never happen
if self.data[self.button_cats[idx]][self.button_ids[idx]] == nil then
local bad_idx = idx
return 0
end
return self.button_ids[idx], self.button_cats[idx]
else
-- This works for grids without categories, but not ones with
local data_index = (self.start_row - 1) * self.max_width + idx
if self.data[self.current_cat][data_index] ~= nil then
return data_index, 1 -- 1 is the category
end
end
else
return idx
end
end
end
return 0
end
function Vdo_grid_list:get_visible_rows()
local end_row
if self.rows > self.max_height then
end_row = self.start_row + (self.max_height - 1)
else
end_row = self.rows
end
return self.start_row, end_row
end
function Vdo_grid_list:set_selection(new_index, new_category)
if not self.draw_called then
debug_print("vint", "Vdo_grid_list:get_selection called() with invalid document handle")
return
end
self.current_idx = new_index
if new_category ~= nil then
self.current_cat = new_category
else
self.current_cat = 1
end
end
-- Set and store the ui_screen, needed for the callback functions for the scroll and drag events
function Vdo_grid_list:set_ui_screen(ui_screen)
self.ui_screen = ui_screen
end
function Vdo_grid_list:add_mouse_inputs(callback_action, callback_nav, input_tracker, priority, update_scrollbar)
if (self.buttons == nil) or (callback_action == nil) or (callback_nav == nil) then
return
end
-- Store the callback functions for the update_mouse_inputs function
if self.callback_action ~= callback_action then
self.callback_action = callback_action
end
if self.callback_nav ~= callback_nav then
self.callback_nav = callback_nav
end
-- Default priority value to 150
priority = priority or 150
-- Add mouse_click and mouse_move events for each button in the list
for idx, button in pairs(self.buttons) do
input_tracker:add_mouse_input("mouse_click", callback_action, 50, button.handle)
input_tracker:add_mouse_input("mouse_move", callback_nav, 50, button.handle)
end
-- Add mouse inputs for the scroll region and scrolltab if needed
if self.rows > self.max_height and self.ui_screen ~= nil then
input_tracker:add_mouse_input("mouse_scroll", self.ui_screen.."_mouse_scroll", priority, self.bg.handle)
-- This forces the scroll wheel to work in "empty" areas of the grid
input_tracker:add_mouse_input("mouse_click", callback_action, priority, self.bg.handle)
if update_scrollbar == nil or update_scrollbar == true then
self.scrollbar:add_mouse_inputs(self.ui_screen, Scrollbar_input_tracker, priority)
end
end
-- Calculate the buttons' categories and ids (if categories are being used)
if self.num_categories > 1 then
-- Set the row of each self.data element
local cur_row = 1
local row_offset
for i = 1, self.num_categories do
cur_row = cur_row + 1
for j = 1, #self.data[i] do
row_offset = ((j - 1) - self:recursive_mod((j - 1), self.max_width)) / self.max_width
self.data[i][j].row = cur_row + row_offset
end
cur_row = cur_row + (row_offset + 1)
end
self.button_cats = {}
self.button_ids = {}
self.num_button_ids = 0
local end_row = self.start_row + self.max_height - 1
-- Loop through it all again, creating the button_ids and button_cats lists
for i = 1, self.num_categories do
for j = 1, #self.data[i] do
if self.data[i][j].row >= self.start_row and self.data[i][j].row <= end_row then
self.num_button_ids = self.num_button_ids + 1
self.button_cats[self.num_button_ids] = i
self.button_ids[self.num_button_ids] = j
end
end
end
end
end
-- Custom recursive mod function because it doesn't exist
function Vdo_grid_list:recursive_mod(value, modulus)
if (value >= modulus) then
return self:recursive_mod(value - modulus, modulus)
else
return value
end
end
-- Rebuilds the mouse input subscriptions, usually done when the list was rebuilt with draw_items()
--
function Vdo_grid_list:update_mouse_inputs(input_tracker)
if game_get_platform() ~= "PC" then
return
end
-- Default the input tracker to the Grid_mouse_input_tracker if not specified
if input_tracker == nil then
input_tracker = Grid_mouse_input_tracker
end
input_tracker:remove_all()
self:add_mouse_inputs(self.callback_action, self.callback_nav, input_tracker, 50, false)
input_tracker:subscribe(true)
end
function Vdo_grid_list:scroll_list(scroll_lines, new_start_index)
new_start_index = new_start_index or 0
if scroll_lines == 0 and (new_start_index == self.start_row or new_start_index == 0) then
return
end
local old_start_row = self.start_row
if new_start_index ~= 0 then
-- Set the new start index (calculated by the scrolltab)
self.start_row = new_start_index
else
-- Update the rows that are visible if scrolled with the scroll wheel
self.start_row = self.start_row + scroll_lines
local end_row = self.start_row + (self.max_height - 1)
if self.start_row < 1 then
self.start_row = 1
elseif end_row > self.rows then
self.start_row = self.rows - (self.max_height - 1)
end
end
local end_row = self.start_row + (self.max_height - 1)
-- Move the highlight to a visible row if necessary (cannot go outside the visible range)
if self.num_categories == 1 then
local current_row = ceil(self.current_idx / self.max_width)
if current_row < self.start_row then
self.current_idx = self.current_idx + ((self.start_row - current_row) * self.max_width)
elseif current_row > end_row then
self.current_idx = self.current_idx - ((current_row - end_row) * self.max_width)
end
end
-- Don't want draw_items to scroll the list or move the scrolltab
self.update_start_row = false;
if scroll_lines ~= 0 then
self.scrollbar:set_value(self.rows - (self.max_height - 1), self.start_row)
end
-- Only update the list if the visible rows have changed
if old_start_row ~= self.start_row then
self:draw_items(self.data, self.current_idx, self.max_width, self.max_height, self.button_w, self.button_h, self.hint_button_offset, self.current_cat, self.outline_scale, self.background_enabled, self.show_current_button_bool, self.grid_spacing, self.set_size)
--self:draw_items(self.data, self.current_idx, self.max_width, self.max_height, self.button_w, self.button_h, self.hint_button_offset, self.current_cat)
self:update_mouse_inputs()
end
end
function Vdo_grid_list:show_highlight_text( show_text )
--show_text is a boolean from the screen
self.highlight_name:set_visible( show_text )
end
function Vdo_grid_list:show_current_button( show_button )
--show_button is a boolean, used on the radio station select screen
self.show_current_button_bool = show_button
end
function Vdo_grid_list:tint_current_button( tint_button )
--tint_button is a boolean, used on the radio station select screen
--tints unhighlighted buttons grey
self.tint_current_button = tint_button
end
function Vdo_grid_list:set_input_tracker(input_tracker)
self.store_input_tracker = input_tracker
end