/ gui.lua
gui.lua
  1  local gui = flow.widgets
  2  local _ps = player_settings
  3  local S = minetest.get_translator("player_settings")
  4  
  5  _ps.gui = flow.make_gui(function(player,ctx)
  6      ctx.name = player:get_player_name()
  7      if not ctx.showinfo then ctx.showinfo = {} end
  8      if not ctx.navbarData then
  9          local settings_by_category = {}
 10          for k,v in pairs(_ps.registered_settings) do
 11              if v.allow_show(ctx.name) then
 12                  if not settings_by_category[v.category] then
 13                      settings_by_category[v.category] = {}
 14                  end
 15                  settings_by_category[v.category][k] = v
 16              end
 17          end
 18          local categories_by_metacat = {}
 19          for k,v in pairs(settings_by_category) do
 20              if not (_ps.registered_categories[k] and _ps.registered_categories[k].allow_show(ctx.name)) then
 21                  settings_by_category[k] = nil
 22              end
 23              if not categories_by_metacat[_ps.registered_categories[k].metacategory] then
 24                  categories_by_metacat[_ps.registered_categories[k].metacategory] = {}
 25              end
 26              categories_by_metacat[_ps.registered_categories[k].metacategory][k] = v
 27          end
 28          for k,v in pairs(categories_by_metacat) do
 29              if not (_ps.registered_metacategories[k] and _ps.registered_metacategories[k].allow_show(ctx.name)) then
 30                  categories_by_metacat[k] = nil
 31              end
 32          end
 33          ctx.navbarData = categories_by_metacat
 34      end
 35      local navbar = {}
 36      for k,v in pairs(ctx.navbarData) do
 37          table.insert(navbar,gui.Label{ label = _ps.registered_metacategories[k].title })
 38          for k2,v2 in pairs(v) do
 39              table.insert(navbar,gui.Button {
 40                  label = _ps.registered_categories[k2].title, 
 41                  w = 1, expand = true,
 42                  ---@diagnostic disable-next-line: redefined-local, unused-local
 43                  on_event = function(player,ctx)
 44                      if ctx.current_category == k2 then return end
 45                      ctx.current_metacat = k
 46                      ctx.current_category = k2
 47                      return true
 48                  end,
 49              })
 50          end
 51      end
 52      navbar.w = 4; navbar.h = 10;
 53      navbar.name = "shbox"
 54  
 55      local settings_screen
 56      if not ctx.current_category then
 57          settings_screen = gui.Label {
 58              w = 10, h = 10,
 59              label = S("Select a category on the left."),
 60              expand = true, align_h = "centre", align_w = "centre",
 61          }
 62      else
 63          local list_settings = ctx.navbarData[ctx.current_metacat][ctx.current_category]
 64          local svbox = {}
 65          for k,v in pairs(list_settings) do
 66              local desc = S("@1 (@2)",v.description,_ps.util.types[v.type] or v.type)
 67              if v.type == "enum" then
 68                  desc = S("@1 (Multiple-choice of @2)",
 69                      v.description,
 70                      _ps.util.types[v.enum_type] or v.enum_type)
 71              end
 72  
 73              local display_type = v.display_type
 74              if display_type == "enum" and v.type ~= "enum" or 
 75                  display_type == "bool" and v.type ~= "bool" then
 76                  display_type = nil
 77              end
 78  
 79              -- TODO: Add support to scrollbar for numbers (waiting for flow mod support)
 80              if not display_type then
 81                  if v.type == "bool" then
 82                      display_type = "bool"
 83                  elseif v.type == "enum" then
 84                      display_type = "enum"
 85                  else
 86                      display_type = "string"
 87                  end
 88              end
 89              
 90  
 91              local s_status, selected = _ps.get_setting(ctx.name,k)
 92              if not s_status then
 93                  ctx.errmsg = {k, S("Failed to get setting of @1: @2",
 94                      k, _ps.util.errmsgs[selected] or selected
 95                  )}
 96              elseif display_type == "bool" then
 97                  table.insert(svbox, gui.HBox {
 98                      gui.Checkbox {
 99                          w = 5,h=1,
100                          name = "settings_" .. k,
101                          label = desc,
102                          selected = selected,
103                          on_event = function(player,ctx)
104                              ctx.errmsg = nil
105                              local form = ctx.form
106                              if type(form["settings_" .. k]) == "boolean" then
107                                  local status, errmsg =_ps.set_setting(ctx.name,k,form["settings_" .. k])
108                                  if not status then
109                                      ctx.errmsg = {k,errmsg}
110                                      form["settings_" .. k] = _ps.get_setting(ctx.name,k)
111                                  end
112                                  return true
113                              end
114                          end,
115                          expand = true, align_h = "left",
116                      },
117                      gui.ImageButton {
118                          w = 1, h = 1,
119                          texture_name = "settings_reset.png",
120                          name = "settingsReset_" .. k,
121                          ---@diagnostic disable-next-line: redefined-local, unused-local
122                          on_event = function(player,ctx)
123                              ctx.errmsg = nil
124                              local form = ctx.form
125                              _ps.set_default(ctx.name,k)
126                              form["settings_" .. k] = v.default
127                              return true
128                          end,
129                          drawborder = false,
130                      },
131                      gui.ImageButton {
132                          w = 1, h = 1,
133                          texture_name = "settings_info.png",
134                          name = "settingsInfo_" .. k,
135                          ---@diagnostic disable-next-line: redefined-local, unused-local
136                          on_event = function(player,ctx)
137                              ctx.showinfo[k] = not ctx.showinfo[k]
138                              return true
139                          end,
140                          drawborder = false,
141                      }
142                  })
143              elseif display_type == "enum" then
144                  table.insert(svbox, gui.Label {
145                      label = desc
146                  })
147                  table.insert(svbox, gui.HBox {
148                      gui.Dropdown {
149                          w = 3,h=1,
150                          name = "settings_" .. k,
151                          items = v.enum_choices,
152                          selected_idx = _ps.util.idx_in_table(v.enum_choices,selected),
153                      },
154                      gui.Button {
155                          w = 2, h = 1,
156                          name = "settingsSubmit_" .. k,
157                          label = S("Set"),
158                          ---@diagnostic disable-next-line: redefined-local, unused-local
159                          on_event = function(player,ctx)
160                              ctx.errmsg = nil
161                              local form = ctx.form
162                              print(form["settings_" .. k])
163                              local status, errmsg =_ps.set_setting(ctx.name,k,form["settings_" .. k])
164                              if not status then
165                                  ctx.errmsg = {k,errmsg}
166                                  form["settings_" .. k] = _ps.get_setting(ctx.name,k)
167                              end
168                              return true
169                          end,
170                          expand = true, align_h = "left",
171                      },
172                      gui.ImageButton {
173                          w = 1, h = 1,
174                          texture_name = "settings_reset.png",
175                          name = "settingsReset_" .. k,
176                          ---@diagnostic disable-next-line: redefined-local, unused-local
177                          on_event = function(player,ctx)
178                              ctx.errmsg = nil
179                              local form = ctx.form
180                              _ps.set_default(ctx.name,k)
181                              form["settings_" .. k] = v.default
182                              return true
183                          end,
184                          drawborder = false,
185                      },
186                      gui.ImageButton {
187                          w = 1, h = 1,
188                          texture_name = "settings_info.png",
189                          name = "settingsInfo_" .. k,
190                          ---@diagnostic disable-next-line: redefined-local, unused-local
191                          on_event = function(player,ctx)
192                              ctx.showinfo[k] = not ctx.showinfo[k]
193                              return true
194                          end,
195                          drawborder = false,
196                      }
197                  })
198              elseif display_type == "string" then -- String-like
199                  table.insert(svbox, gui.Label {
200                      label = desc
201                  })
202                  table.insert(svbox, gui.HBox {
203                      gui.Field {
204                          w = 3,h=1,
205                          name = "settings_" .. k,
206                          default = selected,
207                      },
208                      gui.Button {
209                          w = 2,h=1,
210                          name = "settingsSubmit_" .. k,
211                          label = S("Set"),
212                          ---@diagnostic disable-next-line: redefined-local, unused-local
213                          on_event = function(player,ctx)
214                              ctx.errmsg = nil
215                              local form = ctx.form
216                              local status, errmsg =_ps.set_setting(ctx.name,k,form["settings_" .. k])
217                              if not status then
218                                  ctx.errmsg = {k,errmsg}
219                                  form["settings_" .. k] = _ps.get_setting(ctx.name,k)
220                              end
221                              return true
222                          end,
223                          expand = true, align_h = "left",
224                      },
225                      gui.ImageButton {
226                          w = 1, h = 1,
227                          texture_name = "settings_reset.png",
228                          name = "settingsReset_" .. k,
229                          ---@diagnostic disable-next-line: redefined-local, unused-local
230                          on_event = function(player,ctx)
231                              ctx.errmsg = nil
232                              local form = ctx.form
233                              _ps.set_default(ctx.name,k)
234                              form["settings_" .. k] = v.default
235                              return true
236                          end,
237                          drawborder = false,
238                      },
239                      gui.ImageButton {
240                          w = 1, h = 1,
241                          texture_name = "settings_info.png",
242                          name = "settingsInfo_" .. k,
243                          ---@diagnostic disable-next-line: redefined-local, unused-local
244                          on_event = function(player,ctx)
245                              ctx.showinfo[k] = not ctx.showinfo[k]
246                              return true
247                          end,
248                          drawborder = false,
249                      }
250                  })
251              else
252                  error("[player_settings] Attempt to display setting with unknown display type " .. display_type)
253              end
254              if ctx.errmsg and ctx.errmsg[1] == k then
255                  local user_errmsg = _ps.util.errmsgs[ctx.errmsg[2]] or ctx.errmsg[2]
256                  table.insert(svbox, gui.Label {
257                      label = minetest.colorize("#FF0000", S("Error: @1", user_errmsg)),
258                      -- label = ctx.errmsg[2],
259                  })
260              end
261              if ctx.showinfo[k] and v.long_description then
262                  table.insert(svbox, gui.Label {
263                      label = minetest.get_color_escape_sequence("#00FF00") .. v.long_description,
264                  })
265              end
266          end
267          svbox.w = 10; svbox.h = 10;
268          svbox.name = "svbox"
269          settings_screen = gui.ScrollableVBox(svbox)
270      end
271      local content_body = gui.HBox {
272          gui.ScrollableVBox(navbar),
273          settings_screen
274      }
275      local content_with_header = gui.VBox {
276          gui.HBox {
277              gui.Label { label = S("Settings"), expand = true, align_h = "left" },
278              gui.ButtonExit { w = 0.7, h = 0.7, label = "x" }
279          },
280          gui.Box{w = 1, h = 0.05, color = "grey", padding = 0},
281          content_body
282      }
283      return ctx.inside_sway and content_body or content_with_header
284  end)
285  
286  minetest.register_chatcommand("settings", {
287      description = S("Open settings menu"),
288      func = function(name,param)
289          _ps.gui:show(minetest.get_player_by_name(name))
290      end
291  })
292  
293  if minetest.get_modpath("sway") then
294      sway.register_page("player_settings:settings", {
295          title = S("Settings"),
296          get = function (_self, player, ctx)
297              if not ctx.player_settings then
298                  ctx.player_settings = { inside_sway = true }
299              end
300              return sway.Form {
301                  _ps.gui:embed {
302                      player = player,
303                      name = "player_settings"
304                  }
305              }
306          end
307      })
308  end