tabview.lua 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. --Minetest
  2. --Copyright (C) 2014 sapier
  3. --
  4. --This program is free software; you can redistribute it and/or modify
  5. --it under the terms of the GNU Lesser General Public License as published by
  6. --the Free Software Foundation; either version 2.1 of the License, or
  7. --(at your option) any later version.
  8. --
  9. --This program is distributed in the hope that it will be useful,
  10. --but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. --MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. --GNU Lesser General Public License for more details.
  13. --
  14. --You should have received a copy of the GNU Lesser General Public License along
  15. --with this program; if not, write to the Free Software Foundation, Inc.,
  16. --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. --------------------------------------------------------------------------------
  18. -- A tabview implementation --
  19. -- Usage: --
  20. -- tabview.create: returns initialized tabview raw element --
  21. -- element.add(tab): add a tab declaration --
  22. -- element.handle_buttons() --
  23. -- element.handle_events() --
  24. -- element.getFormspec() returns formspec of tabview --
  25. --------------------------------------------------------------------------------
  26. --------------------------------------------------------------------------------
  27. local function add_tab(self,tab)
  28. assert(tab.size == nil or (type(tab.size) == table and
  29. tab.size.x ~= nil and tab.size.y ~= nil))
  30. assert(tab.cbf_formspec ~= nil and type(tab.cbf_formspec) == "function")
  31. assert(tab.cbf_button_handler == nil or
  32. type(tab.cbf_button_handler) == "function")
  33. assert(tab.cbf_events == nil or type(tab.cbf_events) == "function")
  34. local newtab = {
  35. name = tab.name,
  36. caption = tab.caption,
  37. button_handler = tab.cbf_button_handler,
  38. event_handler = tab.cbf_events,
  39. get_formspec = tab.cbf_formspec,
  40. tabsize = tab.tabsize,
  41. formspec_version = tab.formspec_version or 6,
  42. on_change = tab.on_change,
  43. tabdata = {},
  44. }
  45. self.tablist[#self.tablist + 1] = newtab
  46. if self.last_tab_index == #self.tablist then
  47. self.current_tab = tab.name
  48. if tab.on_activate ~= nil then
  49. tab.on_activate(nil,tab.name)
  50. end
  51. end
  52. end
  53. --------------------------------------------------------------------------------
  54. local function get_formspec(self)
  55. if self.hidden or (self.parent ~= nil and self.parent.hidden) then
  56. return ""
  57. end
  58. local tab = self.tablist[self.last_tab_index]
  59. local content, prepend = tab.get_formspec(self, tab.name, tab.tabdata, tab.tabsize)
  60. local ENABLE_TOUCH = core.settings:get_bool("enable_touch")
  61. local orig_tsize = tab.tabsize or { width = self.width, height = self.height }
  62. local tsize = { width = orig_tsize.width, height = orig_tsize.height }
  63. tsize.height = tsize.height
  64. + TABHEADER_H -- tabheader included in formspec size
  65. + (ENABLE_TOUCH and GAMEBAR_OFFSET_TOUCH or GAMEBAR_OFFSET_DESKTOP)
  66. + GAMEBAR_H -- gamebar included in formspec size
  67. if self.parent == nil and not prepend then
  68. prepend = string.format("size[%f,%f,%s]", tsize.width, tsize.height,
  69. dump(self.fixed_size))
  70. local anchor_pos = TABHEADER_H + orig_tsize.height / 2
  71. prepend = prepend .. ("anchor[0.5,%f]"):format(anchor_pos / tsize.height)
  72. if tab.formspec_version then
  73. prepend = ("formspec_version[%d]"):format(tab.formspec_version) .. prepend
  74. end
  75. end
  76. local end_button_size = 0.75
  77. local tab_header_size = { width = tsize.width, height = TABHEADER_H }
  78. if self.end_button then
  79. tab_header_size.width = tab_header_size.width - end_button_size - 0.1
  80. end
  81. local formspec = (prepend or "")
  82. formspec = formspec .. ("bgcolor[;neither]container[0,%f]box[0,0;%f,%f;#0000008C]"):format(
  83. TABHEADER_H, orig_tsize.width, orig_tsize.height)
  84. formspec = formspec .. self:tab_header(tab_header_size) .. content
  85. if self.end_button then
  86. formspec = formspec ..
  87. ("style[%s;noclip=true;border=false]"):format(self.end_button.name) ..
  88. ("tooltip[%s;%s]"):format(self.end_button.name, self.end_button.label) ..
  89. ("image_button[%f,%f;%f,%f;%s;%s;]"):format(
  90. self.width - end_button_size,
  91. (-tab_header_size.height - end_button_size) / 2,
  92. end_button_size,
  93. end_button_size,
  94. core.formspec_escape(self.end_button.icon),
  95. self.end_button.name)
  96. end
  97. formspec = formspec .. "container_end[]"
  98. return formspec
  99. end
  100. --------------------------------------------------------------------------------
  101. local function handle_buttons(self,fields)
  102. if self.hidden then
  103. return false
  104. end
  105. if self:handle_tab_buttons(fields) then
  106. return true
  107. end
  108. if self.end_button and fields[self.end_button.name] then
  109. return self.end_button.on_click(self)
  110. end
  111. if self.glb_btn_handler ~= nil and
  112. self.glb_btn_handler(self, fields) then
  113. return true
  114. end
  115. local tab = self.tablist[self.last_tab_index]
  116. if tab.button_handler ~= nil then
  117. return tab.button_handler(self, fields, tab.name, tab.tabdata)
  118. end
  119. return false
  120. end
  121. --------------------------------------------------------------------------------
  122. local function handle_events(self,event)
  123. if self.hidden then
  124. return false
  125. end
  126. if self.glb_evt_handler ~= nil and
  127. self.glb_evt_handler(self,event) then
  128. return true
  129. end
  130. local tab = self.tablist[self.last_tab_index]
  131. if tab.evt_handler ~= nil then
  132. return tab.evt_handler(self, event, tab.name, tab.tabdata)
  133. end
  134. return false
  135. end
  136. --------------------------------------------------------------------------------
  137. local function tab_header(self, size)
  138. local toadd = ""
  139. for i = 1, #self.tablist do
  140. if toadd ~= "" then
  141. toadd = toadd .. ","
  142. end
  143. local caption = self.tablist[i].caption
  144. if type(caption) == "function" then
  145. caption = caption(self)
  146. end
  147. toadd = toadd .. caption
  148. end
  149. return string.format("tabheader[%f,%f;%f,%f;%s;%s;%i;true;false]",
  150. self.header_x, self.header_y, size.width, size.height, self.name, toadd, self.last_tab_index)
  151. end
  152. --------------------------------------------------------------------------------
  153. local function switch_to_tab(self, index)
  154. --first call on_change for tab to leave
  155. if self.tablist[self.last_tab_index].on_change ~= nil then
  156. self.tablist[self.last_tab_index].on_change("LEAVE",
  157. self.current_tab, self.tablist[index].name)
  158. end
  159. --update tabview data
  160. self.last_tab_index = index
  161. local old_tab = self.current_tab
  162. self.current_tab = self.tablist[index].name
  163. if (self.autosave_tab) then
  164. core.settings:set(self.name .. "_LAST",self.current_tab)
  165. end
  166. -- call for tab to enter
  167. if self.tablist[index].on_change ~= nil then
  168. self.tablist[index].on_change("ENTER",
  169. old_tab,self.current_tab)
  170. end
  171. end
  172. --------------------------------------------------------------------------------
  173. local function handle_tab_buttons(self,fields)
  174. --save tab selection to config file
  175. if fields[self.name] then
  176. local index = tonumber(fields[self.name])
  177. switch_to_tab(self, index)
  178. return true
  179. end
  180. return false
  181. end
  182. --------------------------------------------------------------------------------
  183. local function set_tab_by_name(self, name)
  184. for i=1,#self.tablist,1 do
  185. if self.tablist[i].name == name then
  186. switch_to_tab(self, i)
  187. return true
  188. end
  189. end
  190. return false
  191. end
  192. --------------------------------------------------------------------------------
  193. local function hide_tabview(self)
  194. self.hidden=true
  195. --call on_change as we're not gonna show self tab any longer
  196. if self.tablist[self.last_tab_index].on_change ~= nil then
  197. self.tablist[self.last_tab_index].on_change("LEAVE",
  198. self.current_tab, nil)
  199. end
  200. end
  201. --------------------------------------------------------------------------------
  202. local function show_tabview(self)
  203. self.hidden=false
  204. -- call for tab to enter
  205. if self.tablist[self.last_tab_index].on_change ~= nil then
  206. self.tablist[self.last_tab_index].on_change("ENTER",
  207. nil,self.current_tab)
  208. end
  209. end
  210. local tabview_metatable = {
  211. add = add_tab,
  212. handle_buttons = handle_buttons,
  213. handle_events = handle_events,
  214. get_formspec = get_formspec,
  215. show = show_tabview,
  216. hide = hide_tabview,
  217. delete = function(self) ui.delete(self) end,
  218. set_parent = function(self,parent) self.parent = parent end,
  219. set_autosave_tab =
  220. function(self,value) self.autosave_tab = value end,
  221. set_tab = set_tab_by_name,
  222. set_global_button_handler =
  223. function(self,handler) self.glb_btn_handler = handler end,
  224. set_global_event_handler =
  225. function(self,handler) self.glb_evt_handler = handler end,
  226. set_fixed_size =
  227. function(self,state) self.fixed_size = state end,
  228. set_end_button =
  229. function(self, v) self.end_button = v end,
  230. tab_header = tab_header,
  231. handle_tab_buttons = handle_tab_buttons
  232. }
  233. tabview_metatable.__index = tabview_metatable
  234. --------------------------------------------------------------------------------
  235. function tabview_create(name, size, tabheaderpos)
  236. local self = {}
  237. self.name = name
  238. self.type = "toplevel"
  239. self.width = size.x
  240. self.height = size.y
  241. self.header_x = tabheaderpos.x
  242. self.header_y = tabheaderpos.y
  243. setmetatable(self, tabview_metatable)
  244. self.fixed_size = true
  245. self.hidden = true
  246. self.current_tab = nil
  247. self.last_tab_index = 1
  248. self.tablist = {}
  249. self.autosave_tab = false
  250. ui.add(self)
  251. return self
  252. end