From 868f35e27a0553b440fe057cc13e9a4d5acc6770 Mon Sep 17 00:00:00 2001
From: sapier <Sapier at GMX dot net>
Date: Sun, 14 Jul 2013 13:19:37 +0200
Subject: [PATCH] Replace worldlist by generic filterlist implementation

---
 builtin/mainmenu.lua           |  78 +++++++-----
 builtin/mainmenu_worldlist.lua | 215 +++++++++++++++++++--------------
 2 files changed, 172 insertions(+), 121 deletions(-)

diff --git a/builtin/mainmenu.lua b/builtin/mainmenu.lua
index 8cb786047..91084c2c6 100644
--- a/builtin/mainmenu.lua
+++ b/builtin/mainmenu.lua
@@ -10,6 +10,7 @@ dofile(scriptpath .. DIR_DELIM .. "gamemgr.lua")
 local menu = {}
 local tabbuilder = {}
 local menubar = {}
+local worldlist = nil
 
 --------------------------------------------------------------------------------
 function render_favourite(spec,render_details)
@@ -166,7 +167,7 @@ function menu.update_gametype()
 		
 		local gamedetails = menu.lastgame()
 		engine.set_topleft_text(gamedetails.name)
-		worldlist.set_gamefilter(gamedetails.id)
+		filterlist.set_filtercriteria(worldlist,gamedetails.id)
 		
 		--background
 		local background_set = false
@@ -208,7 +209,7 @@ end
 
 --------------------------------------------------------------------------------
 function menu.reset_gametype()
-	worldlist.set_gamefilter(nil)
+	filterlist.set_filtercriteria(worldlist,nil)
 	menu.game_last_check = nil
 	
 	local path_background_texture = menu.basetexturedir .. "menu_background.png"
@@ -246,6 +247,27 @@ end
 function init_globals()
 	--init gamedata
 	gamedata.worldindex = 0
+	
+	worldlist = filterlist.create(
+					engine.get_worlds,
+					compare_worlds,
+					function(element,uid)
+						if element.name == uid then
+							return true
+						end
+						return false
+					end, --unique id compare fct
+					function(element,gameid)
+						if element.gameid == gameid then
+							return true
+						end
+						return false
+					end --filter fct
+					)
+					
+	filterlist.add_sort_mechanism(worldlist,"alphabetic",sort_worlds_alphabetic)
+	filterlist.set_sortmode(worldlist,"alphabetic")
+					
 end
 
 --------------------------------------------------------------------------------
@@ -309,7 +331,7 @@ end
 function menu.render_world_list()
 	local retval = ""
 	
-	local current_worldlist = worldlist.get_list()
+	local current_worldlist = filterlist.get_list(worldlist)
 	
 	for i,v in ipairs(current_worldlist) do
 		if retval ~= "" then
@@ -371,7 +393,7 @@ end
 --------------------------------------------------------------------------------
 function menu.update_last_game()
 
-	local current_world = worldlist.get_raw_world(
+	local current_world = filterlist.get_raw_element(worldlist,
 							engine.setting_get("mainmenu_last_selected_world")
 							)
 							
@@ -397,17 +419,17 @@ function menu.handle_key_up_down(fields,textlist,settingname)
 		if oldidx > 1 then
 			local newidx = oldidx -1
 			engine.setting_set(settingname,
-				worldlist.get_engine_index(newidx))
+				filterlist.get_engine_index(worldlist,newidx))
 		end
 	end
 	
 	if fields["key_down"] then
 		local oldidx = engine.get_textlist_index(textlist)
 		
-		if oldidx < worldlist.size() then
+		if oldidx < filterlist.size(worldlist) then
 			local newidx = oldidx + 1
 			engine.setting_set(settingname,
-				worldlist.get_engine_index(newidx))
+				filterlist.get_engine_index(worldlist,newidx))
 		end
 	end
 end
@@ -508,7 +530,7 @@ end
 
 --------------------------------------------------------------------------------
 function tabbuilder.dialog_delete_world()
-	return	"label[2,2;Delete World \"" .. worldlist.get_raw_list()[menu.world_to_del].name .. "\"?]"..
+	return	"label[2,2;Delete World \"" .. filterlist.get_raw_list(worldlist)[menu.world_to_del].name .. "\"?]"..
 			"button[3.5,4.2;2.6,0.5;world_delete_confirm;Yes]" ..
 			"button[6,4.2;2.8,0.5;world_delete_cancel;No]"
 end
