Add formspec toolkit and refactor mainmenu to use it
authorsapier <Sapier at GMX dot net>
Fri, 18 Apr 2014 13:39:15 +0000 (15:39 +0200)
committersapier <Sapier at GMX dot net>
Fri, 16 May 2014 20:57:14 +0000 (22:57 +0200)
Fix crash on using cursor keys in client menu without selected server
Add support for non fixed size tabviews

29 files changed:
builtin/common/filterlist.lua [new file with mode: 0644]
builtin/fstk/buttonbar.lua [new file with mode: 0644]
builtin/fstk/dialog.lua [new file with mode: 0644]
builtin/fstk/tabview.lua [new file with mode: 0644]
builtin/fstk/ui.lua [new file with mode: 0644]
builtin/mainmenu/common.lua [new file with mode: 0644]
builtin/mainmenu/dlg_config_world.lua [new file with mode: 0644]
builtin/mainmenu/dlg_create_world.lua [new file with mode: 0644]
builtin/mainmenu/dlg_delete_mod.lua [new file with mode: 0644]
builtin/mainmenu/dlg_delete_world.lua [new file with mode: 0644]
builtin/mainmenu/dlg_rename_modpack.lua [new file with mode: 0644]
builtin/mainmenu/filterlist.lua [deleted file]
builtin/mainmenu/gamemgr.lua
builtin/mainmenu/init.lua
builtin/mainmenu/menubar.lua [deleted file]
builtin/mainmenu/modmgr.lua
builtin/mainmenu/modstore.lua [deleted file]
builtin/mainmenu/store.lua [new file with mode: 0644]
builtin/mainmenu/tab_credits.lua [new file with mode: 0644]
builtin/mainmenu/tab_mods.lua [new file with mode: 0644]
builtin/mainmenu/tab_multiplayer.lua [new file with mode: 0644]
builtin/mainmenu/tab_server.lua [new file with mode: 0644]
builtin/mainmenu/tab_settings.lua [new file with mode: 0644]
builtin/mainmenu/tab_simple_main.lua [new file with mode: 0644]
builtin/mainmenu/tab_singleplayer.lua [new file with mode: 0644]
builtin/mainmenu/tab_texturepacks.lua [new file with mode: 0644]
builtin/mainmenu/textures.lua
doc/fst_api.txt [new file with mode: 0644]
doc/menu_lua_api.txt

diff --git a/builtin/common/filterlist.lua b/builtin/common/filterlist.lua
new file mode 100644 (file)
index 0000000..99c4bca
--- /dev/null
@@ -0,0 +1,317 @@
+--Minetest
+--Copyright (C) 2013 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+--------------------------------------------------------------------------------
+-- TODO improve doc                                                           --
+-- TODO code cleanup                                                          --
+-- Generic implementation of a filter/sortable list                           --
+-- Usage:                                                                     --
+-- Filterlist needs to be initialized on creation. To achieve this you need to --
+-- pass following functions:                                                  --
+-- raw_fct() (mandatory):                                                     --
+--     function returning a table containing the elements to be filtered      --
+-- compare_fct(element1,element2) (mandatory):                                --
+--     function returning true/false if element1 is same element as element2  --
+-- uid_match_fct(element1,uid) (optional)                                     --
+--     function telling if uid is attached to element1                        --
+-- filter_fct(element,filtercriteria) (optional)                              --
+--     function returning true/false if filtercriteria met to element         --
+-- fetch_param (optional)                                                     --
+--     parameter passed to raw_fct to aquire correct raw data                 --
+--                                                                            --
+--------------------------------------------------------------------------------
+filterlist = {}
+
+--------------------------------------------------------------------------------
+function filterlist.refresh(this)
+       this.m_raw_list = this.m_raw_list_fct(this.m_fetch_param)
+       filterlist.process(this)
+end
+
+--------------------------------------------------------------------------------
+function filterlist.create(raw_fct,compare_fct,uid_match_fct,filter_fct,fetch_param)
+
+       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_fetch_param = fetch_param
+       
+       this.m_sortmode = "none"
+       this.m_sort_list = {}
+
+       this.m_processed_list = nil
+       this.m_raw_list = this.m_raw_list_fct(this.m_fetch_param)
+
+       this.add_sort_mechanism = filterlist.add_sort_mechanism
+       this.set_filtercriteria = filterlist.set_filtercriteria
+       this.get_filtercriteria = filterlist.get_filtercriteria
+       this.set_sortmode       = filterlist.set_sortmode
+       this.get_list           = filterlist.get_list
+       this.get_raw_list       = filterlist.get_raw_list
+       this.get_raw_element    = filterlist.get_raw_element
+       this.get_raw_index      = filterlist.get_raw_index
+       this.get_current_index  = filterlist.get_current_index
+       this.size               = filterlist.size
+       this.uid_exists_raw     = filterlist.uid_exists_raw
+       this.raw_index_by_uid   = filterlist.raw_index_by_uid
+       this.refresh            = filterlist.refresh
+
+       filterlist.process(this)
+       
+       return this
+end
+
+--------------------------------------------------------------------------------
+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 and
+               type(criteria) ~= "table" then
+               return
+       end
+       this.m_filtercriteria = criteria
+       filterlist.process(this)
+end
+
+--------------------------------------------------------------------------------
+function filterlist.get_filtercriteria(this)
+       return this.m_filtercriteria
+end
+
+--------------------------------------------------------------------------------
+--supported sort mode "alphabetic|none"
+function filterlist.set_sortmode(this,mode)
+       if (mode == this.m_sortmode) then
+               return
+       end
+       this.m_sortmode = mode
+       filterlist.process(this)
+end
+
+--------------------------------------------------------------------------------
+function filterlist.get_list(this)
+       return this.m_processed_list
+end
+
+--------------------------------------------------------------------------------
+function filterlist.get_raw_list(this)
+       return this.m_raw_list
+end
+
+--------------------------------------------------------------------------------
+function filterlist.get_raw_element(this,idx)
+       if type(idx) ~= "number" then
+               idx = tonumber(idx)
+       end
+       
+       if idx ~= nil and idx > 0 and idx < #this.m_raw_list then
+               return this.m_raw_list[idx]
+       end
+       
+       return nil
+end
+
+--------------------------------------------------------------------------------
+function filterlist.get_raw_index(this,listindex)
+       assert(this.m_processed_list ~= nil)
+       
+       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(this.m_raw_list) do
+               
+                       if this.m_compare_fct(v,entry) then
+                               return i
+                       end
+               end
+       end
+       
+       return 0
+end
+
+--------------------------------------------------------------------------------
+function filterlist.get_current_index(this,listindex)
+       assert(this.m_processed_list ~= nil)
+       
+       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(this.m_processed_list) do
+               
+                       if this.m_compare_fct(v,entry) then
+                               return i
+                       end
+               end
+       end
+       
+       return 0
+end
+
+--------------------------------------------------------------------------------
+function filterlist.process(this)
+       assert(this.m_raw_list ~= nil)
+
+       if this.m_sortmode == "none" and
+               this.m_filtercriteria == nil then
+               this.m_processed_list = this.m_raw_list
+               return
+       end
+       
+       this.m_processed_list = {}
+       
+       for k,v in pairs(this.m_raw_list) do
+               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 this.m_sortmode == "none" then
+               return
+       end
+       
+       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
+end
+
+--------------------------------------------------------------------------------
+function filterlist.size(this)
+       if this.m_processed_list == nil then
+               return 0
+       end
+       
+       return #this.m_processed_list
+end
+
+--------------------------------------------------------------------------------
+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 filterlist.raw_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 elements than one with same name uid can't decide which
+       -- one is meant. This shouldn't be possible but just for sure.
+       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 true
+end
+
+--------------------------------------------------------------------------------
+function sort_worlds_alphabetic(this)
+
+       table.sort(this.m_processed_list, function(a, b)
+               --fixes issue #857 (crash due to sorting nil in worldlist)
+               if a == nil or b == nil then
+                       if a == nil and b ~= nil then return false end
+                       if b == nil and a ~= nil then return true end
+                       return false
+               end
+               if a.name:lower() == b.name:lower() then
+                       return a.name < b.name
+               end
+               return a.name:lower() < b.name:lower()
+       end)
+end
+
+--------------------------------------------------------------------------------
+function sort_mod_list(this)
+
+       table.sort(this.m_processed_list, function(a, b)
+               -- Show game mods at bottom
+               if a.typ ~= b.typ then
+                       return b.typ == "game_mod"
+               end
+               -- If in same or no modpack, sort by name
+               if a.modpack == b.modpack then
+                       if a.name:lower() == b.name:lower() then
+                               return a.name < b.name
+                       end
+                       return a.name:lower() < b.name:lower()
+               -- Else compare name to modpack name
+               else
+                       -- Always show modpack pseudo-mod on top of modpack mod list
+                       if a.name == b.modpack then
+                               return true
+                       elseif b.name == a.modpack then
+                               return false
+                       end
+                       
+                       local name_a = a.modpack or a.name
+                       local name_b = b.modpack or b.name
+                       if name_a:lower() == name_b:lower() then
+                               return  name_a < name_b
+                       end
+                       return name_a:lower() < name_b:lower()
+               end
+       end)
+end
diff --git a/builtin/fstk/buttonbar.lua b/builtin/fstk/buttonbar.lua
new file mode 100644 (file)
index 0000000..f5ac890
--- /dev/null
@@ -0,0 +1,209 @@
+--Minetest
+--Copyright (C) 2014 sapier
+--
+--self program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--self program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with self program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+local function buttonbar_formspec(self)
+
+       if self.hidden then
+               return ""
+       end
+
+       local formspec = string.format("box[%f,%f;%f,%f;%s]",
+                       self.pos.x,self.pos.y ,self.size.x,self.size.y,self.bgcolor)
+               
+       for i=self.startbutton,#self.buttons,1 do
+               local btn_name = self.buttons[i].name
+               local btn_pos = {}
+               
+               if self.orientation == "horizontal" then
+                       btn_pos.x = self.pos.x + --base pos
+                       (i - self.startbutton) * self.btn_size +       --button offset
+                       self.btn_initial_offset
+               else
+                       btn_pos.x = self.pos.x + (self.btn_size * 0.05)
+               end
+               
+               if self.orientation == "vertical" then
+                       btn_pos.y = self.pos.y + --base pos
+                       (i - self.startbutton) * self.btn_size +       --button offset
+                       self.btn_initial_offset
+               else
+                       btn_pos.y = self.pos.y + (self.btn_size * 0.05)
+               end
+               
+               if (self.orientation == "vertical" and
+                       (btn_pos.y + self.btn_size <= self.pos.y + self.size.y)) or
+                       (self.orientation == "horizontal" and
+                       (btn_pos.x + self.btn_size <= self.pos.x + self.size.x)) then
+                       
+               local borders="true"
+               
+               if self.buttons[i].image ~= nil then
+                       borders="false"
+               end
+                       
+               formspec = formspec ..
+                       string.format("image_button[%f,%f;%f,%f;%s;%s;%s;true;%s]",
+                                       btn_pos.x, btn_pos.y, self.btn_size, self.btn_size,
+                                       self.buttons[i].image, btn_name, self.buttons[i].caption,
+                                       borders)
+               else
+                       --print("end of displayable buttons: orientation: " .. self.orientation)
+                       --print( "button_end: " .. (btn_pos.y + self.btn_size - (self.btn_size * 0.05)))
+                       --print( "bar_end: " .. (self.pos.x + self.size.x))
+                       break
+               end
+       end
+
+       if (self.have_move_buttons) then
+               local btn_dec_pos = {}
+               btn_dec_pos.x = self.pos.x + (self.btn_size * 0.05)
+               btn_dec_pos.y = self.pos.y + (self.btn_size * 0.05)
+               local btn_inc_pos = {}
+               local btn_size = {}
+               
+               if self.orientation == "horizontal" then
+                       btn_size.x = 0.5
+                       btn_size.y = self.btn_size
+                       btn_inc_pos.x = self.pos.x + self.size.x - 0.5
+                       btn_inc_pos.y = self.pos.y + (self.btn_size * 0.05)
+               else
+                       btn_size.x = self.btn_size
+                       btn_size.y = 0.5
+                       btn_inc_pos.x = self.pos.x + (self.btn_size * 0.05)
+                       btn_inc_pos.y = self.pos.y + self.size.y - 0.5
+               end
+               
+               local text_dec = "<"
+               local text_inc = ">"
+               if self.orientation == "vertical" then
+                       text_dec = "^"
+                       text_inc = "v"
+               end
+               
+               formspec = formspec ..
+                       string.format("image_button[%f,%f;%f,%f;;btnbar_dec_%s;%s;true;true]",
+                                       btn_dec_pos.x, btn_dec_pos.y, btn_size.x, btn_size.y,
+                                       self.name, text_dec)
+                               
+               formspec = formspec ..
+                       string.format("image_button[%f,%f;%f,%f;;btnbar_dec_%s;%s;true;true]",
+                                       btn_inc_pos.x, btn_inc_pos.y, btn_size.x, btn_size.y,
+                                        self.name, text_inc)
+       end
+       
+       return formspec
+end
+
+local function buttonbar_buttonhandler(self, fields)
+
+       if fields["btnbar_inc_" .. self.name] ~= nil and
+               self.startbutton < #self.buttons then
+               
+               self.startbutton = self.startbutton + 1
+               return true
+       end
+       
+       if fields["btnbar_dec_" .. self.name] ~= nil and self.startbutton > 1 then
+               self.startbutton = self.startbutton - 1
+               return true
+       end
+       
+       for i=1,#self.buttons,1 do
+               if fields[self.buttons[i].name] ~= nil then
+                       return self.userbuttonhandler(fields)
+               end
+       end
+end
+
+local buttonbar_metatable = {
+       handle_buttons = buttonbar_buttonhandler,
+       handle_events  = function(self, event) end,
+       get_formspec   = buttonbar_formspec,
+       
+       hide = function(self) self.hidden = true end,
+       show = function(self) self.hidden = false end,
+
+       delete = function(self) ui.delete(self) end,
+       
+       add_button = function(self, name, caption, image)
+                       if caption == nil then caption = "" end
+                       if image == nil then image = "" end
+                       
+                       table.insert(self.buttons,{ name=name, caption=caption, image=image})
+                       if self.orientation == "horizontal" then
+                               if ( (self.btn_size * #self.buttons) + (self.btn_size * 0.05 *2)
+                                       > self.size.x ) then
+                                       
+                                       self.btn_initial_offset = self.btn_size * 0.05 + 0.5
+                                       self.have_move_buttons = true
+                               end
+                       else
+                               if ((self.btn_size * #self.buttons) + (self.btn_size * 0.05 *2)
+                                       > self.size.y ) then
+                                       
+                                       self.btn_initial_offset = self.btn_size * 0.05 + 0.5
+                                       self.have_move_buttons = true
+                               end
+                       end
+               end,
+               
+       set_bgparams = function(self, bgcolor)
+                       if (type(bgcolor) == "string") then
+                               self.bgcolor = bgcolor
+                       end
+               end,
+}
+
+buttonbar_metatable.__index = buttonbar_metatable
+
+function buttonbar_create(name, cbf_buttonhandler, pos, orientation, size)
+       assert(name ~= nil)
+       assert(cbf_buttonhandler ~= nil)
+       assert(orientation == "vertical" or orientation == "horizontal")
+       assert(pos ~= nil and type(pos) == "table")
+       assert(size ~= nil and type(size) == "table")
+
+       local self = {}
+       self.name = name
+       self.type = "addon"
+       self.bgcolor = "#000000"
+       self.pos = pos
+       self.size = size
+       self.orientation = orientation
+       self.startbutton = 1
+       self.have_move_buttons = false
+       self.hidden = false
+       
+       if self.orientation == "horizontal" then
+                       self.btn_size = self.size.y
+       else
+                       self.btn_size = self.size.x
+       end
+       
+       if (self.btn_initial_offset == nil) then
+               self.btn_initial_offset = self.btn_size * 0.05
+       end
+
+       self.userbuttonhandler = cbf_buttonhandler
+       self.buttons = {}
+       
+       setmetatable(self,buttonbar_metatable)
+
+       ui.add(self)
+       return self
+end
diff --git a/builtin/fstk/dialog.lua b/builtin/fstk/dialog.lua
new file mode 100644 (file)
index 0000000..214b038
--- /dev/null
@@ -0,0 +1,69 @@
+--Minetest
+--Copyright (C) 2014 sapier
+--
+--self program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--self program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with self program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+local function dialog_event_handler(self,event)
+       if self.user_eventhandler == nil or
+               self.user_eventhandler(event) == false then
+
+               --close dialog on esc
+               if event == "MenuQuit" then
+                       self:delete()
+                       return true
+               end
+       end
+end
+
+local dialog_metatable = {
+       eventhandler = dialog_event_handler,
+       get_formspec = function(self)
+                               if not self.hidden then return self.formspec(self.data) end
+                       end,
+       handle_buttons = function(self,fields)
+                               if not self.hidden then return self.buttonhandler(self,fields) end
+                       end,
+       handle_events  = function(self,event)
+                               if not self.hidden then return self.eventhandler(self,event) end
+                       end,
+       hide = function(self) self.hidden = true end,
+       show = function(self) self.hidden = false end,
+       delete = function(self)
+                       if self.parent ~= nil then
+                               self.parent:show()
+                       end
+                       ui.delete(self)
+               end,
+       set_parent = function(self,parent) self.parent = parent end
+}
+dialog_metatable.__index = dialog_metatable
+
+function dialog_create(name,get_formspec,buttonhandler,eventhandler)
+       local self = {}
+
+       self.name = name
+       self.type = "toplevel"
+       self.hidden = true
+       self.data = {}
+
+       self.formspec      = get_formspec
+       self.buttonhandler = buttonhandler
+       self.user_eventhandler  = eventhandler
+       
+       setmetatable(self,dialog_metatable)
+
+       ui.add(self)
+       return self
+end
diff --git a/builtin/fstk/tabview.lua b/builtin/fstk/tabview.lua
new file mode 100644 (file)
index 0000000..47603fb
--- /dev/null
@@ -0,0 +1,273 @@
+--Minetest
+--Copyright (C) 2014 sapier
+--
+--self program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--self program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with self program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+--------------------------------------------------------------------------------
+-- A tabview implementation                                                   --
+-- Usage:                                                                     --
+-- tabview.create: returns initialized tabview raw element                    --
+-- element.add(tab): add a tab declaration                                    --
+-- element.handle_buttons()                                                   --
+-- element.handle_events()                                                    --
+-- element.getFormspec() returns formspec of tabview                          --
+--------------------------------------------------------------------------------
+
+--------------------------------------------------------------------------------
+local function add_tab(self,tab)
+       assert(tab.size == nil or (type(tab.size) == table and
+                       tab.size.x ~= nil and tab.size.y ~= nil))
+       assert(tab.cbf_formspec ~= nil and type(tab.cbf_formspec) == "function")
+       assert(tab.cbf_button_handler == nil or
+                       type(tab.cbf_button_handler) == "function")
+       assert(tab.cbf_events == nil or type(tab.cbf_events) == "function")
+
+       local newtab = {
+               name = tab.name,
+               caption = tab.caption,
+               button_handler = tab.cbf_button_handler,
+               event_handler = tab.cbf_events,
+               get_formspec = tab.cbf_formspec,
+               tabsize = tab.tabsize,
+               on_change = tab.on_change,
+               tabdata = {},
+       }
+
+       table.insert(self.tablist,newtab)
+
+       if self.last_tab_index == #self.tablist then
+               self.current_tab = tab.name
+               if tab.on_activate ~= nil then
+                       tab.on_activate(nil,tab.name)
+               end
+       end
+end
+
+--------------------------------------------------------------------------------
+local function get_formspec(self)
+       local formspec = ""
+
+       if not self.hidden and (self.parent == nil or not self.parent.hidden) then
+       
+               if self.parent == nil then
+                       local tsize = self.tablist[self.last_tab_index].tabsize or
+                                       {width=self.width, height=self.height}
+                       formspec = formspec ..
+                                       string.format("size[%f,%f,%s]",tsize.width,tsize.height,
+                                               dump(self.fixed_size))
+               end
+               formspec = formspec .. self:tab_header()
+               formspec = formspec ..
+                               self.tablist[self.last_tab_index].get_formspec(
+                                       self,
+                                       self.tablist[self.last_tab_index].name,
+                                       self.tablist[self.last_tab_index].tabdata,
+                                       self.tablist[self.last_tab_index].tabsize
+                                       )
+       end
+       return formspec
+end
+
+--------------------------------------------------------------------------------
+local function handle_buttons(self,fields)
+
+       if self.hidden then
+               return false
+       end
+       
+       if self:handle_tab_buttons(fields) then
+               return true
+       end
+       
+       if self.glb_btn_handler ~= nil and
+               self.glb_btn_handler(self,fields) then
+               return true
+       end
+
+       if self.tablist[self.last_tab_index].button_handler ~= nil then
+               return
+                       self.tablist[self.last_tab_index].button_handler(
+                                       self,
+                                       fields,
+                                       self.tablist[self.last_tab_index].name,
+                                       self.tablist[self.last_tab_index].tabdata
+                                       )
+       end
+
+       return false
+end
+
+--------------------------------------------------------------------------------
+local function handle_events(self,event)
+       
+       if self.hidden then
+               return false
+       end
+       
+       if self.glb_evt_handler ~= nil and
+               self.glb_evt_handler(self,event) then
+               return true
+       end
+       
+       if self.tablist[self.last_tab_index].evt_handler ~= nil then
+               return
+                       self.tablist[self.last_tab_index].evt_handler(
+                                       self,
+                                       event,
+                                       self.tablist[self.last_tab_index].name,
+                                       self.tablist[self.last_tab_index].tabdata
+                                       )
+       end
+       
+       return false
+end
+
+
+--------------------------------------------------------------------------------
+local function tab_header(self)
+
+       local toadd = ""
+
+       for i=1,#self.tablist,1 do
+
+               if toadd ~= "" then
+                       toadd = toadd .. ","
+               end
+
+               toadd = toadd .. self.tablist[i].caption
+       end
+       return string.format("tabheader[%f,%f;%s;%s;%i;true;false]",
+                       self.header_x, self.header_y, self.name, toadd, self.last_tab_index);
+end
+
+--------------------------------------------------------------------------------
+local function switch_to_tab(self, index)
+       --first call on_change for tab to leave
+       if self.tablist[self.last_tab_index].on_change ~= nil then
+               self.tablist[self.last_tab_index].on_change("LEAVE",
+                               self.current_tab, self.tablist[index].name)
+       end
+       
+       --update tabview data
+       self.last_tab_index = index
+       local old_tab = self.current_tab
+       self.current_tab = self.tablist[index].name
+       
+       if (self.autosave_tab) then
+               core.setting_set(self.name .. "_LAST",self.current_tab)
+       end
+       
+       -- call for tab to enter
+       if self.tablist[index].on_change ~= nil then
+               self.tablist[index].on_change("ENTER",
+                               old_tab,self.current_tab)
+       end
+end
+
+--------------------------------------------------------------------------------
+local function handle_tab_buttons(self,fields)
+       --save tab selection to config file
+       if fields[self.name] then
+               local index = tonumber(fields[self.name])
+               switch_to_tab(self, index)
+               return true
+       end
+
+       return false
+end
+
+--------------------------------------------------------------------------------
+local function set_tab_by_name(self, name)
+       for i=1,#self.tablist,1 do
+               if self.tablist[i].name == name then
+                       switch_to_tab(self, i)
+                       return true
+               end
+       end
+       
+       return false
+end
+
+--------------------------------------------------------------------------------
+local function hide_tabview(self)
+       self.hidden=true
+       
+       --call on_change as we're not gonna show self tab any longer
+       if self.tablist[self.last_tab_index].on_change ~= nil then
+               self.tablist[self.last_tab_index].on_change("LEAVE",
+                               self.current_tab, nil)
+       end
+end
+
+--------------------------------------------------------------------------------
+local function show_tabview(self)
+       self.hidden=false
+       
+       -- call for tab to enter
+       if self.tablist[self.last_tab_index].on_change ~= nil then
+               self.tablist[self.last_tab_index].on_change("ENTER",
+                               nil,self.current_tab)
+       end
+end
+
+local tabview_metatable = {
+       add                       = add_tab,
+       handle_buttons            = handle_buttons,
+       handle_events             = handle_events,
+       get_formspec              = get_formspec,
+       show                      = show_tabview,
+       hide                      = hide_tabview,
+       delete                    = function(self) ui.delete(self) end,
+       set_parent                = function(self,parent) self.parent = parent end,
+       set_autosave_tab          =
+                       function(self,value) self.autosave_tab = value end,
+       set_tab                   = set_tab_by_name,
+       set_global_button_handler =
+                       function(self,handler) self.glb_btn_handler = handler end,
+       set_global_event_handler =
+                       function(self,handler) self.glb_evt_handler = handler end,
+       set_fixed_size =
+                       function(self,state) self.fixed_size = state end,
+       tab_header = tab_header,
+       handle_tab_buttons = handle_tab_buttons
+}
+
+tabview_metatable.__index = tabview_metatable
+
+--------------------------------------------------------------------------------
+function tabview_create(name, size, tabheaderpos)
+       local self = {}
+
+       self.name     = name
+       self.type     = "toplevel"
+       self.width    = size.x
+       self.height   = size.y
+       self.header_x = tabheaderpos.x
+       self.header_y = tabheaderpos.y
+
+       setmetatable(self, tabview_metatable)
+
+       self.fixed_size     = true
+       self.hidden         = true
+       self.current_tab    = nil
+       self.last_tab_index = 1
+       self.tablist        = {}
+       
+       self.autosave_tab   = false
+
+       ui.add(self)
+       return self
+end
diff --git a/builtin/fstk/ui.lua b/builtin/fstk/ui.lua
new file mode 100644 (file)
index 0000000..e043824
--- /dev/null
@@ -0,0 +1,172 @@
+--Minetest
+--Copyright (C) 2014 sapier
+--
+--self program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--self program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with self program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ui = {}
+ui.childlist = {}
+ui.default = nil
+
+--------------------------------------------------------------------------------
+function ui.add(child)
+       --TODO check child
+       ui.childlist[child.name] = child
+       
+       return child.name
+end
+
+--------------------------------------------------------------------------------
+function ui.delete(child)
+
+       if ui.childlist[child.name] == nil then
+               return false
+       end
+       
+       ui.childlist[child.name] = nil
+       return true
+end
+
+--------------------------------------------------------------------------------
+function ui.set_default(name)
+       ui.default = name
+end
+
+--------------------------------------------------------------------------------
+function ui.find_by_name(name)
+       return ui.childlist[name]
+end
+
+--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
+-- Internal functions not to be called from user
+--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
+
+--------------------------------------------------------------------------------
+function ui.update()
+       local formspec = ""
+
+       -- handle errors
+       if gamedata ~= nil and gamedata.errormessage ~= nil then
+               formspec = "size[12,3.2]" ..
+                       "textarea[1,1;10,2;;ERROR: " ..
+                       core.formspec_escape(gamedata.errormessage) ..
+                       ";]"..
+                       "button[4.5,2.5;3,0.5;btn_error_confirm;" .. fgettext("Ok") .. "]"
+       else
+               local active_toplevel_ui_elements = 0
+               for key,value in pairs(ui.childlist) do
+                       if (value.type == "toplevel") then
+                               local retval = value:get_formspec()
+
+                               if retval ~= nil and retval ~= "" then
+                                       active_toplevel_ui_elements = active_toplevel_ui_elements +1
+                                       formspec = formspec .. retval
+                               end
+                       end
+               end
+               
+               -- no need to show addons if there ain't a toplevel element
+               if (active_toplevel_ui_elements > 0) then
+                       for key,value in pairs(ui.childlist) do
+                               if (value.type == "addon") then
+                                       local retval = value:get_formspec()
+
+                                       if retval ~= nil and retval ~= "" then
+                                               formspec = formspec .. retval
+                                       end
+                               end
+                       end
+               end
+
+               if (active_toplevel_ui_elements > 1) then
+                       print("WARNING: ui manager detected more then one active ui element, self most likely isn't intended")
+               end
+
+               if (active_toplevel_ui_elements == 0) then
+                       print("WARNING: not a single toplevel ui element active switching to default")
+                       ui.childlist[ui.default]:show()
+                       formspec = ui.childlist[ui.default]:get_formspec()
+               end
+       end
+       core.update_formspec(formspec)
+end
+
+--------------------------------------------------------------------------------
+function ui.handle_buttons(fields)
+
+       if fields["btn_error_confirm"] then
+               gamedata.errormessage = nil
+               update_menu()
+               return
+       end
+
+       for key,value in pairs(ui.childlist) do
+
+               local retval = value:handle_buttons(fields)
+
+               if retval then
+                       ui.update()
+                       return
+               end
+       end
+end
+
+
+--------------------------------------------------------------------------------
+function ui.handle_events(event)
+       
+       for key,value in pairs(ui.childlist) do
+
+               if value.handle_events ~= nil then
+                       local retval = value:handle_events(event)
+
+                       if retval then
+                               print("event handled by: " .. key)
+                               return retval
+                       end
+               end
+       end
+end
+
+--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
+-- initialize callbacks
+--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
+core.button_handler = function(fields)
+       if fields["btn_error_confirm"] then
+               gamedata.errormessage = nil
+               ui.update()
+               return
+       end
+
+       if ui.handle_buttons(fields) then
+               ui.update()
+       end
+end
+
+--------------------------------------------------------------------------------
+core.event_handler = function(event)
+       if ui.handle_events(event) then
+               ui.update()
+               return
+       end
+
+       if event == "Refresh" then
+               ui.update()
+               return
+       end
+end
diff --git a/builtin/mainmenu/common.lua b/builtin/mainmenu/common.lua
new file mode 100644 (file)
index 0000000..c555ec9
--- /dev/null
@@ -0,0 +1,193 @@
+--Minetest
+--Copyright (C) 2014 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+--------------------------------------------------------------------------------
+-- Global menu data
+---------------------------------------------------------------------------------
+menudata = {}
+
+--------------------------------------------------------------------------------
+-- Menu helper functions
+--------------------------------------------------------------------------------
+
+--------------------------------------------------------------------------------
+function render_favorite(spec,render_details)
+       local text = ""
+
+       if spec.name ~= nil then
+               text = text .. core.formspec_escape(spec.name:trim())
+
+--             if spec.description ~= nil and
+--                     core.formspec_escape(spec.description):trim() ~= "" then
+--                     text = text .. " (" .. core.formspec_escape(spec.description) .. ")"
+--             end
+       else
+               if spec.address ~= nil then
+                       text = text .. spec.address:trim()
+
+                       if spec.port ~= nil then
+                               text = text .. ":" .. spec.port
+                       end
+               end
+       end
+
+       if not render_details then
+               return text
+       end
+
+       local details = ""
+       if spec.password == true then
+               details = details .. "*"
+       else
+               details = details .. "_"
+       end
+
+       if spec.creative then
+               details = details .. "C"
+       else
+               details = details .. "_"
+       end
+
+       if spec.damage then
+               details = details .. "D"
+       else
+               details = details .. "_"
+       end
+
+       if spec.pvp then
+               details = details .. "P"
+       else
+               details = details .. "_"
+       end
+       details = details .. " "
+
+       local playercount = ""
+
+       if spec.clients ~= nil and
+               spec.clients_max ~= nil then
+               playercount = string.format("%03d",spec.clients) .. "/" ..
+                                               string.format("%03d",spec.clients_max) .. " "
+       end
+
+       return playercount .. core.formspec_escape(details) ..  text
+end
+
+--------------------------------------------------------------------------------
+os.tempfolder = function()
+       if core.setting_get("TMPFolder") then
+               return core.setting_get("TMPFolder") .. DIR_DELIM .. "MT_" .. math.random(0,10000)
+       end
+
+       local filetocheck = os.tmpname()
+       os.remove(filetocheck)
+
+       local randname = "MTTempModFolder_" .. math.random(0,10000)
+       if DIR_DELIM == "\\" then
+               local tempfolder = os.getenv("TEMP")
+               return tempfolder .. filetocheck
+       else
+               local backstring = filetocheck:reverse()
+               return filetocheck:sub(0,filetocheck:len()-backstring:find(DIR_DELIM)+1) ..randname
+       end
+
+end
+
+--------------------------------------------------------------------------------
+function menu_render_worldlist()
+       local retval = ""
+
+       local current_worldlist = menudata.worldlist:get_list()
+
+       for i,v in ipairs(current_worldlist) do
+               if retval ~= "" then
+                       retval = retval ..","
+               end
+
+               retval = retval .. core.formspec_escape(v.name) ..
+                                       " \\[" .. core.formspec_escape(v.gameid) .. "\\]"
+       end
+
+       return retval
+end
+
+--------------------------------------------------------------------------------
+function menu_handle_key_up_down(fields,textlist,settingname)
+
+       if fields["key_up"] then
+               local oldidx = core.get_textlist_index(textlist)
+
+               if oldidx ~= nil and oldidx > 1 then
+                       local newidx = oldidx -1
+                       core.setting_set(settingname,
+                               menudata.worldlist:get_raw_index(newidx))
+               end
+               return true
+       end
+
+       if fields["key_down"] then
+               local oldidx = core.get_textlist_index(textlist)
+
+               if oldidx ~= nil and oldidx < menudata.worldlist:size() then
+                       local newidx = oldidx + 1
+                       core.setting_set(settingname,
+                               menudata.worldlist:get_raw_index(newidx))
+               end
+               
+               return true
+       end
+       
+       return false
+end
+
+--------------------------------------------------------------------------------
+function asyncOnlineFavourites()
+
+       menudata.favorites = {}
+       core.handle_async(
+               function(param)
+                       return core.get_favorites("online")
+               end,
+               nil,
+               function(result)
+                       menudata.favorites = result
+                       core.event_handler("Refresh")
+               end
+               )
+end
+
+--------------------------------------------------------------------------------
+function text2textlist(xpos,ypos,width,height,tl_name,textlen,text,transparency)
+       local textlines = core.splittext(text,textlen)
+       
+       local retval = "textlist[" .. xpos .. "," .. ypos .. ";"
+                                                               .. width .. "," .. height .. ";"
+                                                               .. tl_name .. ";"
+       
+       for i=1, #textlines, 1 do
+               textlines[i] = textlines[i]:gsub("\r","")
+               retval = retval .. core.formspec_escape(textlines[i]) .. ","
+       end
+       
+       retval = retval .. ";0;"
+       
+       if transparency then
+               retval = retval .. "true"
+       end
+       
+       retval = retval .. "]"
+
+       return retval
+end
diff --git a/builtin/mainmenu/dlg_config_world.lua b/builtin/mainmenu/dlg_config_world.lua
new file mode 100644 (file)
index 0000000..a459f0f
--- /dev/null
@@ -0,0 +1,290 @@
+--Minetest
+--Copyright (C) 2013 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+--------------------------------------------------------------------------------
+
+local function get_formspec(data)
+
+       local mod = data.list:get_list()[data.selected_mod]
+
+       local retval =
+               "size[11,6.5,true]" ..
+               "label[0.5,-0.25;" .. fgettext("World:") .. "]" ..
+               "label[1.75,-0.25;" .. data.worldspec.name .. "]"
+
+       if data.hide_gamemods then
+               retval = retval .. "checkbox[0,5.75;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";true]"
+       else
+               retval = retval .. "checkbox[0,5.75;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";false]"
+       end
+
+       if data.hide_modpackcontents then
+               retval = retval .. "checkbox[2,5.75;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";true]"
+       else
+               retval = retval .. "checkbox[2,5.75;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";false]"
+       end
+
+       if mod == nil then
+               mod = {name=""}
+       end
+       
+       retval = retval ..
+               "label[0,0.45;" .. fgettext("Mod:") .. "]" ..
+               "label[0.75,0.45;" .. mod.name .. "]" ..
+               "label[0,1;" .. fgettext("Depends:") .. "]" ..
+               "textlist[0,1.5;5,4.25;world_config_depends;" ..
+               modmgr.get_dependencies(mod.path) .. ";0]" ..
+               "button[9.25,6.35;2,0.5;btn_config_world_save;" .. fgettext("Save") .. "]" ..
+               "button[7.4,6.35;2,0.5;btn_config_world_cancel;" .. fgettext("Cancel") .. "]"
+
+       if mod ~= nil and mod.name ~= "" and mod.typ ~= "game_mod" then
+               if mod.is_modpack then
+                       local rawlist = data.list:get_raw_list()
+
+                       local all_enabled = true
+                       for j=1,#rawlist,1 do
+                               if rawlist[j].modpack == mod.name and
+                                       rawlist[j].enabled ~= true then
+                                               all_enabled = false
+                                               break
+                               end
+                       end
+
+                       if all_enabled == false then
+                               retval = retval .. "button[5.5,-0.125;2,0.5;btn_mp_enable;" .. fgettext("Enable MP") .. "]"
+                       else
+                               retval = retval .. "button[5.5,-0.125;2,0.5;btn_mp_disable;" .. fgettext("Disable MP") .. "]"
+                       end
+               else
+                       if mod.enabled then
+                               retval = retval .. "checkbox[5.5,-0.375;cb_mod_enable;" .. fgettext("enabled") .. ";true]"
+                       else
+                               retval = retval .. "checkbox[5.5,-0.375;cb_mod_enable;" .. fgettext("enabled") .. ";false]"
+                       end
+               end
+       end
+
+       retval = retval ..
+               "button[8.5,-0.125;2.5,0.5;btn_all_mods;" .. fgettext("Enable all") .. "]" ..
+               "textlist[5.5,0.5;5.5,5.75;world_config_modlist;"
+
+       retval = retval .. modmgr.render_modlist(data.list)
+       retval = retval .. ";" .. data.selected_mod .."]"
+
+       return retval
+end
+
+local function enable_mod(this, toset)
+       local mod = this.data.list:get_list()[this.data.selected_mod]
+
+       if mod.typ == "game_mod" then
+               -- game mods can't be enabled or disabled
+       elseif not mod.is_modpack then
+               if toset == nil then
+                       mod.enabled = not mod.enabled
+               else
+                       mod.enabled = toset
+               end
+       else
+               local list = this.data.list:get_raw_list()
+               for i=1,#list,1 do
+                       if list[i].modpack == mod.name then
+                               if toset == nil then
+                                       toset = not list[i].enabled
+                               end
+                               list[i].enabled = toset
+                       end
+               end
+       end
+end
+
+
+local function handle_buttons(this, fields)
+
+       if fields["world_config_modlist"] ~= nil then
+               local event = core.explode_textlist_event(fields["world_config_modlist"])
+               this.data.selected_mod = event.index
+
+               if event.type == "DCL" then
+                       enable_mod(this)
+               end
+               
+               return true
+       end
+
+       if fields["key_enter"] ~= nil then
+               enable_mod(this)
+               return true
+       end
+
+       if fields["cb_mod_enable"] ~= nil then
+               local toset = core.is_yes(fields["cb_mod_enable"])
+               enable_mod(this,toset)
+               return true
+       end
+
+       if fields["btn_mp_enable"] ~= nil or
+               fields["btn_mp_disable"] then
+               local toset = (fields["btn_mp_enable"] ~= nil)
+               enable_mod(this,toset)
+               return true
+       end
+
+       if fields["cb_hide_gamemods"] ~= nil or
+               fields["cb_hide_mpcontent"] ~= nil then
+               local current = this.data.list:get_filtercriteria()
+
+               if current == nil then
+                       current = {}
+               end
+
+               if core.is_yes(fields["cb_hide_gamemods"]) then
+                       current.hide_game = true
+                       this.data.hide_gamemods = true
+               else
+                       current.hide_game = false
+                       this.data.hide_gamemods = false
+               end
+               
+               if core.is_yes(fields["cb_hide_mpcontent"]) then
+                       current.hide_modpackcontents = true
+                       this.data.hide_modpackcontents = true
+               else
+                       current.hide_modpackcontents = false
+                       this.data.hide_modpackcontents = false
+               end
+
+               this.data.list:set_filtercriteria(current)
+               return true
+       end
+
+       if fields["btn_config_world_save"] then
+
+               local filename = this.data.worldspec.path ..
+                               DIR_DELIM .. "world.mt"
+
+               local worldfile = Settings(filename)
+               local mods = worldfile:to_table()
+
+               local rawlist = this.data.list:get_raw_list()
+
+               local i,mod
+               for i,mod in ipairs(rawlist) do
+                       if not mod.is_modpack and
+                                       mod.typ ~= "game_mod" then
+                               if mod.enabled then
+                                       worldfile:set("load_mod_"..mod.name, "true")
+                               else
+                                       worldfile:set("load_mod_"..mod.name, "false")
+                               end
+                               mods["load_mod_"..mod.name] = nil
+                       end
+               end
+
+               -- Remove mods that are not present anymore
+               for key,value in pairs(mods) do
+                       if key:sub(1,9) == "load_mod_" then
+                               worldfile:remove(key)
+                       end
+               end
+
+               if not worldfile:write() then
+                       core.log("error", "Failed to write world config file")
+               end
+       
+               this:delete()
+               return true
+       end
+
+       if fields["btn_config_world_cancel"] then
+               this:delete()
+               return true
+       end
+
+       if fields["btn_all_mods"] then
+               local list = this.data.list:get_raw_list()
+
+               for i=1,#list,1 do
+                       if list[i].typ ~= "game_mod" and
+                               not list[i].is_modpack then
+                               list[i].enabled = true
+                       end
+               end
+               return true
+       end
+
+       return false
+end
+
+function create_configure_world_dlg(worldidx)
+
+       local dlg = dialog_create("sp_config_world",
+                                       get_formspec,
+                                       handle_buttons,
+                                       nil)
+
+       --TODO read from settings
+       dlg.data.hide_gamemods = false
+       dlg.data.hide_modpackcontents = false
+       dlg.data.selected_mod = 0
+
+       dlg.data.worldspec = core.get_worlds()[worldidx]
+       if dlg.data.worldspec == nil then dlg:delete() return nil end
+
+       dlg.data.worldconfig = modmgr.get_worldconfig(dlg.data.worldspec.path)
+       
+       if dlg.data.worldconfig == nil or dlg.data.worldconfig.id == nil or
+                       dlg.data.worldconfig.id == "" then
+
+               dlg:delete()
+               return nil
+       end
+       
+       dlg.data.list = filterlist.create(
+                       modmgr.preparemodlist, --refresh
+                       modmgr.comparemod, --compare
+                       function(element,uid) --uid match
+                                       if element.name == uid then
+                                               return true
+                                       end
+                               end,
+                               function(element,criteria)
+                                       if criteria.hide_game and
+                                               element.typ == "game_mod" then
+                                                       return false
+                                       end
+
+                                       if criteria.hide_modpackcontents and
+                                               element.modpack ~= nil then
+                                                       return false
+                                               end
+                                       return true
+                               end, --filter
+                               { worldpath= dlg.data.worldspec.path,
+                                 gameid = dlg.data.worldspec.gameid }
+                       )
+                       
+       dlg.data.list:set_filtercriteria(
+               {
+                       hide_game=dlg.data.hide_gamemods,
+                       hide_modpackcontents= dlg.data.hide_modpackcontents
+               })
+       dlg.data.list:add_sort_mechanism("alphabetic", sort_mod_list)
+       dlg.data.list:set_sortmode("alphabetic")
+       
+       return dlg
+end
diff --git a/builtin/mainmenu/dlg_create_world.lua b/builtin/mainmenu/dlg_create_world.lua
new file mode 100644 (file)
index 0000000..5d18bfd
--- /dev/null
@@ -0,0 +1,132 @@
+--Minetest
+--Copyright (C) 2014 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+local function create_world_formspec(dialogdata)
+       local mapgens = {"v6", "v7", "indev", "singlenode", "math"}
+
+       local current_seed = core.setting_get("fixed_map_seed") or ""
+       local current_mg   = core.setting_get("mg_name")
+
+       local mglist = ""
+       local selindex = 1
+       local i = 1
+       for k,v in pairs(mapgens) do
+               if current_mg == v then
+                       selindex = i
+               end
+               i = i + 1
+               mglist = mglist .. v .. ","
+       end
+       mglist = mglist:sub(1, -2)
+       
+       local gameid = core.setting_get("menu_last_game")
+       
+       local game, gameidx = nil , 0
+       if gameid ~= nil then
+               game, gameidx = gamemgr.find_by_gameid(gameid)
+               
+               if gameidx == nil then
+                       gameidx = 0
+               end
+       end
+
+       local retval =
+               "size[12,6,true]" ..
+               "label[2,0;" .. fgettext("World name") .. "]"..
+               "field[4.5,0.4;6,0.5;te_world_name;;]" ..
+
+               "label[2,1;" .. fgettext("Seed") .. "]"..
+               "field[4.5,1.4;6,0.5;te_seed;;".. current_seed .. "]" ..
+
+               "label[2,2;" .. fgettext("Mapgen") .. "]"..
+               "dropdown[4.2,2;6.3;dd_mapgen;" .. mglist .. ";" .. selindex .. "]" ..
+
+               "label[2,3;" .. fgettext("Game") .. "]"..
+               "textlist[4.2,3;5.8,2.3;games;" .. gamemgr.gamelist() ..
+               ";" .. gameidx .. ";true]" ..
+
+               "button[5,5.5;2.6,0.5;world_create_confirm;" .. fgettext("Create") .. "]" ..
+               "button[7.5,5.5;2.8,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
+
+       return retval
+
+end
+
+local function create_world_buttonhandler(this, fields)
+
+       if fields["world_create_confirm"] or
+               fields["key_enter"] then
+
+               local worldname = fields["te_world_name"]
+               local gameindex = core.get_textlist_index("games")
+
+               if gameindex ~= nil and
+                       worldname ~= "" then
+
+                       local message = nil
+
+                       if not menudata.worldlist:uid_exists_raw(worldname) then
+                               core.setting_set("mg_name",fields["dd_mapgen"])
+                               message = core.create_world(worldname,gameindex)
+                       else
+                               message = fgettext("A world named \"$1\" already exists", worldname)
+                       end
+
+                       core.setting_set("fixed_map_seed", fields["te_seed"])
+
+                       if message ~= nil then
+                               gamedata.errormessage = message
+                       else
+                               core.setting_set("menu_last_game",gamemgr.games[gameindex].id)
+                               if this.data.update_worldlist_filter then
+                                       menudata.worldlist:set_filtercriteria(gamemgr.games[gameindex].id)
+                                       mm_texture.update("singleplayer", gamemgr.games[gameindex].id)
+                               end
+                               menudata.worldlist:refresh()
+                               core.setting_set("mainmenu_last_selected_world",
+                                                                       menudata.worldlist:raw_index_by_uid(worldname))
+                       end
+               else
+                       gamedata.errormessage =
+                               fgettext("No worldname given or no game selected")
+               end
+               this:delete()
+               return true
+       end
+
+       if fields["games"] then
+               return true
+       end
+       
+       if fields["world_create_cancel"] then
+               this:delete()
+               return true
+       end
+
+       return false
+end
+
+
+function create_create_world_dlg(update_worldlistfilter)
+       local retval = dialog_create("sp_create_world",
+                                       create_world_formspec,
+                                       create_world_buttonhandler,
+                                       nil)
+       retval.update_worldlist_filter = update_worldlistfilter
+       
+       return retval
+end
diff --git a/builtin/mainmenu/dlg_delete_mod.lua b/builtin/mainmenu/dlg_delete_mod.lua
new file mode 100644 (file)
index 0000000..6e00b80
--- /dev/null
@@ -0,0 +1,68 @@
+--Minetest
+--Copyright (C) 2014 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+--------------------------------------------------------------------------------
+
+local function delete_mod_formspec(dialogdata)
+       
+       dialogdata.mod = modmgr.global_mods:get_list()[dialogdata.selected]
+
+       local retval =
+               "size[12.4,5,true]" ..
+               "field[1.75,1;10,3;;" .. fgettext("Are you sure you want to delete \"$1\"?", dialogdata.mod.name) ..  ";]"..
+               "button[4,4.2;1,0.5;dlg_delete_mod_confirm;" .. fgettext("Yes") .. "]" ..
+               "button[6.5,4.2;3,0.5;dlg_delete_mod_cancel;" .. fgettext("No of course not!") .. "]"
+       
+       return retval
+end
+
+--------------------------------------------------------------------------------
+local function delete_mod_buttonhandler(this, fields)
+       if fields["dlg_delete_mod_confirm"] ~= nil then
+
+               if this.data.mod.path ~= nil and
+                       this.data.mod.path ~= "" and
+                       this.data.mod.path ~= core.get_modpath() then
+                       if not core.delete_dir(this.data.mod.path) then
+                               gamedata.errormessage = fgettext("Modmgr: failed to delete \"$1\"", this.data.mod.path)
+                       end
+                       modmgr.refresh_globals()
+               else
+                       gamedata.errormessage = fgettext("Modmgr: invalid modpath \"$1\"", this.data.mod.path)
+               end
+               this:delete()
+               return true
+       end
+       
+       if fields["dlg_delete_mod_cancel"] then
+               this:delete()
+               return true
+       end
+
+       return false
+end
+
+--------------------------------------------------------------------------------
+function create_delete_mod_dlg(selected_index)
+
+       local retval = dialog_create("dlg_delete_mod",
+                                       delete_mod_formspec,
+                                       delete_mod_buttonhandler,
+                                       nil)
+       retval.data.selected = selected_index
+       return retval
+end
diff --git a/builtin/mainmenu/dlg_delete_world.lua b/builtin/mainmenu/dlg_delete_world.lua
new file mode 100644 (file)
index 0000000..e979bd5
--- /dev/null
@@ -0,0 +1,64 @@
+--Minetest
+--Copyright (C) 2014 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+local function create_world_formspec(dialogdata)
+
+       local retval =
+               "size[12,6,true]" ..
+               "label[2,2;" ..
+               fgettext("Delete World \"$1\"?", dialogdata.delete_name) .. "]"..
+               "button[3.5,4.2;2.6,0.5;world_delete_confirm;" .. fgettext("Yes").. "]" ..
+               "button[6,4.2;2.8,0.5;world_delete_cancel;" .. fgettext("No") .. "]"
+       return retval
+end
+
+local function create_world_buttonhandler(this, fields)
+       if fields["world_delete_confirm"] then
+
+               if this.data.delete_index > 0 and
+                       this.data.delete_index <= #menudata.worldlist:get_raw_list() then
+                       core.delete_world(this.data.delete_index)
+                       menudata.worldlist:refresh()
+               end
+               this:delete()
+               return true
+       end
+       
+       if fields["world_delete_cancel"] then
+               this:delete()
+               return true
+       end
+       
+       return false
+end
+
+
+function create_delete_world_dlg(name_to_del,index_to_del)
+
+       assert(name_to_del ~= nil and type(name_to_del) == "string" and name_to_del ~= "")
+       assert(index_to_del ~= nil and type(index_to_del) == "number")
+
+       local retval = dialog_create("sp_create_world",
+                                       create_world_formspec,
+                                       create_world_buttonhandler,
+                                       nil)
+       retval.data.delete_name  = name_to_del
+       retval.data.delete_index = index_to_del
+       
+       return retval
+end
diff --git a/builtin/mainmenu/dlg_rename_modpack.lua b/builtin/mainmenu/dlg_rename_modpack.lua
new file mode 100644 (file)
index 0000000..9e25240
--- /dev/null
@@ -0,0 +1,69 @@
+--Minetest
+--Copyright (C) 2014 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+--------------------------------------------------------------------------------
+
+local function rename_modpack_formspec(dialogdata)
+       
+       dialogdata.mod = modmgr.global_mods:get_list()[dialogdata.selected]
+
+       local retval =
+               "size[12.4,5,true]" ..
+               "label[1.75,1;".. fgettext("Rename Modpack:") .. "]"..
+               "field[4.5,1.4;6,0.5;te_modpack_name;;" ..
+               dialogdata.mod.name ..
+               "]" ..
+               "button[5,4.2;2.6,0.5;dlg_rename_modpack_confirm;"..
+                               fgettext("Accept") .. "]" ..
+               "button[7.5,4.2;2.8,0.5;dlg_rename_modpack_cancel;"..
+                               fgettext("Cancel") .. "]"
+       
+       return retval
+end
+
+--------------------------------------------------------------------------------
+local function rename_modpack_buttonhandler(this, fields)
+       if fields["dlg_rename_modpack_confirm"] ~= nil then
+               local oldpath = core.get_modpath() .. DIR_DELIM .. this.data.mod.name
+               local targetpath = core.get_modpath() .. DIR_DELIM .. fields["te_modpack_name"]
+               core.copy_dir(oldpath,targetpath,false)
+               modmgr.refresh_globals()
+               modmgr.selected_mod = modmgr.global_mods:get_current_index(
+                       modmgr.global_mods:raw_index_by_uid(fields["te_modpack_name"]))
+                       
+               this:delete()
+               return true
+       end
+       
+       if fields["dlg_rename_modpack_cancel"] then
+               this:delete()
+               return true
+       end
+
+       return false
+end
+
+--------------------------------------------------------------------------------
+function create_rename_modpack_dlg(selected_index)
+
+       local retval = dialog_create("dlg_delete_mod",
+                                       rename_modpack_formspec,
+                                       rename_modpack_buttonhandler,
+                                       nil)
+       retval.data.selected = selected_index
+       return retval
+end
diff --git a/builtin/mainmenu/filterlist.lua b/builtin/mainmenu/filterlist.lua
deleted file mode 100644 (file)
index 379a5ce..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
---Minetest
---Copyright (C) 2013 sapier
---
---This program is free software; you can redistribute it and/or modify
---it under the terms of the GNU Lesser General Public License as published by
---the Free Software Foundation; either version 2.1 of the License, or
---(at your option) any later version.
---
---This program is distributed in the hope that it will be useful,
---but WITHOUT ANY WARRANTY; without even the implied warranty of
---MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
---GNU Lesser General Public License for more details.
---
---You should have received a copy of the GNU Lesser General Public License along
---with this program; if not, write to the Free Software Foundation, Inc.,
---51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
---------------------------------------------------------------------------------
--- Generic implementation of a filter/sortable list                           --
--- Usage:                                                                     --
--- Filterlist needs to be initialized on creation. To achieve this you need to --
--- pass following functions:                                                  --
--- raw_fct() (mandatory):                                                     --
---     function returning a table containing the elements to be filtered      --
--- compare_fct(element1,element2) (mandatory):                                --
---     function returning true/false if element1 is same element as element2  --
--- uid_match_fct(element1,uid) (optional)                                     --
---     function telling if uid is attached to element1                        --
--- filter_fct(element,filtercriteria) (optional)                              --
---     function returning true/false if filtercriteria met to element         --
--- fetch_param (optional)                                                     --
---     parameter passed to raw_fct to aquire correct raw data                 --
---                                                                            --
---------------------------------------------------------------------------------
-filterlist = {}
-
---------------------------------------------------------------------------------
-function filterlist.refresh(this)
-       this.m_raw_list = this.m_raw_list_fct(this.m_fetch_param)
-       filterlist.process(this)
-end
-
---------------------------------------------------------------------------------
-function filterlist.create(raw_fct,compare_fct,uid_match_fct,filter_fct,fetch_param)
-
-       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_fetch_param = fetch_param
-       
-       this.m_sortmode = "none"
-       this.m_sort_list = {}
-
-       this.m_processed_list = nil
-       this.m_raw_list = this.m_raw_list_fct(this.m_fetch_param)
-
-       filterlist.process(this)
-       
-       return this
-end
-
---------------------------------------------------------------------------------
-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 and
-               type(criteria) ~= "table" then
-               return
-       end
-       this.m_filtercriteria = criteria
-       filterlist.process(this)
-end
-
---------------------------------------------------------------------------------
-function filterlist.get_filtercriteria(this)
-       return this.m_filtercriteria
-end
-
---------------------------------------------------------------------------------
---supported sort mode "alphabetic|none"
-function filterlist.set_sortmode(this,mode)
-       if (mode == this.m_sortmode) then
-               return
-       end
-       this.m_sortmode = mode
-       filterlist.process(this)
-end
-
---------------------------------------------------------------------------------
-function filterlist.get_list(this)
-       return this.m_processed_list
-end
-
---------------------------------------------------------------------------------
-function filterlist.get_raw_list(this)
-       return this.m_raw_list
-end
-
---------------------------------------------------------------------------------
-function filterlist.get_raw_element(this,idx)
-       if type(idx) ~= "number" then
-               idx = tonumber(idx)
-       end
-       
-       if idx ~= nil and idx > 0 and idx < #this.m_raw_list then
-               return this.m_raw_list[idx]
-       end
-       
-       return nil
-end
-
---------------------------------------------------------------------------------
-function filterlist.get_raw_index(this,listindex)
-       assert(this.m_processed_list ~= nil)
-       
-       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(this.m_raw_list) do
-               
-                       if this.m_compare_fct(v,entry) then
-                               return i
-                       end
-               end
-       end
-       
-       return 0
-end
-
---------------------------------------------------------------------------------
-function filterlist.get_current_index(this,listindex)
-       assert(this.m_processed_list ~= nil)
-       
-       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(this.m_processed_list) do
-               
-                       if this.m_compare_fct(v,entry) then
-                               return i
-                       end
-               end
-       end
-       
-       return 0
-end
-
---------------------------------------------------------------------------------
-function filterlist.process(this)
-       assert(this.m_raw_list ~= nil)
-
-       if this.m_sortmode == "none" and
-               this.m_filtercriteria == nil then
-               this.m_processed_list = this.m_raw_list
-               return
-       end
-       
-       this.m_processed_list = {}
-       
-       for k,v in pairs(this.m_raw_list) do
-               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 this.m_sortmode == "none" then
-               return
-       end
-       
-       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
-end
-
---------------------------------------------------------------------------------
-function filterlist.size(this)
-       if this.m_processed_list == nil then
-               return 0
-       end
-       
-       return #this.m_processed_list
-end
-
---------------------------------------------------------------------------------
-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 filterlist.raw_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 elements than one with same name uid can't decide which
-       -- one is meant. This shouldn't be possible but just for sure.
-       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 true
-end
-
---------------------------------------------------------------------------------
-function sort_worlds_alphabetic(this)
-
-       table.sort(this.m_processed_list, function(a, b)
-               --fixes issue #857 (crash due to sorting nil in worldlist)
-               if a == nil or b == nil then
-                       if a == nil and b ~= nil then return false end
-                       if b == nil and a ~= nil then return true end
-                       return false
-               end
-               if a.name:lower() == b.name:lower() then
-                       return a.name < b.name
-               end
-               return a.name:lower() < b.name:lower()
-       end)
-end
-
---------------------------------------------------------------------------------
-function sort_mod_list(this)
-
-       table.sort(this.m_processed_list, function(a, b)
-               -- Show game mods at bottom
-               if a.typ ~= b.typ then
-                       return b.typ == "game_mod"
-               end
-               -- If in same or no modpack, sort by name
-               if a.modpack == b.modpack then
-                       if a.name:lower() == b.name:lower() then
-                               return a.name < b.name
-                       end
-                       return a.name:lower() < b.name:lower()
-               -- Else compare name to modpack name
-               else
-                       -- Always show modpack pseudo-mod on top of modpack mod list
-                       if a.name == b.modpack then
-                               return true
-                       elseif b.name == a.modpack then
-                               return false
-                       end
-                       
-                       local name_a = a.modpack or a.name
-                       local name_b = b.modpack or b.name
-                       if name_a:lower() == name_b:lower() then
-                               return  name_a < name_b
-                       end
-                       return name_a:lower() < name_b:lower()
-               end
-       end)
-end
index c99c2de21ab8e787cbd143e57d0065cb4991c832..64fb41b9dfa904b9b395107ba2356766cd5febea 100644 (file)
 
 gamemgr = {}
 
