575f130854
* cherry picked from commit14a7fe0266
* fix main menu minor changes cherry picked from commitf917f5c8d0
431 lines
13 KiB
Lua
431 lines
13 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 fmt = string.format
|
|
local tconcat = table.concat
|
|
|
|
--------------------------------------------------------------------------------
|
|
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 add_side_button(self, btn)
|
|
if btn.pos then
|
|
table.insert(self.side_buttons, btn.pos, btn)
|
|
else
|
|
self.side_buttons[#self.side_buttons + 1] = btn
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
local tpath = defaulttexturedir_esc .. "gui" .. DIR_DELIM_esc
|
|
local function add_side_menu(self, fs, selected_tab, x, fs_h, darken)
|
|
if #self.side_buttons == 0 then return end
|
|
|
|
local side_menu_h = #self.side_buttons * 1.41 + 0.14
|
|
local bg_y = fs_h / 2 - side_menu_h / 2
|
|
fs[#fs + 1] = fmt("image[%s,%s;1.15,%s;%sside_menu.png;30]", x, bg_y, side_menu_h, tpath)
|
|
|
|
for i, btn in ipairs(self.side_buttons) do
|
|
local y = bg_y - 1.31 + 1.41 * i
|
|
if i > 1 then
|
|
fs[#fs + 1] = fmt("image[%s,%s;0.9,0.06;%sside_menu_divider.png]", x + 0.1, y - 0.06, tpath)
|
|
end
|
|
|
|
local btn_name = self.name .. "_side_" .. i
|
|
fs[#fs + 1] = fmt("style[%s;bgimg=", btn_name)
|
|
|
|
local tab_name = btn.tab_name or btn.tab_name_selected
|
|
local texture_prefix = btn.texture_prefix or tab_name
|
|
if tab_name and tab_name == selected_tab then
|
|
fs[#fs + 1] = btn.texture_selected or tpath .. texture_prefix .. "_menu_selected.png"
|
|
else
|
|
fs[#fs + 1] = btn.texture or tpath .. texture_prefix .. "_menu.png"
|
|
fs[#fs + 1] = ";bgimg_hovered="
|
|
fs[#fs + 1] = btn.texture_hover or tpath .. texture_prefix .. "_menu_hover.png"
|
|
end
|
|
fs[#fs + 1] = "]"
|
|
|
|
fs[#fs + 1] = fmt("image_button[%s,%s;1,1.35;;%s;;true;false]", x + 0.09, y, btn_name)
|
|
fs[#fs + 1] = fmt("tooltip[%s;%s]", btn_name, btn.tooltip)
|
|
end
|
|
|
|
if darken then
|
|
fs[#fs + 1] = fmt("style[cancel;bgimg=%sside_menu_darken.png;bgimg_middle=30]", tpath)
|
|
fs[#fs + 1] = fmt("image_button[%s,%s;1.15,%s;;cancel;;true;false]", x, bg_y, side_menu_h)
|
|
|
|
-- Reset "cancel" button styling
|
|
fs[#fs + 1] = "style[cancel;bgimg=;bgimg_middle=]"
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
local function add_button_header(self, fs, fs_w)
|
|
local visible_tabs = {}
|
|
for _, tab in ipairs(self.tablist) do
|
|
if not tab.hidden and tab.caption ~= "" then
|
|
visible_tabs[#visible_tabs + 1] = tab
|
|
end
|
|
end
|
|
|
|
local x = 1.5
|
|
local w = (fs_w - 0.53) / #visible_tabs
|
|
for i = 1, #visible_tabs do
|
|
local caption = visible_tabs[i].caption
|
|
local side = i == 1 and "left" or (i < #visible_tabs and "middle" or "right")
|
|
local btn_name = self.name .. "_" .. i
|
|
if i == math.abs(self.last_tab_index) then
|
|
side = side .. "_pressed"
|
|
end
|
|
|
|
fs[#fs + 1] = btn_style(btn_name, side)
|
|
fs[#fs + 1] = fmt("style[%s;content_offset=0;font_size=+1]", btn_name)
|
|
fs[#fs + 1] = fmt("image_button[%s,0.25;%s,0.9;;%s;%s;true;false]",
|
|
x, w + 0.03, btn_name, caption)
|
|
x = x + w
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
local function get_formspec(self, popup_w, popup_h, popup_fs)
|
|
if (self.hidden or (self.parent and self.parent.hidden)) and not popup_fs then
|
|
return ""
|
|
end
|
|
|
|
local fs = {}
|
|
|
|
local current_tab = self.tablist[self.last_tab_index]
|
|
local content, prepend_override = current_tab.get_formspec(self,
|
|
current_tab.name, current_tab.tabdata, current_tab.size)
|
|
local real_coords = current_tab.formspec_version and current_tab.formspec_version > 1
|
|
local w, h
|
|
if prepend_override then
|
|
fs[#fs + 1] = prepend_override
|
|
elseif not self.parent then
|
|
fs[#fs + 1] = "formspec_version[4]"
|
|
|
|
local s = current_tab.tabsize or self
|
|
w, h = s.width, s.height
|
|
if not real_coords then
|
|
w = w * 1.25 + 0.6
|
|
h = h * 1.15 + 0.9
|
|
end
|
|
fs[#fs + 1] = fmt("size[%s,%s]", w + 2.5, h + 1.15)
|
|
|
|
-- Background
|
|
fs[#fs + 1] = "bgcolor[;neither]"
|
|
fs[#fs + 1] = "listcolors[#000;#000;#000;#dff6f5;#302c2e]"
|
|
fs[#fs + 1] = fmt("background9[1.25,0;%s,%s;%sbg_common.png;false;32]",
|
|
w, h + 1.15, defaulttexturedir_esc)
|
|
|
|
add_button_header(self, fs, w)
|
|
|
|
-- This container isn't ideal for real_coordinates formspecs but
|
|
-- keeps compatibility with existing code
|
|
fs[#fs + 1] = "container[1,1]"
|
|
fs[#fs + 1] = "real_coordinates[false]"
|
|
end
|
|
|
|
fs[#fs + 1] = content
|
|
|
|
if not prepend_override and not self.parent then
|
|
-- Make sure that real_coordinates is enabled
|
|
fs[#fs + 1] = "real_coordinates[true]"
|
|
fs[#fs + 1] = "container_end[]"
|
|
|
|
-- Darken background
|
|
if popup_fs then
|
|
-- This styling gets reset in add_side_menu
|
|
fs[#fs + 1] = fmt("style[cancel;bgimg=%sbg_darken.png;bgimg_middle=32]", tpath)
|
|
fs[#fs + 1] = fmt("image_button[1.25,0;%s,%s;;cancel;;false;false]",
|
|
w, h + 1.15)
|
|
end
|
|
|
|
-- Add the side menu after the darkened background
|
|
add_side_menu(self, fs, current_tab.name, w + 1.175, h + 1.15, popup_fs)
|
|
|
|
-- Draw the popup
|
|
if popup_fs then
|
|
fs[#fs + 1] = fmt("container[%s,%s]", (w + 2.5 - popup_w) / 2,
|
|
(h + 1.15 - popup_h) / 2)
|
|
fs[#fs + 1] = fmt("style[popup_bg;bgimg=%sbg_common.png;bgimg_middle=32]",
|
|
defaulttexturedir_esc)
|
|
fs[#fs + 1] = fmt("image_button[0,0;%s,%s;;popup_bg;;false;false]",
|
|
popup_w, popup_h)
|
|
fs[#fs + 1] = popup_fs
|
|
fs[#fs + 1] = "container_end[]"
|
|
end
|
|
|
|
-- Disable real_coordinates again in case there are other UI elements
|
|
-- (like the game switcher in buttonbar.lua)
|
|
fs[#fs + 1] = "real_coordinates[false]"
|
|
end
|
|
|
|
return tconcat(fs)
|
|
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 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 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
|
|
if field:sub(name_prefix_len + 1, name_prefix_len + 5) == "side_" then
|
|
local btn = self.side_buttons[tonumber(field:sub(name_prefix_len + 6))]
|
|
if btn.tab_name then
|
|
set_tab_by_name(self, btn.tab_name)
|
|
else
|
|
btn.on_click(self)
|
|
end
|
|
else
|
|
local index = tonumber(field:sub(name_prefix_len + 1))
|
|
if math.abs(self.last_tab_index) == index then return false end
|
|
switch_to_tab(self, index)
|
|
end
|
|
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,
|
|
add_side_button = add_side_button,
|
|
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.side_buttons = {}
|
|
|
|
self.autosave_tab = false
|
|
|
|
ui.add(self)
|
|
return self
|
|
end
|