@@ -570,7 +592,7 @@ function tabbuilder.handle_create_world_buttons(fields)
 			
 			local message = nil
 			
-			if not worldlist.exists(worldname) then
+			if not filterlist.uid_exists(worldlist,worldname) then
 				engine.setting_set("mg_name",fields["dd_mapgen"])
 				message = engine.create_world(worldname,gameindex)
 			else
@@ -583,9 +605,9 @@ function tabbuilder.handle_create_world_buttons(fields)
 				menu.last_game = gameindex
 				engine.setting_set("main_menu_last_game_idx",gameindex)
 				
-				worldlist.refresh()
+				filterlist.refresh(worldlist)
 				engine.setting_set("mainmenu_last_selected_world",
-									worldlist.engine_index_by_name(worldname))
+									filterlist.engine_index_by_uid(worldlist,worldname))
 			end
 		else
 			gamedata.errormessage = "No worldname given or no game selected"
@@ -608,10 +630,10 @@ function tabbuilder.handle_delete_world_buttons(fields)
 	
 	if fields["world_delete_confirm"] then
 		if menu.world_to_del > 0 and 
-			menu.world_to_del <= #worldlist.get_raw_list() then
+			menu.world_to_del <= #filterlist.get_raw_list(worldlist) then
 			engine.delete_world(menu.world_to_del)
 			menu.world_to_del = 0
-			worldlist.refresh()
+			filterlist.refresh(worldlist)
 		end
 	end
 	
@@ -756,7 +778,7 @@ function tabbuilder.handle_server_buttons(fields)
 		end
 		if event.typ == "CHG" then
 			engine.setting_set("mainmenu_last_selected_world",
-				worldlist.get_engine_index(engine.get_textlist_index("srv_worlds")))
+				filterlist.get_engine_index(worldlist,engine.get_textlist_index("srv_worlds")))
 		end
 	end
 	
@@ -783,7 +805,7 @@ function tabbuilder.handle_server_buttons(fields)
 			gamedata.password		= fields["te_passwd"]
 			gamedata.port			= fields["te_serverport"]
 			gamedata.address		= ""
-			gamedata.selected_world	= worldlist.get_engine_index(selected)
+			gamedata.selected_world	= filterlist.get_engine_index(worldlist,selected)
 			
 			menu.update_last_game(gamedata.selected_world)
 			engine.start()
@@ -799,12 +821,12 @@ function tabbuilder.handle_server_buttons(fields)
 	if fields["world_delete"] ~= nil then
 		local selected = engine.get_textlist_index("srv_worlds")
 		if selected > 0 and
-			selected <= worldlist.size() then
-			local world = worldlist.get_list()[selected]
+			selected <= filterlist.size(worldlist) then
+			local world = filterlist.get_list(worldlist)[selected]
 			if world ~= nil and
 				world.name ~= nil and
 				world.name ~= "" then
-				menu.world_to_del = worldlist.get_engine_index(selected)
+				menu.world_to_del = filterlist.get_engine_index(worldlist,selected)
 				tabbuilder.current_tab = "dialog_delete_world"
 				tabbuilder.is_dialog = true
 				tabbuilder.show_buttons = false
@@ -817,7 +839,7 @@ function tabbuilder.handle_server_buttons(fields)
 	if fields["world_configure"] ~= nil then
 		selected = engine.get_textlist_index("srv_worlds")
 		if selected > 0 then
-			modmgr.world_config_selected_world = worldlist.get_engine_index(selected)
+			modmgr.world_config_selected_world = filterlist.get_engine_index(worldlist,selected)
 			if modmgr.init_worldconfig() then
 				tabbuilder.current_tab = "dialog_configure_world"
 				tabbuilder.is_dialog = true
@@ -897,7 +919,7 @@ function tabbuilder.handle_singleplayer_buttons(fields)
 		
 		if event.typ == "CHG" then
 			engine.setting_set("mainmenu_last_selected_world",
-				worldlist.get_engine_index(engine.get_textlist_index("sp_worlds")))
+				filterlist.get_engine_index(worldlist,engine.get_textlist_index("sp_worlds")))
 		end
 	end
 	
@@ -916,7 +938,7 @@ function tabbuilder.handle_singleplayer_buttons(fields)
 		fields["key_enter"] then
 		local selected = engine.get_textlist_index("sp_worlds")
 		if selected > 0 then