---------------------------------------------------------------------------------
-function gamemgr.dialog_new_game()
-       local retval = 
-               "label[2,2;" .. fgettext("Game Name") .. "]"..
-               "field[4.5,2.4;6,0.5;te_game_name;;]" ..
-               "button[5,4.2;2.6,0.5;new_game_confirm;" .. fgettext("Create") .. "]" ..
-               "button[7.5,4.2;2.8,0.5;new_game_cancel;" .. fgettext("Cancel") .. "]"
-
-       return retval
-end
-
---------------------------------------------------------------------------------
-function gamemgr.handle_games_buttons(fields)
-       if fields["gamelist"] ~= nil then
-               local event = engine.explode_textlist_event(fields["gamelist"])
-               gamemgr.selected_game = event.index
-       end
-       
-       if fields["btn_game_mgr_edit_game"] ~= nil then
-               return {
-                       is_dialog = true,
-                       show_buttons = false,
-                       current_tab = "dialog_edit_game"
-               }
-       end
-       
-       if fields["btn_game_mgr_new_game"] ~= nil then
-               return {
-                       is_dialog = true,
-                       show_buttons = false,
-                       current_tab = "dialog_new_game"
-               }
-       end
-       
-       return nil
-end
-
---------------------------------------------------------------------------------
-function gamemgr.handle_new_game_buttons(fields)
-
-       if fields["new_game_confirm"] and
-               fields["te_game_name"] ~= nil and
-               fields["te_game_name"] ~= "" then
-               local gamepath = engine.get_gamepath()
-               
-               if gamepath ~= nil and
-                       gamepath ~= "" then
-                       local gamefolder = cleanup_path(fields["te_game_name"])
-                       
-                       --TODO check for already existing first
-                       engine.create_dir(gamepath .. DIR_DELIM .. gamefolder)
-                       engine.create_dir(gamepath .. DIR_DELIM .. gamefolder .. DIR_DELIM .. "mods")
-                       engine.create_dir(gamepath .. DIR_DELIM .. gamefolder .. DIR_DELIM .. "menu")
-                       
-                       local gameconf = 
-                               io.open(gamepath .. DIR_DELIM .. gamefolder .. DIR_DELIM .. "game.conf","w")
-                       
-                       if gameconf then
-                               gameconf:write("name = " .. fields["te_game_name"])
-                               gameconf:close()
-                       end
-               end
-       end
-
-       return {
-               is_dialog = false,
-               show_buttons = true,
-               current_tab = engine.setting_get("main_menu_tab")
-               }
-end
-
---------------------------------------------------------------------------------
-function gamemgr.handle_edit_game_buttons(fields)
-       local current_game = gamemgr.get_game(gamemgr.selected_game)
-       
-       if fields["btn_close_edit_game"] ~= nil or
-               current_game == nil then
-               return {
-                       is_dialog = false,
-                       show_buttons = true,
-                       current_tab = engine.setting_get("main_menu_tab")
-                       }
-       end
-
-       if fields["btn_remove_mod_from_game"] ~= nil then
-               gamemgr.delete_mod(current_game,engine.get_textlist_index("mods_current"))
-       end
-       
-       if fields["btn_add_mod_to_game"] ~= nil then
-               local modindex = engine.get_textlist_index("mods_available")
-               
-               local mod = modmgr.get_global_mod(modindex)
-               if mod ~= nil then
-                       
-                       local sourcepath = mod.path
-                       
-                       if not gamemgr.add_mod(current_game,sourcepath) then
-                               gamedata.errormessage =
-                                       fgettext("Gamemgr: Unable to copy mod \"$1\" to game \"$2\"", mod.name, current_game.id)
-                       end
-               end
-       end
-       
-       return nil
-end
-
---------------------------------------------------------------------------------
-function gamemgr.add_mod(gamespec,sourcepath)
-       if gamespec.gamemods_path ~= nil and
-               gamespec.gamemods_path ~= "" then
-               
-               local modname = get_last_folder(sourcepath)
-               
-               return engine.copy_dir(sourcepath,gamespec.gamemods_path .. DIR_DELIM .. modname);
-       end
-       
-       return false
-end
-
---------------------------------------------------------------------------------
-function gamemgr.delete_mod(gamespec,modindex)
-       if gamespec.gamemods_path ~= nil and
-               gamespec.gamemods_path ~= "" then
-               local game_mods = {}
-               get_mods(gamespec.gamemods_path,game_mods)
-               
-               if modindex > 0 and
-                       #game_mods >= modindex then
-
-                       if game_mods[modindex].path:sub(0,gamespec.gamemods_path:len()) 
-                                       == gamespec.gamemods_path then
-                               engine.delete_dir(game_mods[modindex].path)
-                       end
-               end
-       end
-end
-
 --------------------------------------------------------------------------------
 function gamemgr.find_by_gameid(gameid)
-       for i=1,#gamemgr.games,1 do             
+       for i=1,#gamemgr.games,1 do
                if gamemgr.games[i].id == gameid then
                        return gamemgr.games[i], i
                end
@@ -183,129 +46,22 @@ function gamemgr.get_game_modlist(gamespec)
                        retval = retval..","
                end
                retval = retval .. game_mods[i].name
