summaryrefslogtreecommitdiff
path: root/builtin/fstk
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/fstk')
-rw-r--r--builtin/fstk/buttonbar.lua209
-rw-r--r--builtin/fstk/dialog.lua69
-rw-r--r--builtin/fstk/tabview.lua273
-rw-r--r--builtin/fstk/ui.lua172
4 files changed, 723 insertions, 0 deletions
diff --git a/builtin/fstk/buttonbar.lua b/builtin/fstk/buttonbar.lua
new file mode 100644
index 000000000..f5ac8905e
--- /dev/null
+++ b/builtin/fstk/buttonbar.lua
@@ -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
index 000000000..214b0388f
--- /dev/null
+++ b/builtin/fstk/dialog.lua
@@ -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
index 000000000..47603fb1b
--- /dev/null
+++ b/builtin/fstk/tabview.lua
@@ -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
index 000000000..e0438247c
--- /dev/null
+++ b/builtin/fstk/ui.lua
@@ -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