-			gamedata.selected_world	= worldlist.get_engine_index(selected)
+			gamedata.selected_world	= filterlist.get_engine_index(worldlist,selected)
 			gamedata.singleplayer	= true
 			
 			menu.update_last_game(gamedata.selected_world)
@@ -934,12 +956,12 @@ function tabbuilder.handle_singleplayer_buttons(fields)
 	if fields["world_delete"] ~= nil then
 		local selected = engine.get_textlist_index("sp_worlds")
 		if selected > 0 and
-			selected <= worldlist.size() then
-			local world = worldlist.get_list()[selected]
+			selected <= filterlist.size(worldlist) then
+			local world = filterlist.get_list(worldlist)[selected]
 			if world ~= nil and
 				world.name ~= nil and
 				world.name ~= "" then
-				menu.world_to_del = worldlist.get_engine_index(selected)
+				menu.world_to_del = filterlist.get_engine_index(worldlist,selected)
 				tabbuilder.current_tab = "dialog_delete_world"
 				tabbuilder.is_dialog = true
 				tabbuilder.show_buttons = false
@@ -952,7 +974,7 @@ function tabbuilder.handle_singleplayer_buttons(fields)
 	if fields["world_configure"] ~= nil then
 		selected = engine.get_textlist_index("sp_worlds")
 		if selected > 0 then
-			modmgr.world_config_selected_world = worldlist.get_engine_index(selected)
+			modmgr.world_config_selected_world = filterlist.get_engine_index(worldlist,selected)
 			if modmgr.init_worldconfig() then
 				tabbuilder.current_tab = "dialog_configure_world"
 				tabbuilder.is_dialog = true
@@ -1102,7 +1124,7 @@ end
 --------------------------------------------------------------------------------
 function tabbuilder.tab_server()
 