-       end 
-       return retval
-end
-
---------------------------------------------------------------------------------
-function gamemgr.gettab(name)
-       local retval = ""
-       
-       if name == "dialog_edit_game" then
-               retval = retval .. gamemgr.dialog_edit_game()
-       end
-       
-       if name == "dialog_new_game" then
-               retval = retval .. gamemgr.dialog_new_game()
-       end
-       
-       if name == "game_mgr" then
-               retval = retval .. gamemgr.tab()
-       end
-       
-       return retval
-end
-
---------------------------------------------------------------------------------
-function gamemgr.tab()
-       if gamemgr.selected_game == nil then
-               gamemgr.selected_game = 1
-       end
-       
-       local retval = 
-               "vertlabel[0,-0.25;" .. fgettext("GAMES") .. "]" ..
-               "label[1,-0.25;" .. fgettext("Games") .. ":]" ..
-               "textlist[1,0.25;4.5,4.4;gamelist;" ..
-               gamemgr.gamelist() ..
-               ";" .. gamemgr.selected_game .. "]"
-       
-       local current_game = gamemgr.get_game(gamemgr.selected_game)
-       
-       if current_game ~= nil then
-               if current_game.menuicon_path ~= nil and
-                       current_game.menuicon_path ~= "" then
-                       retval = retval .. 
-                               "image[5.8,-0.25;2,2;" ..
-                               engine.formspec_escape(current_game.menuicon_path) .. "]"
-               end
-               
-               retval = retval ..
-                       "field[8,-0.25;6,2;;" .. current_game.name .. ";]"..
-                       "label[6,1.4;" .. fgettext("Mods:") .."]" ..
-                       "button[9.7,1.5;2,0.2;btn_game_mgr_edit_game;" .. fgettext("edit game") .. "]" ..
-                       "textlist[6,2;5.5,3.3;game_mgr_modlist;"
-                       .. gamemgr.get_game_modlist(current_game) ..";0]" ..
-                       "button[1,4.75;3.2,0.5;btn_game_mgr_new_game;" .. fgettext("new game") .. "]"
        end
        return retval
 end
 
 --------------------------------------------------------------------------------
-function gamemgr.dialog_edit_game()
-       local current_game = gamemgr.get_game(gamemgr.selected_game)
-       if current_game ~= nil then
-               local retval = 
-                       "vertlabel[0,-0.25;" .. fgettext("EDIT GAME") .."]" ..
-                       "label[0,-0.25;" .. current_game.name .. "]" ..
-                       "button[11.55,-0.2;0.75,0.5;btn_close_edit_game;x]"
-               
-               if current_game.menuicon_path ~= nil and
-                       current_game.menuicon_path ~= "" then
-                       retval = retval .. 
-                               "image[5.25,0;2,2;" ..
-                               engine.formspec_escape(current_game.menuicon_path) .. "]"
-               end
-               
-               retval = retval .. 
-                       "textlist[0.5,0.5;4.5,4.3;mods_current;"
-                       .. gamemgr.get_game_modlist(current_game) ..";0]"
-                       
-                       
-               retval = retval .. 
-                       "textlist[7,0.5;4.5,4.3;mods_available;"
-                       .. modmgr.render_modlist() .. ";0]"
-
-               retval = retval ..
-                       "button[0.55,4.95;4.7,0.5;btn_remove_mod_from_game;" .. fgettext("Remove selected mod") .."]"
-                       
-               retval = retval ..
-                       "button[7.05,4.95;4.7,0.5;btn_add_mod_to_game;" .. fgettext("<<-- Add mod") .."]"
-               
-               return retval
-       end
-end
-
---------------------------------------------------------------------------------
-function gamemgr.handle_buttons(tab,fields)
-       local retval = nil
-       
-       if tab == "dialog_edit_game" then
-               retval = gamemgr.handle_edit_game_buttons(fields)
-       end
-       
-       if tab == "dialog_new_game" then
-               retval = gamemgr.handle_new_game_buttons(fields)
-       end
-       
-       if tab == "game_mgr" then
-               retval = gamemgr.handle_games_buttons(fields)
-       end
-       
-       return retval
-end
-
---------------------------------------------------------------------------------
-function gamemgr.get_game(index) 
+function gamemgr.get_game(index)
        if index > 0 and index <= #gamemgr.games then
                return gamemgr.games[index]
        end
-       
+
        return nil
 end
 
 --------------------------------------------------------------------------------
 function gamemgr.update_gamelist()
-       gamemgr.games = engine.get_games()
+       gamemgr.games = core.get_games()
 end
 
 --------------------------------------------------------------------------------
@@ -313,10 +69,15 @@ function gamemgr.gamelist()
        local retval = ""
        if #gamemgr.games > 0 then
                retval = retval .. gamemgr.games[1].id
-               
+
                for i=2,#gamemgr.games,1 do
                        retval = retval .. "," .. gamemgr.games[i].name
                end
        end
        return retval
 end
+
+--------------------------------------------------------------------------------
+-- read initial data
+--------------------------------------------------------------------------------
+gamemgr.update_gamelist()
index 58e9ab9494cc68ed287719472415ad0946611bfb..ab2b8d80cc073ca840cfd45b3bb9dea946c92926 100644 (file)
-
-engine = core
-local menupath = core.get_mainmenu_path()..DIR_DELIM
-local commonpath = core.get_builtin_path()..DIR_DELIM.."common"..DIR_DELIM
-
-dofile(menupath.."filterlist.lua")
-dofile(menupath.."modmgr.lua")
-dofile(menupath.."modstore.lua")
-dofile(menupath.."gamemgr.lua")
-dofile(menupath.."textures.lua")
-dofile(menupath.."menubar.lua")
-dofile(commonpath.."async_event.lua")
+--Minetest
+--Copyright (C) 2014 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
 mt_color_grey  = "#AAAAAA"
 mt_color_blue  = "#0000DD"
 mt_color_green = "#00DD00"
 mt_color_dark_green = "#003300"
 
---for all other colors ask sfan5 to complete his worK!
-
-menu = {}
-local tabbuilder = {}
-local worldlist = nil
-
---------------------------------------------------------------------------------
-local function filter_texture_pack_list(list)
-       retval = {"None"}
-       for _,i in ipairs(list) do
-               if i~="base" then
-                       table.insert(retval, i)
-               end
-       end
-       return retval
-end
-
---------------------------------------------------------------------------------
-function menu.render_favorite(spec,render_details)
-       local text = ""
-
-       if spec.name ~= nil then
-               text = text .. engine.formspec_escape(spec.name:trim())
-
---             if spec.description ~= nil and
---                     engine.formspec_escape(spec.description):trim() ~= "" then
---                     text = text .. " (" .. engine.formspec_escape(spec.description) .. ")"
---             end
-       else
-               if spec.address ~= nil then
-                       text = text .. spec.address:trim()
-
-                       if spec.port ~= nil then
-                               text = text .. ":" .. spec.port
-                       end
-               end
-       end
-
-       if not render_details then
-               return text
-       end
-
-       local details = ""
-       if spec.password == true then
-               details = details .. "*"
-       else
-               details = details .. "_"
-       end
-
-       if spec.creative then
-               details = details .. "C"
-       else
-               details = details .. "_"
-       end
-
-       if spec.damage then
-               details = details .. "D"
-       else
-               details = details .. "_"
-       end
-
-       if spec.pvp then
-               details = details .. "P"
-       else
-               details = details .. "_"
-       end
-       details = details .. " "
-
-       local playercount = ""
-
-       if spec.clients ~= nil and
-               spec.clients_max ~= nil then
-               playercount = string.format("%03d",spec.clients) .. "/" ..
-                                               string.format("%03d",spec.clients_max) .. " "
-       end
+--for all other colors ask sfan5 to complete his work!
 
-       return playercount .. engine.formspec_escape(details) ..  text
-end
-
---------------------------------------------------------------------------------
-os.tempfolder = function()
-       local filetocheck = os.tmpname()
-       os.remove(filetocheck)
-
-       local randname = "MTTempModFolder_" .. math.random(0,10000)
-       if DIR_DELIM == "\\" then
-               local tempfolder = os.getenv("TEMP")
-               return tempfolder .. filetocheck
-       else
-               local backstring = filetocheck:reverse()
-               return filetocheck:sub(0,filetocheck:len()-backstring:find(DIR_DELIM)+1) ..randname
-       end
-
-end
+local menupath = core.get_mainmenu_path()
+local basepath = core.get_builtin_path()
+defaulttexturedir = core.get_texturepath_share() .. DIR_DELIM .. "base" ..
+                                       DIR_DELIM .. "pack" .. DIR_DELIM
 
---------------------------------------------------------------------------------
-function text2textlist(xpos,ypos,width,height,tl_name,textlen,text,transparency)
-       local textlines = engine.splittext(text,textlen)
-       
-       local retval = "textlist[" .. xpos .. "," .. ypos .. ";"
-                                                               .. width .. "," .. height .. ";"
-                                                               .. tl_name .. ";"
-       
-       for i=1, #textlines, 1 do
-               textlines[i] = textlines[i]:gsub("\r","")
-               retval = retval .. engine.formspec_escape(textlines[i]) .. ","
-       end
-       
-       retval = retval .. ";0;"
-       
-       if transparency then
-               retval = retval .. "true"
+dofile(basepath .. DIR_DELIM .. "common" .. DIR_DELIM .. "async_event.lua")
+dofile(basepath .. DIR_DELIM .. "common" .. DIR_DELIM .. "filterlist.lua")
+dofile(basepath .. DIR_DELIM .. "fstk" .. DIR_DELIM .. "buttonbar.lua")
+dofile(basepath .. DIR_DELIM .. "fstk" .. DIR_DELIM .. "dialog.lua")
+dofile(basepath .. DIR_DELIM .. "fstk" .. DIR_DELIM .. "tabview.lua")
+dofile(basepath .. DIR_DELIM .. "fstk" .. DIR_DELIM .. "ui.lua")
+dofile(menupath .. DIR_DELIM .. "common.lua")
+dofile(menupath .. DIR_DELIM .. "gamemgr.lua")
+dofile(menupath .. DIR_DELIM .. "modmgr.lua")
+dofile(menupath .. DIR_DELIM .. "store.lua")
+dofile(menupath .. DIR_DELIM .. "dlg_config_world.lua")
+dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua")
+dofile(menupath .. DIR_DELIM .. "dlg_delete_mod.lua")
+dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua")
+dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
+dofile(menupath .. DIR_DELIM .. "tab_credits.lua")
+dofile(menupath .. DIR_DELIM .. "tab_mods.lua")
+dofile(menupath .. DIR_DELIM .. "tab_multiplayer.lua")
+dofile(menupath .. DIR_DELIM .. "tab_server.lua")
+dofile(menupath .. DIR_DELIM .. "tab_settings.lua")
+dofile(menupath .. DIR_DELIM .. "tab_singleplayer.lua")
+dofile(menupath .. DIR_DELIM .. "tab_texturepacks.lua")
+dofile(menupath .. DIR_DELIM .. "textures.lua")
+
+--------------------------------------------------------------------------------
+local function main_event_handler(tabview,event)
+       if event == "MenuQuit" then
+               core.close()
        end
-       
-       retval = retval .. "]"
-
-       return retval
+       return true
 end
 
 --------------------------------------------------------------------------------
-function init_globals()
+local function init_globals()
        --init gamedata
        gamedata.worldindex = 0
 
