./vdo_grid_list.lua

  1. Vdo_grid_list_tween_done = true 
  2. local Input_tracker 
  3. local Grid_mouse_input_tracker 
  4. local Scrollbar_input_tracker 
  5.  
  6. local GRID_BUTTON_SPACING	= 3 
  7. local GRID_BUTTON_SIZE 		= 150 
  8. local MOVE_UP					= -2 
  9. local MOVE_DOWN				= 2 
  10. local MOVE_LEFT				= -1 
  11. local MOVE_RIGHT				= 1 
  12.  
  13. local SCALE_STD_RES_GRID_BUTTON = .67 --.9 
  14. local ANCHOR_SCROLLBAR_BUFFER = 28 
  15. local ANCHOR_TITLE_SPACE = 32 
  16. local SIZE_GRID_BUTTON = 59 
  17.  
  18. function vdo_grid_list_init() 
  19. end 
  20.  
  21. function vdo_grid_list_cleanup() 
  22. end 
  23.  
  24. -- Inherited from Vdo_base_object 
  25. Vdo_grid_list = Vdo_base_object:new_base() 
  26.  
  27. function Vdo_grid_list:init() 
  28. 	-- Hide the initial button 
  29. 	vint_set_property(vint_object_find("grid_base"), "visible", false) 
  30. 	vint_set_property(vint_object_find("grid_layered"), "visible", false) 
  31. 	vint_set_property(vint_object_find("grid_check"), "visible", false) 
  32. 	vint_set_property(vint_object_find("grid_canceled"), "visible", false) 
  33. 	vint_set_property(vint_object_find("grid_anchor"), "visible", false) 
  34. 	vint_set_property(vint_object_find("grid_title"), "visible", false) 
  35.  
  36. 	self.scrollbar = Vdo_scrollbar:new("grid_scrollbar", self.handle, self.doc_handle) 
  37. 	self.group = Vdo_base_object:new("grid_group", self.handle, self.doc_handle) 
  38. 	self.bg = Vdo_base_object:new("grid_list_bg",self.handle, self.doc_handle) 
  39. 	self.highlight_name = Vdo_base_object:new("grid_highlight_name", self.handle, self.doc_handle) 
  40. 	self.input_enabled = false 
  41. 	 
  42. 	self.scrollbar:set_visible(false)	 
  43. 	 
  44. 	Vdo_grid_list_tween_done = true 
  45. 	 
  46. 	local highlight = Vdo_hint_button:new( "grid_hint_button", self.handle, self.doc_handle) 
  47. 	highlight:set_button(CTRL_MENU_BUTTON_A) 
  48. 	if game_is_active_input_gamepad() == false then 
  49. 		highlight:set_visible(false) 
  50. 	end 
  51. 		 
  52. 	local list_anim = Vdo_anim_object:new("grid_group_anim", self.handle, self.doc_handle) 
  53. 	list_anim:stop() 
  54. 	 
  55. 	Input_tracker = Vdo_input_tracker:new() 
  56. 	 
  57. 	--clone title and add it to grid here 
  58. 	local base_title_grp = Vdo_base_object:new("grid_title_grp", self.handle, self.doc_handle) 
  59. 	base_title_grp:set_visible(false)	 
  60. 	 
  61. 	self.draw_called = false 
  62. 	self.title_added = false	 
  63. 	self.update_start_row = true	 
  64. 	 
  65. 	if game_get_platform() == "PC" then 
  66. 		Grid_mouse_input_tracker = Vdo_input_tracker:new() 
  67. 		Scrollbar_input_tracker = Vdo_input_tracker:new()				 
  68. 	end 
  69. end 
  70.  
  71. -- Deletes the internal data and destroys the button clones 
  72. function Vdo_grid_list:cleanup() 
  73. 	if self.draw_called then 
  74. 		for i, button in pairs(self.buttons) do 
  75. 			button:object_destroy() 
  76. 		end 
  77. 		self.draw_called = false 
  78. 	end 
  79. 	 
  80. 	if self.title_added then 
  81. 		for i = 1, #self.titles do 
  82. 			self.titles[i]:object_destroy() 
  83. 		end 
  84. 		self.title_added = false 
  85. 	end 
  86. 	 
  87. 	if Grid_mouse_input_tracker ~= nil then 
  88. 		--Grid_mouse_input_tracker:remove_all() 
  89. 		Grid_mouse_input_tracker:subscribe(false) 
  90. 		 
  91. 		-- Not unsubscribing from the scrollbar here is intentional 
  92. 		-- If you do, it prevents the mouse from dragging the scrollbar correctly 
  93. 	end 
  94. 	 
  95. 	self.data = nil 
  96. end 
  97.  
  98. 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) 
  99. 	max_width = max_width or 999 
  100. 	max_height = max_height or 999 
  101. 	 
  102. 	if self.draw_called == false then 
  103. 		self.update_start_row = true 
  104. 	end 
  105. 	 
  106. 	-- Nuke the shit out of whatever was previously here 
  107. 	self:cleanup() 
  108.  
  109. 	local data = {} 
  110. 	 
  111. 	-- 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 
  112. 	-- it greatly simplifies the script.  We just won't draw the header for grids that only have one category. 
  113. 	if input_data[1].category_name == nil then 
  114. 		data[1] = input_data 
  115. 		current_category = 1 
  116. 		data[1].category_name = "filler cat name" 
  117. 	else 
  118. 		data = input_data 
  119. 	end 
  120. 	 
  121. 	-- Set up tables to manage handles and data for this object 
  122. 	self.draw_called = true 
  123. 	self.buttons = {} 
  124. 	self.data = data 
  125. 	self.open = false 
  126. 	self.max_width = max_width 
  127. 	self.max_height = max_height	 
  128. 	self.button_w = button_w or GRID_BUTTON_SIZE 
  129. 	self.button_h = button_h or GRID_BUTTON_SIZE 
  130. 	self.hint_button_offset = hint_button_offset 
  131. 	self.outline_scale = outline_scale 
  132. 	self.background_enabled = background_enabled 
  133. 	self.show_current_button_bool = show_current_button_bool 
  134. 	self.grid_spacing = grid_spacing or GRID_BUTTON_SPACING 
  135. 	self.set_size = set_size 
  136. 	self.titles = {} 
  137. 	self.rows = 0 
  138. 	self.num_buttons = 0 
  139. 	self.cat_rows = {} 
  140. 	self.cat_buttons = {} 
  141. 	 
  142. 	local curr_row = 1 
  143. 		 
  144. 	self.num_categories = #data 
  145. 	 
  146. 	-- Set up handle for base button 
  147. 	local base_button 
  148. 	 
  149. 	-- Check which button to use 
  150. 	if data[1][1].is_layered then 
  151. 		base_button = Vdo_grid_button_layered:new("grid_layered", self.handle, self.doc_handle) 
  152. 	elseif data[1][1].is_checked ~= nil then 
  153. 		base_button = Vdo_grid_button_check:new("grid_check", self.handle, self.doc_handle) 
  154. 	elseif data[1][1].is_canceled_type then 
  155. 		base_button = Vdo_grid_button_canceled:new("grid_canceled", self.handle, self.doc_handle) 
  156. 	else 
  157. 		base_button = Vdo_grid_button:new("grid_base", self.handle, self.doc_handle) 
  158. 	end 
  159. 	 
  160. 	if base_button.handle == 0 then 
  161. 		return 
  162. 	end	 
  163. 	 
  164. 	--get the x and y of the button 
  165. 	base_button:set_property("anchor", -1 * self.button_w, -1 * self.button_h) 
  166. 	base_button.x, base_button.y = base_button:get_property("anchor") 
  167. 	 
  168. 	--adjust for negative grid padding 
  169. 	if self.grid_spacing < 0 then 
  170. 		base_button:set_anchor(base_button.x + (self.grid_spacing * -2), base_button.y + (self.grid_spacing * -2)) 
  171. 		base_button.x, base_button.y = base_button:get_property("anchor") 
  172. 	end 
  173. 		 
  174. 	-- Set initial category 
  175. 	if current_category == nil or current_category < 1 or current_category > self.num_categories then 
  176. 		current_category = 1 
  177. 	end 
  178. 	self.current_cat = current_category 
  179. 	 
  180. 	-- We need to go through all the categories and add up the rows, and find which row number our 
  181. 	-- current choice is in 
  182. 	local header_offset = 0 
  183. 	if self.num_categories > 1 then 
  184. 		header_offset = 1 
  185. 	end	 
  186. 	 
  187. 	local adjusted_height = (self.max_height * (self.button_h + self.grid_spacing)) + (self.grid_spacing * 2)  
  188. 	local adjusted_width = (self.button_w + self.grid_spacing) * self.max_width + (self.grid_spacing * 2) 
  189. 	 
  190. 	--adjust background for negative grid spacing 
  191. 	if self.grid_spacing < 0 then 
  192. 		adjusted_width = (self.button_w + self.grid_spacing) * self.max_width + (self.grid_spacing * 2) + (self.grid_spacing * -4) 
  193. 		adjusted_height = (self.max_height * (self.button_h + self.grid_spacing)) + (self.grid_spacing * 2) + (self.grid_spacing * -4) 
  194. 	end	 
  195. 	 
  196. 	--set background size and anchor 
  197. 	if self.background_enabled == nil then 
  198. 		self.background_enabled = true 
  199. 	end 
  200. 	 
  201. 	self.bg:set_visible(self.background_enabled) 
  202. 	 
  203. 	element_set_actual_size(self.bg.handle, adjusted_width, adjusted_height ) 
  204. 	 
  205. 	self.bg:set_anchor((self.button_w + self.grid_spacing) * -0.5, (self.button_h + self.grid_spacing) * -0.5)		 
  206. 	 
  207. 	local bg_x, bg_y = self.bg:get_anchor()	 
  208. 	 
  209. 	for i = 1, #data do 
  210. 	 
  211. 		self.cat_buttons[i] = #data[i] 
  212. 		self.num_buttons = self.num_buttons + self.cat_buttons[i] 
  213. 		 
  214. 		-- see if this category holds our current highlighted item 
  215. 		if i == self.current_cat then 
  216. 		 
  217. 			-- Set initial cursor position 
  218. 			if current_option == nil or current_option < 1  or current_option > self.cat_buttons[i] then 
  219. 				current_option = 1 
  220. 			end 
  221. 			 
  222. 			curr_row = self.rows + header_offset + ceil(current_option / self.max_width) 
  223. 		end 
  224. 		 
  225. 		self.cat_rows[i] = header_offset + ceil(self.cat_buttons[i]/max_width) 
  226. 		self.rows = self.rows + self.cat_rows[i] 
  227. 		 
  228. 	end 
  229. 	 
  230. 	--set the curent button to the passed in variable for the current option (as long as it's not nil) 
  231. 	if self.data[self.current_cat][current_option] ~= nil then 
  232. 		self.current_idx = current_option 
  233. 	end 
  234. 	 
  235. 	--if we have less rows than the max visible set the max visible to the number of rows 
  236. 	if self.rows < self.max_height then 
  237. 		self.max_height = self.rows 
  238. 	end	 
  239. 	 
  240. 	local start_row  
  241. 	if self.update_start_row then 
  242. 		-- calculate the first row we should display 
  243. 		start_row = curr_row - floor(self.max_height / 2) 
  244. 		if start_row < 1 then 
  245. 			start_row = 1 
  246. 		end 
  247. 		if start_row + self.max_height - 1 > self.rows then 
  248. 			start_row = self.rows - self.max_height + 1 
  249. 		end 
  250. 		 
  251. 		self.start_row = start_row 
  252. 		 
  253. 	else 
  254. 		-- If self.update_start_row is false, use self.start_row since then the starting row was already set 
  255. 		start_row = self.start_row 
  256. 	end 
  257. 	 
  258. 	local new_x = base_button.x 
  259. 	local new_y = base_button.y 
  260. 	 
  261. 	--loop through the visible rows and populate our table of buttons 
  262. 	local data_index 
  263. 	local cat_index 
  264. 	local grid_index = 1	 
  265. 	local draw_header = false	 
  266. 	 
  267. 	if self.num_categories > 1 then 
  268. 		local row_count = 0 
  269. 		for i = 1,self.num_categories do 
  270.  
  271. 			if start_row <= row_count + self.cat_rows[i] then 
  272. 				cat_index = i 
  273.  
  274. 				if start_row - row_count == 1 then 
  275. 					-- the first row to draw is a header row 
  276. 					draw_header = true 
  277. 					data_index = ((start_row - row_count - 1) * self.max_width) + 1 
  278. 				else 
  279. 					-- -2 to account for indexing starting at 1, and 1 row for category header 
  280. 					data_index = ((start_row - row_count - 2) * self.max_width) + 1				 
  281. 				end 
  282. 				 
  283. 				-- found category, stop loop 
  284. 				break 
  285. 			end 
  286. 			 
  287. 			row_count = row_count + self.cat_rows[i] 
  288. 		end 
  289. 	else 
  290. 		cat_index = 1 
  291. 		data_index = ((start_row - 1) * self.max_width) + 1	 
  292. 	end	 
  293. 		 
  294. 	local title_count = 0 
  295. 	 
  296. 	for i = 1,self.max_height do 
  297. 		-- are we on a category header row? 
  298. 		-- BTW, I can't believe lua doesn't have a continue operation... 
  299. 		if draw_header then 
  300. 			draw_header = false 
  301.  
  302. 			-- draw the category header 
  303. 			title_count = title_count + 1 
  304. 			self:add_subtitle(self.data[cat_index].category_name, title_count, new_y) 
  305. 					 
  306. 		else 	 
  307. 	 
  308. 			--only use grid spacing after the first row 
  309. 			--if i > 1 then 
  310. 				new_y = base_button.y + ((self.button_h + self.grid_spacing) * (i)) 
  311. 			--else 
  312. 			--	new_y = 0--base_button.y 
  313. 			--end 
  314. 			 
  315. 			--loop through the columns 
  316. 			for j = 1, max_width do 
  317. 				--check so that we don't run out of valid data 
  318. 				if data_index > self.num_buttons then 
  319. 					break 
  320. 				end 
  321. 				 
  322. 				--only use grid spacing after the first column 
  323. 				--if j == 1 then 
  324. 				--	new_x = 0--base_button.x 
  325. 				--else 
  326. 					new_x = base_button.x + ((self.button_w + self.grid_spacing) * j)	 
  327. 				--end 
  328. 								 
  329. 				if self.data[1][1].is_layered then 
  330. 					self.buttons[grid_index] = Vdo_grid_button_layered:clone(base_button.handle) 
  331. 				elseif self.data[1][1].is_checked ~= nil then 
  332. 					self.buttons[grid_index] = Vdo_grid_button_check:clone(base_button.handle)					 
  333. 				elseif self.data[1][1].is_canceled_type ~= nil then 
  334. 					self.buttons[grid_index] = Vdo_grid_button_canceled:clone(base_button.handle)					 
  335. 				else 
  336. 					self.buttons[grid_index] = Vdo_grid_button:clone(base_button.handle) 
  337. 				end				 
  338. 				self.buttons[grid_index]:set_visible(true) 
  339. 				local button = self.buttons[grid_index] 
  340. 				 
  341. 				local button_data = data[cat_index][data_index] 
  342.  
  343. 				-- Set the button icon 
  344. 				-- check for dual icons 
  345. 				if button_data.dual_wield == true then 
  346. 					button:set_icon(button_data.icon, true) 
  347. 				else 
  348. 					self:set_icon(button, button_data) 
  349. 				end 
  350. 			 
  351. 				-- Set the button toggle text 
  352. 				if button_data.label ~= nil then 
  353. 					button:set_text(button_data.label) 
  354. 				else 
  355. 					button:set_text_crc(button_data.label_crc) 
  356. 				end				 
  357. 				 
  358. 				-- Only color it if it's not a layered button 
  359. 				if self.data[1][1].is_layered == nil or self.data[1][1].is_layered == false then 
  360. 					button:set_color(button_data.color.red, button_data.color.green, button_data.color.blue)					 
  361. 				end 
  362.  
  363. 				-- If it's canceled_type button, then set whether it starts disabled 
  364. 				if self.data[1][1].is_canceled_type then 
  365. 					button:set_cancel(button_data.disabled) 
  366. 				end 
  367. 				 
  368. 				--debug_print("vint", "cat_index = "..cat_index..", grid_index = "..grid_index..", data_index = "..data_index.."\n") 
  369. 				 
  370. 				if self.data[cat_index][data_index].is_checked == true then 
  371. 					button:set_checkbox(1,self.highlight_color) 
  372. 				end 
  373. 				 
  374. 				-- Make the button visible 
  375. 				button:set_visible(true) 
  376. 				button:set_property("anchor", new_x, new_y) 
  377. 				 
  378. 				if set_size == true then 
  379. 					button:set_size(button_w,button_h) 
  380. 									 
  381. 					if vint_is_std_res() == true then			 
  382. 						button:set_scale(SCALE_STD_RES_GRID_BUTTON, SCALE_STD_RES_GRID_BUTTON) 
  383. 					end	 
  384. 				end				 
  385. 				 
  386. 				--check to see if we want unhighlighted buttons greyed out, used for radio station select 
  387. 				if self.tint_current_button == true then 
  388. 					local grey = 100 
  389. 					button:set_color(grey/255,grey/255,grey/255) 
  390. 				end 
  391. 				 
  392. 				-- if this is the highlighted choice, save for easy reference 
  393. 				if cat_index == self.current_cat and data_index == self.current_idx then 
  394. 					self.current_button = button 
  395. 				end 
  396. 				 
  397. 				self.prev_title = button_data.title 
  398. 				 
  399. 				data_index = data_index + 1 
  400. 				grid_index = grid_index + 1 
  401. 				 
  402. 				-- have we reached the end of the category? 
  403. 				if self.num_categories > 1 and data_index > self.cat_buttons[cat_index] then 
  404. 					data_index = 1 
  405. 					cat_index = cat_index + 1 
  406. 					draw_header = true 
  407. 					break 
  408. 				end 
  409. 			end 
  410. 		end 
  411. 	end 
  412.  
  413. 	if self.rows > self.max_height then 
  414. 		 
  415. 		self.scrollbar:set_anchor(bg_x + adjusted_width + GRID_BUTTON_SPACING, bg_y) 
  416. 		 
  417. 		if game_get_platform() == "PC" then	 
  418. 			local adjusted_total_height = (self.rows * (self.button_h + self.grid_spacing)) + (self.grid_spacing * 2)  
  419. 			self.scrollbar:set_size(SCROLLBAR_WIDTH, adjusted_height, adjusted_total_height) 
  420. 			 
  421. 			-- If self.update_start_row was false, then the scrollbar's value is already being set. 
  422. 			if self.update_start_row then 
  423. 				self.scrollbar:set_value(self.rows - (self.max_height - 1), self.start_row) 
  424. 			end 
  425. 			 
  426. 		else 
  427. 			self.scrollbar:set_size(SCROLLBAR_WIDTH, adjusted_height) 
  428. 			self.scrollbar:set_value(self.rows, curr_row) 
  429. 		end 
  430. 		 
  431. 		self.scrollbar:set_property("visible",true) 
  432. 	else 
  433. 		self.scrollbar:set_property("visible",false) 
  434. 	end 
  435. 	 
  436. 	--position name for highlighted item 
  437. 	self.highlight_name:set_anchor(bg_x, bg_y + adjusted_height + GRID_BUTTON_SPACING, 1) 
  438. 	 
  439. 	-- Highlight current button 
  440. 	local highlight_button = Vdo_grid_button:new("grid_top_button", self.handle, self.doc_handle) 
  441. 	local highlight_button_outline = Vdo_grid_button:new("grid_top_button_outline", self.handle, self.doc_handle) 
  442. 	local highlight_button_layered = Vdo_grid_button:new("grid_top_button_layered", self.handle, self.doc_handle) 
  443. 	local highlight_button_outline_layered = Vdo_grid_button:new("grid_top_button_outline_layered", self.handle, self.doc_handle) 
  444. 	local highlight_button_check = Vdo_grid_button_check:new("grid_top_button_check", self.handle, self.doc_handle) 
  445. 	local highlight_button_canceled = Vdo_grid_button_canceled:new("grid_top_button_canceled", self.handle, self.doc_handle) 
  446.  
  447. 	highlight_button:set_visible(false)	 
  448. 	highlight_button_outline:set_visible(false)	 
  449. 	highlight_button_layered:set_visible(false)	 
  450. 	highlight_button_outline_layered:set_visible(false)	 
  451. 	highlight_button_check:set_visible(false)	 
  452. 	highlight_button_canceled:set_visible(false)	 
  453. 	 
  454. 	-- Make sure current_button was set to a valid button, otherwise set it to the first button 
  455. 	if self.current_button.handle < 1 then 
  456. 		self.current_button = self.buttons[1] 
  457. 	end 
  458. 	self.current_button:set_visible(true) 
  459. 	 
  460. 	if self.data[1][1].is_layered then 
  461. 		highlight_button = Vdo_grid_button_layered:new("grid_top_button_layered", self.handle, self.doc_handle) 
  462. 		highlight_button_outline = Vdo_grid_button_layered:new("grid_top_button_outline_layered", self.handle, self.doc_handle)	 
  463. 		highlight_button_outline:set_visible(true) 
  464. 	elseif self.data[1][1].is_checked ~= nil then 
  465. 		highlight_button = Vdo_grid_button_check:new("grid_top_button_check", self.handle, self.doc_handle) 
  466. 		highlight_button_outline = Vdo_grid_button_check:new("grid_top_button_check", self.handle, self.doc_handle)	 
  467. 		--highlight_button:set_checkbox(1,self.highlight_color)		 
  468. 	elseif self.data[1][1].is_canceled_type ~= nil then 
  469. 		highlight_button = Vdo_grid_button_canceled:new("grid_top_button_canceled", self.handle, self.doc_handle) 
  470. 		highlight_button_outline = Vdo_grid_button_canceled:new("grid_top_button_canceled", self.handle, self.doc_handle)			 
  471. 	else 
  472. 		highlight_button = Vdo_grid_button:new("grid_top_button", self.handle, self.doc_handle) 
  473. 		highlight_button_outline = Vdo_grid_button:new("grid_top_button_outline", self.handle, self.doc_handle) 
  474. 		highlight_button_outline:set_visible(true) 
  475. 	end	 
  476. 	 
  477. 	-- Hide button underneath for checked buttons 
  478. 	if self.data[self.current_cat][current_option].is_checked ~= nil then 
  479. 		self.current_button:set_visible(false) 
  480. 	end 
  481. 	 
  482. 	-- check to see if we want to show the icon behind the highlight, used on radio station select 
  483. 	-- after the first draw save the status in self.show_current_button 
  484. 	if self.show_current_button_bool ~= nil then 
  485. 		--self.show_current_button = show_current_button 
  486. 		self.current_button:set_visible(show_current_button_bool) 
  487. 	end 
  488.  
  489. 	local button_data = self.data[self.current_cat][self.current_idx] 
  490. 		 
  491. 	--set the size of the highlight 
  492. 	self:set_highlight_size(button_data.dual_wield) 
  493.  
  494. 	highlight_button:set_visible(true)	 
  495. 		 
  496. 			 
  497. 	if outline_scale ~= nil then 
  498. 		highlight_button_outline:set_scale(outline_scale, outline_scale)			 
  499. 	end 
  500. 	 
  501. 	if self.data[1][1].is_layered == nil or self.data[1][1].is_layered == false then 
  502. 		highlight_button:set_color(button_data.color.red, button_data.color.green, button_data.color.blue) 
  503. 	end 
  504. 	 
  505. 	--do we have a check box type button? 
  506. 	--if so set the highlight color if highlight color is valid 
  507. 	if self.highlight_color ~= nil and self.data[1][1].is_checked ~= nil  then 
  508. 		highlight_button:set_highlight_color(self.highlight_color) 
  509. 	end 
  510. 	 
  511. 	--Set the button icon 
  512. 	self:set_icon(highlight_button, button_data)	 
  513. 	self:set_icon(highlight_button_outline, button_data)	 
  514. 	 
  515. 	-- set hightlight anchor position 
  516. 	local button_x,button_y = self.current_button:get_property("anchor") 
  517. 	local highlight = Vdo_base_object:new( "grid_highlight", self.handle, self.doc_handle) 
  518. 	highlight:set_property( "anchor", button_x, button_y) 
  519. 	highlight:set_visible(true) 
  520. 	 
  521. 	--don't play highlight anim if index is the same 
  522. 	--if old_idx ~= self.current_idx then 
  523. 	local highlight_anim = Vdo_anim_object:new("highlight_anim", self.handle, self.doc_handle) 
  524. 	highlight_anim:play() 
  525. 	--end 
  526. 		 
  527. 	local hint_button = Vdo_base_object:new("grid_hint_button", self.handle, self.doc_handle) 
  528. 	local highlight_scale_twn = Vdo_tween_object:new("grid_highlight_scale_twn", self.handle, self.doc_handle) 
  529. 	 
  530. 	if hint_button_offset == nil then 
  531. 		-- Reposition hint button to bottom right corner of highlighted button 
  532. 		local highlight_width, highlight_height = highlight_button:get_screen_size() 
  533. 		local highlight_scale_x, highlight_scale_y = highlight_scale_twn:get_end_value()		 
  534. 		hint_button:set_anchor(button_x + (highlight_width * highlight_scale_x * .5) - 35, button_y + (highlight_height * highlight_scale_y * .5) - 35) 
  535. 	else 
  536. 		hint_button:set_anchor(button_x + hint_button_offset, button_y + hint_button_offset) 
  537. 	end	 
  538. 		 
  539. 	-- Set highlighted item name 
  540. 	local highlight_label = self.data[self.current_cat][self.current_idx].label 
  541. 	local highlight_label_crc = self.data[self.current_cat][self.current_idx].label_crc 
  542. 	 
  543. 	if highlight_label ~= nil then 
  544. 		self.highlight_name:set_text(highlight_label) 
  545. 	else 
  546. 		self.highlight_name:set_text_crc(highlight_label_crc) 
  547. 	end	 
  548. 	 
  549. 	-- align grid list to the top right of the button for easier placement in the doc 
  550. 	--local first_btn_width, first_btn_height = self.buttons[1]:get_screen_size()	 
  551. 	self.group:set_anchor((self.button_w - SIZE_GRID_BUTTON) * 0.5, (self.button_h - SIZE_GRID_BUTTON)* 0.5) 
  552. 	 
  553. 	--disable the clip/mask for now 
  554. 	--local grid_clip = Vdo_base_object:new("grid_clip") 
  555. 	--grid_clip:set_property("clip_enabled", false) 
  556. 	 
  557. 	self.update_start_row = true 
  558. end 
  559.  
  560. function Vdo_grid_list:move_cursor(direction, do_not_redraw, is_index_set) 
  561. 	if not self.draw_called then 
  562. 		return 
  563. 	end 
  564. 	 
  565. 	local num_rows = ceil(self.cat_buttons[self.current_cat] / self.max_width) 
  566. 	 
  567. 	-- Don't update the start row when using the mouse to select something 
  568. 	if direction == 0 then 
  569. 		self.update_start_row = false 
  570. 	end 
  571. 	 
  572. 	--check if we have more than one row or category 
  573. 	if self.num_categories == 1 and num_rows <= 1 and (direction == MOVE_UP or direction == MOVE_DOWN) then 
  574. 		return 
  575. 	--check if we have one item 
  576. 	elseif self.num_categories == 1 and self.num_buttons <= 1 then 
  577. 		return 
  578. 	else 
  579. 		--check if we can process input 
  580. 		if Vdo_grid_list_tween_done then 
  581. 		 
  582. 			-- Clear out old highlight 
  583. 			for idx, button in pairs(self.buttons) do 
  584. 				button:set_highlight(false)			 
  585. 			end 
  586. 			 
  587. 			-- apply movement 
  588. 			local move_offset 
  589. 			if direction == MOVE_UP then 
  590. 				move_offset = - self.max_width 
  591. 			elseif direction == MOVE_DOWN then 
  592. 				move_offset = self.max_width 
  593. 			else 
  594. 				move_offset = direction 
  595. 			end 
  596. 			local old_idx = self.current_idx 
  597. 			local prev_row = ceil(self.current_idx / self.max_width) 
  598.  
  599. 			-- apply movement 
  600. 			self.current_idx = self.current_idx + move_offset 
  601. 			local new_row = ceil(self.current_idx / self.max_width) 
  602. 			 
  603.  
  604. 			-- do we need a header row? 
  605. 			local offset = 1 
  606. 			if self.num_categories > 1 then 
  607. 				offset = 2 
  608. 			end 
  609. 			 
  610. 			local num_buttons = self.cat_buttons[self.current_cat]		 
  611. 			local last_row_len = num_buttons - ((self.cat_rows[self.current_cat] - offset) * self.max_width) 
  612. 			 
  613. 			if is_index_set then 
  614. 				-- if the index was set from mouse_move, update only the highlight since the grid's contents have not changed 
  615. 				self:update_highlight(self.hint_button_offset) 
  616. 				 
  617. 			else 
  618. 				-- handle all wrapping 
  619. 				if direction == MOVE_RIGHT then 
  620. 					-- row wrap 
  621. 					if new_row ~= prev_row then 
  622. 						self.current_idx = self.current_idx - self.max_width 
  623. 					end 
  624. 					-- last short row wrap 
  625. 					if self.current_idx > num_buttons then 
  626. 						self.current_idx = self.current_idx - last_row_len 
  627. 					end 
  628. 				elseif direction == MOVE_LEFT then 
  629. 					-- row wrap 
  630. 					if new_row ~= prev_row then 
  631. 						self.current_idx = self.current_idx + self.max_width 
  632. 					end 
  633. 					-- last short row wrap 
  634. 					if self.current_idx > num_buttons then 
  635. 						self.current_idx = self.current_idx - (self.max_width - last_row_len) 
  636. 					end 
  637. 				elseif direction == MOVE_UP then 
  638. 					-- top of grid wrap 
  639. 					if self.current_idx < 1 then 
  640. 					 
  641. 						-- go to previous category 
  642. 						self.current_cat = self.current_cat - 1 
  643. 						if self.current_cat < 1 then 
  644. 							self.current_cat = self.num_categories 
  645. 						end 
  646. 						 
  647. 						-- We now need to calculate the index in the new category to use 
  648. 						self.current_idx = ((old_idx - 1) % self.max_width) + 1 + ((num_rows - 1) * self.max_width) 
  649.  
  650. 						if self.current_idx > self.cat_buttons[self.current_cat] then 
  651. 							self.current_idx = self.current_idx - self.max_width 
  652. 							if self.current_idx > self.cat_buttons[self.current_cat] or self.current_idx < 1 then 
  653. 								self.current_idx = self.cat_buttons[self.current_cat] 
  654. 							end 
  655. 						end 
  656.  
  657. 					end 
  658. 				elseif direction == MOVE_DOWN then 
  659. 					-- end of grid wrap 
  660. 					if self.current_idx > num_buttons then 
  661. 					 
  662. 						-- go to next category 
  663. 						self.current_cat = self.current_cat + 1 
  664. 						if self.current_cat > self.num_categories then 
  665. 							self.current_cat = 1 
  666. 						end 
  667. 						 
  668. 						-- We now need to calculate the index in the new category to use 
  669. 						self.current_idx = ((old_idx - 1) % self.max_width) + 1 
  670. 						if self.current_idx > self.cat_buttons[self.current_cat] then 
  671. 							self.current_idx = self.cat_buttons[self.current_cat] 
  672. 						end 
  673.  
  674. 					end 
  675. 				end 
  676. 				 
  677. 				--redraw the list 
  678. 				if do_not_redraw ~= true then 
  679. 					--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 
  680. 					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) 
  681. 					self:update_mouse_inputs() 
  682. 				end 
  683. 			end 
  684. 		end 
  685. 		 
  686. 		--check if we should play scrolling audio 
  687. 		if direction ~= 0 or is_index_set then 
  688. 			if self.num_buttons > 1 then 
  689. 				game_UI_audio_play("UI_Reward_Store_Menu_Navigation") 
  690. 			end 
  691. 		end 
  692. 	end 
  693. end 
  694.  
  695. function Vdo_grid_list:get_selection() 
  696. 	if not self.draw_called then 
  697. 		return 
  698. 	end 
  699.  
  700. 	return self.current_idx 
  701. end 
  702.  
  703. -- Gets an optional ID value if one is saved 
  704. function Vdo_grid_list:get_id() 
  705. 	if not self.draw_called then 
  706. 		return 
  707. 	end 
  708. 	 
  709. 	return self.data[self.current_cat][self.current_idx].id 
  710. end 
  711.  
  712. function Vdo_grid_list:get_data_from_id(id) 
  713.  
  714. 	for i, category in pairs (self.data) do 
  715. 		for j, entry in pairs (category) do 
  716. 			if entry.id == id then 
  717. 				return entry 
  718. 			end 
  719. 		end 
  720. 	end 
  721.  
  722. end 
  723.  
  724. function Vdo_grid_list:button_a() 
  725. 	if not self.draw_called then 
  726. 		return 
  727. 	end 
  728. 		 
  729. 	--check if we can process input 
  730. 	if not Vdo_grid_list_tween_done then 
  731. 		return 
  732. 	end 
  733. 	 
  734. 	self:toggle_checked()	 
  735. end 
  736.  
  737. function Vdo_grid_list:button_b() 
  738. 	if not self.draw_called then 
  739. 		return 
  740. 	end 
  741.  
  742. end 
  743.  
  744. function Vdo_grid_list:toggle_checked() 
  745. 	local current_idx = self.current_idx 
  746. 	local current_cat = self.current_cat 
  747. 	local current_data = self.data[current_cat][current_idx] 
  748. 	if current_data.is_checked then 
  749. 		local current_button = self.buttons[current_idx] 
  750. 		if current_data.checked ~= nil then 
  751. 			if current_data.locked == false or current_data.locked == nil then 
  752. 				if current_data.checked == true then 
  753. 					current_data.checked = false 
  754. 				else 
  755. 					current_data.checked = true 
  756. 				end 
  757. 			end 
  758. 		end 
  759. 		current_button:set_check_box(current_data.checked,current_data.locked) 
  760.  
  761. 	elseif current_data.is_canceled_type then 
  762. 		local new_disabled_state = not current_data.disabled 
  763. 		current_data.disabled = new_disabled_state 
  764. 		local current_button = self.buttons[current_idx] 
  765. 		local highlight_button = Vdo_grid_button_canceled:new("grid_top_button_canceled", self.handle, self.doc_handle) 
  766. 		current_button:set_cancel(new_disabled_state) 
  767. 		highlight_button:set_cancel(new_disabled_state) 
  768. 	end 
  769.  
  770. end 
  771.  
  772.  
  773. function Vdo_grid_list:return_data() 
  774. 	if not self.draw_called then 
  775. 		return 
  776. 	end 
  777. 	 
  778. 	return self.data 
  779. end 
  780.  
  781. function Vdo_grid_list:return_selected_data() 
  782. 	if not self.draw_called then 
  783. 		return 
  784. 	end 
  785. 	 
  786. 	return self.data[self.current_cat][self.current_idx] 
  787. end 
  788.  
  789. function Vdo_grid_list:return_selected_index() 
  790. 	if not self.draw_called then 
  791. 		return 
  792. 	end 
  793. 	 
  794. 	return self.current_idx 
  795. end 
  796.  
  797. function Vdo_grid_list:return_selected_cat() 
  798. 	if not self.draw_called then 
  799. 		return 
  800. 	end 
  801. 	 
  802. 	return self.current_cat 
  803. end 
  804.  
  805. function Vdo_grid_list:is_tween_done() 
  806. 	return Vdo_grid_list_tween_done 
  807. end 
  808.  
  809. function vdo_grid_list_scroll_done(tween_h, event_name) 
  810. 	-- remove this callback 
  811. 	remove_tween_end_callback( vint_object_find("grid_group_anchor_tween") ) 
  812. 	Vdo_grid_list_tween_done = true 
  813. end 
  814.  
  815. function Vdo_grid_list:nav_enable(is_on, callback_action, callback_nav) 
  816. 		 
  817. 	if is_on then 
  818. 		-- Subscribe to the button presses we need 
  819. 		Input_tracker:add_input("select", callback_action, 150) 
  820. 		Input_tracker:add_input("back", callback_action, 150) 
  821. 		Input_tracker:add_input("nav_up", callback_nav, 150) 
  822. 		Input_tracker:add_input("nav_down", callback_nav, 150)			 
  823. 		Input_tracker:add_input("nav_left", callback_nav, 150) 
  824. 		Input_tracker:add_input("nav_right", callback_nav, 150)		 
  825. 		Input_tracker:subscribe(true)	 
  826. 		--self:set_visible(true) 
  827. 		 
  828. 		-- Subscribe to the mouse inputs we need 
  829. 		if Grid_mouse_input_tracker ~= nil then 
  830. 			self:add_mouse_inputs(callback_action, callback_nav, Grid_mouse_input_tracker) 
  831. 			Grid_mouse_input_tracker:subscribe(true) 
  832. 			Scrollbar_input_tracker:subscribe(true) 
  833. 		end 
  834. 		 
  835. 		if self.store_input_tracker then 
  836. 			self.store_input_tracker:subscribe(false) 
  837. 		end		 
  838. 	else 
  839. 		-- Remove the button presses we needed 
  840. 		Input_tracker:remove_input("select") 
  841. 		Input_tracker:remove_input("back") 
  842. 		Input_tracker:remove_input("nav_up") 
  843. 		Input_tracker:remove_input("nav_down") 
  844. 		Input_tracker:remove_input("nav_left") 
  845. 		Input_tracker:remove_input("nav_right")		 
  846. 		Input_tracker:subscribe(false) 
  847. 		--self:set_visible(false) 
  848. 		 
  849. 		if Grid_mouse_input_tracker ~= nil then 
  850. 			Grid_mouse_input_tracker:remove_all() 
  851. 			Scrollbar_input_tracker:remove_all() 
  852. 		end 
  853. 		 
  854. 		if self.store_input_tracker and self.input_enabled then 
  855. 			self.store_input_tracker:subscribe(true) 
  856. 		end			 
  857. 	end 
  858. 	 
  859. 	self.input_enabled = is_on 
  860. end 
  861.  
  862. function Vdo_grid_list:set_highlight_color(color) 
  863. 	self.scrollbar:set_highlight_color(color) 
  864. 	self.highlight_name:set_color(color.R, color.G, color.B) 
  865. 	self.highlight_color = color 
  866. end 
  867.  
  868. function Vdo_grid_list:show_grid(is_visible) 
  869.  
  870. 	--self:set_visible(is_visible) 
  871. 	 
  872. end 
  873.  
  874. function Vdo_grid_list:add_subtitle(title_name, title_index, y_pos) 
  875.  
  876. 	--clone title and add it to grid here 
  877. 	local base_title_grp = Vdo_base_object:new("grid_title_grp", self.handle, self.doc_handle) 
  878. 	 
  879. 	self.titles[title_index] = Vdo_base_object:clone(base_title_grp.handle) 
  880. 	self.titles[title_index].title = Vdo_base_object:new("grid_title",self.titles[title_index].handle, self.doc_handle) 
  881. 	self.titles[title_index].line = Vdo_base_object:new("grid_title_line",self.titles[title_index].handle, self.doc_handle) 
  882. 	 
  883. 	self.titles[title_index].title:set_text(title_name) 
  884. 	self.titles[title_index].title:set_visible(true) 
  885.  
  886. 	local text_width, text_height = self.titles[title_index].title:get_screen_size() 
  887. 	local bg_width, bg_height = self.bg:get_screen_size() 
  888. 	 
  889. 	self.titles[title_index].line:set_anchor(text_width + 10, text_height * 0.5) 
  890. 	 
  891. 	self.titles[title_index].line:set_screen_size(bg_width - (text_width + 30), 3) 
  892.  
  893. 	self.titles[title_index].line:set_visible(true) 
  894. 	self.titles[title_index].line:set_alpha(1) 
  895. 	 
  896. 	self.titles[title_index]:set_anchor(self.button_w * -0.5 + 10, y_pos + self.button_h) 
  897. 	 
  898. 	self.titles[title_index]:set_visible(true) 
  899. 	 
  900. 	self.title_added = true 
  901.  
  902. end 
  903.  
  904. function Vdo_grid_list:set_icon(button, button_data) 
  905. 	if button_data.is_layered then 
  906. 		button:set_icon(button_data)	 
  907. 	else	 
  908. 		if nil ~= button_data.icon then 
  909. 			button:set_icon(button_data.icon) 
  910. 		elseif nil ~= button_data.icon_crc then 
  911. 			button:set_icon_crc(button_data.icon_crc) 
  912. 		end	 
  913. 	end 
  914.  
  915. 	if button_data.is_canceled_type then 
  916. 		button:set_cancel(button_data.disabled) 
  917. 	end 
  918. 	 
  919. 	if button_data.is_checked then 
  920. 		button:set_checkbox(1, self.highlight_color) 
  921. 	end 
  922. end 
  923.  
  924. function Vdo_grid_list:set_highlight_size(dual_is_visible) 
  925. 	local highlight_button	 
  926. 	if self.data[1][1].is_layered then 
  927. 		highlight_button = Vdo_grid_button_layered:new("grid_top_button_layered", self.handle) 
  928. 	elseif self.data[1][1].is_checked ~= nil then 
  929. 		highlight_button = Vdo_grid_button_check:new("grid_top_button_check", self.handle) 
  930. 	elseif self.data[1][1].is_canceled_type ~= nil then 
  931. 		highlight_button = Vdo_grid_button_canceled:new("grid_top_button_canceled", self.handle) 
  932. 	else 
  933. 		highlight_button = Vdo_grid_button:new("grid_top_button", self.handle) 
  934. 	end 
  935. --	highlight_button:set_size(self.button_w, self.button_h) 
  936. 	--highlight_button:set_scale(self.outline_scale, self.outline_scale) 
  937. 	 
  938. 	if dual_is_visible == true then 
  939. 		highlight_button:set_highlight(true, true)		 
  940. 	else 
  941. 		highlight_button:set_highlight(true)		 
  942. 	end 
  943. end 
  944.  
  945. -- Only updates the highlighted button based on the current index without redrawing the entire list 
  946. -- This function's code copies the highlight button code in draw_items 
  947. -- 
  948. function Vdo_grid_list:update_highlight(hint_button_offset) 
  949. 	-- Highlight current button 
  950. 	local highlight_button = Vdo_grid_button_layered:new("grid_top_button", self.handle, self.doc_handle) 
  951. 	local highlight_button_outline = Vdo_grid_button_layered:new("grid_top_button_outline", self.handle, self.doc_handle) 
  952. 	local highlight_button_layered = Vdo_grid_button_layered:new("grid_top_button_layered", self.handle, self.doc_handle) 
  953. 	local highlight_button_outline_layered = Vdo_grid_button_layered:new("grid_top_button_outline_layered", self.handle, self.doc_handle) 
  954. 	local highlight_button_check = Vdo_grid_button_check:new("grid_top_button_check", self.handle, self.doc_handle) 
  955. 	local highlight_button_canceled = Vdo_grid_button_canceled:new("grid_top_button_canceled", self.handle, self.doc_handle) 
  956.  
  957. 	highlight_button:set_visible(false)	 
  958. 	highlight_button_outline:set_visible(false)	 
  959. 	highlight_button_layered:set_visible(false)	 
  960. 	highlight_button_outline_layered:set_visible(false)	 
  961. 	highlight_button_check:set_visible(false)	 
  962. 	highlight_button_canceled:set_visible(false)	 
  963. 	 
  964. 	-- Get the current button based on the current index 
  965. 	local grid_index = self.current_idx - ((self.start_row - 1) * self.max_width) 
  966. 	self.current_button = self.buttons[grid_index] 
  967. 	self.current_button:set_visible(true) 
  968. 	 
  969. 	if self.data[1][1].is_layered then 
  970. 		highlight_button = Vdo_grid_button_layered:new("grid_top_button_layered", self.handle, self.doc_handle) 
  971. 		highlight_button_outline = Vdo_grid_button_layered:new("grid_top_button_outline_layered", self.handle, self.doc_handle)	 
  972. 		highlight_button_outline:set_visible(true) 
  973. 	elseif self.data[1][1].is_checked ~= nil then 
  974. 		highlight_button = Vdo_grid_button_check:new("grid_top_button_check", self.handle, self.doc_handle) 
  975. 	elseif self.data[1][1].is_canceled_type ~= nil then 
  976. 		highlight_button = Vdo_grid_button_canceled:new("grid_top_button_canceled", self.handle, self.doc_handle) 
  977. 	else 
  978. 		highlight_button = Vdo_grid_button:new("grid_top_button", self.handle, self.doc_handle) 
  979. 		highlight_button_outline = Vdo_grid_button:new("grid_top_button_outline", self.handle, self.doc_handle) 
  980. 		highlight_button_outline:set_visible(true) 
  981. 	end	 
  982. 	 
  983. 	-- Hide button underneath for checked buttons 
  984. 	if self.data[self.current_cat][self.current_idx].is_checked ~= nil then 
  985. 		self.current_button:set_visible(false) 
  986. 		 
  987. 		--hide check for highlight 
  988. 		--self.current_button:set_checkbox(-1) 
  989. 	end 
  990. 	 
  991. 	local dual_is_visible = self.data[self.current_cat][self.current_idx].dual_wield 
  992. 	 
  993. 	--set the size of the highlight 
  994. 	self:set_highlight_size(dual_is_visible) 
  995.  
  996. 	highlight_button:set_visible(true) 
  997. 	 
  998. 	local val = self.data[self.current_cat][self.current_idx] 
  999. 	 
  1000. 	if self.data[1][1].is_layered == nil or self.data[1][1].is_layered == false then 
  1001. 		highlight_button:set_color(val.color.red, val.color.green, val.color.blue) 
  1002. 	end 
  1003. 	 
  1004. 	if self.highlight_color ~= nil then 
  1005. 		highlight_button:set_highlight_color(self.highlight_color) 
  1006. 	end 
  1007. 	 
  1008. 	--Set the button icon 
  1009. 	self:set_icon(highlight_button, val) 
  1010. 	self:set_icon(highlight_button_outline, val) 
  1011.  
  1012. 	-- set hightlight anchor position 
  1013. 	local button_x,button_y = self.current_button:get_property("anchor") 
  1014. 	local highlight = Vdo_base_object:new( "grid_highlight", self.handle, self.doc_handle) 
  1015. 	highlight:set_property( "anchor", button_x, button_y) 
  1016. 	highlight:set_visible(true) 
  1017. 	 
  1018. 	--don't play highlight anim if index is the same 
  1019. 	--if old_idx ~= self.current_idx then 
  1020. 	local highlight_anim = Vdo_anim_object:new("highlight_anim", self.handle, self.doc_handle) 
  1021. 	highlight_anim:play() 
  1022. 	--end 
  1023. 		 
  1024. 	local hint_button = Vdo_base_object:new("grid_hint_button", self.handle, self.doc_handle) 
  1025. 	local highlight_scale_twn = Vdo_tween_object:new("grid_highlight_scale_twn", self.handle, self.doc_handle) 
  1026. 	 
  1027. 	if hint_button_offset == nil then 
  1028. 		-- Reposition hint button to bottom right corner of highlighted button 
  1029. 		local highlight_width, highlight_height = highlight_button:get_screen_size() 
  1030. 		local highlight_scale_x, highlight_scale_y = highlight_scale_twn:get_end_value()		 
  1031. 		hint_button:set_anchor(button_x + (highlight_width * highlight_scale_x * .5) - 35, button_y + (highlight_height * highlight_scale_y * .5) - 35) 
  1032. 	else 
  1033. 		hint_button:set_anchor(button_x + hint_button_offset, button_y + hint_button_offset) 
  1034. 	end	 
  1035. 		 
  1036. 	-- Set highlighted item name 
  1037. 	local highlight_label = self.data[self.current_cat][self.current_idx].label 
  1038. 	local highlight_label_crc = self.data[self.current_cat][self.current_idx].label_crc 
  1039. 	 
  1040. 	if highlight_label ~= nil then 
  1041. 		self.highlight_name:set_text(highlight_label) 
  1042. 	else 
  1043. 		self.highlight_name:set_text_crc(highlight_label_crc) 
  1044. 	end 
  1045. 	 
  1046. 	self.group:set_anchor((self.button_w - SIZE_GRID_BUTTON) * 0.5, (self.button_h - SIZE_GRID_BUTTON)* 0.5) 
  1047. end 
  1048.  
  1049.  
  1050. -- ===================================== 
  1051. --       Mouse Specific Functions 
  1052. -- ===================================== 
  1053.  
  1054. -- Returns the data index of the button selected based on the target handle. 
  1055. -- Returns 0 (invalid index) if no button was found 
  1056. -- 
  1057. function Vdo_grid_list:get_data_index(target_handle) 
  1058. 	if not self.draw_called then 
  1059. 		debug_print("vint", "Vdo_grid_list:get_selection called() with invalid document handle") 
  1060. 		return 
  1061. 	end 
  1062. 	 
  1063. 	for idx, button in pairs(self.buttons) do 
  1064. 		if button.handle == target_handle then 
  1065. 			if self.rows > self.max_height then 
  1066. 				if self.num_categories > 1 then 
  1067. 					-- This should never happen 
  1068. 					if self.data[self.button_cats[idx]][self.button_ids[idx]] == nil then 
  1069. 						local bad_idx = idx 
  1070. 						return 0 
  1071. 					end 
  1072. 					return self.button_ids[idx], self.button_cats[idx] 
  1073. 				else 
  1074. 					-- This works for grids without categories, but not ones with 
  1075. 					local data_index = (self.start_row - 1) * self.max_width + idx 
  1076. 					if self.data[self.current_cat][data_index] ~= nil then 
  1077. 						return data_index, 1 -- 1 is the category 
  1078. 					end 
  1079. 				end 
  1080. 			else 
  1081. 				return idx 
  1082. 			end 
  1083. 		end 
  1084. 	end 
  1085. 	 
  1086. 	return 0 
  1087. end 
  1088.  
  1089. function Vdo_grid_list:get_visible_rows() 
  1090. 	local end_row 
  1091. 	if self.rows > self.max_height then 
  1092. 		end_row = self.start_row + (self.max_height - 1) 
  1093. 	else 
  1094. 		end_row = self.rows 
  1095. 	end 
  1096. 	 
  1097. 	return self.start_row, end_row 
  1098. end 
  1099.  
  1100. function Vdo_grid_list:set_selection(new_index, new_category) 
  1101. 	if not self.draw_called then 
  1102. 		debug_print("vint", "Vdo_grid_list:get_selection called() with invalid document handle") 
  1103. 		return 
  1104. 	end 
  1105. 	 
  1106. 	self.current_idx = new_index 
  1107. 	if new_category ~= nil then 
  1108. 		self.current_cat = new_category 
  1109. 	else 
  1110. 		self.current_cat = 1 
  1111. 	end 
  1112. end 
  1113.  
  1114. -- Set and store the ui_screen, needed for the callback functions for the scroll and drag events 
  1115. function Vdo_grid_list:set_ui_screen(ui_screen) 
  1116. 	self.ui_screen = ui_screen 
  1117. end 
  1118.  
  1119. function Vdo_grid_list:add_mouse_inputs(callback_action, callback_nav, input_tracker, priority, update_scrollbar) 
  1120. 	if (self.buttons == nil) or (callback_action == nil) or (callback_nav == nil) then 
  1121. 		return 
  1122. 	end 
  1123. 	 
  1124. 	-- Store the callback functions for the update_mouse_inputs function 
  1125. 	if self.callback_action ~= callback_action then 
  1126. 		self.callback_action = callback_action 
  1127. 	end 
  1128. 	 
  1129. 	if self.callback_nav ~= callback_nav then 
  1130. 		self.callback_nav = callback_nav 
  1131. 	end 
  1132. 	 
  1133. 	-- Default priority value to 150 
  1134. 	priority = priority or 150 
  1135.  
  1136. 	-- Add mouse_click and mouse_move events for each button in the list 
  1137. 	for idx, button in pairs(self.buttons) do 
  1138. 		input_tracker:add_mouse_input("mouse_click", callback_action, 50, button.handle) 
  1139. 		input_tracker:add_mouse_input("mouse_move", callback_nav, 50, button.handle) 
  1140. 	end 
  1141. 	 
  1142. 	-- Add mouse inputs for the scroll region and scrolltab if needed 
  1143. 	if self.rows > self.max_height and self.ui_screen ~= nil then 
  1144. 		input_tracker:add_mouse_input("mouse_scroll", self.ui_screen.."_mouse_scroll", priority, self.bg.handle) 
  1145. 		-- This forces the scroll wheel to work in "empty" areas of the grid 
  1146. 		input_tracker:add_mouse_input("mouse_click", callback_action, priority, self.bg.handle) 
  1147. 		 
  1148. 		if update_scrollbar == nil or update_scrollbar == true then 
  1149. 			self.scrollbar:add_mouse_inputs(self.ui_screen, Scrollbar_input_tracker, priority) 
  1150. 		end 
  1151. 	end 
  1152.  
  1153. 	-- Calculate the buttons' categories and ids (if categories are being used) 
  1154. 	if self.num_categories > 1 then 
  1155. 		-- Set the row of each self.data element 
  1156. 		local cur_row = 1 
  1157. 		local row_offset 
  1158. 		for i = 1, self.num_categories do 
  1159. 			cur_row = cur_row + 1 
  1160. 			for j = 1, #self.data[i] do 
  1161. 				row_offset = ((j - 1) - self:recursive_mod((j - 1), self.max_width)) / self.max_width 
  1162. 				self.data[i][j].row = cur_row + row_offset 
  1163. 			end 
  1164. 			cur_row = cur_row + (row_offset + 1) 
  1165. 		end 
  1166. 		 
  1167. 		self.button_cats = {} 
  1168. 		self.button_ids = {} 
  1169. 		self.num_button_ids = 0 
  1170. 		local end_row = self.start_row + self.max_height - 1 
  1171. 		-- Loop through it all again, creating the button_ids and button_cats lists 
  1172. 		for i = 1, self.num_categories do 
  1173. 			for j = 1, #self.data[i] do 
  1174. 				if self.data[i][j].row >= self.start_row and self.data[i][j].row <= end_row then 
  1175. 					self.num_button_ids = self.num_button_ids + 1 
  1176. 					self.button_cats[self.num_button_ids] = i 
  1177. 					self.button_ids[self.num_button_ids] = j 
  1178. 				end 
  1179. 			end 
  1180. 		end 
  1181. 	end 
  1182. end 
  1183.  
  1184. -- Custom recursive mod function because it doesn't exist 
  1185. function Vdo_grid_list:recursive_mod(value, modulus) 
  1186. 	if (value >= modulus) then 
  1187. 		return self:recursive_mod(value - modulus, modulus) 
  1188. 	else 
  1189. 		return value 
  1190. 	end 
  1191. end 
  1192.  
  1193. -- Rebuilds the mouse input subscriptions, usually done when the list was rebuilt with draw_items() 
  1194. -- 
  1195. function Vdo_grid_list:update_mouse_inputs(input_tracker) 
  1196. 	if game_get_platform() ~= "PC" then 
  1197. 		return 
  1198. 	end 
  1199.  
  1200. 	-- Default the input tracker to the Grid_mouse_input_tracker if not specified 
  1201. 	if input_tracker == nil then 
  1202. 		input_tracker = Grid_mouse_input_tracker 
  1203. 	end 
  1204. 	 
  1205. 	input_tracker:remove_all() 
  1206. 	self:add_mouse_inputs(self.callback_action, self.callback_nav, input_tracker, 50, false) 
  1207. 	input_tracker:subscribe(true) 
  1208. end 
  1209.  
  1210. function Vdo_grid_list:scroll_list(scroll_lines, new_start_index) 
  1211. 	new_start_index = new_start_index or 0 
  1212. 	if scroll_lines == 0 and (new_start_index == self.start_row or new_start_index == 0) then 
  1213. 		return 
  1214. 	end 
  1215. 	 
  1216. 	 
  1217. 	local old_start_row = self.start_row 
  1218. 	if new_start_index ~= 0 then 
  1219. 		-- Set the new start index (calculated by the scrolltab) 
  1220. 		self.start_row = new_start_index 
  1221. 	 
  1222. 	else 
  1223. 		-- Update the rows that are visible if scrolled with the scroll wheel 
  1224. 		self.start_row = self.start_row + scroll_lines 
  1225. 		local end_row = self.start_row + (self.max_height - 1) 
  1226. 		if self.start_row < 1 then 
  1227. 			self.start_row = 1 
  1228. 		elseif end_row > self.rows then 
  1229. 			self.start_row = self.rows - (self.max_height - 1) 
  1230. 		end 
  1231. 	end 
  1232. 	local end_row = self.start_row + (self.max_height - 1) 
  1233. 	 
  1234. 	-- Move the highlight to a visible row if necessary (cannot go outside the visible range) 
  1235. 	if self.num_categories == 1 then 
  1236. 		local current_row = ceil(self.current_idx / self.max_width) 
  1237. 		if current_row < self.start_row then 
  1238. 			self.current_idx = self.current_idx + ((self.start_row - current_row) * self.max_width) 
  1239. 		elseif current_row > end_row then 
  1240. 			self.current_idx = self.current_idx - ((current_row - end_row) * self.max_width) 
  1241. 		end 
  1242. 	end 
  1243. 	 
  1244. 	-- Don't want draw_items to scroll the list or move the scrolltab 
  1245. 	self.update_start_row = false; 
  1246. 	if scroll_lines ~= 0 then 
  1247. 		self.scrollbar:set_value(self.rows - (self.max_height - 1), self.start_row) 
  1248. 	end 
  1249. 	 
  1250. 	-- Only update the list if the visible rows have changed 
  1251. 	if old_start_row ~= self.start_row then 
  1252. 		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) 
  1253. 		--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) 
  1254. 		self:update_mouse_inputs() 
  1255. 	end 
  1256. end 
  1257.  
  1258. function Vdo_grid_list:show_highlight_text( show_text ) 
  1259. 	--show_text is a boolean from the screen 
  1260. 	self.highlight_name:set_visible( show_text ) 
  1261. end 
  1262.  
  1263. function Vdo_grid_list:show_current_button( show_button ) 
  1264. 	--show_button is a boolean, used on the radio station select screen  
  1265. 	self.show_current_button_bool = show_button 
  1266. end 
  1267.  
  1268. function Vdo_grid_list:tint_current_button( tint_button ) 
  1269. 	--tint_button is a boolean, used on the radio station select screen 
  1270. 	--tints unhighlighted buttons grey 
  1271. 	self.tint_current_button = tint_button 
  1272. end 
  1273.  
  1274. function Vdo_grid_list:set_input_tracker(input_tracker) 
  1275. 	self.store_input_tracker = input_tracker 
  1276. end 
  1277.