MultiCraft2/builtin/fstk/tabview.lua

396 lines
12 KiB
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 3.0 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.
--------------------------------------------------------------------------------
-- 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 defaulttexturedir = core.formspec_escape(defaulttexturedir)
--------------------------------------------------------------------------------
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 = {},
}
-- Hidden tabs have a negative index
local i
if tab.hidden then
newtab.tabdata.hidden = true
i = -1
while self.tablist[i] do
i = i - 1
end
else
i = #self.tablist + 1
end
self.tablist[i] = newtab
if self.last_tab_index == i then
self.current_tab = tab.name
if tab.on_activate ~= nil then
tab.on_activate(nil,tab.name)
end
end
end
--------------------------------------------------------------------------------
local function make_side_pane_tab(y, tab_name, tooltip, selected)
local formspec = "style[" .. tab_name .. "_tab;bgimg=" ..
defaulttexturedir .. tab_name
if selected then
formspec = formspec .. "_menu_selected.png]"
else
formspec = formspec .. "_menu.png;bgimg_hovered=" ..
defaulttexturedir .. tab_name .. "_menu_hover.png]"
end
return formspec ..
"image_button[12.1," .. y .. ";1,1.5;;" .. tab_name .. "_tab;;true;false]" ..
"tooltip[" .. tab_name .. "_tab;" .. tooltip .. "]"
end
local function get_formspec(self)
local formspec = ""
if not self.hidden and (self.parent == nil or not self.parent.hidden) then
local name = self.tablist[self.last_tab_index].name
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 + 2,tsize.height + 1,
dump(self.fixed_size)) ..
"bgcolor[#0000]" ..
"container[1,1]" ..
"background9[-0.2,-1.26;" .. tsize.width + 0.4 .. "," ..
tsize.height + 1.75 .. ";" .. defaulttexturedir ..
"bg_common.png;false;40]" ..
"background9[12.13,1.05;0.9,2.6;" .. defaulttexturedir .. "side_menu.png;false;30]" ..
make_side_pane_tab(0.9, "settings", fgettext("Settings"), name == "settings") ..
"image[12.15,2.26;0.9,0.06;" .. defaulttexturedir .. "side_menu_divider.png]" ..
make_side_pane_tab(2.3, "authors", fgettext("Credits"), name == "credits")
end
-- formspec = formspec .. self:tab_header()
formspec = formspec .. self:button_header() ..
self.tablist[self.last_tab_index].get_formspec(
self,
name,
self.tablist[self.last_tab_index].tabdata,
self.tablist[self.last_tab_index].tabsize
)
if self.parent == nil then
formspec = formspec .. "container_end[]"
end
end
return formspec
end
local set_tab_by_name
--------------------------------------------------------------------------------
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 fields.authors_tab then
set_tab_by_name(self, "credits")
return true
elseif fields.settings_tab then
set_tab_by_name(self, "settings")
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 captions = {}
for i = 1, #self.tablist do
captions[i] = self.tablist[i].caption
end
local toadd = table.concat(captions, ",")
return string.format("tabheader[%f,%f;%s;%s;%i;true;false]",
self.header_x, self.header_y, self.name, toadd,
math.max(self.last_tab_index, 1))
end]]
--------------------------------------------------------------------------------
local function button_header(self)
local visible_tabs = {}
local btn_widths = {}
local total_width = 0
for i, tab in ipairs(self.tablist) do
if not tab.hidden and tab.caption ~= "" then
visible_tabs[#visible_tabs + 1] = tab
local w = utf8.len(core.get_translated_string(tab.caption))
btn_widths[#visible_tabs] = w
total_width = total_width + w
end
end
local toadd = ""
local coords_per_char = 12 / total_width
-- The formspec is 15.4875 "real" coordinates wide
-- local x = (12.39 - total_width) / 2 - 0.3
local x = -0.1
for i = 1, #visible_tabs do
local caption = visible_tabs[i].caption
local w = btn_widths[i] * coords_per_char
local texture = "upper_buttons_middle"
if i == 1 then
texture = "upper_buttons_left"
elseif i == #visible_tabs then
texture = "upper_buttons_right"
end
local btn_name = self.name .. "_" .. i
toadd = toadd ..
"style[" .. btn_name .. ";padding=-10;bgimg=" .. defaulttexturedir ..
texture
if i == math.abs(self.last_tab_index) then
toadd = toadd .. "_selected.png;"
else
toadd = toadd .. ".png;bgimg_hovered=" .. defaulttexturedir ..
texture .. "_hover.png;"
end
toadd = toadd .. "bgimg_middle=20;content_offset=0]" ..
"image_button[" .. x .. ",-1.1;" .. w + 0.22 .. ",0.9;;" ..
btn_name .. ";" .. caption .. ";true;false]"
x = x + w
end
return toadd
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, self)
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.settings: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,self)
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]]
local name_prefix = self.name .. "_"
local name_prefix_len = #name_prefix
for field in pairs(fields) do
if field:sub(1, name_prefix_len) == name_prefix then
local index = tonumber(field:sub(name_prefix_len + 1))
if self.last_tab_index == index then return false end
switch_to_tab(self, index)
return true
end
end
return false
end
--------------------------------------------------------------------------------
-- Declared as a local variable above handle_buttons
function set_tab_by_name(self, name)
-- This uses pairs so that hidden tabs (with a negative index) are searched
-- as well
for i, tab in pairs(self.tablist) do
if tab.name == name then
switch_to_tab(self, i)
if name ~= "local" then
mm_texture.set_dirt_bg()
end
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,self)
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,
button_header = button_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