-       worldlist = filterlist.create(
-                                       engine.get_worlds,
+       menudata.worldlist = filterlist.create(
+                                       core.get_worlds,
                                        compare_worlds,
                                        function(element,uid)
                                                if element.name == uid then
@@ -157,1182 +81,34 @@ function init_globals()
                                        end --filter fct
                                        )
 
-       filterlist.add_sort_mechanism(worldlist,"alphabetic",sort_worlds_alphabetic)
-       filterlist.set_sortmode(worldlist,"alphabetic")
-end
-
---------------------------------------------------------------------------------
-function update_menu()
-
-       local formspec
-
-       -- handle errors
-       if gamedata.errormessage ~= nil then
-               formspec = "size[12,5.2,true]" ..
-                       "textarea[1,2;10,2;;ERROR: " ..
-                       engine.formspec_escape(gamedata.errormessage) ..
-                       ";]"..
-                       "button[4.5,4.2;3,0.5;btn_error_confirm;" .. fgettext("Ok") .. "]"
-       else
-               formspec = tabbuilder.gettab()
-       end
-
-       engine.update_formspec(formspec)
-end
-
---------------------------------------------------------------------------------
-function menu.render_world_list()
-       local retval = ""
-
-       local current_worldlist = filterlist.get_list(worldlist)
-
-       for i,v in ipairs(current_worldlist) do
-               if retval ~= "" then
-                       retval = retval ..","
-               end
-
-               retval = retval .. engine.formspec_escape(v.name) ..
-                                       " \\[" .. engine.formspec_escape(v.gameid) .. "\\]"
-       end
-
-       return retval
-end
-
---------------------------------------------------------------------------------
-function menu.render_texture_pack_list(list)
-       local retval = ""
-
-       for i, v in ipairs(list) do
-               if retval ~= "" then
-                       retval = retval ..","
-               end
-
-               retval = retval .. engine.formspec_escape(v)
-       end
-
-       return retval
-end
-
---------------------------------------------------------------------------------
-function menu.asyncOnlineFavourites()
-       menu.favorites = {}
-       engine.handle_async(
-               function(param)
-                       --return core.get_favorites("online")
-               end,
-               nil,
-               function(result)
-                       menu.favorites = result
-                       engine.event_handler("Refresh")
-               end
-               )
-end
-
---------------------------------------------------------------------------------
-function menu.init()
-       --init menu data
-       gamemgr.update_gamelist()
-
-       menu.last_game  = tonumber(engine.setting_get("main_menu_last_game_idx"))
-
-       if type(menu.last_game) ~= "number" then
-               menu.last_game = 1
-       end
-
-       if engine.setting_getbool("public_serverlist") then
-               menu.asyncOnlineFavourites()
-       else
-               menu.favorites = engine.get_favorites("local")
-       end
-
-       menu.defaulttexturedir = engine.get_texturepath_share() .. DIR_DELIM .. "base" ..
-                                       DIR_DELIM .. "pack" .. DIR_DELIM
-end
-
---------------------------------------------------------------------------------
-function menu.lastgame()
-       if menu.last_game > 0 and menu.last_game <= #gamemgr.games then
-               return gamemgr.games[menu.last_game]
-       end
-
-       if #gamemgr.games >= 1 then
-               menu.last_game = 1
-               return gamemgr.games[menu.last_game]
-       end
-
-       --error case!!
-       return nil
-end
-
---------------------------------------------------------------------------------
-function menu.update_last_game()
-
-       local current_world = filterlist.get_raw_element(worldlist,
-                                                       engine.setting_get("mainmenu_last_selected_world")
-                                                       )
-
-       if current_world == nil then
-               return
-       end
-
-       local gamespec, i = gamemgr.find_by_gameid(current_world.gameid)
-       if i ~= nil then
-               menu.last_game = i
-               engine.setting_set("main_menu_last_game_idx",menu.last_game)
-       end
-end
-
---------------------------------------------------------------------------------
-function menu.handle_key_up_down(fields,textlist,settingname)
-
-       if fields["key_up"] then
-               local oldidx = engine.get_textlist_index(textlist)
-
-               if oldidx ~= nil and oldidx > 1 then
-                       local newidx = oldidx -1
-                       engine.setting_set(settingname,
-                               filterlist.get_raw_index(worldlist,newidx))
-               end
-       end
-
-       if fields["key_down"] then
-               local oldidx = engine.get_textlist_index(textlist)
-
-               if oldidx ~= nil and oldidx < filterlist.size(worldlist) then
-                       local newidx = oldidx + 1
-                       engine.setting_set(settingname,
-                               filterlist.get_raw_index(worldlist,newidx))
-               end
-       end
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.dialog_create_world()
-       local mapgens = {"v6", "v7", "indev", "singlenode", "math"}
-
-       local current_seed = engine.setting_get("fixed_map_seed") or ""
-       local current_mg   = engine.setting_get("mg_name")
-
-       local mglist = ""
-       local selindex = 1
-       local i = 1
-       for k,v in pairs(mapgens) do
-               if current_mg == v then
-                       selindex = i
-               end
-               i = i + 1
-               mglist = mglist .. v .. ","
-       end
-       mglist = mglist:sub(1, -2)
-
-       local retval =
-               "label[2,0;" .. fgettext("World name") .. "]"..
-               "field[4.5,0.4;6,0.5;te_world_name;;]" ..
-
-               "label[2,1;" .. fgettext("Seed") .. "]"..
-               "field[4.5,1.4;6,0.5;te_seed;;".. current_seed .. "]" ..
-
-               "label[2,2;" .. fgettext("Mapgen") .. "]"..
-               "dropdown[4.2,2;6.3;dd_mapgen;" .. mglist .. ";" .. selindex .. "]" ..
-
-               "label[2,3;" .. fgettext("Game") .. "]"..
-               "textlist[4.2,3;5.8,2.3;games;" .. gamemgr.gamelist() ..
-               ";" .. menu.last_game .. ";true]" ..
-
-               "button[5,5.5;2.6,0.5;world_create_confirm;" .. fgettext("Create") .. "]" ..
-               "button[7.5,5.5;2.8,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
-
-       return retval
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.dialog_delete_world()
-       return  "label[2,2;" ..
-                       fgettext("Delete World \"$1\"?", filterlist.get_raw_list(worldlist)[menu.world_to_del].name) .. "]"..
-                       "button[3.5,4.2;2.6,0.5;world_delete_confirm;" .. fgettext("Yes").. "]" ..
-                       "button[6,4.2;2.8,0.5;world_delete_cancel;" .. fgettext("No") .. "]"
-end
-
---------------------------------------------------------------------------------
-
-function tabbuilder.gettab()
-       local tsize = tabbuilder.tabsizes[tabbuilder.current_tab] or {width=12, height=5.2}
-       local retval = "size[" .. tsize.width .. "," .. tsize.height .. ",true]"
-
-       if tabbuilder.show_buttons then
-               retval = retval .. tabbuilder.tab_header()
-       end
-
-       local buildfunc = tabbuilder.tabfuncs[tabbuilder.current_tab]
-       if buildfunc ~= nil then
-               retval = retval .. buildfunc()
-       end
-
-       retval = retval .. modmgr.gettab(tabbuilder.current_tab)
-       retval = retval .. gamemgr.gettab(tabbuilder.current_tab)
-       retval = retval .. modstore.gettab(tabbuilder.current_tab)
-
-       return retval
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.handle_create_world_buttons(fields)
-
-       if fields["world_create_confirm"] or
-               fields["key_enter"] then
-
-               local worldname = fields["te_world_name"]
-               local gameindex = engine.get_textlist_index("games")
-
-               if gameindex ~= nil and
-                       worldname ~= "" then
-
-                       local message = nil
-
-                       if not filterlist.uid_exists_raw(worldlist,worldname) then
-                               engine.setting_set("mg_name",fields["dd_mapgen"])
-                               message = engine.create_world(worldname,gameindex)
-                       else
-                               message = fgettext("A world named \"$1\" already exists", worldname)
-                       end
-
-                       engine.setting_set("fixed_map_seed", fields["te_seed"])
-
-                       if message ~= nil then
-                               gamedata.errormessage = message
-                       else
-                               menu.last_game = gameindex
-                               engine.setting_set("main_menu_last_game_idx",gameindex)
-
-                               filterlist.refresh(worldlist)
-                               engine.setting_set("mainmenu_last_selected_world",
-                                                                       filterlist.raw_index_by_uid(worldlist,worldname))
-                       end
-               else
-                       gamedata.errormessage =
-                               fgettext("No worldname given or no game selected")
-               end
-       end
-
-       if fields["games"] then
-               tabbuilder.skipformupdate = true
-               return
-       end
-
-       --close dialog
-       tabbuilder.is_dialog = false
-       tabbuilder.show_buttons = true
-       tabbuilder.current_tab = engine.setting_get("main_menu_tab")
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.handle_delete_world_buttons(fields)
-
-       if fields["world_delete_confirm"] then
-               if menu.world_to_del > 0 and
-                       menu.world_to_del <= #filterlist.get_raw_list(worldlist) then
-                       engine.delete_world(menu.world_to_del)
-                       menu.world_to_del = 0
-                       filterlist.refresh(worldlist)
-               end
-       end
-
-       tabbuilder.is_dialog = false
-       tabbuilder.show_buttons = true
-       tabbuilder.current_tab = engine.setting_get("main_menu_tab")
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.handle_multiplayer_buttons(fields)
-
-       if fields["te_name"] ~= nil then
-               gamedata.playername = fields["te_name"]
-               engine.setting_set("name", fields["te_name"])
-       end
-
-       if fields["favourites"] ~= nil then
-               local event = engine.explode_textlist_event(fields["favourites"])
-               if event.type == "DCL" then
-                       if event.index <= #menu.favorites then
-                               gamedata.address = menu.favorites[event.index].address
-                               gamedata.port = menu.favorites[event.index].port
-                               gamedata.playername             = fields["te_name"]
-                               if fields["te_pwd"] ~= nil then
-                                       gamedata.password               = fields["te_pwd"]
-                               end
-                               gamedata.selected_world = 0
-
-                               if menu.favorites ~= nil then
-                                       gamedata.servername = menu.favorites[event.index].name
-                                       gamedata.serverdescription = menu.favorites[event.index].description
-                               end
-
-                               if gamedata.address ~= nil and
-                                       gamedata.port ~= nil then
-                                       engine.setting_set("address",gamedata.address)
-                                       engine.setting_set("remote_port",gamedata.port)
-                                       engine.start()
-                               end
-                       end
-               end
-
-               if event.type == "CHG" then
-                       if event.index <= #menu.favorites then
-                               local address = menu.favorites[event.index].address
-                               local port = menu.favorites[event.index].port
-
-                               if address ~= nil and
-                                       port ~= nil then
-                                       engine.setting_set("address",address)
-                                       engine.setting_set("remote_port",port)
-                               end
-
-                               menu.fav_selected = event.index
-                       end
-               end
-               return
-       end
-
-       if fields["key_up"] ~= nil or
-               fields["key_down"] ~= nil then
-
-               local fav_idx = engine.get_textlist_index("favourites")
-
-               if fav_idx ~= nil then
-                       if fields["key_up"] ~= nil and fav_idx > 1 then
-                               fav_idx = fav_idx -1
-                       else if fields["key_down"] and fav_idx < #menu.favorites then
-                               fav_idx = fav_idx +1
-                       end end
-               end
-
-               local address = menu.favorites[fav_idx].address
-               local port = menu.favorites[fav_idx].port
-
-               if address ~= nil and
-                       port ~= nil then
-                       engine.setting_set("address",address)
-                       engine.setting_set("remote_port",port)
-               end
-
-               menu.fav_selected = fav_idx
-               return
-       end
-
-       if fields["cb_public_serverlist"] ~= nil then
-               engine.setting_set("public_serverlist", fields["cb_public_serverlist"])
-
-               if engine.setting_getbool("public_serverlist") then
-                       menu.asyncOnlineFavourites()
-               else
-                       menu.favorites = engine.get_favorites("local")
-               end
-               menu.fav_selected = nil
-               return
-       end
-
-       if fields["btn_delete_favorite"] ~= nil then
-               local current_favourite = engine.get_textlist_index("favourites")
-               if current_favourite == nil then return end
-               engine.delete_favorite(current_favourite)
-               menu.favorites = engine.get_favorites()
-               menu.fav_selected = nil
-
-               engine.setting_set("address","")
-               engine.setting_set("remote_port","30000")
-
-               return
-       end
-
-       if fields["btn_mp_connect"] ~= nil or
-               fields["key_enter"] ~= nil then
-
-               gamedata.playername             = fields["te_name"]
-               gamedata.password               = fields["te_pwd"]
-               gamedata.address                = fields["te_address"]
-               gamedata.port                   = fields["te_port"]
-
-               local fav_idx = engine.get_textlist_index("favourites")
-
-               if fav_idx ~= nil and fav_idx <= #menu.favorites and
-                       menu.favorites[fav_idx].address == fields["te_address"] and
-                       menu.favorites[fav_idx].port    == fields["te_port"] then
-
-                       gamedata.servername                     = menu.favorites[fav_idx].name
-                       gamedata.serverdescription      = menu.favorites[fav_idx].description
-               else
-                       gamedata.servername                     = ""
-                       gamedata.serverdescription      = ""
-               end
-
-               gamedata.selected_world = 0
-
-               engine.setting_set("address",fields["te_address"])
-               engine.setting_set("remote_port",fields["te_port"])
-
-               engine.start()
-               return
-       end
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.handle_server_buttons(fields)
-
-       local world_doubleclick = false
-
-       if fields["srv_worlds"] ~= nil then
-               local event = engine.explode_textlist_event(fields["srv_worlds"])
-
-               if event.type == "DCL" then
-                       world_doubleclick = true
-               end
-               if event.type == "CHG" then
-                       engine.setting_set("mainmenu_last_selected_world",
-                               filterlist.get_raw_index(worldlist,engine.get_textlist_index("srv_worlds")))
-               end
-       end
-
-       menu.handle_key_up_down(fields,"srv_worlds","mainmenu_last_selected_world")
-
-       if fields["cb_creative_mode"] then
-               engine.setting_set("creative_mode", fields["cb_creative_mode"])
-       end
-
-       if fields["cb_enable_damage"] then
-               engine.setting_set("enable_damage", fields["cb_enable_damage"])
-       end
-
-       if fields["cb_server_announce"] then
-               engine.setting_set("server_announce", fields["cb_server_announce"])
-       end
-
-       if fields["start_server"] ~= nil or
-               world_doubleclick or
-               fields["key_enter"] then
-               local selected = engine.get_textlist_index("srv_worlds")
-               if selected ~= nil then
-                       gamedata.playername             = fields["te_playername"]
-                       gamedata.password               = fields["te_passwd"]
-                       gamedata.port                   = fields["te_serverport"]
-                       gamedata.address                = ""
-                       gamedata.selected_world = filterlist.get_raw_index(worldlist,selected)
-
-                       engine.setting_set("port",gamedata.port)
-                       if fields["te_serveraddr"] ~= nil then
-                               engine.setting_set("bind_address",fields["te_serveraddr"])
-                       end
-
-                       menu.update_last_game(gamedata.selected_world)
-                       engine.start()
-               end
-       end
-
-       if fields["world_create"] ~= nil then
-               tabbuilder.current_tab = "dialog_create_world"
-               tabbuilder.is_dialog = true
-               tabbuilder.show_buttons = false
-       end
-
-       if fields["world_delete"] ~= nil then
-               local selected = engine.get_textlist_index("srv_worlds")
-               if selected ~= nil and
-                       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 = filterlist.get_raw_index(worldlist,selected)
-                               tabbuilder.current_tab = "dialog_delete_world"
-                               tabbuilder.is_dialog = true
-                               tabbuilder.show_buttons = false
-                       else
-                               menu.world_to_del = 0
-                       end
-               end
-       end
-
-       if fields["world_configure"] ~= nil then
-               selected = engine.get_textlist_index("srv_worlds")
-               if selected ~= nil then
-                       modmgr.world_config_selected_world = filterlist.get_raw_index(worldlist,selected)
-                       if modmgr.init_worldconfig() then
-                               tabbuilder.current_tab = "dialog_configure_world"
-                               tabbuilder.is_dialog = true
-                               tabbuilder.show_buttons = false
-                       end
-               end
-       end
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.handle_settings_buttons(fields)
-       if fields["cb_fancy_trees"] then
-               engine.setting_set("new_style_leaves", fields["cb_fancy_trees"])
-       end
-       if fields["cb_smooth_lighting"] then
-               engine.setting_set("smooth_lighting", fields["cb_smooth_lighting"])
-       end
-       if fields["cb_3d_clouds"] then
-               engine.setting_set("enable_3d_clouds", fields["cb_3d_clouds"])
-       end
-       if fields["cb_opaque_water"] then
-               engine.setting_set("opaque_water", fields["cb_opaque_water"])
-       end
-
-       if fields["cb_mipmapping"] then
-               engine.setting_set("mip_map", fields["cb_mipmapping"])
-       end
-       if fields["cb_anisotrophic"] then
-               engine.setting_set("anisotropic_filter", fields["cb_anisotrophic"])
-       end
-       if fields["cb_bilinear"] then
-               engine.setting_set("bilinear_filter", fields["cb_bilinear"])
-       end
-       if fields["cb_trilinear"] then
-               engine.setting_set("trilinear_filter", fields["cb_trilinear"])
-       end
-
-       if fields["cb_shaders"] then
-               if (engine.setting_get("video_driver") == "direct3d8" or engine.setting_get("video_driver") == "direct3d9") then
-                       engine.setting_set("enable_shaders", "false")
-                       gamedata.errormessage = fgettext("To enable shaders the OpenGL driver needs to be used.")
-               else
-                       engine.setting_set("enable_shaders", fields["cb_shaders"])
-               end
-       end
-       if fields["cb_pre_ivis"] then
-               engine.setting_set("preload_item_visuals", fields["cb_pre_ivis"])
-       end
-       if fields["cb_particles"] then
-               engine.setting_set("enable_particles", fields["cb_particles"])
-       end
-       if fields["cb_bumpmapping"] then
-               engine.setting_set("enable_bumpmapping", fields["cb_bumpmapping"])
-       end
-       if fields["cb_parallax"] then
-               engine.setting_set("enable_parallax_occlusion", fields["cb_parallax"])
-       end
-       if fields["cb_generate_normalmaps"] then
-               engine.setting_set("generate_normalmaps", fields["cb_generate_normalmaps"])
-       end
-       if fields["cb_waving_water"] then
-               engine.setting_set("enable_waving_water", fields["cb_waving_water"])
-       end
-       if fields["cb_waving_leaves"] then
-               engine.setting_set("enable_waving_leaves", fields["cb_waving_leaves"])
-       end
-       if fields["cb_waving_plants"] then
-               engine.setting_set("enable_waving_plants", fields["cb_waving_plants"])
-       end
-       if fields["btn_change_keys"] ~= nil then
-               engine.show_keys_menu()
-       end
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.handle_singleplayer_buttons(fields)
-
-       local world_doubleclick = false
-
-       if fields["sp_worlds"] ~= nil then
-               local event = engine.explode_textlist_event(fields["sp_worlds"])
-
-               if event.type == "DCL" then
-                       world_doubleclick = true
-               end
-
-               if event.type == "CHG" then
-                       engine.setting_set("mainmenu_last_selected_world",
-                               filterlist.get_raw_index(worldlist,engine.get_textlist_index("sp_worlds")))
-               end
-       end
-
-       menu.handle_key_up_down(fields,"sp_worlds","mainmenu_last_selected_world")
-
-       if fields["cb_creative_mode"] then
-               engine.setting_set("creative_mode", fields["cb_creative_mode"])
-       end
-
-       if fields["cb_enable_damage"] then
-               engine.setting_set("enable_damage", fields["cb_enable_damage"])
-       end
-
-       if fields["play"] ~= nil or
-               world_doubleclick or
-               fields["key_enter"] then
-               local selected = engine.get_textlist_index("sp_worlds")
-               if selected ~= nil then
-                       gamedata.selected_world = filterlist.get_raw_index(worldlist,selected)
-                       gamedata.singleplayer   = true
-
-                       menu.update_last_game(gamedata.selected_world)
-
-                       engine.start()
-               end
-       end
-
-       if fields["world_create"] ~= nil then
-               tabbuilder.current_tab = "dialog_create_world"
-               tabbuilder.is_dialog = true
-               tabbuilder.show_buttons = false
-       end
-
-       if fields["world_delete"] ~= nil then
-               local selected = engine.get_textlist_index("sp_worlds")
-               if selected ~= nil and
-                       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 = filterlist.get_raw_index(worldlist,selected)
-                               tabbuilder.current_tab = "dialog_delete_world"
-                               tabbuilder.is_dialog = true
-                               tabbuilder.show_buttons = false
-                       else
-                               menu.world_to_del = 0
-                       end
-               end
-       end
-
-       if fields["world_configure"] ~= nil then
-               selected = engine.get_textlist_index("sp_worlds")
-               if selected ~= nil then
-                       modmgr.world_config_selected_world = filterlist.get_raw_index(worldlist,selected)
-                       if modmgr.init_worldconfig() then
-                               tabbuilder.current_tab = "dialog_configure_world"
-                               tabbuilder.is_dialog = true
-                               tabbuilder.show_buttons = false
-                       end
-               end
-       end
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.handle_texture_pack_buttons(fields)
-       if fields["TPs"] ~= nil then
-               local event = engine.explode_textlist_event(fields["TPs"])
-               if event.type == "CHG" or event.type == "DCL" then
-                       local index = engine.get_textlist_index("TPs")
-                       engine.setting_set("mainmenu_last_selected_TP",
-                               index)
-                       local list = filter_texture_pack_list(engine.get_dirlist(engine.get_texturepath(), true))
-                       local current_index = engine.get_textlist_index("TPs")
-                       if current_index ~= nil and #list >= current_index then
-                               local new_path = engine.get_texturepath()..DIR_DELIM..list[current_index]
-                               if list[current_index] == "None" then new_path = "" end
-
-                               engine.setting_set("texture_path", new_path)
-                       end
-               end
-       end
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.tab_header()
-
-       if tabbuilder.last_tab_index == nil then
-               tabbuilder.last_tab_index = 1
-       end
-
-       local toadd = ""
-
-       for i=1,#tabbuilder.current_buttons,1 do
-
-               if toadd ~= "" then
-                       toadd = toadd .. ","
-               end
-
-               toadd = toadd .. tabbuilder.current_buttons[i].caption
-       end
-       return "tabheader[-0.3,-0.99;main_tab;" .. toadd ..";" .. tabbuilder.last_tab_index .. ";true;false]"
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.handle_tab_buttons(fields)
-
-       if fields["main_tab"] then
-               local index = tonumber(fields["main_tab"])
-               tabbuilder.last_tab_index = index
-               tabbuilder.current_tab = tabbuilder.current_buttons[index].name
-
-               engine.setting_set("main_menu_tab",tabbuilder.current_tab)
-       end
-
-       --handle tab changes
-       if tabbuilder.current_tab ~= tabbuilder.old_tab then
-               if tabbuilder.current_tab ~= "singleplayer" and not tabbuilder.is_dialog then
-                       menu.update_gametype(true)
-               end
-       end
-
-       if tabbuilder.current_tab == "singleplayer" then
-               menu.update_gametype()
-       end
-
-       tabbuilder.old_tab = tabbuilder.current_tab
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.tab_multiplayer()
-
-       local retval =
-               "vertlabel[0,-0.25;".. fgettext("CLIENT") .. "]" ..
-               "label[1,-0.25;".. fgettext("Favorites:") .. "]"..
-               "label[1,4.25;".. fgettext("Address/Port") .. "]"..
-               "label[9,2.75;".. fgettext("Name/Password") .. "]" ..
-               "field[1.25,5.25;5.5,0.5;te_address;;" ..engine.setting_get("address") .."]" ..
-               "field[6.75,5.25;2.25,0.5;te_port;;" ..engine.setting_get("remote_port") .."]" ..
-               "checkbox[1,3.6;cb_public_serverlist;".. fgettext("Public Serverlist") .. ";" ..
-               dump(engine.setting_getbool("public_serverlist")) .. "]"
-
-       if not engine.setting_getbool("public_serverlist") then
-               retval = retval ..
-               "button[6.45,3.95;2.25,0.5;btn_delete_favorite;".. fgettext("Delete") .. "]"
-       end
-
-       retval = retval ..
-               "button[9,4.95;2.5,0.5;btn_mp_connect;".. fgettext("Connect") .. "]" ..
-               "field[9.3,3.75;2.5,0.5;te_name;;" ..engine.setting_get("name") .."]" ..
-               "pwdfield[9.3,4.5;2.5,0.5;te_pwd;]" ..
-               "textarea[9.3,0.25;2.5,2.75;;"
-       if menu.fav_selected ~= nil and
-               menu.favorites[menu.fav_selected].description ~= nil then
-               retval = retval ..
-                       engine.formspec_escape(menu.favorites[menu.fav_selected].description,true)
-       end
-
-       retval = retval ..
-               ";]" ..
-               "textlist[1,0.35;7.5,3.35;favourites;"
-
-       local render_details = engine.setting_getbool("public_serverlist")
-
-       if #menu.favorites > 0 then
-               retval = retval .. menu.render_favorite(menu.favorites[1],render_details)
-
-               for i=2,#menu.favorites,1 do
-                       retval = retval .. "," .. menu.render_favorite(menu.favorites[i],render_details)
-               end
-       end
-
-       if menu.fav_selected ~= nil then
-               retval = retval .. ";" .. menu.fav_selected .. "]"
-       else
-               retval = retval .. ";0]"
-       end
-
-       return retval
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.tab_server()
-
-       local index = filterlist.get_current_index(worldlist,
-                               tonumber(engine.setting_get("mainmenu_last_selected_world"))
-                               )
-
-       local retval =
-               "button[4,4.15;2.6,0.5;world_delete;".. fgettext("Delete") .. "]" ..
-               "button[6.5,4.15;2.8,0.5;world_create;".. fgettext("New") .. "]" ..
-               "button[9.2,4.15;2.55,0.5;world_configure;".. fgettext("Configure") .. "]" ..
-               "button[8.5,4.9;3.25,0.5;start_server;".. fgettext("Start Game") .. "]" ..
-               "label[4,-0.25;".. fgettext("Select World:") .. "]"..
-               "vertlabel[0,-0.25;".. fgettext("START SERVER") .. "]" ..
-               "checkbox[0.5,0.25;cb_creative_mode;".. fgettext("Creative Mode") .. ";" ..
-               dump(engine.setting_getbool("creative_mode")) .. "]"..
-               "checkbox[0.5,0.7;cb_enable_damage;".. fgettext("Enable Damage") .. ";" ..
-               dump(engine.setting_getbool("enable_damage")) .. "]"..
-               "checkbox[0.5,1.15;cb_server_announce;".. fgettext("Public") .. ";" ..
-               dump(engine.setting_getbool("server_announce")) .. "]"..
-               "field[0.8,3.2;3.5,0.5;te_playername;".. fgettext("Name") .. ";" ..
-               engine.setting_get("name") .. "]" ..
-               "pwdfield[0.8,4.2;3.5,0.5;te_passwd;".. fgettext("Password") .. "]"
-               
-       local bind_addr = engine.setting_get("bind_address")
-       if bind_addr ~= nil and bind_addr ~= "" then
-               retval = retval ..
-                       "field[0.8,5.2;2.25,0.5;te_serveraddr;".. fgettext("Bind Address") .. ";" ..
-                       engine.setting_get("bind_address") .."]" ..
-                       "field[3.05,5.2;1.25,0.5;te_serverport;".. fgettext("Port") .. ";" ..
-                       engine.setting_get("port") .."]"
-       else
-               retval = retval ..
-                       "field[0.8,5.2;3.5,0.5;te_serverport;".. fgettext("Server Port") .. ";" ..
-                       engine.setting_get("port") .."]"
-       end
+       menudata.worldlist:add_sort_mechanism("alphabetic",sort_worlds_alphabetic)
+       menudata.worldlist:set_sortmode("alphabetic")
        
-       retval = retval ..
-               "textlist[4,0.25;7.5,3.7;srv_worlds;" ..
-               menu.render_world_list() ..
-               ";" .. index .. "]"
-
-       return retval
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.tab_settings()
-       tab_string =
-                       "vertlabel[0,0;" .. fgettext("SETTINGS") .. "]" ..
-                       "checkbox[1,0;cb_fancy_trees;".. fgettext("Fancy Trees") .. ";"
-                                       .. dump(engine.setting_getbool("new_style_leaves")) .. "]"..
-                       "checkbox[1,0.5;cb_smooth_lighting;".. fgettext("Smooth Lighting")
-                                       .. ";".. dump(engine.setting_getbool("smooth_lighting")) .. "]"..
-                       "checkbox[1,1;cb_3d_clouds;".. fgettext("3D Clouds") .. ";"
-                                       .. dump(engine.setting_getbool("enable_3d_clouds")) .. "]"..
-                       "checkbox[1,1.5;cb_opaque_water;".. fgettext("Opaque Water") .. ";"
-                                       .. dump(engine.setting_getbool("opaque_water")) .. "]"..
-                       "checkbox[1,2.0;cb_pre_ivis;".. fgettext("Preload item visuals") .. ";"
-                                       .. dump(engine.setting_getbool("preload_item_visuals")) .. "]"..
-                       "checkbox[1,2.5;cb_particles;".. fgettext("Enable Particles") .. ";"
-                                       .. dump(engine.setting_getbool("enable_particles"))     .. "]"..
-                       "checkbox[4.5,0;cb_mipmapping;".. fgettext("Mip-Mapping") .. ";"
-                                       .. dump(engine.setting_getbool("mip_map")) .. "]"..
-                       "checkbox[4.5,0.5;cb_anisotrophic;".. fgettext("Anisotropic Filtering") .. ";"
-                                       .. dump(engine.setting_getbool("anisotropic_filter")) .. "]"..
-                       "checkbox[4.5,1.0;cb_bilinear;".. fgettext("Bi-Linear Filtering") .. ";"
-                                       .. dump(engine.setting_getbool("bilinear_filter")) .. "]"..
-                       "checkbox[4.5,1.5;cb_trilinear;".. fgettext("Tri-Linear Filtering") .. ";"
-                                       .. dump(engine.setting_getbool("trilinear_filter")) .. "]"..
-
-                       "checkbox[8,0;cb_shaders;".. fgettext("Shaders") .. ";"
-                                       .. dump(engine.setting_getbool("enable_shaders")) .. "]"..
-                       "button[1,4.5;2.25,0.5;btn_change_keys;".. fgettext("Change keys") .. "]"
-
-       if engine.setting_getbool("enable_shaders") then
-               tab_string = tab_string ..
-                       "checkbox[8,0.5;cb_bumpmapping;".. fgettext("Bumpmapping") .. ";"
-                                       .. dump(engine.setting_getbool("enable_bumpmapping")) .. "]"..
-                       "checkbox[8,1.0;cb_parallax;".. fgettext("Parallax Occlusion") .. ";"
-                                       .. dump(engine.setting_getbool("enable_parallax_occlusion")) .. "]"..
-                       "checkbox[8,1.5;cb_generate_normalmaps;".. fgettext("Generate Normalmaps") .. ";"
-                                       .. dump(engine.setting_getbool("generate_normalmaps")) .. "]"..
-                       "checkbox[8,2.0;cb_waving_water;".. fgettext("Waving Water") .. ";"
-                                       .. dump(engine.setting_getbool("enable_waving_water")) .. "]"..
-                       "checkbox[8,2.5;cb_waving_leaves;".. fgettext("Waving Leaves") .. ";"
-                                       .. dump(engine.setting_getbool("enable_waving_leaves")) .. "]"..
-                       "checkbox[8,3.0;cb_waving_plants;".. fgettext("Waving Plants") .. ";"
-                                       .. dump(engine.setting_getbool("enable_waving_plants")) .. "]"
-       else
-               tab_string = tab_string ..
-                       "textlist[8.33,0.7;4,1;;#888888" .. fgettext("Bumpmapping") .. ";0;true]" ..
-                       "textlist[8.33,1.2;4,1;;#888888" .. fgettext("Parallax Occlusion") .. ";0;true]" ..
-                       "textlist[8.33,1.7;4,1;;#888888" .. fgettext("Generate Normalmaps") .. ";0;true]" ..
-                       "textlist[8.33,2.2;4,1;;#888888" .. fgettext("Waving Water") .. ";0;true]" ..
-                       "textlist[8.33,2.7;4,1;;#888888" .. fgettext("Waving Leaves") .. ";0;true]" ..
-                       "textlist[8.33,3.2;4,1;;#888888" .. fgettext("Waving Plants") .. ";0;true]"
-       end
-       return tab_string
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.tab_singleplayer()
-
-       local index = filterlist.get_current_index(worldlist,
-                               tonumber(engine.setting_get("mainmenu_last_selected_world"))
-                               )
-
-       return  "button[4,4.15;2.6,0.5;world_delete;".. fgettext("Delete") .. "]" ..
-                       "button[6.5,4.15;2.8,0.5;world_create;".. fgettext("New") .. "]" ..
-                       "button[9.2,4.15;2.55,0.5;world_configure;".. fgettext("Configure") .. "]" ..
-                       "button[8.5,4.95;3.25,0.5;play;".. fgettext("Play") .. "]" ..
-                       "label[4,-0.25;".. fgettext("Select World:") .. "]"..
-                       "vertlabel[0,-0.25;".. fgettext("SINGLE PLAYER") .. "]" ..
-                       "checkbox[0.5,0.25;cb_creative_mode;".. fgettext("Creative Mode") .. ";" ..
-                       dump(engine.setting_getbool("creative_mode")) .. "]"..
-                       "checkbox[0.5,0.7;cb_enable_damage;".. fgettext("Enable Damage") .. ";" ..
-                       dump(engine.setting_getbool("enable_damage")) .. "]"..
-                       "textlist[4,0.25;7.5,3.7;sp_worlds;" ..
-                       menu.render_world_list() ..
-                       ";" .. index .. "]" ..
-                       menubar.formspec
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.tab_texture_packs()
-       local retval = "label[4,-0.25;".. fgettext("Select texture pack:") .. "]"..
-                       "vertlabel[0,-0.25;".. fgettext("TEXTURE PACKS") .. "]" ..
-                       "textlist[4,0.25;7.5,5.0;TPs;"
-
-       local current_texture_path = engine.setting_get("texture_path")
-       local list = filter_texture_pack_list(engine.get_dirlist(engine.get_texturepath(), true))
-       local index = tonumber(engine.setting_get("mainmenu_last_selected_TP"))
-
-       if index == nil then index = 1 end
-
-       if current_texture_path == "" then
-               retval = retval ..
-                       menu.render_texture_pack_list(list) ..
-                       ";" .. index .. "]"
-               return retval
-       end
-
-       local infofile = current_texture_path ..DIR_DELIM.."info.txt"
-       local infotext = ""
-       local f = io.open(infofile, "r")
-       if f==nil then
-               infotext = fgettext("No information available")
-       else
-               infotext = f:read("*all")
-               f:close()
-       end
-
-       local screenfile = current_texture_path..DIR_DELIM.."screenshot.png"
-       local no_screenshot = nil
-       if not file_exists(screenfile) then
-               screenfile = nil
-               no_screenshot = menu.defaulttexturedir .. "no_screenshot.png"
-       end
-
-       return  retval ..
-                       menu.render_texture_pack_list(list) ..
-                       ";" .. index .. "]" ..
-                       "image[0.65,0.25;4.0,3.7;"..engine.formspec_escape(screenfile or no_screenshot).."]"..
-                       "textarea[1.0,3.25;3.7,1.5;;"..engine.formspec_escape(infotext or "")..";]"
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.tab_credits()
-       local logofile = menu.defaulttexturedir .. "logo.png"
-       return  "vertlabel[0,-0.5;CREDITS]" ..
-                       "label[0.5,3;Minetest " .. engine.get_version() .. "]" ..
-                       "label[0.5,3.3;http://minetest.net]" ..
-                       "image[0.5,1;" .. engine.formspec_escape(logofile) .. "]" ..
-                       "textlist[3.5,-0.25;8.5,5.8;list_credits;" ..
-                       "#FFFF00" .. fgettext("Core Developers") .."," ..
-                       "Perttu Ahola (celeron55) <celeron55@gmail.com>,"..
-                       "Ryan Kwolek (kwolekr) <kwolekr@minetest.net>,"..
-                       "PilzAdam <pilzadam@minetest.net>," ..
-                       "Ilya Zhuravlev (xyz) <xyz@minetest.net>,"..
-                       "Lisa Milne (darkrose) <lisa@ltmnet.com>,"..
-                       "Maciej Kasatkin (RealBadAngel) <mk@realbadangel.pl>,"..
-                       "proller <proler@gmail.com>,"..
-                       "sfan5 <sfan5@live.de>,"..
-                       "kahrl <kahrl@gmx.net>,"..
-                       "sapier,"..
-                       "ShadowNinja <shadowninja@minetest.net>,"..
-                       "Nathanael Courant (Nore/Novatux) <nore@mesecons.net>,"..
-                       "BlockMen,"..
-                       ","..
-                       "#FFFF00" .. fgettext("Active Contributors") .. "," ..
-                       "Vanessa Ezekowitz (VanessaE) <vanessaezekowitz@gmail.com>,"..
-                       "Jurgen Doser (doserj) <jurgen.doser@gmail.com>,"..
-                       "Jeija <jeija@mesecons.net>,"..
-                       "MirceaKitsune <mirceakitsune@gmail.com>,"..
-                       "dannydark <the_skeleton_of_a_child@yahoo.co.uk>,"..
-                       "0gb.us <0gb.us@0gb.us>,"..
-                       "," ..
-                       "#FFFF00" .. fgettext("Previous Contributors") .. "," ..
-                       "Guiseppe Bilotta (Oblomov) <guiseppe.bilotta@gmail.com>,"..
-                       "Jonathan Neuschafer <j.neuschaefer@gmx.net>,"..
-                       "Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net>,"..
-                       "Constantin Wenger (SpeedProg) <constantin.wenger@googlemail.com>,"..
-                       "matttpt <matttpt@gmail.com>,"..
-                       "JacobF <queatz@gmail.com>,"..
-                       ";0;true]"
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.init()
-       tabbuilder.tabfuncs = {
-               singleplayer  = tabbuilder.tab_singleplayer,
-               multiplayer   = tabbuilder.tab_multiplayer,
-               server        = tabbuilder.tab_server,
-               settings      = tabbuilder.tab_settings,
-               texture_packs = tabbuilder.tab_texture_packs,
-               credits       = tabbuilder.tab_credits,
-               dialog_create_world = tabbuilder.dialog_create_world,
-               dialog_delete_world = tabbuilder.dialog_delete_world
-       }
-
-       tabbuilder.tabsizes = {
-               dialog_create_world = {width=12, height=7},
-               dialog_delete_world = {width=12, height=5.2}
-       }
-
-       tabbuilder.current_tab = engine.setting_get("main_menu_tab")
-
-       if tabbuilder.current_tab == nil or
-               tabbuilder.current_tab == "" then
-               tabbuilder.current_tab = "singleplayer"
-               engine.setting_set("main_menu_tab",tabbuilder.current_tab)
-       end
-
-       --initialize tab buttons
-       tabbuilder.last_tab = nil
-       tabbuilder.show_buttons = true
-
-       tabbuilder.current_buttons = {}
-       table.insert(tabbuilder.current_buttons,{name="singleplayer", caption=fgettext("Singleplayer")})
-       table.insert(tabbuilder.current_buttons,{name="multiplayer", caption=fgettext("Client")})
-       table.insert(tabbuilder.current_buttons,{name="server", caption=fgettext("Server")})
-       table.insert(tabbuilder.current_buttons,{name="settings", caption=fgettext("Settings")})
-       table.insert(tabbuilder.current_buttons,{name="texture_packs", caption=fgettext("Texture Packs")})
-
-       if engine.setting_getbool("main_menu_game_mgr") then
-               table.insert(tabbuilder.current_buttons,{name="game_mgr", caption=fgettext("Games")})
-       end
-
-       if engine.setting_getbool("main_menu_mod_mgr") then
-               table.insert(tabbuilder.current_buttons,{name="mod_mgr", caption=fgettext("Mods")})
-       end
-       table.insert(tabbuilder.current_buttons,{name="credits", caption=fgettext("Credits")})
-
-
-       for i=1,#tabbuilder.current_buttons,1 do
-               if tabbuilder.current_buttons[i].name == tabbuilder.current_tab then
-                       tabbuilder.last_tab_index = i
-               end
-       end
-
-       if tabbuilder.current_tab ~= "singleplayer" then
-               menu.update_gametype(true)
-       else
-               menu.update_gametype()
-       end
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.checkretval(retval)
-
-       if retval ~= nil then
-               if retval.current_tab ~= nil then
-                       tabbuilder.current_tab = retval.current_tab
-               end
-
-               if retval.is_dialog ~= nil then
-                       tabbuilder.is_dialog = retval.is_dialog
-               end
-
-               if retval.show_buttons ~= nil then
-                       tabbuilder.show_buttons = retval.show_buttons
-               end
-
-               if retval.skipformupdate ~= nil then
-                       tabbuilder.skipformupdate = retval.skipformupdate
-               end
-
-               if retval.ignore_menu_quit == true then
-                       tabbuilder.ignore_menu_quit = true
-               else
-                       tabbuilder.ignore_menu_quit = false
-               end
-       end
-end
-
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
--- initialize callbacks
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
-engine.button_handler = function(fields)
-       --print("Buttonhandler: tab: " .. tabbuilder.current_tab .. " fields: " .. dump(fields))
-
-       if fields["btn_error_confirm"] then
-               gamedata.errormessage = nil
-       end
-
-       local retval = modmgr.handle_buttons(tabbuilder.current_tab,fields)
-       tabbuilder.checkretval(retval)
-
-       retval = gamemgr.handle_buttons(tabbuilder.current_tab,fields)
-       tabbuilder.checkretval(retval)
-
-       retval = modstore.handle_buttons(tabbuilder.current_tab,fields)
-       tabbuilder.checkretval(retval)
-
-       if tabbuilder.current_tab == "dialog_create_world" then
-               tabbuilder.handle_create_world_buttons(fields)
-       end
-
-       if tabbuilder.current_tab == "dialog_delete_world" then
-               tabbuilder.handle_delete_world_buttons(fields)
-       end
-
-       if tabbuilder.current_tab == "singleplayer" then
-               tabbuilder.handle_singleplayer_buttons(fields)
-       end
-
-       if tabbuilder.current_tab == "texture_packs" then
-               tabbuilder.handle_texture_pack_buttons(fields)
-       end
-
-       if tabbuilder.current_tab == "multiplayer" then
-               tabbuilder.handle_multiplayer_buttons(fields)
-       end
-
-       if tabbuilder.current_tab == "settings" then
-               tabbuilder.handle_settings_buttons(fields)
-       end
-
-       if tabbuilder.current_tab == "server" then
-               tabbuilder.handle_server_buttons(fields)
-       end
-
-       --tab buttons
-       tabbuilder.handle_tab_buttons(fields)
-
-       --menubar buttons
-       menubar.handle_buttons(fields)
-
-       if not tabbuilder.skipformupdate then
-               --update menu
-               update_menu()
-       else
-               tabbuilder.skipformupdate = false
-       end
-end
-
---------------------------------------------------------------------------------
-engine.event_handler = function(event)
-       if event == "MenuQuit" then
-               if tabbuilder.is_dialog then
-                       if tabbuilder.ignore_menu_quit then
-                               return
-                       end
-
-                       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()
-               end
-       end
-
-       if event == "Refresh" then
-               update_menu()
-       end
-end
+       mm_texture.init()
+       
+       --create main tabview
+       local tv_main = tabview_create("maintab",{x=12,y=5.2},{x=-0.3,y=-0.99})
+       tv_main:set_autosave_tab(true)
+       tv_main:add(tab_singleplayer)
+       tv_main:add(tab_multiplayer)
+       tv_main:add(tab_server)
+       tv_main:add(tab_settings)
+       tv_main:add(tab_texturepacks)
+       tv_main:add(tab_mods)
+       tv_main:add(tab_credits)
+       
+       tv_main:set_global_event_handler(main_event_handler)
+       
+       tv_main:set_tab(core.setting_get("maintab_LAST"))
+       ui.set_default("maintab")
+       tv_main:show()
 
---------------------------------------------------------------------------------
-function menu.update_gametype(reset)
-       local game = menu.lastgame()
+       --create modstore ui
+       modstore.init({x=12,y=8},4,3)
 
-       if reset or game == nil then
-               mm_texture.reset()
-               engine.set_topleft_text("")
-               filterlist.set_filtercriteria(worldlist,nil)
-       else
-               mm_texture.update(tabbuilder.current_tab,game)
-               engine.set_topleft_text(game.name)
-               filterlist.set_filtercriteria(worldlist,game.id)
-       end
+       ui.update()
+       
+       core.sound_play("main_menu", true)
 end
 
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
--- menu startup
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
 init_globals()
-mm_texture.init()
-menu.init()
-tabbuilder.init()
-menubar.refresh()
-modstore.init()
-
-engine.sound_play("main_menu", true)
-
-update_menu()
diff --git a/builtin/mainmenu/menubar.lua b/builtin/mainmenu/menubar.lua
deleted file mode 100644 (file)
index 2e4d5f8..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
---Minetest
---Copyright (C) 2013 sapier
---
---This program is free software; you can redistribute it and/or modify
---it under the terms of the GNU Lesser General Public License as published by
---the Free Software Foundation; either version 2.1 of the License, or
---(at your option) any later version.
---
---This program is distributed in the hope that it will be useful,
---but WITHOUT ANY WARRANTY; without even the implied warranty of
---MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
---GNU Lesser General Public License for more details.
---
---You should have received a copy of the GNU Lesser General Public License along
---with this program; if not, write to the Free Software Foundation, Inc.,
---51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-menubar = {}
-
---------------------------------------------------------------------------------
-function menubar.handle_buttons(fields)
-       for i=1,#menubar.buttons,1 do
-               if fields[menubar.buttons[i].btn_name] ~= nil then
-                       menu.last_game = menubar.buttons[i].index
-                       engine.setting_set("main_menu_last_game_idx",menu.last_game)
-                       menu.update_gametype()
-               end
-       end
-end
-
---------------------------------------------------------------------------------
-function menubar.refresh()
-
-       menubar.formspec = "box[-0.3,5.625;12.4,1.2;#000000]" ..
-                                          "box[-0.3,5.6;12.4,0.05;#FFFFFF]"
-       menubar.buttons = {}
-
-       local button_base = -0.08
-       
-       local maxbuttons = #gamemgr.games
-       
-       if maxbuttons > 11 then
-               maxbuttons = 11
-       end
-       
-       for i=1,maxbuttons,1 do
-
-               local btn_name = "menubar_btn_" .. gamemgr.games[i].id
-               local buttonpos = button_base + (i-1) * 1.1
-               if gamemgr.games[i].menuicon_path ~= nil and
-                       gamemgr.games[i].menuicon_path ~= "" then
-
-                       menubar.formspec = menubar.formspec ..
-                               "image_button[" .. buttonpos ..  ",5.72;1.165,1.175;"  ..
-                               engine.formspec_escape(gamemgr.games[i].menuicon_path) .. ";" ..
-                               btn_name .. ";;true;false]"
-               else
-               
-                       local part1 = gamemgr.games[i].id:sub(1,5)
-                       local part2 = gamemgr.games[i].id:sub(6,10)
-                       local part3 = gamemgr.games[i].id:sub(11)
-                       
-                       local text = part1 .. "\n" .. part2
-                       if part3 ~= nil and
-                               part3 ~= "" then
-                               text = text .. "\n" .. part3
-                       end
-                       menubar.formspec = menubar.formspec ..
-                               "image_button[" .. buttonpos ..  ",5.72;1.165,1.175;;" ..btn_name ..
-                               ";" .. text .. ";true;true]"
-               end
-               
-               local toadd = {
-                       btn_name = btn_name,
-                       index = i,
-               }
-               
-               table.insert(menubar.buttons,toadd)
-       end
-end
index baf61d2a525c36cca5bea223c432554a317eadc1..dcd1eb256e341d87cb267437aed2e7d4d77ff0cc 100644 (file)
 --------------------------------------------------------------------------------
 function get_mods(path,retval,modpack)
 
-       local mods = engine.get_dirlist(path,true)
+       local mods = core.get_dirlist(path,true)
        for i=1,#mods,1 do
                local toadd = {}
                local modpackfile = nil
 
-               toadd.name              = mods[i]
-               toadd.path              = path .. DIR_DELIM .. mods[i] .. DIR_DELIM
+               toadd.name = mods[i]
+               toadd.path = path .. DIR_DELIM .. mods[i] .. DIR_DELIM
                if modpack ~= nil and
                        modpack ~= "" then
-                       toadd.modpack   = modpack
+                       toadd.modpack = modpack
                else
                        local filename = path .. DIR_DELIM .. mods[i] .. DIR_DELIM .. "modpack.txt"
                        local error = nil
@@ -55,8 +55,8 @@ function modmgr.extract(modfile)
 
                if tempfolder ~= nil and
                        tempfolder ~= "" then
-                       engine.create_dir(tempfolder)
-                       if engine.extract_zip(modfile.name,tempfolder) then
+                       core.create_dir(tempfolder)
+                       if core.extract_zip(modfile.name,tempfolder) then
                                return tempfolder
                        end
                end
@@ -92,7 +92,7 @@ function modmgr.getbasefolder(temppath)
                                }
        end
 
-       local subdirs = engine.get_dirlist(temppath,true)
+       local subdirs = core.get_dirlist(temppath,true)
 
        --only single mod or modpack allowed
        if #subdirs ~= 1 then
@@ -193,9 +193,16 @@ function modmgr.identify_modname(modpath,filename)
                while line~= nil do
                        local modname = nil
 
-                       if line:find("register_tool") or
-                          line:find("register_craftitem") or
-                          line:find("register_node") then
+                       if line:find("minetest.register_tool") then
+                               modname = modmgr.parse_register_line(line)
+                       end
+
+                       if line:find("minetest.register_craftitem") then
+                               modname = modmgr.parse_register_line(line)
+                       end
+
+
+                       if line:find("minetest.register_node") then
                                modname = modmgr.parse_register_line(line)
                        end
 
@@ -215,139 +222,6 @@ function modmgr.identify_modname(modpath,filename)
 
        return nil
 end
-
---------------------------------------------------------------------------------
-function modmgr.tab()
-       if modmgr.global_mods == nil then
-               modmgr.refresh_globals()
-       end
-
-       if modmgr.selected_mod == nil then
-               modmgr.selected_mod = 1
-       end
-
-       local retval =
-               "vertlabel[0,-0.25;".. fgettext("MODS") .. "]" ..
-               "label[0.8,-0.25;".. fgettext("Installed Mods:") .. "]" ..
-               "textlist[0.75,0.25;4.5,4;modlist;" ..
-               modmgr.render_modlist(modmgr.global_mods) ..
-               ";" .. modmgr.selected_mod .. "]"
-
-       retval = retval ..
-               "label[0.8,4.2;" .. fgettext("Add mod:") .. "]" ..
---             TODO Disabled due to upcoming release 0.4.8 and irrlicht messing up localization
---             "button[0.75,4.85;1.8,0.5;btn_mod_mgr_install_local;".. fgettext("Local install") .. "]" ..
-               "button[2.45,4.85;3.05,0.5;btn_mod_mgr_download;".. fgettext("Online mod repository") .. "]"
-
-       local selected_mod = nil
-
-       if filterlist.size(modmgr.global_mods) >= modmgr.selected_mod then
-               selected_mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
-       end
-
-       if selected_mod ~= nil then
-               local modscreenshot = nil
-
-               --check for screenshot beeing available
-               local screenshotfilename = selected_mod.path .. DIR_DELIM .. "screenshot.png"
-               local error = nil
-               screenshotfile,error = io.open(screenshotfilename,"r")
-               if error == nil then
-                       screenshotfile:close()
-                       modscreenshot = screenshotfilename
-               end
-
-               if modscreenshot == nil then
-                               modscreenshot = modstore.basetexturedir .. "no_screenshot.png"
-               end
-
-               retval = retval
-                               .. "image[5.5,0;3,2;" .. engine.formspec_escape(modscreenshot) .. "]"
-                               .. "label[8.25,0.6;" .. selected_mod.name .. "]"
-
-               local descriptionlines = nil
-               error = nil
-               local descriptionfilename = selected_mod.path .. "description.txt"
-               descriptionfile,error = io.open(descriptionfilename,"r")
-               if error == nil then
-                       descriptiontext = descriptionfile:read("*all")
-
-                       descriptionlines = engine.splittext(descriptiontext,42)
-                       descriptionfile:close()
-               else
-                       descriptionlines = {}
-                       table.insert(descriptionlines,fgettext("No mod description available"))
-               end
-
-               retval = retval ..
-                       "label[5.5,1.7;".. fgettext("Mod information:") .. "]" ..
-                       "textlist[5.5,2.2;6.2,2.4;description;"
-
-               for i=1,#descriptionlines,1 do
-                       retval = retval .. engine.formspec_escape(descriptionlines[i]) .. ","
-               end
-
-
-               if selected_mod.is_modpack then
-                       retval = retval .. ";0]" ..
-                               "button[10,4.85;2,0.5;btn_mod_mgr_rename_modpack;" ..
-                               fgettext("Rename") .. "]"
-                       retval = retval .. "button[5.5,4.85;4.5,0.5;btn_mod_mgr_delete_mod;"
-                               .. fgettext("Uninstall selected modpack") .. "]"
-               else
-                       --show dependencies
-
-                       retval = retval .. ",Depends:,"
-
-                       toadd = modmgr.get_dependencies(selected_mod.path)
-
-                       retval = retval .. toadd .. ";0]"
-
-                       retval = retval .. "button[5.5,4.85;4.5,0.5;btn_mod_mgr_delete_mod;"
-                               .. fgettext("Uninstall selected mod") .. "]"
-               end
-       end
-       return retval
-end
-
---------------------------------------------------------------------------------
-function modmgr.dialog_rename_modpack()
-
-       local mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
-
-       local retval =
-               "label[1.75,1;".. fgettext("Rename Modpack:") .. "]"..
-               "field[4.5,1.4;6,0.5;te_modpack_name;;" ..
-               mod.name ..
-               "]" ..
-               "button[5,4.2;2.6,0.5;dlg_rename_modpack_confirm;"..
-                               fgettext("Accept") .. "]" ..
-               "button[7.5,4.2;2.8,0.5;dlg_rename_modpack_cancel;"..
-                               fgettext("Cancel") .. "]"
-
-       return retval
-end
-
---------------------------------------------------------------------------------
-function modmgr.precheck()
-
-       if modmgr.world_config_selected_world == nil then
-               modmgr.world_config_selected_world = 1
-       end
-
-       if modmgr.world_config_selected_mod == nil then
-               modmgr.world_config_selected_mod = 1
-       end
-
-       if modmgr.hide_gamemods == nil then
-               modmgr.hide_gamemods = true
-       end
-
-       if modmgr.hide_modpackcontents == nil then
-               modmgr.hide_modpackcontents = true
-       end
-end
-
 --------------------------------------------------------------------------------
 function modmgr.render_modlist(render_list)
        local retval = ""
