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 = 6 
 
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() 
 
			self.buttons[i] = nil 
 
		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 
 
		table_clear(self.titles, true) 
 
	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 
 
	vint_force_lua_gc() 
 
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 = {}  
	local data_size = 1 
 
	 
 
	-- 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 
 
		 
 
		if(input_data[0] ~= nil)then -- Some input_data tables come in with a 0 value, copy over to data table but start with 1 instead 
 
			data[1] = {}  
			for i = 0, #input_data do 
 
				data[1][data_size] = input_data[i] 
 
				i = i + 1 
 
				data_size = data_size + 1 
 
			end 
 
		else 
 
			data[1] = input_data 
 
		end 
 
		 
 
		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 + ANCHOR_SCROLLBAR_BUFFER, 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 
 
						 
 
						local num_rows_new_cat = ceil(self.cat_buttons[self.current_cat] / self.max_width) 
 
						 
 
						-- We now need to calculate the index in the new category to use 
 
						self.current_idx = (num_rows_new_cat * self.max_width) - (self.max_width - old_idx) 
 
 
 
						if self.current_idx > self.cat_buttons[self.current_cat] then 
 
							if( self.cat_buttons[self.current_cat] <= self.max_width ) then  
 
								self.current_idx = old_idx 
 
							else 
 
								self.current_idx = self.current_idx - self.max_width 
 
							end 
 
							 
 
							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_actual_size() 
 
	local bg_width, bg_height = self.bg:get_actual_size() 
 
	 
 
	self.titles[title_index].line:set_anchor(text_width + 10, text_height * 0.5) 
 
	 
 
	self.titles[title_index].line:set_actual_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