ui.lua 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. --Luanti
  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. ui = {}
  18. ui.childlist = {}
  19. ui.default = nil
  20. -- Whether fstk is currently showing its own formspec instead of active ui elements.
  21. ui.overridden = false
  22. --------------------------------------------------------------------------------
  23. function ui.add(child)
  24. --TODO check child
  25. ui.childlist[child.name] = child
  26. return child.name
  27. end
  28. --------------------------------------------------------------------------------
  29. function ui.delete(child)
  30. if ui.childlist[child.name] == nil then
  31. return false
  32. end
  33. ui.childlist[child.name] = nil
  34. return true
  35. end
  36. --------------------------------------------------------------------------------
  37. function ui.set_default(name)
  38. ui.default = name
  39. end
  40. --------------------------------------------------------------------------------
  41. function ui.find_by_name(name)
  42. return ui.childlist[name]
  43. end
  44. --------------------------------------------------------------------------------
  45. -- "title" and "message" must already be formspec-escaped, e.g. via fgettext or
  46. -- core.formspec_escape.
  47. function ui.get_message_formspec(title, message, btn_id)
  48. return table.concat({
  49. "size[14,8]",
  50. "real_coordinates[true]",
  51. "set_focus[", btn_id, ";true]",
  52. "box[0.5,1.2;13,5;#000]",
  53. ("textarea[0.5,1.2;13,5;;%s;%s]"):format(title, message),
  54. "button[5,6.6;4,1;", btn_id, ";" .. fgettext("OK") .. "]",
  55. })
  56. end
  57. --------------------------------------------------------------------------------
  58. --------------------------------------------------------------------------------
  59. -- Internal functions not to be called from user
  60. --------------------------------------------------------------------------------
  61. --------------------------------------------------------------------------------
  62. function ui.update()
  63. ui.overridden = false
  64. local formspec = {}
  65. -- handle errors
  66. if gamedata ~= nil and gamedata.reconnect_requested then
  67. local error_message = core.formspec_escape(gamedata.errormessage)
  68. or fgettext("<none available>")
  69. formspec = {
  70. "size[14,8]",
  71. "real_coordinates[true]",
  72. "set_focus[btn_reconnect_yes;true]",
  73. "box[0.5,1.2;13,5;#000]",
  74. ("textarea[0.5,1.2;13,5;;%s;%s]"):format(
  75. fgettext("The server has requested a reconnect:"), error_message),
  76. "button[2,6.6;4,1;btn_reconnect_yes;" .. fgettext("Reconnect") .. "]",
  77. "button[8,6.6;4,1;btn_reconnect_no;" .. fgettext("Main menu") .. "]"
  78. }
  79. ui.overridden = true
  80. elseif gamedata ~= nil and gamedata.errormessage ~= nil then
  81. -- Note to API users:
  82. -- "gamedata.errormessage" must not be formspec-escaped yet.
  83. -- For translations, fgettext_ne should be used.
  84. local error_message = core.formspec_escape(gamedata.errormessage)
  85. local error_title
  86. if string.find(gamedata.errormessage, "ModError") then
  87. error_title = fgettext("An error occurred in a Lua script:")
  88. else
  89. error_title = fgettext("An error occurred:")
  90. end
  91. formspec = {ui.get_message_formspec(error_title, error_message, "btn_error_confirm")}
  92. ui.overridden = true
  93. else
  94. local active_toplevel_ui_elements = 0
  95. for key,value in pairs(ui.childlist) do
  96. if (value.type == "toplevel") then
  97. local retval = value:get_formspec()
  98. if retval ~= nil and retval ~= "" then
  99. active_toplevel_ui_elements = active_toplevel_ui_elements + 1
  100. table.insert(formspec, retval)
  101. end
  102. end
  103. end
  104. -- no need to show addons if there ain't a toplevel element
  105. if (active_toplevel_ui_elements > 0) then
  106. for key,value in pairs(ui.childlist) do
  107. if (value.type == "addon") then
  108. local retval = value:get_formspec()
  109. if retval ~= nil and retval ~= "" then
  110. table.insert(formspec, retval)
  111. end
  112. end
  113. end
  114. end
  115. if (active_toplevel_ui_elements > 1) then
  116. core.log("warning", "more than one active ui "..
  117. "element, self most likely isn't intended")
  118. end
  119. if (active_toplevel_ui_elements == 0) then
  120. core.log("warning", "no toplevel ui element "..
  121. "active; switching to default")
  122. ui.childlist[ui.default]:show()
  123. formspec = {ui.childlist[ui.default]:get_formspec()}
  124. end
  125. end
  126. core.update_formspec(table.concat(formspec))
  127. end
  128. --------------------------------------------------------------------------------
  129. function ui.handle_buttons(fields)
  130. for key,value in pairs(ui.childlist) do
  131. local retval = value:handle_buttons(fields)
  132. if retval then
  133. ui.update()
  134. return
  135. end
  136. end
  137. end
  138. --------------------------------------------------------------------------------
  139. function ui.handle_events(event)
  140. for key,value in pairs(ui.childlist) do
  141. if value.handle_events ~= nil then
  142. local retval = value:handle_events(event)
  143. if retval then
  144. return retval
  145. end
  146. end
  147. end
  148. end
  149. --------------------------------------------------------------------------------
  150. --------------------------------------------------------------------------------
  151. -- initialize callbacks
  152. --------------------------------------------------------------------------------
  153. --------------------------------------------------------------------------------
  154. core.button_handler = function(fields)
  155. if fields["btn_reconnect_yes"] then
  156. gamedata.reconnect_requested = false
  157. gamedata.errormessage = nil
  158. gamedata.do_reconnect = true
  159. core.start()
  160. return
  161. elseif fields["btn_reconnect_no"] or fields["btn_error_confirm"] then
  162. gamedata.errormessage = nil
  163. gamedata.reconnect_requested = false
  164. ui.update()
  165. return
  166. end
  167. if ui.handle_buttons(fields) then
  168. ui.update()
  169. end
  170. end
  171. --------------------------------------------------------------------------------
  172. core.event_handler = function(event)
  173. -- Handle error messages
  174. if ui.overridden then
  175. if event == "MenuQuit" then
  176. gamedata.errormessage = nil
  177. gamedata.reconnect_requested = false
  178. ui.update()
  179. end
  180. return
  181. end
  182. if ui.handle_events(event) then
  183. ui.update()
  184. return
  185. end
  186. if event == "Refresh" then
  187. ui.update()
  188. return
  189. end
  190. end