@@ -359,7 +233,7 @@ function modmgr.render_modlist(render_list)
                render_list = modmgr.global_mods
        end
 
-       local list = filterlist.get_list(render_list)
+       local list = render_list:get_list()
        local last_modpack = nil
 
        for i,v in ipairs(list) do
@@ -370,7 +244,7 @@ function modmgr.render_modlist(render_list)
                local color = ""
 
                if v.is_modpack then
-                       local rawlist = filterlist.get_raw_list(render_list)
+                       local rawlist = render_list:get_raw_list()
 
                        local all_enabled = true
                        for j=1,#rawlist,1 do
@@ -406,104 +280,6 @@ function modmgr.render_modlist(render_list)
        return retval
 end
 
---------------------------------------------------------------------------------
-function modmgr.dialog_configure_world()
-       modmgr.precheck()
-
-       local worldspec = engine.get_worlds()[modmgr.world_config_selected_world]
-       local mod = filterlist.get_list(modmgr.modlist)[modmgr.world_config_selected_mod]
-
-       local retval =
-               "size[11,6.5,true]" ..
-               "label[0.5,-0.25;" .. fgettext("World:") .. "]" ..
-               "label[1.75,-0.25;" .. worldspec.name .. "]"
-
-       if modmgr.hide_gamemods then
-               retval = retval .. "checkbox[0,5.75;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";true]"
-       else
-               retval = retval .. "checkbox[0,5.75;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";false]"
-       end
-
-       if modmgr.hide_modpackcontents then
-               retval = retval .. "checkbox[2,5.75;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";true]"
-       else
-               retval = retval .. "checkbox[2,5.75;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";false]"
-       end
-
-       if mod == nil then
-               mod = {name=""}
-       end
-       retval = retval ..
-               "label[0,0.45;" .. fgettext("Mod:") .. "]" ..
-               "label[0.75,0.45;" .. mod.name .. "]" ..
-               "label[0,1;" .. fgettext("Depends:") .. "]" ..
-               "textlist[0,1.5;5,4.25;world_config_depends;" ..
-               modmgr.get_dependencies(mod.path) .. ";0]" ..
-               "button[9.25,6.35;2,0.5;btn_config_world_save;" .. fgettext("Save") .. "]" ..
-               "button[7.4,6.35;2,0.5;btn_config_world_cancel;" .. fgettext("Cancel") .. "]"
-
-       if mod ~= nil and mod.name ~= "" and mod.typ ~= "game_mod" then
-               if mod.is_modpack then
-                       local rawlist = filterlist.get_raw_list(modmgr.modlist)
-
-                       local all_enabled = true
-                       for j=1,#rawlist,1 do
-                               if rawlist[j].modpack == mod.name and
-                                       rawlist[j].enabled ~= true then
-                                               all_enabled = false
-                                               break
-                               end
-                       end
-
-                       if all_enabled == false then
-                               retval = retval .. "button[5.5,-0.125;2,0.5;btn_mp_enable;" .. fgettext("Enable MP") .. "]"
-                       else
-                               retval = retval .. "button[5.5,-0.125;2,0.5;btn_mp_disable;" .. fgettext("Disable MP") .. "]"
-                       end
-               else
-                       if mod.enabled then
-                               retval = retval .. "checkbox[5.5,-0.375;cb_mod_enable;" .. fgettext("enabled") .. ";true]"
-                       else
-                               retval = retval .. "checkbox[5.5,-0.375;cb_mod_enable;" .. fgettext("enabled") .. ";false]"
-                       end
-               end
-       end
-
-       retval = retval ..
-               "button[8.5,-0.125;2.5,0.5;btn_all_mods;" .. fgettext("Enable all") .. "]" ..
-               "textlist[5.5,0.5;5.5,5.75;world_config_modlist;"
-
-       retval = retval .. modmgr.render_modlist(modmgr.modlist)
-
-       retval = retval .. ";" .. modmgr.world_config_selected_mod .."]"
-
-       return retval
-end
-
---------------------------------------------------------------------------------
-function modmgr.handle_buttons(tab,fields)
-
-       local retval = nil
-
-       if tab == "mod_mgr" then
-               retval = modmgr.handle_modmgr_buttons(fields)
-       end
-
-       if tab == "dialog_rename_modpack" then
-               retval = modmgr.handle_rename_modpack_buttons(fields)
-       end
-
-       if tab == "dialog_delete_mod" then
-               retval = modmgr.handle_delete_mod_buttons(fields)
-       end
-
-       if tab == "dialog_configure_world" then
-               retval = modmgr.handle_configure_world_buttons(fields)
-       end
-
-       return retval
-end
-
 --------------------------------------------------------------------------------
 function modmgr.get_dependencies(modfolder)
        local toadd = ""
@@ -529,7 +305,6 @@ function modmgr.get_dependencies(modfolder)
        return toadd
 end
 
-
 --------------------------------------------------------------------------------
 function modmgr.get_worldconfig(worldpath)
        local filename = worldpath ..
@@ -545,7 +320,7 @@ function modmgr.get_worldconfig(worldpath)
                if key == "gameid" then
                        worldconfig.id = value
                else
-                       worldconfig.global_mods[key] = engine.is_yes(value)
+                       worldconfig.global_mods[key] = core.is_yes(value)
                end
        end
 
@@ -555,52 +330,6 @@ function modmgr.get_worldconfig(worldpath)
 
        return worldconfig
 end
---------------------------------------------------------------------------------
-function modmgr.handle_modmgr_buttons(fields)
-       local retval = {
-                       tab = nil,
-                       is_dialog = nil,
-                       show_buttons = nil,
-               }
-
-       if fields["modlist"] ~= nil then
-               local event = engine.explode_textlist_event(fields["modlist"])
-               modmgr.selected_mod = event.index
-       end
-
-       if fields["btn_mod_mgr_install_local"] ~= nil then
-               engine.show_file_open_dialog("mod_mgt_open_dlg",fgettext("Select Mod File:"))
-       end
-
-       if fields["btn_mod_mgr_download"] ~= nil then
-               modstore.update_modlist()
-               retval.current_tab = "dialog_modstore_unsorted"
-               retval.is_dialog = true
-               retval.show_buttons = false
-               return retval
-       end
-
-       if fields["btn_mod_mgr_rename_modpack"] ~= nil then
-               retval.current_tab = "dialog_rename_modpack"
-               retval.is_dialog = true
-               retval.show_buttons = false
-               return retval
-       end
-
-       if fields["btn_mod_mgr_delete_mod"] ~= nil then
-               retval.current_tab = "dialog_delete_mod"
-               retval.is_dialog = true
-               retval.show_buttons = false
-               return retval
-       end
-
-       if fields["mod_mgt_open_dlg_accepted"] ~= nil and
-               fields["mod_mgt_open_dlg_accepted"] ~= "" then
-               modmgr.installmod(fields["mod_mgt_open_dlg_accepted"],nil)
-       end
-
-       return nil;
-end
 
 --------------------------------------------------------------------------------
 function modmgr.installmod(modfilename,basename)
@@ -613,7 +342,6 @@ function modmgr.installmod(modfilename,basename)
                return
        end
 
-
        local basefolder = modmgr.getbasefolder(modpath)
 
        if basefolder.type == "modpack" then
@@ -628,8 +356,8 @@ function modmgr.installmod(modfilename,basename)
                end
 
                if clean_path ~= nil then
-                       local targetpath = engine.get_modpath() .. DIR_DELIM .. clean_path
-                       if not engine.copy_dir(basefolder.path,targetpath) then
+                       local targetpath = core.get_modpath() .. DIR_DELIM .. clean_path
+                       if not core.copy_dir(basefolder.path,targetpath) then
                                gamedata.errormessage = fgettext("Failed to install $1 to $2", basename, targetpath)
                        end
                else
@@ -650,234 +378,19 @@ function modmgr.installmod(modfilename,basename)
                end
 
                if targetfolder ~= nil and modmgr.isValidModname(targetfolder) then
-                       local targetpath = engine.get_modpath() .. DIR_DELIM .. targetfolder
-                       engine.copy_dir(basefolder.path,targetpath)
+                       local targetpath = core.get_modpath() .. DIR_DELIM .. targetfolder
+                       core.copy_dir(basefolder.path,targetpath)
                else
                        gamedata.errormessage = fgettext("Install Mod: unable to find real modname for: $1", modfilename)
                end
        end
 
-       engine.delete_dir(modpath)
+       core.delete_dir(modpath)
 
        modmgr.refresh_globals()
 
 end
 
---------------------------------------------------------------------------------
-function modmgr.handle_rename_modpack_buttons(fields)
-
-       if fields["dlg_rename_modpack_confirm"] ~= nil then
-               local mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
-               local oldpath = engine.get_modpath() .. DIR_DELIM .. mod.name
-               local targetpath = engine.get_modpath() .. DIR_DELIM .. fields["te_modpack_name"]
-               engine.copy_dir(oldpath,targetpath,false)
-               modmgr.refresh_globals()
-               modmgr.selected_mod = filterlist.get_current_index(modmgr.global_mods,
-                       filterlist.raw_index_by_uid(modmgr.global_mods, fields["te_modpack_name"]))
-       end
-
-       return {
-               is_dialog = false,
-               show_buttons = true,
-               current_tab = engine.setting_get("main_menu_tab")
-               }
-end
---------------------------------------------------------------------------------
-function modmgr.handle_configure_world_buttons(fields)
-       if fields["world_config_modlist"] ~= nil then
-               local event = engine.explode_textlist_event(fields["world_config_modlist"])
-               modmgr.world_config_selected_mod = event.index
-
-               if event.type == "DCL" then
-                       modmgr.world_config_enable_mod(nil)
-               end
-       end
-
-       if fields["key_enter"] ~= nil then
-               modmgr.world_config_enable_mod(nil)
-       end
-
-       if fields["cb_mod_enable"] ~= nil then
-               local toset = engine.is_yes(fields["cb_mod_enable"])
-               modmgr.world_config_enable_mod(toset)
-       end
-
-       if fields["btn_mp_enable"] ~= nil or
-               fields["btn_mp_disable"] then
-               local toset = (fields["btn_mp_enable"] ~= nil)
-               modmgr.world_config_enable_mod(toset)
-       end
-
-       if fields["cb_hide_gamemods"] ~= nil then
-               local current = filterlist.get_filtercriteria(modmgr.modlist)
-
-               if current == nil then
-                       current = {}
-               end
-
-               if engine.is_yes(fields["cb_hide_gamemods"]) then
-                       current.hide_game = true
-                       modmgr.hide_gamemods = true
-               else
-                       current.hide_game = false
-                       modmgr.hide_gamemods = false
-               end
-
-               filterlist.set_filtercriteria(modmgr.modlist,current)
-       end
-
-               if fields["cb_hide_mpcontent"] ~= nil then
-               local current = filterlist.get_filtercriteria(modmgr.modlist)
-
-               if current == nil then
-                       current = {}
-               end
-
-               if engine.is_yes(fields["cb_hide_mpcontent"]) then
-                       current.hide_modpackcontents = true
-                       modmgr.hide_modpackcontents = true
-               else
-                       current.hide_modpackcontents = false
-                       modmgr.hide_modpackcontents = false
-               end
-
-               filterlist.set_filtercriteria(modmgr.modlist,current)
-       end
-
-       if fields["btn_config_world_save"] then
-               local worldspec = engine.get_worlds()[modmgr.world_config_selected_world]
-
-               local filename = worldspec.path ..
-                               DIR_DELIM .. "world.mt"
-
-               local worldfile = Settings(filename)
-               local mods = worldfile:to_table()
-
-               local rawlist = filterlist.get_raw_list(modmgr.modlist)
-
-               local i,mod
-               for i,mod in ipairs(rawlist) do
-                       if not mod.is_modpack and
-                                       mod.typ ~= "game_mod" then
-                               if mod.enabled then
-                                       worldfile:set("load_mod_"..mod.name, "true")
-                               else
-                                       worldfile:set("load_mod_"..mod.name, "false")
-                               end
-                               mods["load_mod_"..mod.name] = nil
-                       end
-               end
-
-               -- Remove mods that are not present anymore
-               for key,value in pairs(mods) do
-                       if key:sub(1,9) == "load_mod_" then
-                               worldfile:remove(key)
-                       end
-               end
-
-               if not worldfile:write() then
-                       engine.log("error", "Failed to write world config file")
-               end
-
-               modmgr.modlist = nil
-               modmgr.worldconfig = nil
-
-               return {
-                       is_dialog = false,
-                       show_buttons = true,
-                       current_tab = engine.setting_get("main_menu_tab")
-               }
-       end
-
-       if fields["btn_config_world_cancel"] then
-
-               modmgr.worldconfig = nil
-
-               return {
-                       is_dialog = false,
-                       show_buttons = true,
-                       current_tab = engine.setting_get("main_menu_tab")
-               }
-       end
-
-       if fields["btn_all_mods"] then
-               local list = filterlist.get_raw_list(modmgr.modlist)
-
-               for i=1,#list,1 do
-                       if list[i].typ ~= "game_mod" and
-                               not list[i].is_modpack then
-                               list[i].enabled = true
-                       end
-               end
-       end
-
-
-
-       return nil
-end
---------------------------------------------------------------------------------
-function modmgr.world_config_enable_mod(toset)
-       local mod = filterlist.get_list(modmgr.modlist)
-               [engine.get_textlist_index("world_config_modlist")]
-
-       if mod.typ == "game_mod" then
-               -- game mods can't be enabled or disabled
-       elseif not mod.is_modpack then
-               if toset == nil then
-                       mod.enabled = not mod.enabled
-               else
-                       mod.enabled = toset
-               end
-       else
-               local list = filterlist.get_raw_list(modmgr.modlist)
-               for i=1,#list,1 do
-                       if list[i].modpack == mod.name then
-                               if toset == nil then
-                                       toset = not list[i].enabled
-                               end
-                               list[i].enabled = toset
-                       end
-               end
-       end
-end
---------------------------------------------------------------------------------
-function modmgr.handle_delete_mod_buttons(fields)
-       local mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
-
-       if fields["dlg_delete_mod_confirm"] ~= nil then
-
-               if mod.path ~= nil and
-                       mod.path ~= "" and
-                       mod.path ~= engine.get_modpath() then
-                       if not engine.delete_dir(mod.path) then
-                               gamedata.errormessage = fgettext("Modmgr: failed to delete \"$1\"", mod.path)
-                       end
-                       modmgr.refresh_globals()
-               else
-                       gamedata.errormessage = fgettext("Modmgr: invalid modpath \"$1\"", mod.path)
-               end
-       end
-
-       return {
-               is_dialog = false,
-               show_buttons = true,
-               current_tab = engine.setting_get("main_menu_tab")
-               }
-end
-
---------------------------------------------------------------------------------
-function modmgr.dialog_delete_mod()
-
-       local mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
-
-       local retval =
-               "field[1.75,1;10,3;;" .. fgettext("Are you sure you want to delete \"$1\"?", mod.name) ..  ";]"..
-               "button[4,4.2;1,0.5;dlg_delete_mod_confirm;" .. fgettext("Yes") .. "]" ..
-               "button[6.5,4.2;3,0.5;dlg_delete_mod_cancel;" .. fgettext("No of course not!") .. "]"
-
-       return retval
-end
-
 --------------------------------------------------------------------------------
 function modmgr.preparemodlist(data)
        local retval = {}
@@ -886,7 +399,7 @@ function modmgr.preparemodlist(data)
        local game_mods = {}
 
        --read global mods
-       local modpath = engine.get_modpath()
+       local modpath = core.get_modpath()
 
        if modpath ~= nil and
                modpath ~= "" then
@@ -922,15 +435,16 @@ function modmgr.preparemodlist(data)
                        key = key:sub(10)
                        local element = nil
                        for i=1,#retval,1 do
-                               if retval[i].name == key then
+                               if retval[i].name == key and
+                                       not retval[i].is_modpack then
                                        element = retval[i]
                                        break
                                end
                        end
                        if element ~= nil then
-                               element.enabled = engine.is_yes(value)
+                               element.enabled = core.is_yes(value)
                        else
-                               engine.log("info", "Mod: " .. key .. " " .. dump(value) .. " but not found")
+                               core.log("info", "Mod: " .. key .. " " .. dump(value) .. " but not found")
                        end
                end
        end
@@ -938,58 +452,6 @@ function modmgr.preparemodlist(data)
        return retval
 end
 
---------------------------------------------------------------------------------
-function modmgr.init_worldconfig()
-       modmgr.precheck()
-       local worldspec = engine.get_worlds()[modmgr.world_config_selected_world]
-
-       if worldspec ~= nil then
-               --read worldconfig
-               modmgr.worldconfig = modmgr.get_worldconfig(worldspec.path)
-
-               if modmgr.worldconfig.id == nil or
-                       modmgr.worldconfig.id == "" then
-                       modmgr.worldconfig = nil
-                       return false
-               end
-
-               modmgr.modlist = filterlist.create(
-                                               modmgr.preparemodlist, --refresh
-                                               modmgr.comparemod, --compare
-                                               function(element,uid) --uid match
-                                                       if element.name == uid then
-                                                               return true
-                                                       end
-                                               end,
-                                               function(element,criteria)
-                                                       if criteria.hide_game and
-                                                               element.typ == "game_mod" then
-                                                                       return false
-                                                       end
-
-                                                       if criteria.hide_modpackcontents and
-                                                               element.modpack ~= nil then
-                                                                       return false
-                                                               end
-                                                       return true
-                                               end, --filter
-                                               { worldpath= worldspec.path,
-                                                 gameid = worldspec.gameid }
-                                       )
-
-               filterlist.set_filtercriteria(modmgr.modlist, {
-                                                                       hide_game=modmgr.hide_gamemods,
-                                                                       hide_modpackcontents= modmgr.hide_modpackcontents
-                                                                       })
-               filterlist.add_sort_mechanism(modmgr.modlist, "alphabetic", sort_mod_list)
-               filterlist.set_sortmode(modmgr.modlist, "alphabetic")
-
-               return true
-       end
-
-       return false
-end
-
 --------------------------------------------------------------------------------
 function modmgr.comparemod(elem1,elem2)
        if elem1 == nil or elem2 == nil then
@@ -1015,29 +477,6 @@ function modmgr.comparemod(elem1,elem2)
        return true
 end
 
---------------------------------------------------------------------------------
-function modmgr.gettab(name)
-       local retval = ""
-
-       if name == "mod_mgr" then
-               retval = retval .. modmgr.tab()
-       end
-
-       if name == "dialog_rename_modpack" then
-               retval = retval .. modmgr.dialog_rename_modpack()
-       end
-
-       if name == "dialog_delete_mod" then
-               retval = retval .. modmgr.dialog_delete_mod()
-       end
-
-       if name == "dialog_configure_world" then
-               retval = retval .. modmgr.dialog_configure_world()
-       end
-
-       return retval
-end
-
 --------------------------------------------------------------------------------
 function modmgr.mod_exists(basename)
 
@@ -1045,7 +484,7 @@ function modmgr.mod_exists(basename)
                modmgr.refresh_globals()
        end
 
-       if filterlist.raw_index_by_uid(modmgr.global_mods,basename) > 0 then
+       if modmgr.global_mods:raw_index_by_uid(basename) > 0 then
                return true
        end
 
@@ -1059,11 +498,12 @@ function modmgr.get_global_mod(idx)
                return nil
        end
 
-       if idx == nil or idx < 1 or idx > filterlist.size(modmgr.global_mods) then
+       if idx == nil or idx < 1 or
+               idx > modmgr.global_mods:size() then
                return nil
        end
 
-       return filterlist.get_list(modmgr.global_mods)[idx]
+       return modmgr.global_mods:get_list()[idx]
 end
 
 --------------------------------------------------------------------------------
@@ -1079,8 +519,8 @@ function modmgr.refresh_globals()
                                        nil, --filter
                                        {}
                                        )
-       filterlist.add_sort_mechanism(modmgr.global_mods, "alphabetic", sort_mod_list)
-       filterlist.set_sortmode(modmgr.global_mods, "alphabetic")
+       modmgr.global_mods:add_sort_mechanism("alphabetic", sort_mod_list)
+       modmgr.global_mods:set_sortmode("alphabetic")
 end
 
 --------------------------------------------------------------------------------