-	local index = worldlist.get_current_index(
+	local index = filterlist.get_current_index(worldlist,
 				tonumber(engine.setting_get("mainmenu_last_selected_world"))
 				)
 	
@@ -1154,7 +1176,7 @@ end
 --------------------------------------------------------------------------------
 function tabbuilder.tab_singleplayer()
 	
-	local index = worldlist.get_current_index(
+	local index = filterlist.get_current_index(worldlist,
 				tonumber(engine.setting_get("mainmenu_last_selected_world"))
 				)
 
@@ -1300,6 +1322,7 @@ engine.event_handler = function(event)
 			tabbuilder.is_dialog = false
 			tabbuilder.show_buttons = true
 			tabbuilder.current_tab = engine.setting_get("main_menu_tab")
+			menu.update_gametype()
 			update_menu()
 		else
 			engine.close()
@@ -1313,7 +1336,6 @@ end
 --------------------------------------------------------------------------------
 --------------------------------------------------------------------------------
 init_globals()
-worldlist.init()
 menu.init()
 tabbuilder.init()
 menubar.refresh()
diff --git a/builtin/mainmenu_worldlist.lua b/builtin/mainmenu_worldlist.lua
index 4f7ba097c..846a4793e 100644
--- a/builtin/mainmenu_worldlist.lua
+++ b/builtin/mainmenu_worldlist.lua
@@ -1,80 +1,105 @@
-worldlist = {}
+--------------------------------------------------------------------------------
+-- Generic implementation of a filter/sortable list                           --
+--------------------------------------------------------------------------------
+filterlist = {}
 
 --------------------------------------------------------------------------------
-function worldlist.refresh()
-	worldlist.m_raw_worldlist = engine.get_worlds()
-	worldlist.process()
+function filterlist.refresh(this)
+	this.m_raw_list = this.m_raw_list_fct()
+	filterlist.process(this)
 end
 
 --------------------------------------------------------------------------------
-function worldlist.init()
-	worldlist.m_gamefilter = nil
-	worldlist.m_sortmode = "alphabetic"
+function filterlist.create(raw_fct,compare_fct,uid_match_fct,filter_fct)
+
+	assert((raw_fct ~= nil) and (type(raw_fct) == "function"))
+	assert((compare_fct ~= nil) and (type(compare_fct) == "function"))
+	
+	local this = {}
+	
+	this.m_raw_list_fct  = raw_fct
+	this.m_compare_fct   = compare_fct
+	this.m_filter_fct    = filter_fct
+	this.m_uid_match_fct = uid_match_fct
+	
+	this.m_filtercriteria = nil
+	
+	this.m_sortmode = "none"
+	this.m_sort_list = {}
+	
+	
 
-	worldlist.m_processed_worldlist = nil
-	worldlist.m_raw_worldlist = engine.get_worlds()
+	this.m_processed_list = nil
+	this.m_raw_list = this.m_raw_list_fct()
 
-	worldlist.process()
+	filterlist.process(this)
+	
+	return this
 end
 
 --------------------------------------------------------------------------------
-function worldlist.set_gamefilter(gameid)
-	if gameid == worldlist.m_gamefilter then
+function filterlist.add_sort_mechanism(this,name,fct)
+	this.m_sort_list[name] = fct
+end
+
+--------------------------------------------------------------------------------
+function filterlist.set_filtercriteria(this,criteria)
+	if criteria == this.m_filtercriteria then
 		return
 	end
-	worldlist.m_gamefilter = gameid
-	worldlist.process()
+	this.m_filtercriteria = criteria
+	filterlist.process(this)
 end
 
 --------------------------------------------------------------------------------
-function worldlist.get_gamefilter()
-	return worldlist.m_gamefilter
+function filterlist.get_filtercriteria(this)
+	return this.m_filtercriteria
 end
 
 --------------------------------------------------------------------------------
 --supported sort mode "alphabetic|none"
-function worldlist.set_sortmode(mode)
-	if (mode == worldlist.m_sortmode) then
+function filterlist.set_sortmode(this,mode)
+	if (mode == this.m_sortmode) then
 		return
 	end
-	worldlist.m_sortmode = mode
-	worldlist.process()
+	this.m_sortmode = mode
+	filterlist.process(this)
 end
 
 --------------------------------------------------------------------------------
-function worldlist.get_list()
-	return worldlist.m_processed_worldlist
+function filterlist.get_list(this)
+	return this.m_processed_list
 end
 
 --------------------------------------------------------------------------------
-function worldlist.get_raw_list()
-	return worldlist.m_raw_worldlist
+function filterlist.get_raw_list(this)
+	return this.m_raw_list
 end
 
 --------------------------------------------------------------------------------
-function worldlist.get_raw_world(idx)
+function filterlist.get_raw_element(this,idx)
 	if type(idx) ~= "number" then
 		idx = tonumber(idx)
 	end
 	
-	if idx ~= nil and idx > 0 and idx < #worldlist.m_raw_worldlist then
-		return worldlist.m_raw_worldlist[idx]
+	if idx ~= nil and idx > 0 and idx < #this.m_raw_list then
+		return this.m_raw_list[idx]
 	end
 	
 	return nil
 end
 
 --------------------------------------------------------------------------------
-function worldlist.get_engine_index(worldlistindex)
-	assert(worldlist.m_processed_worldlist ~= nil)
+function filterlist.get_engine_index(this,listindex)
+	assert(this.m_processed_list ~= nil)
 	
-	if worldlistindex ~= nil and worldlistindex > 0 and
-		worldlistindex <= #worldlist.m_processed_worldlist then
-		local entry = worldlist.m_processed_worldlist[worldlistindex]
+	if listindex ~= nil and listindex > 0 and
+		listindex <= #this.m_processed_list then
+		local entry = this.m_processed_list[listindex]
 		
-		for i,v in ipairs(worldlist.m_raw_worldlist) do
+		for i,v in ipairs(this.m_raw_list) do
 		
-			if worldlist.compare(v,entry) then
+			if this.m_compare_fct(v,entry) then
 				return i
 			end
 		end
@@ -84,16 +109,16 @@ function worldlist.get_engine_index(worldlistindex)
 end
 
 --------------------------------------------------------------------------------
-function worldlist.get_current_index(worldlistindex)
-	assert(worldlist.m_processed_worldlist ~= nil)
+function filterlist.get_current_index(this,listindex)
+	assert(this.m_processed_list ~= nil)
 	
-	if worldlistindex ~= nil and worldlistindex > 0 and
-		worldlistindex <= #worldlist.m_raw_worldlist then
-		local entry = worldlist.m_raw_worldlist[worldlistindex]
+	if listindex ~= nil and listindex > 0 and
+		listindex <= #this.m_raw_list then
+		local entry = this.m_raw_list[listindex]
 		
-		for i,v in ipairs(worldlist.m_processed_worldlist) do
+		for i,v in ipairs(this.m_processed_list) do
 		
-			if worldlist.compare(v,entry) then
+			if this.m_compare_fct(v,entry) then
 				return i
 			end
 		end
@@ -103,98 +128,102 @@ function worldlist.get_current_index(worldlistindex)
 end
 
 --------------------------------------------------------------------------------
-function worldlist.process()
-	assert(worldlist.m_raw_worldlist ~= nil)
+function filterlist.process(this)
+	assert(this.m_raw_list ~= nil)
 
-	if worldlist.m_sortmode == "none" and 
-	   worldlist.m_gamefilter == nil then
-		worldlist.m_processed_worldlist = worldlist.m_raw_worldlist
+	if this.m_sortmode == "none" and
+		this.m_filtercriteria == nil then
+		this.m_processed_list = this.m_raw_list
 		return
 	end
 	
-	worldlist.m_processed_worldlist = {}
+	this.m_processed_list = {}
 	
-	for i,v in ipairs(worldlist.m_raw_worldlist) do
+	for i,v in ipairs(this.m_raw_list) do
 	
-		if worldlist.m_gamefilter == nil or 
-			v.gameid == worldlist.m_gamefilter then
-			table.insert(worldlist.m_processed_worldlist,v)
+		if this.m_filtercriteria == nil or 
+			this.m_filter_fct(v,this.m_filtercriteria) then
+			table.insert(this.m_processed_list,v)
 		end
 	end
 	
-	if worldlist.m_sortmode == "none" then
+	if this.m_sortmode == "none" then
 		return
 	end
 	
-	if worldlist.m_sortmode == "alphabetic" then
-		worldlist.sort_alphabetic()
-	end
-
-end
-
---------------------------------------------------------------------------------
-function worldlist.compare(world1,world2)
-
-	if world1.path ~= world2.path then
-		return false
-	end
-	
-	if world1.name ~= world2.name then
-		return false
-	end
-	
-	if world1.gameid ~= world2.gameid then
-		return false
+	if this.m_sort_list[this.m_sortmode] ~= nil and 
+		type(this.m_sort_list[this.m_sortmode]) == "function" then
+		
+		this.m_sort_list[this.m_sortmode](this)
 	end
-
-	return true
 end
 
 --------------------------------------------------------------------------------
-function worldlist.size()
-	if worldlist.m_processed_worldlist == nil then
+function filterlist.size(this)
+	if this.m_processed_list == nil then
 		return 0
 	end
 	
-	return #worldlist.m_processed_worldlist
+	return #this.m_processed_list
 end
 
 --------------------------------------------------------------------------------
-function worldlist.exists(worldname)
-	for i,v in ipairs(worldlist.m_raw_worldlist) do
-		if v.name == worldname then
+function filterlist.uid_exists_raw(this,uid)
+	for i,v in ipairs(this.m_raw_list) do
+		if this.m_uid_match_fct(v,uid) then
 			return true
 		end
 	end
 	return false
 end
 
-
 --------------------------------------------------------------------------------
-function worldlist.engine_index_by_name(worldname)
-	local worldcount = 0
-	local worldidx = 0
-	for i,v in ipairs(worldlist.m_raw_worldlist) do
-		if v.name == worldname then
-			worldcount = worldcount +1
-			worldidx = i
+function filterlist.engine_index_by_uid(this, uid)
+	local elementcount = 0
+	local elementidx = 0
+	for i,v in ipairs(this.m_raw_list) do
+		if this.m_uid_match_fct(v,uid) then
+			elementcount = elementcount +1
+			elementidx = i
 		end
 	end
 	
 	
-	-- If there are more worlds than one with same name we can't decide which
+	-- If there are more elements than one with same name uid can't decide which
 	-- one is meant. This shouldn't be possible but just for sure.
-	if worldcount > 1 then
-		worldidx=0
+	if elementcount > 1 then
+		elementidx=0
+	end
+
+	return elementidx
+end
+
+--------------------------------------------------------------------------------
+-- COMMON helper functions                                                    --
+--------------------------------------------------------------------------------
+
+--------------------------------------------------------------------------------
+function compare_worlds(world1,world2)
+
+	if world1.path ~= world2.path then
+		return false
+	end
+	
+	if world1.name ~= world2.name then
+		return false
+	end
+	
+	if world1.gameid ~= world2.gameid then
+		return false
 	end
 
-	return worldidx
+	return true
 end
 
 --------------------------------------------------------------------------------
-function worldlist.sort_alphabetic() 
+function sort_worlds_alphabetic(this) 
 
-	table.sort(worldlist.m_processed_worldlist, function(a, b) 
+	table.sort(this.m_processed_list, function(a, b) 
 			local n1 = a.name 
 			local n2 = b.name 
 			local count = math.min(#n1, #n2) 
-- 
GitLab