diff --git a/builtin/mainmenu/modstore.lua b/builtin/mainmenu/modstore.lua
deleted file mode 100644 (file)
index ef7fd01..0000000
+++ /dev/null
@@ -1,615 +0,0 @@
---Minetest
---Copyright (C) 2013 sapier
---
---This program is free software; you can redistribute it and/or modify
---it under the terms of the GNU Lesser General Public License as published by
---the Free Software Foundation; either version 2.1 of the License, or
---(at your option) any later version.
---
---This program is distributed in the hope that it will be useful,
---but WITHOUT ANY WARRANTY; without even the implied warranty of
---MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
---GNU Lesser General Public License for more details.
---
---You should have received a copy of the GNU Lesser General Public License along
---with this program; if not, write to the Free Software Foundation, Inc.,
---51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
---------------------------------------------------------------------------------
-
---modstore implementation
-modstore = {}
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] init
-function modstore.init()
-       modstore.tabnames = {}
-
-       table.insert(modstore.tabnames,"dialog_modstore_unsorted")
-       table.insert(modstore.tabnames,"dialog_modstore_search")
-
-       modstore.modsperpage = 5
-
-       modstore.basetexturedir = engine.get_texturepath() .. DIR_DELIM .. "base" ..
-                                               DIR_DELIM .. "pack" .. DIR_DELIM
-
-       modstore.lastmodtitle = ""
-       modstore.last_search = ""
-       
-       modstore.searchlist = filterlist.create(
-               function()
-                       if modstore.modlist_unsorted ~= nil and
-                               modstore.modlist_unsorted.data ~= nil then
-                               return modstore.modlist_unsorted.data
-                       end
-                       return {}
-               end,
-               function(element,modid)
-                       if element.id == modid then
-                               return true
-                       end
-                       return false
-               end, --compare fct
-               nil, --uid match fct
-               function(element,substring)
-                       if substring == nil or
-                               substring == "" then
-                               return false
-                       end
-                       substring = substring:upper()
-                       
-                       if element.title ~= nil and
-                               element.title:upper():find(substring) ~= nil then
-                               return true
-                       end
-                       
-                       if element.details ~= nil and
-                               element.details.author ~= nil and
-                               element.details.author:upper():find(substring) ~= nil then
-                               return true
-                       end
-                       
-                       if element.details ~= nil and
-                               element.details.description ~= nil and
-                               element.details.description:upper():find(substring) ~= nil then
-                               return true
-                       end
-                       return false
-               end --filter fct
-               )
-
-       modstore.current_list = nil
-end
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] nametoindex
-function modstore.nametoindex(name)
-
-       for i=1,#modstore.tabnames,1 do
-               if modstore.tabnames[i] == name then
-                       return i
-               end
-       end
-
-       return 1
-end
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] getsuccessfuldialog
-function modstore.getsuccessfuldialog()
-       local retval = ""
-       retval = retval .. "size[6,2,true]"
-       if modstore.lastmodentry ~= nil then
-               retval = retval .. "label[0,0.25;" .. fgettext("Successfully installed:") .. "]"
-               retval = retval .. "label[3,0.25;" .. modstore.lastmodentry.moddetails.title .. "]"
-       
-               
-               retval = retval .. "label[0,0.75;" .. fgettext("Shortname:") .. "]"
-               retval = retval .. "label[3,0.75;" .. engine.formspec_escape(modstore.lastmodentry.moddetails.basename) .. "]"
-
-       end
-       retval = retval .. "button[2.5,1.5;1,0.5;btn_confirm_mod_successfull;" .. fgettext("ok") .. "]"
-                               
-                               
-       return retval
-end
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] gettab
-function modstore.gettab(tabname)
-       local retval = ""
-
-       local is_modstore_tab = false
-
-       if tabname == "dialog_modstore_unsorted" then
-               modstore.modsperpage = 5
-               retval = modstore.getmodlist(modstore.modlist_unsorted)
-               is_modstore_tab = true
-       end
-
-       if tabname == "dialog_modstore_search" then
-               retval = modstore.getsearchpage()
-               is_modstore_tab = true
-       end
-
-       if is_modstore_tab then
-               return modstore.tabheader(tabname) .. retval
-       end
-
-       if tabname == "modstore_mod_installed" then
-               return modstore.getsuccessfuldialog()
-       end
-
-       if tabname == "modstore_downloading" then
-               return "size[6,2]label[0.25,0.75;" .. fgettext("Downloading") ..
-                               " " .. modstore.lastmodtitle .. " " ..
-                               fgettext("please wait...") .. "]"
-       end
-
-       return ""
-end
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] tabheader
-function modstore.tabheader(tabname)
-       local retval  = "size[12,10.25,true]"
-       retval = retval .. "tabheader[-0.3,-0.99;modstore_tab;" ..
-                               "Unsorted,Search;" ..
-                               modstore.nametoindex(tabname) .. ";true;false]" ..
-                               "button[4,9.9;4,0.5;btn_modstore_close;" ..
-                               fgettext("Close modstore") .. "]"
-
-       return retval
-end
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] handle_buttons
-function modstore.handle_buttons(current_tab,fields)
-
-       if fields["modstore_tab"] then
-               local index = tonumber(fields["modstore_tab"])
-
-               if index > 0 and
-                       index <= #modstore.tabnames then
-                       if modstore.tabnames[index] == "dialog_modstore_search" then
-                               filterlist.set_filtercriteria(modstore.searchlist,modstore.last_search)
-                               filterlist.refresh(modstore.searchlist)
-                               modstore.modsperpage = 4
-                               modstore.currentlist = {
-                                       page = 0,
-                                       pagecount =
-                                               math.ceil(filterlist.size(modstore.searchlist) / modstore.modsperpage),
-                                       data = filterlist.get_list(modstore.searchlist),
-                               }
-                       end
-                       
-                       return {
-                                       current_tab = modstore.tabnames[index],
-                                       is_dialog = true,
-                                       show_buttons = false
-                       }
-               end
-               
-       end
-
-       if fields["btn_modstore_page_up"] then
-               if modstore.current_list ~= nil and modstore.current_list.page > 0 then
-                       modstore.current_list.page = modstore.current_list.page - 1
-               end
-       end
-
-       if fields["btn_modstore_page_down"] then
-               if modstore.current_list ~= nil and
-                       modstore.current_list.page <modstore.current_list.pagecount-1 then
-                       modstore.current_list.page = modstore.current_list.page +1
-               end
-       end
-
-       if fields["btn_hidden_close_download"] ~= nil then
-               if fields["btn_hidden_close_download"].successfull then
-                       modstore.lastmodentry = fields["btn_hidden_close_download"]
-                       return {
-                                       current_tab = "modstore_mod_installed",
-                                       is_dialog = true,
-                                       show_buttons = false
-                       }
-               else
-                       modstore.lastmodtitle = ""
-                       return {
-                                               current_tab = modstore.tabnames[1],
-                                               is_dialog = true,
-                                               show_buttons = false
-                               }
-               end
-       end
-
-       if fields["btn_confirm_mod_successfull"] then
-               modstore.lastmodentry = nil
-               modstore.lastmodtitle = ""
-               return {
-                                       current_tab = modstore.tabnames[1],
-                                       is_dialog = true,
-                                       show_buttons = false
-                       }
-       end
-
-       if fields["btn_modstore_search"] or
-               (fields["key_enter"] and fields["te_modstore_search"] ~= nil) then
-               modstore.last_search = fields["te_modstore_search"]
-               filterlist.set_filtercriteria(modstore.searchlist,fields["te_modstore_search"])
-               filterlist.refresh(modstore.searchlist)
-               modstore.currentlist = {
-                       page = 0,
-                       pagecount =  math.ceil(filterlist.size(modstore.searchlist) / modstore.modsperpage),
-                       data = filterlist.get_list(modstore.searchlist),
-               }
-       end
-       
-       
-       if fields["btn_modstore_close"] then
-               return {
-                       is_dialog = false,
-                       show_buttons = true,
-                       current_tab = engine.setting_get("main_menu_tab")
-               }
-       end
-       
-       for key,value in pairs(fields) do
-               local foundat = key:find("btn_install_mod_")
-               if ( foundat == 1) then
-                       local modid = tonumber(key:sub(17))
-                       for i=1,#modstore.modlist_unsorted.data,1 do
-                               if modstore.modlist_unsorted.data[i].id == modid then
-                                       local moddetails = modstore.modlist_unsorted.data[i].details
-
-                                       if modstore.lastmodtitle ~= "" then
-                                               modstore.lastmodtitle = modstore.lastmodtitle .. ", "
-                                       end
-       
-                                       modstore.lastmodtitle = modstore.lastmodtitle .. moddetails.title
-       
-                                       engine.handle_async(
-                                               function(param)
-                                               
-                                                       local fullurl = engine.setting_get("modstore_download_url") ..
-                                                                                       param.moddetails.download_url
-                                                                                       
-                                                       if param.version ~= nil then
-                                                               local found = false
-                                                               for i=1,#param.moddetails.versions, 1 do
-                                                                       if param.moddetails.versions[i].date:sub(1,10) == param.version then
-                                                                               fullurl = engine.setting_get("modstore_download_url") ..
-                                                                                                               param.moddetails.versions[i].download_url
-                                                                               found = true
-                                                                       end
-                                                               end
-                                                               
-                                                               if not found then
-                                                                       return {
-                                                                               moddetails = param.moddetails,
-                                                                               successfull = false
-                                                                       }
-                                                               end
-                                                       end
-       
-                                                       if engine.download_file(fullurl,param.filename) then
-                                                               return {
-                                                                       texturename = param.texturename,
-                                                                       moddetails = param.moddetails,
-                                                                       filename = param.filename,
-                                                                       successfull = true
-                                                               }
-                                                       else
-                                                               return {
-                                                                       moddetails = param.moddetails,
-                                                                       successfull = false
-                                                               }
-                                                       end
-                                               end,
-                                               {
-                                                       moddetails = moddetails,
-                                                       version = fields["dd_version" .. modid],
-                                                       filename = os.tempfolder() .. "_MODNAME_" .. moddetails.basename .. ".zip",
-                                                       texturename = modstore.modlist_unsorted.data[i].texturename
-                                               },
-                                               function(result)
-                                                       if result.successfull then
-                                                               modmgr.installmod(result.filename,result.moddetails.basename)
-                                                               os.remove(result.filename)
-                                                       else
-                                                               gamedata.errormessage = "Failed to download " .. result.moddetails.title
-                                                       end
-       
-                                                       if gamedata.errormessage == nil then
-                                                               engine.button_handler({btn_hidden_close_download=result})
-                                                       else
-                                                               engine.button_handler({btn_hidden_close_download={successfull=false}})
-                                                       end
-                                               end
-                                       )
-       
-                                       return {
-                                               current_tab = "modstore_downloading",
-                                               is_dialog = true,
-                                               show_buttons = false,
-                                               ignore_menu_quit = true
-                                       }
-                               end
-                       end
-                       break
-               end
-       end
-end
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] update_modlist
-function modstore.update_modlist()
-       modstore.modlist_unsorted = {}
-       modstore.modlist_unsorted.data = {}
-       modstore.modlist_unsorted.pagecount = 1
-       modstore.modlist_unsorted.page = 0
-
-       engine.handle_async(
-               function(param)
-                       return engine.get_modstore_list()
-               end,
-               nil,
-               function(result)
-                       if result ~= nil then
-                               modstore.modlist_unsorted = {}
-                               modstore.modlist_unsorted.data = result
-
-                               if modstore.modlist_unsorted.data ~= nil then
-                                       modstore.modlist_unsorted.pagecount =
-                                               math.ceil((#modstore.modlist_unsorted.data / modstore.modsperpage))
-                               else
-                                       modstore.modlist_unsorted.data = {}
-                                       modstore.modlist_unsorted.pagecount = 1
-                               end
-                               modstore.modlist_unsorted.page = 0
-                               modstore.fetchdetails()
-                               engine.event_handler("Refresh")
-                       end
-               end
-       )
-end
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] fetchdetails
-function modstore.fetchdetails()
-
-       for i=1,#modstore.modlist_unsorted.data,1 do
-               engine.handle_async(
-               function(param)
-                       param.details = engine.get_modstore_details(tostring(param.modid))
-                       return param
-               end,
-               {
-                       modid=modstore.modlist_unsorted.data[i].id,
-                       listindex=i
-               },
-               function(result)
-                       if result ~= nil and
-                               modstore.modlist_unsorted ~= nil
-                               and modstore.modlist_unsorted.data ~= nil and
-                               modstore.modlist_unsorted.data[result.listindex] ~= nil and
-                               modstore.modlist_unsorted.data[result.listindex].id ~= nil then
-
-                               modstore.modlist_unsorted.data[result.listindex].details = result.details
-                               engine.event_handler("Refresh")
-                       end
-               end
-               )
-       end
-end
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] getscreenshot
-function modstore.getscreenshot(ypos,listentry)
-
-       if      listentry.details ~= nil and
-               (listentry.details.screenshot_url == nil or
-               listentry.details.screenshot_url == "") then
-               
-               if listentry.texturename == nil then
-                       listentry.texturename = modstore.basetexturedir .. "no_screenshot.png"
-               end
-               
-               return "image[0,".. ypos .. ";3,2;" ..
-                       engine.formspec_escape(listentry.texturename) .. "]"
-       end
-       
-       if listentry.details ~= nil and
-               listentry.texturename == nil then
-               --make sure we don't download multiple times
-               listentry.texturename = "in progress"
-       
-               --prepare url and filename
-               local fullurl = engine.setting_get("modstore_download_url") ..
-                                       listentry.details.screenshot_url
-               local filename = os.tempfolder() .. "_MID_" .. listentry.id
-               
-               --trigger download
-               engine.handle_async(
-                       --first param is downloadfct
-                       function(param)
-                               param.successfull = engine.download_file(param.fullurl,param.filename)
-                               return param
-                       end,
-                       --second parameter is data passed to async job
-                       {
-                               fullurl = fullurl,
-                               filename = filename,
-                               modid = listentry.id
-                       },
-                       --integrate result to raw list
-                       function(result)
-                               if result.successfull then
-                                       local found = false
-                                       for i=1,#modstore.modlist_unsorted.data,1 do
-                                               if modstore.modlist_unsorted.data[i].id == result.modid then
-                                                       found = true
-                                                       modstore.modlist_unsorted.data[i].texturename = result.filename
-                                                       break
-                                               end
-                                       end
-                                       if found then
-                                               engine.event_handler("Refresh")
-                                       else
-                                               engine.log("error","got screenshot but didn't find matching mod: " .. result.modid)
-                                       end
-                               end
-                       end
-               )
-       end
-
-       if listentry.texturename ~= nil and
-               listentry.texturename ~= "in progress" then
-               return "image[0,".. ypos .. ";3,2;" ..
-                       engine.formspec_escape(listentry.texturename) .. "]"
-       end
-       
-       return ""
-end
-
---------------------------------------------------------------------------------
---@function [parent=#modstore] getshortmodinfo
-function modstore.getshortmodinfo(ypos,listentry,details)
-       local retval = ""
-       
-       retval = retval .. "box[0," .. ypos .. ";11.4,1.75;#FFFFFF]"
-
-       --screenshot
-       retval = retval .. modstore.getscreenshot(ypos,listentry)
-
-       --title + author
-       retval = retval .."label[2.75," .. ypos .. ";" ..
-               engine.formspec_escape(details.title) .. " (" .. details.author .. ")]"
-
-       --description
-       local descriptiony = ypos + 0.5
-       retval = retval .. "textarea[3," .. descriptiony .. ";6.5,1.55;;" ..
-               engine.formspec_escape(details.description) .. ";]"
-               
-       --rating
-       local ratingy = ypos
-       retval = retval .."label[7," .. ratingy .. ";" ..
-                                       fgettext("Rating") .. ":]"
-       retval = retval .. "label[8.7," .. ratingy .. ";" .. details.rating .."]"
-       
-       --versions (IMPORTANT has to be defined AFTER rating)
-       if details.versions ~= nil and
-               #details.versions > 1 then
-               local versiony = ypos + 0.05
-               retval = retval .. "dropdown[9.1," .. versiony .. ";2.48,0.25;dd_version" .. details.id .. ";"
-               local versions = ""
-               for i=1,#details.versions , 1 do
-                       if versions ~= "" then
-                               versions = versions .. ","
-                       end
-                       
-                       versions = versions .. details.versions[i].date:sub(1,10)
-               end
-               retval = retval .. versions .. ";1]"
-       end
-
-       if details.basename then
-               --install button
-               local buttony = ypos + 1.2
-               retval = retval .."button[9.1," .. buttony .. ";2.5,0.5;btn_install_mod_" .. details.id .. ";"
-
-               if modmgr.mod_exists(details.basename) then
-                       retval = retval .. fgettext("re-Install") .."]"
-               else
-                       retval = retval .. fgettext("Install") .."]"
-               end
-       end
-       
-       return retval
-end
-
---------------------------------------------------------------------------------
---@function [parent=#modstore] getmodlist
-function modstore.getmodlist(list,yoffset)
-
-       modstore.current_list = list
-       
-       if #list.data == 0 then
-               return ""
-       end
-       
-       if yoffset == nil then
-               yoffset = 0
-       end
-
-       local scrollbar = ""
-       scrollbar = scrollbar .. "label[0.1,9.5;"
-                               .. fgettext("Page $1 of $2", list.page+1, list.pagecount) .. "]"
-       scrollbar = scrollbar .. "box[11.6," .. (yoffset + 0.35) .. ";0.28,"
-                               .. (8.6 - yoffset) .. ";#000000]"
-       local scrollbarpos = (yoffset + 0.75) +
-                               ((7.7 -yoffset)/(list.pagecount-1)) * list.page
-       scrollbar = scrollbar .. "box[11.6," ..scrollbarpos .. ";0.28,0.5;#32CD32]"
-       scrollbar = scrollbar .. "button[11.6," .. (yoffset + (0.3))
-                               .. ";0.5,0.5;btn_modstore_page_up;^]"
-       scrollbar = scrollbar .. "button[11.6," .. 9.0
-                               .. ";0.5,0.5;btn_modstore_page_down;v]"
-
-       local retval = ""
-
-       local endmod = (list.page * modstore.modsperpage) + modstore.modsperpage
-
-       if (endmod > #list.data) then
-               endmod = #list.data
-       end
-
-       for i=(list.page * modstore.modsperpage) +1, endmod, 1 do
-               --getmoddetails
-               local details = list.data[i].details
-
-               if details == nil then
-                       details = {}
-                       details.title = list.data[i].title
-                       details.author = ""
-                       details.rating = -1
-                       details.description = ""
-               end
-
-               if details ~= nil then
-                       local screenshot_ypos =
-                               yoffset +(i-1 - (list.page * modstore.modsperpage))*1.9 +0.2
-                               
-                       retval = retval .. modstore.getshortmodinfo(screenshot_ypos,
-                                                                                                               list.data[i],
-                                                                                                               details)
-               end
-       end
-       
-       return retval .. scrollbar
-end
-
---------------------------------------------------------------------------------
---@function [parent=#modstore] getsearchpage
-function modstore.getsearchpage()
-       local retval = ""
-       local search = ""
-       
-       if modstore.last_search ~= nil then
-               search = modstore.last_search
-       end
-
-       retval = retval ..
-               "button[9.5,0.2;2.5,0.5;btn_modstore_search;".. fgettext("Search") .. "]" ..
-               "field[0.5,0.5;9,0.5;te_modstore_search;;" .. search .. "]"
-
-       
-       --show 4 mods only
-       modstore.modsperpage = 4
-       retval = retval ..
-               modstore.getmodlist(
-                       modstore.currentlist,
-                       1.75)
-
-       return retval;
-end
-
diff --git a/builtin/mainmenu/store.lua b/builtin/mainmenu/store.lua
new file mode 100644 (file)
index 0000000..48433e5
--- /dev/null
@@ -0,0 +1,618 @@
+--Minetest
+--Copyright (C) 2013 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+--------------------------------------------------------------------------------
+
+--modstore implementation
+modstore = {}
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] init
+function modstore.init(size, unsortedmods, searchmods)
+
+       modstore.mods_on_unsorted_page = unsortedmods
+       modstore.mods_on_search_page = searchmods
+       modstore.modsperpage = modstore.mods_on_unsorted_page
+
+       modstore.basetexturedir = core.get_texturepath() .. DIR_DELIM .. "base" ..
+                                               DIR_DELIM .. "pack" .. DIR_DELIM
+
+       modstore.lastmodtitle = ""
+       modstore.last_search = ""
+
+       modstore.searchlist = filterlist.create(
+               function()
+                       if modstore.modlist_unsorted ~= nil and
+                               modstore.modlist_unsorted.data ~= nil then
+                               return modstore.modlist_unsorted.data
+                       end
+                       return {}
+               end,
+               function(element,modid)
+                       if element.id == modid then
+                               return true
+                       end
+                       return false
+               end, --compare fct
+               nil, --uid match fct
+               function(element,substring)
+                       if substring == nil or
+                               substring == "" then
+                               return false
+                       end
+                       substring = substring:upper()
+
+                       if element.title ~= nil and
+                               element.title:upper():find(substring) ~= nil then
+                               return true
+                       end
+
+                       if element.details ~= nil and
+                               element.details.author ~= nil and
+                               element.details.author:upper():find(substring) ~= nil then
+                               return true
+                       end
+
+                       if element.details ~= nil and
+                               element.details.description ~= nil and
+                               element.details.description:upper():find(substring) ~= nil then
+                               return true
+                       end
+                       return false
+               end --filter fct
+               )
+
+       modstore.current_list = nil
+
+       modstore.tv_store = tabview_create("modstore",size,{x=-0.3,y=-0.99})
+       
+       modstore.tv_store:set_global_event_handler(modstore.handle_events)
+
+       modstore.tv_store:add(
+               {
+               name = "unsorted",
+               caption = fgettext("Unsorted"),
+               cbf_formspec       = modstore.unsorted_tab,
+               cbf_button_handler = modstore.handle_buttons,
+               on_change          =
+                       function() modstore.modsperpage = modstore.mods_on_unsorted_page end
+               }
+       )
+
+       modstore.tv_store:add(
+               {
+               name = "search",
+               caption            = fgettext("Search"),
+               cbf_formspec       = modstore.getsearchpage,
+               cbf_button_handler = modstore.handle_buttons,
+               on_change          = modstore.activate_search_tab
+               }
+       )
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] nametoindex
+function modstore.nametoindex(name)
+
+       for i=1,#modstore.tabnames,1 do
+               if modstore.tabnames[i] == name then
+                       return i
+               end
+       end
+
+       return 1
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] showdownloading
+function modstore.showdownloading(title)
+       local new_dlg = dialog_create("store_downloading",
+               function(data)
+                       return "size[6,2]label[0.25,0.75;" .. fgettext("Downloading") ..
+                               " " .. data.title .. " " ..
+                               fgettext("please wait...") .. "]"
+               end,
+               function(this,fields)
+                       if fields["btn_hidden_close_download"] ~= nil then
+                               if fields["btn_hidden_close_download"].successfull then
+                                       modstore.lastmodentry = fields["btn_hidden_close_download"]
+                                       modstore.successfulldialog()
+                               else
+                                       modstore.lastmodtitle = ""
+                               end
+
+                               this:delete()
+                               return true
+                       end
+
+                       return false
+               end,
+               nil,
+               modstore.tv_store)
+
+       new_dlg.data.title = title
+       new_dlg:show()
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] successfulldialog
+function modstore.successfulldialog()
+       local new_dlg = dialog_create("store_downloading",
+               function(data)
+                       local retval = ""
+                       retval = retval .. "size[6,2,true]"
+                       if modstore.lastmodentry ~= nil then
+                               retval = retval .. "label[0,0.25;" .. fgettext("Successfully installed:") .. "]"
+                               retval = retval .. "label[3,0.25;" .. modstore.lastmodentry.moddetails.title .. "]"
+
+
+                               retval = retval .. "label[0,0.75;" .. fgettext("Shortname:") .. "]"
+                               retval = retval .. "label[3,0.75;" .. core.formspec_escape(modstore.lastmodentry.moddetails.basename) .. "]"
+
+                       end
+                       retval = retval .. "button[2.5,1.5;1,0.5;btn_confirm_mod_successfull;" .. fgettext("ok") .. "]"
+               end,
+               function(this,fields)
+                       if fields["btn_confirm_mod_successfull"] ~= nil then
+                               this.parent:show()
+                               this:hide()
+                               this:delete()
+
+                               return true
+                       end
+
+                       return false
+               end,
+               nil,
+               modstore.tv_store)
+
+       new_dlg.data.title = title
+       new_dlg:show()
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] handle_buttons
+function modstore.handle_buttons(parent, fields, name, data)
+
+       if fields["btn_modstore_page_up"] then
+               if modstore.current_list ~= nil and modstore.current_list.page > 0 then
+                       modstore.current_list.page = modstore.current_list.page - 1
+               end
+               return true
+       end
+
+       if fields["btn_modstore_page_down"] then
+               if modstore.current_list ~= nil and
+                       modstore.current_list.page <modstore.current_list.pagecount-1 then
+                       modstore.current_list.page = modstore.current_list.page +1
+               end
+               return true
+       end
+
+       if fields["btn_modstore_search"] or
+               (fields["key_enter"] and fields["te_modstore_search"] ~= nil) then
+               modstore.last_search = fields["te_modstore_search"]
+               filterlist.set_filtercriteria(modstore.searchlist,fields["te_modstore_search"])
+               filterlist.refresh(modstore.searchlist)
+               modstore.currentlist = {
+                       page = 0,
+                       pagecount =  math.ceil(filterlist.size(modstore.searchlist) / modstore.modsperpage),
+                       data = filterlist.get_list(modstore.searchlist),
+               }
+               return true
+       end
+
+       if fields["btn_modstore_close"] then
+               parent:hide()
+               return true
+       end
+
+       for key,value in pairs(fields) do
+               local foundat = key:find("btn_install_mod_")
+               if ( foundat == 1) then
+                       local modid = tonumber(key:sub(17))
+                       for i=1,#modstore.modlist_unsorted.data,1 do
+                               if modstore.modlist_unsorted.data[i].id == modid then
+                                       local moddetails = modstore.modlist_unsorted.data[i].details
+
+                                       if modstore.lastmodtitle ~= "" then
+                                               modstore.lastmodtitle = modstore.lastmodtitle .. ", "
+                                       end
+
+                                       modstore.lastmodtitle = modstore.lastmodtitle .. moddetails.title
+
+                                       if not core.handle_async(
+                                               function(param)
+                                                       local fullurl = core.setting_get("modstore_download_url") ..
+                                                                                       param.moddetails.download_url
+
+                                                       if param.version ~= nil then
+                                                               local found = false
+                                                               for i=1,#param.moddetails.versions, 1 do
+                                                                       if param.moddetails.versions[i].date:sub(1,10) == param.version then
+                                                                               fullurl = core.setting_get("modstore_download_url") ..
+                                                                                                               param.moddetails.versions[i].download_url
+                                                                               found = true
+                                                                       end
+                                                               end
+
+                                                               if not found then
+                                                                       core.log("error","no download url found for version " .. dump(param.version))
+                                                                       return {
+                                                                               moddetails = param.moddetails,
+                                                                               successfull = false
+                                                                       }
+                                                               end
+                                                       end
+
+                                                       if core.download_file(fullurl,param.filename) then
+                                                               return {
+                                                                       texturename = param.texturename,
+                                                                       moddetails = param.moddetails,
+                                                                       filename = param.filename,
+                                                                       successfull = true
+                                                               }
+                                                       else
+                                                               core.log("error","downloading " .. dump(fullurl) .. " failed")
+                                                               return {
+                                                                       moddetails = param.moddetails,
+                                                                       successfull = false
+                                                               }
+                                                       end
+                                               end,
+                                               {
+                                                       moddetails = moddetails,
+                                                       version = fields["dd_version" .. modid],
+                                                       filename = os.tempfolder() .. "_MODNAME_" .. moddetails.basename .. ".zip",
+                                                       texturename = modstore.modlist_unsorted.data[i].texturename
+                                               },
+                                               function(result)
+                                                       print("Result from async: " .. dump(result.successfull))
+                                                       if result.successfull then
+                                                               modmgr.installmod(result.filename,result.moddetails.basename)
+                                                               os.remove(result.filename)
+                                                       else
+                                                               gamedata.errormessage = "Failed to download " .. result.moddetails.title
+                                                       end
+
+                                                       if gamedata.errormessage == nil then
+                                                               core.button_handler({btn_hidden_close_download=result})
+                                                       else
+                                                               core.button_handler({btn_hidden_close_download={successfull=false}})
+                                                       end
+                                               end
+                                       ) then
+                                               print("ERROR: async event failed")
+                                               gamedata.errormessage = "Failed to download " .. modstore.lastmodtitle
+                                       end
+                                       parent:hide()
+                                       modstore.showdownloading(modstore.lastmodtitle)
+                                       return true
+                               end
+                       end
+                       return true
+               end
+       end
+       
+       return false
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] handle_events
+function modstore.handle_events(this,event)
+       if (event == "MenuQuit") then
+               this:hide()
+               return true
+       end
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] update_modlist
+function modstore.update_modlist()
+       modstore.modlist_unsorted = {}
+       modstore.modlist_unsorted.data = {}
+       modstore.modlist_unsorted.pagecount = 1
+       modstore.modlist_unsorted.page = 0
+
+       core.handle_async(
+               function(param)
+                       return core.get_modstore_list()
+               end,
+               nil,
+               function(result)
+                       if result ~= nil then
+                               modstore.modlist_unsorted = {}
+                               modstore.modlist_unsorted.data = result
+
+                               if modstore.modlist_unsorted.data ~= nil then
+                                       modstore.modlist_unsorted.pagecount =
+                                               math.ceil((#modstore.modlist_unsorted.data / modstore.modsperpage))
+                               else
+                                       modstore.modlist_unsorted.data = {}
+                                       modstore.modlist_unsorted.pagecount = 1
+                               end
+                               modstore.modlist_unsorted.page = 0
+                               modstore.fetchdetails()
+                               core.event_handler("Refresh")
+                       end
+               end
+       )
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] fetchdetails
+function modstore.fetchdetails()
+
+       for i=1,#modstore.modlist_unsorted.data,1 do
+               core.handle_async(
+               function(param)
+                       param.details = core.get_modstore_details(tostring(param.modid))
+                       return param
+               end,
+               {
+                       modid=modstore.modlist_unsorted.data[i].id,
+                       listindex=i
+               },
+               function(result)
+                       if result ~= nil and
+                               modstore.modlist_unsorted ~= nil
+                               and modstore.modlist_unsorted.data ~= nil and
+                               modstore.modlist_unsorted.data[result.listindex] ~= nil and
+                               modstore.modlist_unsorted.data[result.listindex].id ~= nil then
+
+                               modstore.modlist_unsorted.data[result.listindex].details = result.details
+                               core.event_handler("Refresh")
+                       end
+               end
+               )
+       end
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] getscreenshot
+function modstore.getscreenshot(ypos,listentry)
+
+       if      listentry.details ~= nil and
+               (listentry.details.screenshot_url == nil or
+               listentry.details.screenshot_url == "") then
+
+               if listentry.texturename == nil then
+                       listentry.texturename = modstore.basetexturedir .. "no_screenshot.png"
+               end
+
+               return "image[0,".. ypos .. ";3,2;" ..
+                       core.formspec_escape(listentry.texturename) .. "]"
+       end
+
+       if listentry.details ~= nil and
+               listentry.texturename == nil then
+               --make sure we don't download multiple times
+               listentry.texturename = "in progress"
+
+               --prepare url and filename
+               local fullurl = core.setting_get("modstore_download_url") ..
+                                       listentry.details.screenshot_url
+               local filename = os.tempfolder() .. "_MID_" .. listentry.id
+
+               --trigger download
+               core.handle_async(
+                       --first param is downloadfct
+                       function(param)
+                               param.successfull = core.download_file(param.fullurl,param.filename)
+                               return param
+                       end,
+                       --second parameter is data passed to async job
+                       {
+                               fullurl = fullurl,
+                               filename = filename,
+                               modid = listentry.id
+                       },
+                       --integrate result to raw list
+                       function(result)
+                               if result.successfull then
+                                       local found = false
+                                       for i=1,#modstore.modlist_unsorted.data,1 do
+                                               if modstore.modlist_unsorted.data[i].id == result.modid then
+                                                       found = true
+                                                       modstore.modlist_unsorted.data[i].texturename = result.filename
+                                                       break
+                                               end
+                                       end
+                                       if found then
+                                               core.event_handler("Refresh")
+                                       else
+                                               core.log("error","got screenshot but didn't find matching mod: " .. result.modid)
+                                       end
+                               end
+                       end
+               )
+       end
+
+       if listentry.texturename ~= nil and
+               listentry.texturename ~= "in progress" then
+               return "image[0,".. ypos .. ";3,2;" ..
+                       core.formspec_escape(listentry.texturename) .. "]"
+       end
+
+       return ""
+end
+
+--------------------------------------------------------------------------------
+--@function [parent=#modstore] getshortmodinfo
+function modstore.getshortmodinfo(ypos,listentry,details)
+       local retval = ""
+
+       retval = retval .. "box[0," .. ypos .. ";11.4,1.75;#FFFFFF]"
+
+       --screenshot
+       retval = retval .. modstore.getscreenshot(ypos,listentry)
+
+       --title + author
+       retval = retval .."label[2.75," .. ypos .. ";" ..
+               core.formspec_escape(details.title) .. " (" .. details.author .. ")]"
+
+       --description
+       local descriptiony = ypos + 0.5
+       retval = retval .. "textarea[3," .. descriptiony .. ";6.5,1.55;;" ..
+               core.formspec_escape(details.description) .. ";]"
+
+       --rating
+       local ratingy = ypos
+       retval = retval .."label[7," .. ratingy .. ";" ..
+                                       fgettext("Rating") .. ":]"
+       retval = retval .. "label[8.7," .. ratingy .. ";" .. details.rating .."]"
+
+       --versions (IMPORTANT has to be defined AFTER rating)
+       if details.versions ~= nil and
+               #details.versions > 1 then
+               local versiony = ypos + 0.05
+               retval = retval .. "dropdown[9.1," .. versiony .. ";2.48,0.25;dd_version" .. details.id .. ";"
+               local versions = ""
+               for i=1,#details.versions , 1 do
+                       if versions ~= "" then
+                               versions = versions .. ","
+                       end
+
+                       versions = versions .. details.versions[i].date:sub(1,10)
+               end
+               retval = retval .. versions .. ";1]"
+       end
+
+       if details.basename then
+               --install button
+               local buttony = ypos + 1.2
+               retval = retval .."button[9.1," .. buttony .. ";2.5,0.5;btn_install_mod_" .. details.id .. ";"
+
+               if modmgr.mod_exists(details.basename) then
+                       retval = retval .. fgettext("re-Install") .."]"
+               else
+                       retval = retval .. fgettext("Install") .."]"
+               end
+       end
+
+       return retval
+end
+
+--------------------------------------------------------------------------------
+--@function [parent=#modstore] getmodlist
+function modstore.getmodlist(list,yoffset)
+       modstore.current_list = list
+
+       if yoffset == nil then
+               yoffset = 0
+       end
+
+       local sb_y_start = 0.2 + yoffset
+       local sb_y_end   = (modstore.modsperpage * 1.75) + ((modstore.modsperpage-1) * 0.15)
+       local close_button = "button[4," .. (sb_y_end + 0.3 + yoffset) ..
+                       ";4,0.5;btn_modstore_close;" .. fgettext("Close store") .. "]"
+
+       if #list.data == 0 then
+               return close_button
+       end
+
+       local scrollbar = ""
+       scrollbar = scrollbar .. "label[0.1,".. (sb_y_end + 0.25 + yoffset) ..";"
+                               .. fgettext("Page $1 of $2", list.page+1, list.pagecount) .. "]"
+       scrollbar = scrollbar .. "box[11.6," .. sb_y_start .. ";0.28," .. sb_y_end .. ";#000000]"
+       local scrollbarpos = (sb_y_start + 0.5) +
+                               ((sb_y_end -1.6)/(list.pagecount-1)) * list.page
+       scrollbar = scrollbar .. "box[11.6," ..scrollbarpos .. ";0.28,0.5;#32CD32]"
+       scrollbar = scrollbar .. "button[11.6," .. (sb_y_start)
+                               .. ";0.5,0.5;btn_modstore_page_up;^]"
+       scrollbar = scrollbar .. "button[11.6," .. (sb_y_start + sb_y_end - 0.5)
+                               .. ";0.5,0.5;btn_modstore_page_down;v]"
+
+       local retval = ""
+
+       local endmod = (list.page * modstore.modsperpage) + modstore.modsperpage
+
+       if (endmod > #list.data) then
+               endmod = #list.data
+       end
+
+       for i=(list.page * modstore.modsperpage) +1, endmod, 1 do
+               --getmoddetails
+               local details = list.data[i].details
+
+               if details == nil then
+                       details = {}
+                       details.title = list.data[i].title
+                       details.author = ""
+                       details.rating = -1
+                       details.description = ""
+               end
+
+               if details ~= nil then
+                       local screenshot_ypos =
+                               yoffset +(i-1 - (list.page * modstore.modsperpage))*1.9 +0.2
+
+                       retval = retval .. modstore.getshortmodinfo(screenshot_ypos,
+                                                                                                               list.data[i],
+                                                                                                               details)
+               end
+       end
+
+       return retval .. scrollbar .. close_button
+end
+
+--------------------------------------------------------------------------------
+--@function [parent=#modstore] getsearchpage
+function modstore.getsearchpage(tabview, name, tabdata)
+       local retval = ""
+       local search = ""
+
+       if modstore.last_search ~= nil then
+               search = modstore.last_search
+       end
+
+       retval = retval ..
+               "button[9.5,0.2;2.5,0.5;btn_modstore_search;".. fgettext("Search") .. "]" ..
+               "field[0.5,0.5;9,0.5;te_modstore_search;;" .. search .. "]"
+
+       retval = retval ..
+               modstore.getmodlist(
+                       modstore.currentlist,
+                       1.75)
+
+       return retval;
+end
+
+--------------------------------------------------------------------------------
+--@function [parent=#modstore] unsorted_tab
+function modstore.unsorted_tab()
+       return modstore.getmodlist(modstore.modlist_unsorted)
+end
+
+--------------------------------------------------------------------------------
+--@function [parent=#modstore] activate_search_tab
+function modstore.activate_search_tab(type, old_tab, new_tab)
+
+       if old_tab == new_tab then
+               return
+       end
+       filterlist.set_filtercriteria(modstore.searchlist,modstore.last_search)
+       filterlist.refresh(modstore.searchlist)
+       modstore.modsperpage = modstore.mods_on_search_page
+       modstore.currentlist = {
+               page = 0,
+               pagecount =
+                       math.ceil(filterlist.size(modstore.searchlist) / modstore.modsperpage),
+               data = filterlist.get_list(modstore.searchlist),
+       }
+end
+
diff --git a/builtin/mainmenu/tab_credits.lua b/builtin/mainmenu/tab_credits.lua
new file mode 100644 (file)
index 0000000..f752d17
--- /dev/null
@@ -0,0 +1,62 @@
+--Minetest
+--Copyright (C) 2013 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+--------------------------------------------------------------------------------
+
+tab_credits = {
+       name = "credits",
+       caption = fgettext("Credits"),
+       cbf_formspec = function (tabview, name, tabdata)
+                       local logofile = defaulttexturedir .. "logo.png"
+                       return  "vertlabel[0,-0.5;CREDITS]" ..
+                               "label[0.5,3;Minetest " .. core.get_version() .. "]" ..
+                               "label[0.5,3.3;http://minetest.net]" ..
+                               "image[0.5,1;" .. core.formspec_escape(logofile) .. "]" ..
+                               "textlist[3.5,-0.25;8.5,5.8;list_credits;" ..
+                               "#FFFF00" .. fgettext("Core Developers") .."," ..
+                               "Perttu Ahola (celeron55) <celeron55@gmail.com>,"..
+                               "Ryan Kwolek (kwolekr) <kwolekr@minetest.net>,"..
+                               "PilzAdam <pilzadam@minetest.net>," ..
+                               "Ilya Zhuravlev (xyz) <xyz@minetest.net>,"..
+                               "Lisa Milne (darkrose) <lisa@ltmnet.com>,"..
+                               "Maciej Kasatkin (RealBadAngel) <mk@realbadangel.pl>,"..
+                               "proller <proler@gmail.com>,"..
+                               "sfan5 <sfan5@live.de>,"..
+                               "kahrl <kahrl@gmx.net>,"..
+                               "sapier,"..
+                               "ShadowNinja <shadowninja@minetest.net>,"..
+                               "Nathanael Courant (Nore/Novatux) <nore@mesecons.net>,"..
+                               "BlockMen,"..
+                               ","..
+                               "#FFFF00" .. fgettext("Active Contributors") .. "," ..
+                               "Vanessa Ezekowitz (VanessaE) <vanessaezekowitz@gmail.com>,"..
+                               "Jurgen Doser (doserj) <jurgen.doser@gmail.com>,"..
+                               "Jeija <jeija@mesecons.net>,"..
+                               "MirceaKitsune <mirceakitsune@gmail.com>,"..
+                               "dannydark <the_skeleton_of_a_child@yahoo.co.uk>,"..
+                               "0gb.us <0gb.us@0gb.us>,"..
+                               "," ..
+                               "#FFFF00" .. fgettext("Previous Contributors") .. "," ..
+                               "Guiseppe Bilotta (Oblomov) <guiseppe.bilotta@gmail.com>,"..
+                               "Jonathan Neuschafer <j.neuschaefer@gmx.net>,"..
+                               "Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net>,"..
+                               "Constantin Wenger (SpeedProg) <constantin.wenger@googlemail.com>,"..
+                               "matttpt <matttpt@gmail.com>,"..
+                               "JacobF <queatz@gmail.com>,"..
+                               ";0;true]"
+                       end
+       }
diff --git a/builtin/mainmenu/tab_mods.lua b/builtin/mainmenu/tab_mods.lua
new file mode 100644 (file)
index 0000000..b258ce6
--- /dev/null
@@ -0,0 +1,170 @@
+--Minetest
+--Copyright (C) 2014 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+--------------------------------------------------------------------------------
+local function get_formspec(tabview, name, tabdata)
+
+       if modmgr.global_mods == nil then
+               modmgr.refresh_globals()
+       end
+
+       if tabdata.selected_mod == nil then
+               tabdata.selected_mod = 1
+       end
+
+       local retval =
+               "vertlabel[0,-0.25;".. fgettext("MODS") .. "]" ..
+               "label[0.8,-0.25;".. fgettext("Installed Mods:") .. "]" ..
+               "textlist[0.75,0.25;4.5,4;modlist;" ..
+               modmgr.render_modlist(modmgr.global_mods) ..
+               ";" .. tabdata.selected_mod .. "]"
+
+       retval = retval ..
+               "label[0.8,4.2;" .. fgettext("Add mod:") .. "]" ..
+--             TODO Disabled due to upcoming release 0.4.8 and irrlicht messing up localization
+--             "button[0.75,4.85;1.8,0.5;btn_mod_mgr_install_local;".. fgettext("Local install") .. "]" ..
+               "button[2.45,4.85;3.05,0.5;btn_modstore;".. fgettext("Online mod repository") .. "]"
+
+       local selected_mod = nil
+
+       if filterlist.size(modmgr.global_mods) >= tabdata.selected_mod then
+               selected_mod = modmgr.global_mods:get_list()[tabdata.selected_mod]
+       end
+
+       if selected_mod ~= nil then
+               local modscreenshot = nil
+
+               --check for screenshot beeing available
+               local screenshotfilename = selected_mod.path .. DIR_DELIM .. "screenshot.png"
+               local error = nil
+               local screenshotfile,error = io.open(screenshotfilename,"r")
+               if error == nil then
+                       screenshotfile:close()
+                       modscreenshot = screenshotfilename
+               end
+
+               if modscreenshot == nil then
+                               modscreenshot = modstore.basetexturedir .. "no_screenshot.png"
+               end
+
+               retval = retval
+                               .. "image[5.5,0;3,2;" .. core.formspec_escape(modscreenshot) .. "]"
+                               .. "label[8.25,0.6;" .. selected_mod.name .. "]"
+
+               local descriptionlines = nil
+               error = nil
+               local descriptionfilename = selected_mod.path .. "description.txt"
+               local descriptionfile,error = io.open(descriptionfilename,"r")
+               if error == nil then
+                       local descriptiontext = descriptionfile:read("*all")
+
+                       descriptionlines = core.splittext(descriptiontext,42)
+                       descriptionfile:close()
+               else
+                       descriptionlines = {}
+                       table.insert(descriptionlines,fgettext("No mod description available"))
+               end
+
+               retval = retval ..
+                       "label[5.5,1.7;".. fgettext("Mod information:") .. "]" ..
+                       "textlist[5.5,2.2;6.2,2.4;description;"
+
+               for i=1,#descriptionlines,1 do
+                       retval = retval .. core.formspec_escape(descriptionlines[i]) .. ","
+               end
+
+
+               if selected_mod.is_modpack then
+                       retval = retval .. ";0]" ..
+                               "button[10,4.85;2,0.5;btn_mod_mgr_rename_modpack;" ..
+                               fgettext("Rename") .. "]"
+                       retval = retval .. "button[5.5,4.85;4.5,0.5;btn_mod_mgr_delete_mod;"
+                               .. fgettext("Uninstall selected modpack") .. "]"
+               else
+                       --show dependencies
+
+                       retval = retval .. ",Depends:,"
+
+                       local toadd = modmgr.get_dependencies(selected_mod.path)
+
+                       retval = retval .. toadd .. ";0]"
+
+                       retval = retval .. "button[5.5,4.85;4.5,0.5;btn_mod_mgr_delete_mod;"
+                               .. fgettext("Uninstall selected mod") .. "]"
+               end
+       end
+       return retval
+end
+
+--------------------------------------------------------------------------------
+local function handle_buttons(tabview, fields, tabname, tabdata)
+       if fields["modlist"] ~= nil then
+               local event = core.explode_textlist_event(fields["modlist"])
+               tabdata.selected_mod = event.index
+               return true
+       end
+
+       if fields["btn_mod_mgr_install_local"] ~= nil then
+               core.show_file_open_dialog("mod_mgt_open_dlg",fgettext("Select Mod File:"))
+               return true
+       end
+
+       if fields["btn_modstore"] ~= nil then
+               local modstore_ui = ui.find_by_name("modstore")
+               if modstore_ui ~= nil then
+                       tabview:hide()
+                       modstore.update_modlist()
+                       modstore_ui:show()
+               else
+                       print("modstore ui element not found")
+               end
+               return true
+       end
+
+       if fields["btn_mod_mgr_rename_modpack"] ~= nil then
+               local dlg_renamemp = create_rename_modpack_dlg(tabdata.selected_mod)
+               dlg_renamemp:set_parent(tabview)
+               tabview:hide()
+               dlg_renamemp:show()
+               return true
+       end
+
+       if fields["btn_mod_mgr_delete_mod"] ~= nil then
+               local dlg_delmod = create_delete_mod_dlg(tabdata.selected_mod)
+               dlg_delmod:set_parent(tabview)
+               tabview:hide()
+               dlg_delmod:show()
+               return true
+       end
+
+       if fields["mod_mgt_open_dlg_accepted"] ~= nil and
+               fields["mod_mgt_open_dlg_accepted"] ~= "" then
+               modmgr.installmod(fields["mod_mgt_open_dlg_accepted"],nil)
+               return true
+       end
+
+       return false
+end
+
+--------------------------------------------------------------------------------
+tab_mods = {
+       name = "mods",
+       caption = fgettext("Mods"),
+       cbf_formspec = get_formspec,
+       cbf_button_handler = handle_buttons,
+       on_change = gamemgr.update_gamelist
+}
diff --git a/builtin/mainmenu/tab_multiplayer.lua b/builtin/mainmenu/tab_multiplayer.lua
new file mode 100644 (file)
index 0000000..e8aad42
--- /dev/null
@@ -0,0 +1,229 @@
+--Minetest
+--Copyright (C) 2014 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+--------------------------------------------------------------------------------
+local function get_formspec(tabview, name, tabdata)
+       local render_details = core.is_yes(core.setting_getbool("public_serverlist"))
+       
+       local retval =
+               "vertlabel[0,-0.25;".. fgettext("CLIENT") .. "]" ..
+               "label[1,-0.25;".. fgettext("Favorites:") .. "]"..
+               "label[1,4.25;".. fgettext("Address/Port") .. "]"..
+               "label[9,2.75;".. fgettext("Name/Password") .. "]" ..
+               "field[1.25,5.25;5.5,0.5;te_address;;" ..core.setting_get("address") .."]" ..
+               "field[6.75,5.25;2.25,0.5;te_port;;" ..core.setting_get("remote_port") .."]" ..
+               "checkbox[1,3.6;cb_public_serverlist;".. fgettext("Public Serverlist") .. ";" ..
+               dump(core.setting_getbool("public_serverlist")) .. "]"
+
+       if not core.setting_getbool("public_serverlist") then
+               retval = retval ..
+               "button[6.45,3.95;2.25,0.5;btn_delete_favorite;".. fgettext("Delete") .. "]"
+       end
+
+       retval = retval ..
+               "button[9,4.95;2.5,0.5;btn_mp_connect;".. fgettext("Connect") .. "]" ..
+               "field[9.3,3.75;2.5,0.5;te_name;;" ..core.setting_get("name") .."]" ..
+               "pwdfield[9.3,4.5;2.5,0.5;te_pwd;]" ..
+               "textarea[9.3,0.25;2.5,2.75;;"
+               
+       if menudata.fav_selected ~= nil and
+               menudata.favorites[menu.fav_selected].description ~= nil then
+               retval = retval ..
+                       core.formspec_escape(menu.favorites[menu.fav_selected].description,true)
+       end
+
+       retval = retval ..
+               ";]"
+               
+       --favourites
+       retval = retval ..
+               "textlist[1,0.35;7.5,3.35;favourites;"
+
+       if #menudata.favorites > 0 then
+               retval = retval .. render_favorite(menudata.favorites[1],render_details)
+
+               for i=2,#menudata.favorites,1 do
+                       retval = retval .. "," .. render_favorite(menudata.favorites[i],render_details)
+               end
+       end
+
+       if tabdata.fav_selected ~= nil then
+               retval = retval .. ";" .. tabdata.fav_selected .. "]"
+       else
+               retval = retval .. ";0]"
+       end
+
+       return retval
+end
+
+--------------------------------------------------------------------------------
+local function main_button_handler(tabview, fields, name, tabdata)
+
+       if fields["te_name"] ~= nil then
+               gamedata.playername = fields["te_name"]
+               core.setting_set("name", fields["te_name"])
+       end
+
+       if fields["favourites"] ~= nil then
+               local event = core.explode_textlist_event(fields["favourites"])
+               if event.type == "DCL" then
+                       if event.index <= #menudata.favorites then
+                               gamedata.address    = menudata.favorites[event.index].address
+                               gamedata.port       = menudata.favorites[event.index].port
+                               gamedata.playername = fields["te_name"]
+                               if fields["te_pwd"] ~= nil then
+                                       gamedata.password               = fields["te_pwd"]
+                               end
+                               gamedata.selected_world = 0
+
+                               if menudata.favorites ~= nil then
+                                       gamedata.servername        = menudata.favorites[event.index].name
+                                       gamedata.serverdescription = menudata.favorites[event.index].description
+                               end
+
+                               if gamedata.address ~= nil and
+                                       gamedata.port ~= nil then
+                                       core.setting_set("address",gamedata.address)
+                                       core.setting_set("remote_port",gamedata.port)
+                                       core.start()
+                               end
+                       end
+                       return true
+               end
+
+               if event.type == "CHG" then
+                       if event.index <= #menudata.favorites then
+                               local address = menudata.favorites[event.index].address
+                               local port    = menudata.favorites[event.index].port
+
+                               if address ~= nil and
+                                       port ~= nil then
+                                       core.setting_set("address",address)
+                                       core.setting_set("remote_port",port)
+                               end
+
+                               tabdata.fav_selected = event.index
+                       end
+                       
+                       return true
+               end
+       end
+
+       if fields["key_up"] ~= nil or
+               fields["key_down"] ~= nil then
+
+               local fav_idx = core.get_textlist_index("favourites")
+
+               if fav_idx ~= nil then
+                       if fields["key_up"] ~= nil and fav_idx > 1 then
+                               fav_idx = fav_idx -1
+                       else if fields["key_down"] and fav_idx < #menudata.favorites then
+                               fav_idx = fav_idx +1
+                       end end
+               else
+                       fav_idx = 1
+               end
+       
+               local address = menudata.favorites[fav_idx].address
+               local port    = menudata.favorites[fav_idx].port
+
+               if address ~= nil and
+                       port ~= nil then
+                       core.setting_set("address",address)
+                       core.setting_set("remote_port",port)
+               end
+
+               tabdata.fav_selected = fav_idx
+               return true
+       end
+
+       if fields["cb_public_serverlist"] ~= nil then
+               core.setting_set("public_serverlist", fields["cb_public_serverlist"])
+
+               if core.setting_getbool("public_serverlist") then
+                       asyncOnlineFavourites()
+               else
+                       menudata.favorites = core.get_favorites("local")
+               end
+               tabdata.fav_selected = nil
+               return true
+       end
+
+       if fields["btn_delete_favorite"] ~= nil then
+               local current_favourite = core.get_textlist_index("favourites")
+               if current_favourite == nil then return end
+               core.delete_favorite(current_favourite)
+               menudata.favorites   = core.get_favorites()
+               tabdata.fav_selected = nil
+
+               core.setting_set("address","")
+               core.setting_set("remote_port","30000")
+
+               return true
+       end
+
+       if fields["btn_mp_connect"] ~= nil or
+               fields["key_enter"] ~= nil then
+
+               gamedata.playername     = fields["te_name"]
+               gamedata.password       = fields["te_pwd"]
+               gamedata.address        = fields["te_address"]
+               gamedata.port           = fields["te_port"]
+
+               local fav_idx = core.get_textlist_index("favourites")
+
+               if fav_idx ~= nil and fav_idx <= #menudata.favorites and
+                       menudata.favorites[fav_idx].address == fields["te_address"] and
+                       menudata.favorites[fav_idx].port    == fields["te_port"] then
+
+                       gamedata.servername        = menudata.favorites[fav_idx].name
+                       gamedata.serverdescription = menudata.favorites[fav_idx].description
+               else
+                       gamedata.servername        = ""
+                       gamedata.serverdescription = ""
+               end
+
+               gamedata.selected_world = 0
+
+               core.setting_set("address",    fields["te_address"])
+               core.setting_set("remote_port",fields["te_port"])
+
+               core.start()
+               return true
+       end
+       return false
+end
+
+local function on_change(type,old_tab,new_tab)
+       if type == "LEAVE" then
+               return
+       end
+       if core.setting_getbool("public_serverlist") then
+               asyncOnlineFavourites()
+       else
+               menudata.favorites = core.get_favorites("local")
+       end
+end
+
+--------------------------------------------------------------------------------
+tab_multiplayer = {
+       name = "multiplayer",
+       caption = fgettext("Client"),
+       cbf_formspec = get_formspec,
+       cbf_button_handler = main_button_handler,
+       on_change = on_change
+       }
diff --git a/builtin/mainmenu/tab_server.lua b/builtin/mainmenu/tab_server.lua
new file mode 100644 (file)
index 0000000..1efe803
--- /dev/null
@@ -0,0 +1,173 @@
+--Minetest
+--Copyright (C) 2014 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+--------------------------------------------------------------------------------
+local function get_formspec(tabview, name, tabdata)
+       
+       local index = menudata.worldlist:get_current_index(
+                               tonumber(core.setting_get("mainmenu_last_selected_world"))
+                               )
+
+       local retval =
+               "button[4,4.15;2.6,0.5;world_delete;".. fgettext("Delete") .. "]" ..
+               "button[6.5,4.15;2.8,0.5;world_create;".. fgettext("New") .. "]" ..
+               "button[9.2,4.15;2.55,0.5;world_configure;".. fgettext("Configure") .. "]" ..
+               "button[8.5,4.9;3.25,0.5;start_server;".. fgettext("Start Game") .. "]" ..
+               "label[4,-0.25;".. fgettext("Select World:") .. "]"..
+               "vertlabel[0,-0.25;".. fgettext("START SERVER") .. "]" ..
+               "checkbox[0.5,0.25;cb_creative_mode;".. fgettext("Creative Mode") .. ";" ..
+               dump(core.setting_getbool("creative_mode")) .. "]"..
+               "checkbox[0.5,0.7;cb_enable_damage;".. fgettext("Enable Damage") .. ";" ..
+               dump(core.setting_getbool("enable_damage")) .. "]"..
+               "checkbox[0.5,1.15;cb_server_announce;".. fgettext("Public") .. ";" ..
+               dump(core.setting_getbool("server_announce")) .. "]"..
+               "field[0.8,3.2;3.5,0.5;te_playername;".. fgettext("Name") .. ";" ..
+               core.setting_get("name") .. "]" ..
+               "pwdfield[0.8,4.2;3.5,0.5;te_passwd;".. fgettext("Password") .. "]"
+               
+       local bind_addr = core.setting_get("bind_address")
+       if bind_addr ~= nil and bind_addr ~= "" then
+               retval = retval ..
+                       "field[0.8,5.2;2.25,0.5;te_serveraddr;".. fgettext("Bind Address") .. ";" ..
+                       core.setting_get("bind_address") .."]" ..
+                       "field[3.05,5.2;1.25,0.5;te_serverport;".. fgettext("Port") .. ";" ..
+                       core.setting_get("port") .."]"
+       else
+               retval = retval ..
+                       "field[0.8,5.2;3.5,0.5;te_serverport;".. fgettext("Server Port") .. ";" ..
+                       core.setting_get("port") .."]"
+       end
+       
+       retval = retval ..
+               "textlist[4,0.25;7.5,3.7;srv_worlds;" ..
+               menu_render_worldlist() ..
+               ";" .. index .. "]"
+       
+       return retval
+end
+
+--------------------------------------------------------------------------------
+local function main_button_handler(this, fields, name, tabdata)
+
+       local world_doubleclick = false
+
+       if fields["srv_worlds"] ~= nil then
+               local event = core.explode_textlist_event(fields["srv_worlds"])
+
+               if event.type == "DCL" then
+                       world_doubleclick = true
+               end
+               if event.type == "CHG" then
+                       core.setting_set("mainmenu_last_selected_world",
+                               menudata.worldlist:get_raw_index(core.get_textlist_index("srv_worlds")))
+               end
+       end
+
+       if menu_handle_key_up_down(fields,"srv_worlds","mainmenu_last_selected_world") then
+               return true
+       end
+
+       if fields["cb_creative_mode"] then
+               core.setting_set("creative_mode", fields["cb_creative_mode"])
+       end
+
+       if fields["cb_enable_damage"] then
+               core.setting_set("enable_damage", fields["cb_enable_damage"])
+       end
+
+       if fields["cb_server_announce"] then
+               core.setting_set("server_announce", fields["cb_server_announce"])
+       end
+
+       if fields["start_server"] ~= nil or
+               world_doubleclick or
+               fields["key_enter"] then
+               local selected = core.get_textlist_index("srv_worlds")
+               if selected ~= nil then
+                       gamedata.playername     = fields["te_playername"]
+                       gamedata.password       = fields["te_passwd"]
+                       gamedata.port           = fields["te_serverport"]
+                       gamedata.address        = ""
+                       gamedata.selected_world = menudata.worldlist:get_raw_index(selected)
+
+                       core.setting_set("port",gamedata.port)
+                       if fields["te_serveraddr"] ~= nil then
+                               core.setting_set("bind_address",fields["te_serveraddr"])
+                       end
+
+                       --update last game
+                       local world = menudata.worldlist:get_raw_element(gamedata.selected_world)
+                       local game,index = gamemgr.find_by_gameid(world.gameid)
+                       core.setting_set("menu_last_game",game.id)
+                       core.start()
+               end
+       end
+
+       if fields["world_create"] ~= nil then
+               print("create world dialog")
+               local create_world_dlg = create_create_world_dlg(true)
+               create_world_dlg:set_parent(this)
+               create_world_dlg:show()
+               this:hide()
+               return true
+       end
+
+       if fields["world_delete"] ~= nil then
+               local selected = core.get_textlist_index("srv_worlds")
+               if selected ~= nil and
+                       selected <= menudata.worldlist:size() then
+                       local world = menudata.worldlist:get_list()[selected]
+                       if world ~= nil and
+                               world.name ~= nil and
+                               world.name ~= "" then
+                               local index = menudata.worldlist:get_raw_index(selected)
+                               local delete_world_dlg = create_delete_world_dlg(world.name,index)
+                               delete_world_dlg:set_parent(this)
+                               delete_world_dlg:show()
+                               this:hide()
+                       end
+               end
+               
+               return true
+       end
+
+       if fields["world_configure"] ~= nil then
+               local selected = core.get_textlist_index("srv_worlds")
+               if selected ~= nil then
+                       local configdialog =
+                               create_configure_world_dlg(
+                                               menudata.worldlist:get_raw_index(selected))
+                       
+                       if (configdialog ~= nil) then
+                               configdialog:set_parent(this)
+                               configdialog:show()
+                               this:hide()
+                       end
+               end
+               return true
+       end
+       return false
+end
+
+--------------------------------------------------------------------------------
+tab_server = {
+       name = "server",
+       caption = fgettext("Server"),
+       cbf_formspec = get_formspec,
+       cbf_button_handler = main_button_handler,
+       on_change = nil
+       }
diff --git a/builtin/mainmenu/tab_settings.lua b/builtin/mainmenu/tab_settings.lua
new file mode 100644 (file)
index 0000000..8710290
--- /dev/null
@@ -0,0 +1,247 @@
+--Minetest
+--Copyright (C) 2013 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+--------------------------------------------------------------------------------
+
+local function dlg_confirm_reset_formspec(data)
+       local retval =
+               "size[8,3]" ..
+               "label[1,1;".. fgettext("Are you sure to reset your singleplayer world?") .. "]"..
+               "button[1,2;2.6,0.5;dlg_reset_singleplayer_confirm;"..
+                               fgettext("Yes") .. "]" ..
+               "button[4,2;2.8,0.5;dlg_reset_singleplayer_cancel;"..
+                               fgettext("No!!!") .. "]"
+       return retval
+end
+
+local function dlg_confirm_reset_btnhandler(this, fields, dialogdata)
+
+       if fields["dlg_reset_singleplayer_confirm"] ~= nil then
+
+               local worldlist = core.get_worlds()
+               local found_singleplayerworld = false
+
+               for i=1,#worldlist,1 do
+                       if worldlist[i].name == "singleplayerworld" then
+                               found_singleplayerworld = true
+                               gamedata.worldindex = i
+                       end
+               end
+
+               if found_singleplayerworld then
+                       core.delete_world(gamedata.worldindex)
+               end
+
+               core.create_world("singleplayerworld", 1)
+
+               worldlist = core.get_worlds()
+
+               found_singleplayerworld = false
+
+               for i=1,#worldlist,1 do
+                       if worldlist[i].name == "singleplayerworld" then
+                               found_singleplayerworld = true
+                               gamedata.worldindex = i
+                       end
+               end
+       end
+
+       this.parent:show()
+       this:hide()
+       this:delete()
+end
+
+local function showconfirm_reset(tabview)
+       local new_dlg = dialog_create("reset_spworld",
+               dlg_confirm_reset_formspec,
+               dlg_confirm_reset_btnhandler,
+               nil,
+               tabview)
+       tabview:hide()
+       new_dlg:show()
+end
+
+
+
+local function formspec(tabview, name, tabdata)
+       local tab_string =
+               "vertlabel[0,0;" .. fgettext("SETTINGS") .. "]" ..
+               "box[0.75,0;3.25,4;#999999]" ..
+               "checkbox[1,0;cb_fancy_trees;".. fgettext("Fancy Trees") .. ";"
+                               .. dump(core.setting_getbool("new_style_leaves")) .. "]"..
+               "checkbox[1,0.5;cb_smooth_lighting;".. fgettext("Smooth Lighting")
+                               .. ";".. dump(core.setting_getbool("smooth_lighting")) .. "]"..
+               "checkbox[1,1;cb_3d_clouds;".. fgettext("3D Clouds") .. ";"
+                               .. dump(core.setting_getbool("enable_3d_clouds")) .. "]"..
+               "checkbox[1,1.5;cb_opaque_water;".. fgettext("Opaque Water") .. ";"
+                               .. dump(core.setting_getbool("opaque_water")) .. "]"..
+               "checkbox[1,2.0;cb_pre_ivis;".. fgettext("Preload item visuals") .. ";"
+                               .. dump(core.setting_getbool("preload_item_visuals"))   .. "]"..
+               "checkbox[1,2.5;cb_particles;".. fgettext("Enable Particles") .. ";"
+                               .. dump(core.setting_getbool("enable_particles"))       .. "]"..
+               "checkbox[1,3.0;cb_finite_liquid;".. fgettext("Finite Liquid") .. ";"
+                               .. dump(core.setting_getbool("liquid_finite")) .. "]"..
+               "box[4.25,0;3.25,2.5;#999999]" ..
+               "checkbox[4.5,0;cb_mipmapping;".. fgettext("Mip-Mapping") .. ";"
+                               .. dump(core.setting_getbool("mip_map")) .. "]"..
+               "checkbox[4.5,0.5;cb_anisotrophic;".. fgettext("Anisotropic Filtering") .. ";"
+                               .. dump(core.setting_getbool("anisotropic_filter")) .. "]"..
+               "checkbox[4.5,1.0;cb_bilinear;".. fgettext("Bi-Linear Filtering") .. ";"
+                               .. dump(core.setting_getbool("bilinear_filter")) .. "]"..
+               "checkbox[4.5,1.5;cb_trilinear;".. fgettext("Tri-Linear Filtering") .. ";"
+                               .. dump(core.setting_getbool("trilinear_filter")) .. "]"..
+               "box[7.75,0;4,3.5;#999999]" ..
+               "checkbox[8,0;cb_shaders;".. fgettext("Shaders") .. ";"
+                               .. dump(core.setting_getbool("enable_shaders")) .. "]"..
+               "button[1,4.5;2.25,0.5;btn_change_keys;".. fgettext("Change keys") .. "]"
+       
+       local android = false
+       if android then
+               tab_string = tab_string ..
+               "box[4.25,2.75;3.25,2.5;#999999]" ..
+               "checkbox[4.5,2.75;cb_touchscreen_target;".. fgettext("Touch free target") .. ";"
+                               .. dump(core.setting_getbool("touchtarget")) .. "]" ..
+               "button[8,4.5;3.75,0.5;btn_reset_singleplayer;".. fgettext("Reset singleplayer world") .. "]"
+       end
+
+       if core.setting_get("touchscreen_threshold") ~= nil then
+               tab_string = tab_string ..
+                               "label[4.5,3.5;" .. fgettext("Touchthreshold (px)") .. "]" ..
+                               "dropdown[4.5,4;3;dd_touchthreshold;0,10,20,30,40,50;" ..
+                               ((tonumber(core.setting_get("touchscreen_threshold"))/10)+1) .. "]"
+       end
+
+       if core.setting_getbool("enable_shaders") then
+               tab_string = tab_string ..
+                               "checkbox[8,0.5;cb_bumpmapping;".. fgettext("Bumpmapping") .. ";"
+                                               .. dump(core.setting_getbool("enable_bumpmapping")) .. "]"..
+                               "checkbox[8,1.0;cb_parallax;".. fgettext("Parallax Occlusion") .. ";"
+                                               .. dump(core.setting_getbool("enable_parallax_occlusion")) .. "]"..
+                               "checkbox[8,1.5;cb_waving_water;".. fgettext("Waving Water") .. ";"
+                                               .. dump(core.setting_getbool("enable_waving_water")) .. "]"..
+                               "checkbox[8,2.0;cb_waving_leaves;".. fgettext("Waving Leaves") .. ";"
+                                               .. dump(core.setting_getbool("enable_waving_leaves")) .. "]"..
+                               "checkbox[8,2.5;cb_waving_plants;".. fgettext("Waving Plants") .. ";"
+                                               .. dump(core.setting_getbool("enable_waving_plants")) .. "]"
+       else
+               tab_string = tab_string ..
+                               "textlist[8.33,0.7;3,1;;#888888" .. fgettext("Bumpmapping") .. ";0;true]" ..
+                               "textlist[8.33,1.2;3,1;;#888888" .. fgettext("Parallax Occlusion") .. ";0;true]" ..
+                               "textlist[8.33,1.7;3,1;;#888888" .. fgettext("Waving Water") .. ";0;true]" ..
+                               "textlist[8.33,2.2;3,1;;#888888" .. fgettext("Waving Leaves") .. ";0;true]" ..
+                               "textlist[8.33,2.7;3,1;;#888888" .. fgettext("Waving Plants") .. ";0;true]"
+               end
+       return tab_string
+end
+
+--------------------------------------------------------------------------------
+local function handle_settings_buttons(this, fields, tabname, tabdata)
+       if fields["cb_fancy_trees"] then
+               core.setting_set("new_style_leaves", fields["cb_fancy_trees"])
+               return true
+       end
+       if fields["cb_smooth_lighting"] then
+               core.setting_set("smooth_lighting", fields["cb_smooth_lighting"])
+               return true
+       end
+       if fields["cb_3d_clouds"] then
+               core.setting_set("enable_3d_clouds", fields["cb_3d_clouds"])
+               return true
+       end
+       if fields["cb_opaque_water"] then
+               core.setting_set("opaque_water", fields["cb_opaque_water"])
+               return true
+       end
+       if fields["cb_mipmapping"] then
+               core.setting_set("mip_map", fields["cb_mipmapping"])
+               return true
+       end
+       if fields["cb_anisotrophic"] then
+               core.setting_set("anisotropic_filter", fields["cb_anisotrophic"])
+               return true
+       end
+       if fields["cb_bilinear"] then
+               core.setting_set("bilinear_filter", fields["cb_bilinear"])
+               return true
+       end
+       if fields["cb_trilinear"] then
+               core.setting_set("trilinear_filter", fields["cb_trilinear"])
+               return true
+       end
+       if fields["cb_shaders"] then
+               if (core.setting_get("video_driver") == "direct3d8" or core.setting_get("video_driver") == "direct3d9") then
+                       core.setting_set("enable_shaders", "false")
+                       gamedata.errormessage = fgettext("To enable shaders the OpenGL driver needs to be used.")
+               else
+                       core.setting_set("enable_shaders", fields["cb_shaders"])
+               end
+               return true
+       end
+       if fields["cb_pre_ivis"] then
+               core.setting_set("preload_item_visuals", fields["cb_pre_ivis"])
+               return true
+       end
+       if fields["cb_particles"] then
+               core.setting_set("enable_particles", fields["cb_particles"])
+               return true
+       end
+       if fields["cb_finite_liquid"] then
+               core.setting_set("liquid_finite", fields["cb_finite_liquid"])
+               return true
+       end
+       if fields["cb_bumpmapping"] then
+               core.setting_set("enable_bumpmapping", fields["cb_bumpmapping"])
+       end
+       if fields["cb_parallax"] then
+               core.setting_set("enable_parallax_occlusion", fields["cb_parallax"])
+               return true
+       end
+       if fields["cb_waving_water"] then
+               core.setting_set("enable_waving_water", fields["cb_waving_water"])
+               return true
+       end
+       if fields["cb_waving_leaves"] then
+               core.setting_set("enable_waving_leaves", fields["cb_waving_leaves"])
+       end
+       if fields["cb_waving_plants"] then
+               core.setting_set("enable_waving_plants", fields["cb_waving_plants"])
+               return true
+       end
+       if fields["btn_change_keys"] ~= nil then
+               core.show_keys_menu()
+               return true
+       end
+       if fields["cb_touchscreen_target"] then
+               core.setting_set("touchtarget", fields["cb_touchscreen_target"])
+               return true
+       end
+       if fields["dd_touchthreshold"] then
+               core.setting_set("touchscreen_threshold",fields["dd_touchthreshold"])
+               return true
+       end
+       if fields["btn_reset_singleplayer"] then
+               showconfirm_reset(this)
+               return true
+       end
+end
+
+tab_settings = {
+       name = "settings",
+       caption = fgettext("Settings"),
+       cbf_formspec = formspec,
+       cbf_button_handler = handle_settings_buttons
+       }
diff --git a/builtin/mainmenu/tab_simple_main.lua b/builtin/mainmenu/tab_simple_main.lua
new file mode 100644 (file)
index 0000000..46f4b61
--- /dev/null
@@ -0,0 +1,176 @@
+--Minetest
+--Copyright (C) 2013 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+--------------------------------------------------------------------------------
+local function get_formspec(tabview, name, tabdata)
+       local retval = ""
+
+       local render_details = dump(core.setting_getbool("public_serverlist"))
+
+       retval = retval ..
+               "label[0,3.0;".. fgettext("Address/Port") .. "]"..
+               "label[8,0.5;".. fgettext("Name/Password") .. "]" ..
+               "field[0.25,3.25;5.5,0.5;te_address;;" ..core.setting_get("address") .."]" ..
+               "field[5.75,3.25;2.25,0.5;te_port;;" ..core.setting_get("remote_port") .."]" ..
+               "checkbox[8,-0.25;cb_public_serverlist;".. fgettext("Public Serverlist") .. ";" ..
+               render_details .. "]"
+
+       retval = retval ..
+               "button[8,2.5;4,1.5;btn_mp_connect;".. fgettext("Connect") .. "]" ..
+               "field[8.75,1.5;3.5,0.5;te_name;;" ..core.setting_get("name") .."]" ..
+               "pwdfield[8.75,2.3;3.5,0.5;te_pwd;]"
+
+       --favourites
+       retval = retval ..
+               "textlist[-0.05,0.0;7.55,2.75;favourites;"
+
+       if #menudata.favorites > 0 then
+               retval = retval .. render_favorite(menudata.favorites[1],render_details)
+
+               for i=2,#menudata.favorites,1 do
+                       retval = retval .. "," .. render_favorite(menudata.favorites[i],render_details)
+               end
+       end
+
+       if tabdata.fav_selected ~= nil then
+               retval = retval .. ";" .. tabdata.fav_selected .. "]"
+       else
+               retval = retval .. ";0]"
+       end
+
+       -- separator
+       retval = retval ..
+               "box[-0.3,3.75;12.4,0.1;#FFFFFF]"
+
+       -- checkboxes
+       retval = retval ..
+               "checkbox[1.0,3.9;cb_creative;".. fgettext("Creative Mode") .. ";" ..
+               dump(core.setting_getbool("creative_mode")) .. "]"..
+               "checkbox[5.0,3.9;cb_damage;".. fgettext("Enable Damage") .. ";" ..
+               dump(core.setting_getbool("enable_damage")) .. "]" ..
+               "checkbox[8,3.9;cb_fly_mode;".. fgettext("Fly mode") .. ";" ..
+               dump(core.setting_getbool("free_move")) .. "]"
+       -- buttons
+       retval = retval ..
+               "button[3.0,4.5;6,1.5;btn_start_singleplayer;" .. fgettext("Start Singleplayer") .. "]"
+
+       return retval
+end
+
+--------------------------------------------------------------------------------
+
+local function main_button_handler(tabview, fields, name, tabdata)
+       if fields["btn_start_singleplayer"] then
+               gamedata.selected_world = gamedata.worldindex
+               gamedata.singleplayer   = true
+               core.start()
+       end
+
+       if fields["favourites"] ~= nil then
+               local event = core.explode_textlist_event(fields["favourites"])
+
+               if event.type == "CHG" then
+                       if event.index <= #maintab_favorites then
+                               local address = maintab_favorites[event.index].address
+                               local port = maintab_favorites[event.index].port
+
+                               if address ~= nil and
+                                       port ~= nil then
+                                       core.setting_set("address",address)
+                                       core.setting_set("remote_port",port)
+                               end
+
+                               tabdata.fav_selected = event.index
+                       end
+               end
+               return
+       end
+
+       if fields["cb_public_serverlist"] ~= nil then
+               core.setting_set("public_serverlist", fields["cb_public_serverlist"])
+
+               if core.setting_getbool("public_serverlist") then
+                       asyncOnlineFavourites()
+               else
+                       maintab_favorites = core.get_favorites("local")
+               end
+               return
+       end
+
+       if fields["cb_creative"] then
+               core.setting_set("creative_mode", fields["cb_creative"])
+       end
+
+       if fields["cb_damage"] then
+               core.setting_set("enable_damage", fields["cb_damage"])
+       end
+
+       if fields["cb_fly_mode"] then
+               core.setting_set("free_move", fields["cb_fly_mode"])
+       end
+
+       if fields["btn_mp_connect"] ~= nil or
+               fields["key_enter"] ~= nil then
+
+               gamedata.playername             = fields["te_name"]
+               gamedata.password               = fields["te_pwd"]
+               gamedata.address                = fields["te_address"]
+               gamedata.port                   = fields["te_port"]
+
+               local fav_idx = core.get_textlist_index("favourites")
+
+               if fav_idx ~= nil and fav_idx <= #menudata.favorites and
+                       menudata.favorites[fav_idx].address == fields["te_address"] and
+                       menudata.favorites[fav_idx].port    == fields["te_port"] then
+
+                       gamedata.servername                     = menudata.favorites[fav_idx].name
+                       gamedata.serverdescription      = menudata.favorites[fav_idx].description
+               else
+                       gamedata.servername                     = ""
+                       gamedata.serverdescription      = ""
+               end
+
+               gamedata.selected_world = 0
+
+               core.setting_set("address",fields["te_address"])
+               core.setting_set("remote_port",fields["te_port"])
+
+               core.start()
+               return
+       end
+end
+
+--------------------------------------------------------------------------------
+local function on_activate(type,old_tab,new_tab)
+       if type == "LEAVE" then
+               return
+       end
+       if core.setting_getbool("public_serverlist") then
+               asyncOnlineFavourites()
+       else
+               menudata.favorites = core.get_favorites("local")
+       end
+end
+
+--------------------------------------------------------------------------------
+tab_simple_main = {
+       name = "main",
+       caption = fgettext("Main"),
+       cbf_formspec = get_formspec,
+       cbf_button_handler = main_button_handler,
+       on_change = on_activate
+       }
diff --git a/builtin/mainmenu/tab_singleplayer.lua b/builtin/mainmenu/tab_singleplayer.lua
new file mode 100644 (file)
index 0000000..72f9188
--- /dev/null
@@ -0,0 +1,218 @@
+--Minetest
+--Copyright (C) 2014 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+local function singleplayer_refresh_gamebar()
+       
+       local old_bar = ui.find_by_name("game_button_bar")
+       
+       if old_bar ~= nil then
+               old_bar:delete()
+       end
+
+       local function game_buttonbar_button_handler(fields)
+               for key,value in pairs(fields) do
+                       for j=1,#gamemgr.games,1 do
+                               if ("game_btnbar_" .. gamemgr.games[j].id == key) then
+                                       mm_texture.update("singleplayer", gamemgr.games[j])
+                                       core.setting_set("menu_last_game",gamemgr.games[j].id)
+                                       menudata.worldlist:set_filtercriteria(gamemgr.games[j].id)
+                                       return true
+                               end
+                       end
+               end
+       end
+
+       local btnbar = buttonbar_create("game_button_bar",
+               game_buttonbar_button_handler,
+               {x=-0.3,y=5.65}, "horizontal", {x=12.4,y=1.15})
+
+       for i=1,#gamemgr.games,1 do
+               local btn_name = "game_btnbar_" .. gamemgr.games[i].id
+               
+               local image = nil
+               local text = nil
+               
+               if gamemgr.games[i].menuicon_path ~= nil and
+                       gamemgr.games[i].menuicon_path ~= "" then
+                       image = core.formspec_escape(gamemgr.games[i].menuicon_path)
+               else
+               
+                       local part1 = gamemgr.games[i].id:sub(1,5)
+                       local part2 = gamemgr.games[i].id:sub(6,10)
+                       local part3 = gamemgr.games[i].id:sub(11)
+                       
+                       text = part1 .. "\n" .. part2
+                       if part3 ~= nil and
+                               part3 ~= "" then
+                               text = text .. "\n" .. part3
+                       end
+               end
+               btnbar:add_button(btn_name, text, image)
+       end
+end
+
+local function get_formspec(tabview, name, tabdata)
+       local retval = ""
+       
+       local index = filterlist.get_current_index(menudata.worldlist,
+                               tonumber(core.setting_get("mainmenu_last_selected_world"))
+                               )
+
+       retval = retval ..
+                       "button[4,4.15;2.6,0.5;world_delete;".. fgettext("Delete") .. "]" ..
+                       "button[6.5,4.15;2.8,0.5;world_create;".. fgettext("New") .. "]" ..
+                       "button[9.2,4.15;2.55,0.5;world_configure;".. fgettext("Configure") .. "]" ..
+                       "button[8.5,4.95;3.25,0.5;play;".. fgettext("Play") .. "]" ..
+                       "label[4,-0.25;".. fgettext("Select World:") .. "]"..
+                       "vertlabel[0,-0.25;".. fgettext("SINGLE PLAYER") .. "]" ..
+                       "checkbox[0.5,0.25;cb_creative_mode;".. fgettext("Creative Mode") .. ";" ..
+                       dump(core.setting_getbool("creative_mode")) .. "]"..
+                       "checkbox[0.5,0.7;cb_enable_damage;".. fgettext("Enable Damage") .. ";" ..
+                       dump(core.setting_getbool("enable_damage")) .. "]"..
+                       "textlist[4,0.25;7.5,3.7;sp_worlds;" ..
+                       menu_render_worldlist() ..
+                       ";" .. index .. "]"
+       return retval
+end
+
+local function main_button_handler(this, fields, name, tabdata)
+
+       assert(name == "singleplayer")
+
+       local world_doubleclick = false
+
+       if fields["sp_worlds"] ~= nil then
+               local event = core.explode_textlist_event(fields["sp_worlds"])
+
+               if event.type == "DCL" then
+                       world_doubleclick = true
+               end
+
+               if event.type == "CHG" then
+                       core.setting_set("mainmenu_last_selected_world",
+                               menudata.worldlist:get_raw_index(core.get_textlist_index("sp_worlds")))
+               end
+               
+               return true
+       end
+
+       if menu_handle_key_up_down(fields,"sp_worlds","mainmenu_last_selected_world") then
+               return true
+       end
+
+       if fields["cb_creative_mode"] then
+               core.setting_set("creative_mode", fields["cb_creative_mode"])
+               return true
+       end
+
+       if fields["cb_enable_damage"] then
+               core.setting_set("enable_damage", fields["cb_enable_damage"])
+               return true
+       end
+
+       if fields["play"] ~= nil or
+               world_doubleclick or
+               fields["key_enter"] then
+               local selected = core.get_textlist_index("sp_worlds")
+               if selected ~= nil then
+                       gamedata.selected_world = menudata.worldlist:get_raw_index(selected)
+                       gamedata.singleplayer   = true
+                       core.start()
+               end
+               return true
+       end
+
+       if fields["world_create"] ~= nil then
+               print("create world dialog")
+               local create_world_dlg = create_create_world_dlg(true)
+               create_world_dlg:set_parent(this)
+               create_world_dlg:show()
+               this:hide()
+               return true
+       end
+
+       if fields["world_delete"] ~= nil then
+               local selected = core.get_textlist_index("sp_worlds")
+               if selected ~= nil and
+                       selected <= menudata.worldlist:size() then
+                       local world = menudata.worldlist:get_list()[selected]
+                       if world ~= nil and
+                               world.name ~= nil and
+                               world.name ~= "" then
+                               local index = menudata.worldlist:get_raw_index(selected)
+                               local delete_world_dlg = create_delete_world_dlg(world.name,index)
+                               delete_world_dlg:set_parent(this)
+                               delete_world_dlg:show()
+                               this:hide()
+                       end
+               end
+               
+               return true
+       end
+
+       if fields["world_configure"] ~= nil then
+               local selected = core.get_textlist_index("sp_worlds")
+               if selected ~= nil then
+                       local configdialog =
+                               create_configure_world_dlg(
+                                               menudata.worldlist:get_raw_index(selected))
+                       
+                       if (configdialog ~= nil) then
+                               configdialog:set_parent(this)
+                               configdialog:show()
+                               this:hide()
+                       end
+               end
+               
+               return true
+       end
+end
+
+local function on_change(type, old_tab, new_tab)
+       local buttonbar = ui.find_by_name("game_button_bar")
+       
+       if ( buttonbar == nil ) then
+               singleplayer_refresh_gamebar()
+               buttonbar = ui.find_by_name("game_button_bar")
+       end
+       
+       if (type == "ENTER") then
+               local last_game_id = core.setting_get("menu_last_game")
+               local game, index = gamemgr.find_by_gameid(last_game_id)
+               
+               if game then
+                       menudata.worldlist:set_filtercriteria(game.id)
+                       core.set_topleft_text(game.name)
+                       mm_texture.update(new_tab,game)
+               end
+               buttonbar:show()
+       else
+               menudata.worldlist:set_filtercriteria(nil)
+               buttonbar:hide()
+               core.set_topleft_text("")
+               mm_texture.update(new_tab,nil)
+       end
+end
+
+--------------------------------------------------------------------------------
+tab_singleplayer = {
+       name = "singleplayer",
+       caption = fgettext("Singleplayer"),
+       cbf_formspec = get_formspec,
+       cbf_button_handler = main_button_handler,
+       on_change = on_change
+       }
diff --git a/builtin/mainmenu/tab_texturepacks.lua b/builtin/mainmenu/tab_texturepacks.lua
new file mode 100644 (file)
index 0000000..7844804
--- /dev/null
@@ -0,0 +1,117 @@
+--Minetest
+--Copyright (C) 2014 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+--------------------------------------------------------------------------------
+local function filter_texture_pack_list(list)
+       retval = {"None"}
+       for _,i in ipairs(list) do
+               if i~="base" then
+                       table.insert(retval, i)
+               end
+       end
+       return retval
+end
+
+--------------------------------------------------------------------------------
+local function render_texture_pack_list(list)
+       local retval = ""
+
+       for i, v in ipairs(list) do
+               if retval ~= "" then
+                       retval = retval ..","
+               end
+
+               retval = retval .. core.formspec_escape(v)
+       end
+
+       return retval
+end
+
+--------------------------------------------------------------------------------
+local function get_formspec(tabview, name, tabdata)
+       
+       local retval = "label[4,-0.25;".. fgettext("Select texture pack:") .. "]"..
+                       "vertlabel[0,-0.25;".. fgettext("TEXTURE PACKS") .. "]" ..
+                       "textlist[4,0.25;7.5,5.0;TPs;"
+
+       local current_texture_path = core.setting_get("texture_path")
+       local list = filter_texture_pack_list(core.get_dirlist(core.get_texturepath(), true))
+       local index = tonumber(core.setting_get("mainmenu_last_selected_TP"))
+
+       if index == nil then index = 1 end
+
+       if current_texture_path == "" then
+               retval = retval ..
+                       render_texture_pack_list(list) ..
+                       ";" .. index .. "]"
+               return retval
+       end
+
+       local infofile = current_texture_path ..DIR_DELIM.."info.txt"
+       local infotext = ""
+       local f = io.open(infofile, "r")
+       if f==nil then
+               infotext = fgettext("No information available")
+       else
+               infotext = f:read("*all")
+               f:close()
+       end
+
+       local screenfile = current_texture_path..DIR_DELIM.."screenshot.png"
+       local no_screenshot = nil
+       if not file_exists(screenfile) then
+               screenfile = nil
+               no_screenshot = defaulttexturedir .. "no_screenshot.png"
+       end
+
+       return  retval ..
+                       render_texture_pack_list(list) ..
+                       ";" .. index .. "]" ..
+                       "image[0.65,0.25;4.0,3.7;"..core.formspec_escape(screenfile or no_screenshot).."]"..
+                       "textarea[1.0,3.25;3.7,1.5;;"..core.formspec_escape(infotext or "")..";]"
+end
+
+--------------------------------------------------------------------------------
+local function main_button_handler(tabview, fields, name, tabdata)
+       if fields["TPs"] ~= nil then
+               local event = core.explode_textlist_event(fields["TPs"])
+               if event.type == "CHG" or event.type == "DCL" then
+                       local index = core.get_textlist_index("TPs")
+                       core.setting_set("mainmenu_last_selected_TP",
+                               index)
+                       local list = filter_texture_pack_list(core.get_dirlist(core.get_texturepath(), true))
+                       local current_index = core.get_textlist_index("TPs")
+                       if current_index ~= nil and #list >= current_index then
+                               local new_path = core.get_texturepath()..DIR_DELIM..list[current_index]
+                               if list[current_index] == "None" then new_path = "" end
+
+                               core.setting_set("texture_path", new_path)
+                       end
+               end
+               return true
+       end
+       return false
+end
+
+--------------------------------------------------------------------------------
+tab_texturepacks = {
+       name = "texturepacks",
+       caption = fgettext("Texturepacks"),
+       cbf_formspec = get_formspec,
+       cbf_button_handler = main_button_handler,
+       on_change = nil
+       }
index 998fc219973b251b20ae22ff3baa71b398a86c82..cec12235c44e88b6b88e01de0ed28558dd99a055 100644 (file)
@@ -20,11 +20,11 @@ mm_texture = {}
 
 --------------------------------------------------------------------------------
 function mm_texture.init()
-       mm_texture.defaulttexturedir = engine.get_texturepath() .. DIR_DELIM .. "base" .. 
+       mm_texture.defaulttexturedir = core.get_texturepath() .. DIR_DELIM .. "base" ..
                                                DIR_DELIM .. "pack" .. DIR_DELIM
        mm_texture.basetexturedir = mm_texture.defaulttexturedir
        
-       mm_texture.texturepack = engine.setting_get("texture_path")
+       mm_texture.texturepack = core.setting_get("texture_path")
        
        mm_texture.gameid = nil
 end
@@ -55,14 +55,14 @@ function mm_texture.reset()
        
        mm_texture.clear("header")
        mm_texture.clear("footer")
-       engine.set_clouds(false)
+       core.set_clouds(false)
        
        mm_texture.set_generic("footer")
        mm_texture.set_generic("header")
        
        if not have_bg and
-               engine.setting_getbool("enable_clouds") then
-                       engine.set_clouds(true)
+               core.setting_getbool("menu_clouds") then
+                       core.set_clouds(true)
        end
 end
 
@@ -72,7 +72,7 @@ function mm_texture.update_game(gamedetails)
                return
        end
        
-       local have_bg      = false 
+       local have_bg      = false
        local have_overlay = mm_texture.set_game("overlay",gamedetails)
        
        if not have_overlay then
@@ -81,11 +81,11 @@ function mm_texture.update_game(gamedetails)
        
        mm_texture.clear("header")
        mm_texture.clear("footer")
-       engine.set_clouds(false)
+       core.set_clouds(false)
        
        if not have_bg and
-               engine.setting_getbool("enable_clouds") then
-                       engine.set_clouds(true)
+               core.setting_getbool("menu_clouds") then
+                       core.set_clouds(true)
        end
        
        mm_texture.set_game("footer",gamedetails)
@@ -96,24 +96,24 @@ end
 
 --------------------------------------------------------------------------------
 function mm_texture.clear(identifier)
-       engine.set_background(identifier,"")
+       core.set_background(identifier,"")
 end
 
 --------------------------------------------------------------------------------
 function mm_texture.set_generic(identifier)
        --try texture pack first
        if mm_texture.texturepack ~= nil then
-               local path = mm_texture.texturepack .. DIR_DELIM .."menu_" .. 
+               local path = mm_texture.texturepack .. DIR_DELIM .."menu_" ..
                                                                                identifier .. ".png"
-               if engine.set_background(identifier,path) then
+               if core.set_background(identifier,path) then
                        return true
                end
        end
        
        if mm_texture.defaulttexturedir ~= nil then
-               local path = mm_texture.defaulttexturedir .. DIR_DELIM .."menu_" .. 
+               local path = mm_texture.defaulttexturedir .. DIR_DELIM .."menu_" ..
                                                                                identifier .. ".png"
-               if engine.set_background(identifier,path) then
+               if core.set_background(identifier,path) then
                        return true
                end
        end
@@ -131,14 +131,14 @@ function mm_texture.set_game(identifier,gamedetails)
        if mm_texture.texturepack ~= nil then
                local path = mm_texture.texturepack .. DIR_DELIM ..
                                                gamedetails.id .. "_menu_" .. identifier .. ".png"
-               if engine.set_background(identifier,path) then
+               if core.set_background(identifier,path) then
                        return true
                end
        end
        
-       local path = gamedetails.path .. DIR_DELIM .."menu" .. 
+       local path = gamedetails.path .. DIR_DELIM .."menu" ..
                                                                         DIR_DELIM .. identifier .. ".png"
-       if engine.set_background(identifier,path) then
+       if core.set_background(identifier,path) then
                return true
        end
        
diff --git a/doc/fst_api.txt b/doc/fst_api.txt
new file mode 100644 (file)
index 0000000..54f2d07
--- /dev/null
@@ -0,0 +1,171 @@
+Formspec toolkit api 0.0.3
+==========================
+
+Formspec toolkit is a set of functions to create basic ui elements.
+
+
+File: fst/ui.lua
+----------------
+
+ui.lua adds base ui interface to add additional components to.
+
+ui.add(component) -> returns name of added component
+^ add component to ui
+^ component: component to add
+
+ui.delete(component) -> true/false if a component was deleted or not
+^ remove a component from ui
+^ component: component to delete
+
+ui.set_default(name)
+^ set component to show if not a single component is set visible
+^ name: name of component to set as default
+
+ui.find_by_name(name) --> returns component or nil
+^ find a component within ui
+^ name: name of component to look for
+
+File: fst/tabview.lua
+---------------------
+
+tabview_create(name, size, tabheaderpos) --> returns tabview component
+^ create a new tabview component
+^ name: name of tabview (has to be unique per ui)
+^ size: size of tabview
+       {
+               x,
+               y
+       }
+^ tabheaderpos: upper left position of tabheader (relative to upper left fs corner)
+       {
+               x,
+               y
+       }
+
+Class reference tabview:
+
+methods:
+- add_tab(tab)
+  ^ add a tab to this tabview
+  ^ tab:
+  {
+       name               = "tabname",      -- name of tab to create
+       caption            = "tab caption",  -- text to show for tab header
+       cbf_button_handler = function(tabview, fields, tabname, tabdata), -- callback for button events
+       --TODO cbf_events         = function(tabview, event, tabname),           -- callback for events
+       cbf_formspec       = function(tabview, name, tabdata),            -- get formspec
+       tabsize            =
+               {
+                       x, -- x width
+                       y  -- y height
+               },                                                            -- special size for this tab (only relevant if no parent for tabview set)
+       on_change          = function(type,old_tab,new_tab)               -- called on tab chang, type is "ENTER" or "LEAVE"
+  }
+- set_autosave_tab(value)
+  ^ tell tabview to automaticaly save current tabname as "tabview_name"_LAST
+  ^ value: true/false
+- set_tab(name)
+  ^ set's tab to tab named "name", returns true/false on success
+  ^ name: name of tab to set
+- set_global_event_handler(handler)
+  ^ set a handler to be called prior calling tab specific event handler
+  ^ handler: function(tabview,event) --> returns true to finish event processing false to continue
+- set_global_button_handler(handler)
+  ^ set a handler to be called prior calling tab specific button handler
+  ^ handler: function(tabview,fields) --> returns true to finish button processing false to continue
+- set_parent(parent)
+  ^ set parent to attach tabview to. TV's with parent are hidden if their parent
+       is hidden and they don't set their specified size.
+  ^ parent: component to attach to
+- show()
+  ^ show tabview
+- hide()
+  ^ hide tabview
+- delete()
+  ^ delete tabview
+- set_fixed_size(state)
+  ^ true/false set to fixed size, variable size
+
+File: fst/dialog.lua
+---------------------
+Only one dialog can be shown at a time. If a dialog is closed it's parent is
+gonna be activated and shown again.
+
+dialog_create(name, cbf_formspec, cbf_button_handler, cbf_events)
+^ create a dialog component
+^ name: name of component (unique per ui)
+^ cbf_formspec: function to be called to get formspec
+       function(dialogdata)
+^ cbf_button_handler: function to handle buttons
+       function(dialog, fields)
+^ cbf_events: function to handle events
+       function(dialog, event)
+
+Class reference dialog:
+
+methods:
+- set_parent(parent)
+  ^ set parent to attach a dialog to
+  ^ parent: component to attach to
+- show()
+  ^ show dialog
+- hide()
+  ^ hide dialog
+- delete()
+  ^ delete dialog from ui
+  
+members:
+- data
+  ^ variable data attached to this dialog
+- parent
+  ^ parent component to return to on exit
+  
+File: fst/buttonbar.lua
+-----------------------
+
+buttonbar_create(name, cbf_buttonhandler, pos, orientation, size)
+^ create a buttonbar
+^ name: name of component (unique per ui)
+^ cbf_buttonhandler: function to be called on button pressed
+       function(buttonbar,buttonname,buttondata)
+^ pos: position relative to upper left of current shown formspec
+       {
+               x,
+               y
+       }
+^ orientation: "vertical" or "horizontal"
+^ size: size of bar
+       {
+               width,
+               height
+       }
+
+Class reference buttonbar:
+
+methods:
+- add_button(btn_id, caption, button_image)
+- set_parent(parent)
+  ^ set parent to attach a buttonbar to
+  ^ parent: component to attach to
+- show()
+  ^ show buttonbar
+- hide()
+  ^ hide buttonbar
+- delete()
+  ^ delete buttonbar from ui
+
+Developer doc:
+==============
+Skeleton for any component:
+{
+       name           = "some id",               -- unique id
+       type           = "toplevel",              -- type of component
+                                                 -- toplevel: componant can be show without additional components
+                                                 -- addon:    component is an addon to be shown along toplevel component
+       hide           = function(this) end,      -- called to hide the component
+       show           = function(this) end,      -- called to show the component
+       delete         = function(this) end,      -- called to delete component from ui
+       handle_buttons = function(this,fields)    -- called upon button press
+       handle_events  = function(this,event)     -- called upon event reception
+       get_formspec   = function(this)           -- has to return formspec to be displayed
+}
index 109aededa5f5e1974d11fd7dc6af7fdac42eeb30..cd44fa81587cc737d821d57d317a6cc0e4657f48 100644 (file)
@@ -1,4 +1,4 @@
-Minetest Lua Mainmenu API Reference 0.4.9
+Minetest Lua Mainmenu API Reference 0.4.10
 ========================================
 
 Introduction
@@ -8,14 +8,14 @@ Description of formspec language to show your menu is in lua_api.txt
 
 Callbacks
 ---------
-engine.buttonhandler(fields): called when a button is pressed.
+core.buttonhandler(fields): called when a button is pressed.
 ^ fields = {name1 = value1, name2 = value2, ...}
-engine.event_handler(event)
+core.event_handler(event)
 ^ event: "MenuQuit", "KeyEnter", "ExitButton" or "EditBoxEnter"
 
 Gamedata
 --------
-The "gamedata" table is read when calling engine.start(). It should contain:
+The "gamedata" table is read when calling core.start(). It should contain:
 {
        playername     = <name>,
        password       = <password>,
@@ -27,15 +27,15 @@ The "gamedata" table is read when calling engine.start(). It should contain:
 
 Functions
 ---------
-engine.start()
-engine.close()
+core.start()
+core.close()
 
 Filesystem:
-engine.get_scriptdir()
+core.get_scriptdir()
 ^ returns directory of script
-engine.get_modpath() (possible in async calls)
+core.get_modpath() (possible in async calls)
 ^ returns path to global modpath
-engine.get_modstore_details(modid) (possible in async calls)
+core.get_modstore_details(modid) (possible in async calls)
 ^ modid numeric id of mod in modstore
 ^ returns {
        id                      = <numeric id of mod in modstore>,
@@ -47,7 +47,7 @@ engine.get_modstore_details(modid) (possible in async calls)
        license         = <short description of license>,
        rating          = <float value of current rating>
 }
-engine.get_modstore_list() (possible in async calls)
+core.get_modstore_list() (possible in async calls)
 ^ returns {
        [1] = {
                id               = <numeric id of mod in modstore>,
@@ -55,60 +55,60 @@ engine.get_modstore_list() (possible in async calls)
                basename = <basename for mod>
        }
 }
-engine.get_gamepath() (possible in async calls)
+core.get_gamepath() (possible in async calls)
 ^ returns path to global gamepath
-engine.get_texturepath() (possible in async calls)
+core.get_texturepath() (possible in async calls)
 ^ returns path to default textures
-engine.get_dirlist(path,onlydirs) (possible in async calls)
+core.get_dirlist(path,onlydirs) (possible in async calls)
 ^ path to get subdirs from
 ^ onlydirs should result contain only dirs?
 ^ returns list of folders within path
-engine.create_dir(absolute_path) (possible in async calls)
+core.create_dir(absolute_path) (possible in async calls)
 ^ absolute_path to directory to create (needs to be absolute)
 ^ returns true/false
-engine.delete_dir(absolute_path) (possible in async calls)
+core.delete_dir(absolute_path) (possible in async calls)
 ^ absolute_path to directory to delete (needs to be absolute)
 ^ returns true/false
-engine.copy_dir(source,destination,keep_soure) (possible in async calls)
+core.copy_dir(source,destination,keep_soure) (possible in async calls)
 ^ source folder
 ^ destination folder
 ^ keep_source DEFAULT true --> if set to false source is deleted after copying
 ^ returns true/false
-engine.extract_zip(zipfile,destination) [unzip within path required]
+core.extract_zip(zipfile,destination) [unzip within path required]
 ^ zipfile to extract
 ^ destination folder to extract to
 ^ returns true/false
-engine.download_file(url,target) (possible in async calls)
+core.download_file(url,target) (possible in async calls)
 ^ url to download
 ^ target to store to
 ^ returns true/false
-engine.get_version() (possible in async calls)
+core.get_version() (possible in async calls)
 ^ returns current core version
-engine.sound_play(spec, looped) -> handle
+core.sound_play(spec, looped) -> handle
 ^ spec = SimpleSoundSpec (see lua-api.txt)
 ^ looped = bool
-engine.sound_stop(handle)
+core.sound_stop(handle)
 
 Formspec:
-engine.update_formspec(formspec)
-engine.get_table_index(tablename) -> index
+core.update_formspec(formspec)
+core.get_table_index(tablename) -> index
 ^ can also handle textlists
-engine.formspec_escape(string) -> string
+core.formspec_escape(string) -> string
 ^ escapes characters [ ] \ , ; that can not be used in formspecs
-engine.explode_table_event(string) -> table
+core.explode_table_event(string) -> table
 ^ returns e.g. {type="CHG", row=1, column=2}
 ^ type: "INV" (no row selected), "CHG" (selected) or "DCL" (double-click)
-engine.explode_textlist_event(string) -> table
+core.explode_textlist_event(string) -> table
 ^ returns e.g. {type="CHG", index=1}
 ^ type: "INV" (no row selected), "CHG" (selected) or "DCL" (double-click)
 
 GUI:
-engine.set_background(type, texturepath)
+core.set_background(type, texturepath)
 ^ type: "background", "overlay", "header" or "footer"
-engine.set_clouds(<true/false>)
-engine.set_topleft_text(text)
-engine.show_keys_menu()
-engine.file_open_dialog(formname,caption)
+core.set_clouds(<true/false>)
+core.set_topleft_text(text)
+core.show_keys_menu()
+core.file_open_dialog(formname,caption)
 ^ shows a file open dialog
 ^ formname is base name of dialog response returned in fields
 ^     -if dialog was accepted "_accepted"
@@ -116,7 +116,7 @@ engine.file_open_dialog(formname,caption)
 ^     -if dialog was canceled "_cancelled"
 ^        will be added to fieldname value is set to formname itself
 ^ returns nil or selected file/folder
-engine.get_screen_info()
+core.get_screen_info()
 ^ returns {
        density         = <screen density 0.75,1.0,2.0,3.0 ... (dpi)>,
        display_width   = <width of display>,
@@ -126,7 +126,7 @@ engine.get_screen_info()
        }
 
 Games:
-engine.get_game(index)
+core.get_game(index)
 ^ returns {
        id               = <id>,
        path             = <full path to game>,
@@ -136,10 +136,10 @@ engine.get_game(index)
        DEPRECATED:
        addon_mods_paths = {[1] = <path>,},
 }
-engine.get_games() -> table of all games in upper format (possible in async calls)
+core.get_games() -> table of all games in upper format (possible in async calls)
 
 Favorites:
-engine.get_favorites(location) -> list of favorites (possible in async calls)
+core.get_favorites(location) -> list of favorites (possible in async calls)
 ^ location: "local" or "online"
 ^ returns {
        [1] = {
@@ -156,24 +156,24 @@ engine.get_favorites(location) -> list of favorites (possible in async calls)
        port          = <port>
        },
 }
-engine.delete_favorite(id, location) -> success
+core.delete_favorite(id, location) -> success
 
 Logging:
-engine.debug(line) (possible in async calls)
+core.debug(line) (possible in async calls)
 ^ Always printed to stderr and logfile (print() is redirected here)
-engine.log(line) (possible in async calls)
-engine.log(loglevel, line) (possible in async calls)
+core.log(line) (possible in async calls)
+core.log(loglevel, line) (possible in async calls)
 ^ loglevel one of "error", "action", "info", "verbose"
 
 Settings:
-engine.setting_set(name, value)
-engine.setting_get(name) -> string or nil (possible in async calls)
-engine.setting_setbool(name, value)
-engine.setting_getbool(name) -> bool or nil (possible in async calls)
-engine.setting_save() -> nil, save all settings to config file
+core.setting_set(name, value)
+core.setting_get(name) -> string or nil (possible in async calls)
+core.setting_setbool(name, value)
+core.setting_getbool(name) -> bool or nil (possible in async calls)
+core.setting_save() -> nil, save all settings to config file
 
 Worlds:
-engine.get_worlds() -> list of worlds (possible in async calls)
+core.get_worlds() -> list of worlds (possible in async calls)
 ^ returns {
        [1] = {
        path   = <full path to world>,
@@ -181,16 +181,16 @@ engine.get_worlds() -> list of worlds (possible in async calls)
        gameid = <gameid of world>,
        },
 }
-engine.create_world(worldname, gameid)
-engine.delete_world(index)
+core.create_world(worldname, gameid)
+core.delete_world(index)
 
 Helpers:
-engine.gettext(string) -> string
+core.gettext(string) -> string
 ^ look up the translation of a string in the gettext message catalog
 fgettext(string, ...) -> string
-^ call engine.gettext(string), replace "$1"..."$9" with the given
-^ extra arguments, call engine.formspec_escape and return the result
-engine.parse_json(string[, nullvalue]) -> something (possible in async calls)
+^ call core.gettext(string), replace "$1"..."$9" with the given
+^ extra arguments, call core.formspec_escape and return the result
+core.parse_json(string[, nullvalue]) -> something (possible in async calls)
 ^ see core.parse_json (lua_api.txt)
 dump(obj, dumped={})
 ^ Return object serialized as a string
@@ -202,7 +202,7 @@ core.is_yes(arg) (possible in async calls)
 ^ returns whether arg can be interpreted as yes
 
 Async:
-engine.handle_async(async_job,parameters,finished)
+core.handle_async(async_job,parameters,finished)
 ^ execute a function asynchronously
 ^ async_job is a function receiving one parameter and returning one parameter
 ^ parameters parameter table passed to async_job
@@ -212,8 +212,8 @@ engine.handle_async(async_job,parameters,finished)
 Limitations of Async operations
  -No access to global lua variables, don't even try
  -Limited set of available functions
-       e.g. No access to functions modifying menu like engine.start,engine.close,
-       engine.file_open_dialog
+       e.g. No access to functions modifying menu like core.start,core.close,
+       core.file_open_dialog
                        
 
 Class reference