------------------------------------------------------------------------------- ---Class to help to build form Form = newclass(Object,function(base,classname) Object.init(base,classname) base:style() base.otherClose = true base.locate = "screen" base.panelClose = true base.help_button = true base.auto_clear = true base.content_verticaly = true base.has_tips = false base.list_tips = { {name="tips-production-line", count=4}, {name="tips-production-block", count=4} } end) ------------------------------------------------------------------------------- ---Style function Form:style() local display_width, display_height, scale = User.getMainSizes() local width_main = display_width/scale local height_main = display_height/scale self.styles = { flow_panel ={ width = width_main, height = height_main, minimal_width = width_main, minimal_height = height_main, maximal_width = width_main, maximal_height = height_main, } } self:onStyle(self.styles, width_main, height_main) end ------------------------------------------------------------------------------- ---On Style ---@param styles table ---@param width_main number ---@param height_main number function Form:onStyle(styles, width_main, height_main) end ------------------------------------------------------------------------------- ---Bind Dispatcher function Form:bind() Dispatcher:bind("on_gui_event", self, self.event) Dispatcher:bind("on_gui_open", self, self.open) Dispatcher:bind("on_gui_open", self, self.update) Dispatcher:bind("on_gui_update", self, self.update) Dispatcher:bind("on_gui_close", self, self.close) Dispatcher:bind("on_gui_error", self, self.updateError) Dispatcher:bind("on_gui_message", self, self.updateMessage) self:onBind() end ------------------------------------------------------------------------------- ---On Bind Dispatcher function Form:onBind() end ------------------------------------------------------------------------------- ---On initialization function Form:onInit() end ------------------------------------------------------------------------------- ---Is visible ---@return boolean function Form:isVisible() return true end ------------------------------------------------------------------------------- ---Is special ---@return boolean function Form:isSpecial() return false end ------------------------------------------------------------------------------- ---Is tool ---@return boolean function Form:isTool() return false end ------------------------------------------------------------------------------- ---Get panel name ---@return string function Form:getPanelName() return self.classname end ------------------------------------------------------------------------------- ---Get the parent panel ---@return LuaGuiElement function Form:getParentPanel() local lua_player = Player.native() return lua_player.gui[self.locate] end ------------------------------------------------------------------------------- ---Set style ---@param element LuaGuiElement ---@param style string ---@param property string function Form:setStyle(element, style, property) if element.style ~= nil and self.styles ~= nil and self.styles[style] ~= nil and self.styles[style][property] ~= nil then element.style[property] = self.styles[style][property] end end -------------------------------------------------------------------------------- ---Get the parent panel ---@return LuaGuiElement function Form:getPanel() local parent_panel = self:getParentPanel() if parent_panel[self:getPanelName()] ~= nil and parent_panel[self:getPanelName()].valid then return parent_panel[self:getPanelName()], parent_panel[self:getPanelName()]["content_panel"], parent_panel[self:getPanelName()]["header_panel"]["menu_panel"] end ---main panel local flow_panel = GuiElement.add(parent_panel, GuiFrameV(self:getPanelName()):style("frame")) flow_panel.style.horizontally_stretchable = true flow_panel.style.vertically_stretchable = true flow_panel.location = User.getLocationForm(self:getPanelName()) self:setFlowStyle(flow_panel) local header_panel = GuiElement.add(flow_panel, GuiFlowH("header_panel")) header_panel.style.horizontally_stretchable = true ---header panel local title_panel = GuiElement.add(header_panel, GuiFrameH("title_panel"):caption(self.panelCaption or self.classname):style("helmod_frame_header")) title_panel.style.horizontally_stretchable = true title_panel.drag_target = flow_panel local menu_panel = GuiElement.add(header_panel, GuiFlowH("menu_panel")) menu_panel.style.horizontal_spacing = 10 menu_panel.style.horizontal_align = "right" local content_panel content_panel = GuiElement.add(flow_panel, GuiFrameV("content_panel"):style("inside_deep_frame")) content_panel.style.vertically_stretchable = true content_panel.style.horizontally_stretchable = true return flow_panel, content_panel, menu_panel end ------------------------------------------------------------------------------- ---Set style ---@param flow_panel LuaGuiElement function Form:setFlowStyle(flow_panel) self:setStyle(flow_panel, "flow_panel", "width") self:setStyle(flow_panel, "flow_panel", "height") self:setStyle(flow_panel, "flow_panel", "minimal_width") self:setStyle(flow_panel, "flow_panel", "minimal_height") self:setStyle(flow_panel, "flow_panel", "maximal_width") self:setStyle(flow_panel, "flow_panel", "maximal_height") end ------------------------------------------------------------------------------- ---Get or create scroll panel ---@param panel_name string ---@return LuaGuiElement function Form:getScrollPanel(panel_name) local flow_panel, content_panel, menu_panel = self:getPanel() if content_panel[panel_name] ~= nil and content_panel[panel_name].valid then return content_panel[panel_name] end local frame_panel = GuiElement.add(content_panel, GuiScroll(panel_name):style("helmod_scroll_pane")) frame_panel.style.horizontally_stretchable = true return frame_panel end ------------------------------------------------------------------------------- ---Get or create scroll panel ---@param panel_name string ---@return LuaGuiElement function Form:getScrollFramePanel(panel_name) local frame_panel = self:getFramePanel(panel_name) local scroll_name = "scroll-panel" if frame_panel[scroll_name] ~= nil and frame_panel[scroll_name].valid then return frame_panel[scroll_name] end local scroll_panel = GuiElement.add(frame_panel, GuiScroll(scroll_name)) scroll_panel.style.horizontally_stretchable = false return scroll_panel end ------------------------------------------------------------------------------- ---Get or create flow panel ---@param panel_name string ---@return LuaGuiElement function Form:getFlowPanel(panel_name, direction) local flow_panel, content_panel, menu_panel = self:getPanel() if content_panel[panel_name] ~= nil and content_panel[panel_name].valid then return content_panel[panel_name] end local frame_panel = nil if direction == "horizontal" then frame_panel = GuiElement.add(content_panel, GuiFlowH(panel_name)) else frame_panel = GuiElement.add(content_panel, GuiFlowV(panel_name)) end frame_panel.style.horizontally_stretchable = true return frame_panel end ------------------------------------------------------------------------------- ---Get or create frame panel ---@param panel_name string ---@param style string ---@param direction string --horizontal, vertical ---@return LuaGuiElement function Form:getFramePanel(panel_name, style, direction) local flow_panel, content_panel, menu_panel = self:getPanel() if content_panel[panel_name] ~= nil and content_panel[panel_name].valid then return content_panel[panel_name] end local frame_panel = nil if direction == "horizontal" then frame_panel = GuiElement.add(content_panel, GuiFrameH(panel_name):style(style or "helmod_frame")) else frame_panel = GuiElement.add(content_panel, GuiFrameV(panel_name):style(style or "helmod_frame")) end frame_panel.style.horizontally_stretchable = true return frame_panel end ------------------------------------------------------------------------------- ---Get or create frame panel ---@param panel_name string ---@param direction string --horizontal, vertical ---@return LuaGuiElement function Form:getFrameInsidePanel(panel_name, direction) return self:getFramePanel(panel_name, "helmod_inside_frame", direction) end ------------------------------------------------------------------------------- ---Get or create frame panel ---@param panel_name string ---@param direction string --horizontal, vertical ---@return LuaGuiElement function Form:getFrameDeepPanel(panel_name, direction) return self:getFramePanel(panel_name, "helmod_deep_frame", direction) end ------------------------------------------------------------------------------- ---Get or create frame panel ---@param panel_name string ---@param direction string --horizontal, vertical ---@return LuaGuiElement function Form:getFrameTabbedPanel(panel_name, direction) return self:getFramePanel(panel_name, "helmod_tabbed_frame", direction) end ------------------------------------------------------------------------------- ---Get the top panel ---@return LuaGuiElement function Form:getTopPanel() local panel = self:getFrameDeepPanel("top") return panel end ------------------------------------------------------------------------------- ---Get the menu panel ---@return LuaGuiElement, LuaGuiElement function Form:getMenuPanel() local content_panel = self:getTopPanel() local panel_name = "menu" local left_name = "left_menu" local right_name = "right_menu" if content_panel[panel_name] ~= nil and content_panel[panel_name].valid then return content_panel[panel_name][left_name], content_panel[panel_name][right_name] end local panel = GuiElement.add(content_panel, GuiFlowH(panel_name)) panel.style.horizontally_stretchable = true panel.style.height = 32 local left_panel = GuiElement.add(panel, GuiFlowH(left_name)) left_panel.style.horizontal_spacing = 10 local right_panel = GuiElement.add(panel, GuiFlowH(right_name)) right_panel.style.horizontal_spacing = 10 right_panel.style.horizontally_stretchable = true right_panel.style.horizontal_align = "right" return left_panel, right_panel end ------------------------------------------------------------------------------- ---Get the menu panel ---@return LuaGuiElement function Form:getMenuSubPanel() local content_panel = self:getTopPanel() local panel_name = "sub_menu" if content_panel[panel_name] ~= nil and content_panel[panel_name].valid then return content_panel[panel_name] end local panel = GuiElement.add(content_panel, GuiFlowH(panel_name)) panel.style.horizontally_stretchable = true panel.style.minimal_height = 32 return panel end ------------------------------------------------------------------------------- ---Is opened panel ---@return boolean function Form:isOpened() local parent_panel = self:getParentPanel() if parent_panel[self:getPanelName()] ~= nil then return true end return false end ------------------------------------------------------------------------------- ---Build first container ---@return boolean function Form:open(event) self:style() self:onBeforeOpen(event) if self:isOpened() then local flow_panel = self:getPanel() flow_panel.bring_to_front() return true end local parent_panel = self:getParentPanel() User.setActiveForm(self.classname) self:updateTopMenu(event) if parent_panel[self:getPanelName()] == nil then self:onOpen(event) end if self.classname == "HMProductionPanel" then Player.setShortcutState(true) Player.native().opened = self:getPanel() end return true end ------------------------------------------------------------------------------- ---On before open ---@return boolean function Form:onBeforeOpen(event) return false end ------------------------------------------------------------------------------- ---Event ---@param event LuaEvent function Form:event(event) if not(self:isOpened()) then return end self:onFormEvent(event) self:onEvent(event) end ------------------------------------------------------------------------------- ---On form event ---@param event LuaEvent function Form:onFormEvent(event) local flow_panel, content_panel, menu_panel = self:getPanel() if event.action == "minimize-window" then content_panel.visible = false flow_panel.style.height = 50 flow_panel.style.minimal_width = 100 end if event.action == "maximize-window" then content_panel.visible = true self:setFlowStyle(flow_panel) end end ------------------------------------------------------------------------------- ---On event ---@param event LuaEvent function Form:onEvent(event) end ------------------------------------------------------------------------------- ---On open ---@param event LuaEvent function Form:onOpen(event) return false end ------------------------------------------------------------------------------- ---Prepare ---@param event LuaEvent function Form:prepare(event) return false end ------------------------------------------------------------------------------- ---Add cell header ---@param guiTable LuaGuiElement ---@param name string ---@param caption string function Form:addCellHeader(guiTable, name, caption) local cell = GuiElement.add(guiTable, GuiFrameH("header", name):style(helmod_frame_style.hidden)) GuiElement.add(cell, GuiLabel("label"):caption(caption)) end ------------------------------------------------------------------------------- ---Update top menu ---@param event LuaEvent function Form:updateTopMenu(event) ---ajoute un menu if self.panelCaption ~= nil then local flow_panel, content_panel, menu_panel = self:getPanel() menu_panel.clear() if self.panelClose then ---pause game if string.find(self.classname, "HMProductionPanel") then local group3 = GuiElement.add(menu_panel, GuiFlowH("group3")) if game.is_multiplayer() and not(game.tick_paused) then local pause_button = GuiElement.add(group3, GuiButton("do-nothing"):sprite("menu", defines.sprites.run.white, defines.sprites.run.black):style("helmod_frame_button"):tooltip({"helmod_button.game-play-multiplayer"})) pause_button.enabled = false else if game.tick_paused then GuiElement.add(group3, GuiButton(self.classname, "game-play"):sprite("menu", defines.sprites.pause.black, defines.sprites.pause.black):style("helmod_frame_button_actived_red"):tooltip({"helmod_button.game-pause"})) else GuiElement.add(group3, GuiButton(self.classname, "game-pause"):sprite("menu", defines.sprites.run.white, defines.sprites.run.black):style("helmod_frame_button"):tooltip({"helmod_button.game-play"})) end end end ---Tool button local tool_group = GuiElement.add(menu_panel, GuiFlowH("tool_group")) for _, form in pairs(Controller.getViews()) do if self.add_special_button == true and form:isVisible() and form:isTool() then local icon_hovered, icon = form:getButtonSprites() GuiElement.add(tool_group, GuiButton(form.classname, "OPEN"):sprite("menu", icon_hovered, icon):style("helmod_frame_button"):tooltip(form.panelCaption)) end end ---special tab local special_group = GuiElement.add(menu_panel, GuiFlowH("special_group")) for _, form in pairs(Controller.getViews()) do if self.add_special_button == true and form:isVisible() and form:isSpecial() then local icon_hovered, icon = form:getButtonSprites() GuiElement.add(special_group, GuiButton(form.classname, "OPEN"):sprite("menu", icon_hovered, icon):style("helmod_frame_button"):tooltip(form.panelCaption)) end end ---Standard group local standard_group = GuiElement.add(menu_panel, GuiFlowH("standard_group")) if self.help_button then GuiElement.add(standard_group, GuiButton("HMHelpPanel", "OPEN"):sprite("menu", defines.sprites.status_help.white, defines.sprites.status_help.black):style("helmod_frame_button"):tooltip({"helmod_button.help"})) end GuiElement.add(standard_group, GuiButton(self.classname, "minimize-window"):sprite("menu", defines.sprites.minimize.white, defines.sprites.minimize.black):style("helmod_frame_button"):tooltip({"helmod_button.minimize"})) GuiElement.add(standard_group, GuiButton(self.classname, "maximize-window"):sprite("menu", defines.sprites.maximize.white, defines.sprites.maximize.black):style("helmod_frame_button"):tooltip({"helmod_button.maximize"})) GuiElement.add(standard_group, GuiButton(self.classname, "CLOSE"):sprite("menu", defines.sprites.close.white, defines.sprites.close.black):style("helmod_frame_button"):tooltip({"helmod_button.close"})) end else Logging:warn(self.classname, "self.panelCaption not found") end end ------------------------------------------------------------------------------- ---Update ---@param event LuaEvent function Form:update(event) if not(self:isOpened()) then return end local flow_panel, content_panel, menu_panel = self:getPanel() if self.auto_clear then content_panel.clear() end self:updateTopMenu(event) self:onUpdate(event) self:updateLocation(event) if self.has_tips and User.getPreferenceSetting("display_tips") then self:updateTips("un tips") end end ------------------------------------------------------------------------------- ---Update location ---@param event LuaEvent function Form:updateLocation(event) local display_width, display_height, scale = Player.getDisplaySizes() local width_main, height_main, scale = User.getMainSizes() local flow_panel, content_panel, menu_panel = self:getPanel() if User.getPreferenceSetting("ui_glue") == true and User.getPreferenceSetting("ui_glue", self.classname) == true then local offset = User.getPreferenceSetting("ui_glue_offset") local navigate = User.getNavigate() local location = {x=50,y=50} if navigate[User.tab_name] ~= nil and navigate[User.tab_name]["location"] ~= nil then location = navigate[User.tab_name]["location"] end local location_x = location.x + width_main/scale + display_width*offset/scale flow_panel.location = {location_x, y=location.y} end local location = flow_panel.location if location.x < 0 or location.x > (display_width - 50)/scale then location.x = 0 flow_panel.location = location end if location.y < 0 or location.y > (display_height - 50)/scale then location.y = 50 flow_panel.location = location end end ------------------------------------------------------------------------------- ---Update message ---@param event LuaEvent function Form:updateMessage(event) if not(self:isOpened()) then return end local panel = self:getFrameDeepPanel("message") panel.clear() GuiElement.add(panel, GuiLabel("message"):caption(event.message)) end ------------------------------------------------------------------------------- ---Get tips ---@return string function Form:getTips() local list_tips = {} if self.list_tips ~= nil then for _,tips in pairs(self.list_tips) do for line = 1, tips.count, 1 do local localised_text = {string.format("helmod_help.%s-%s", tips.name, line)} table.insert(list_tips, localised_text) end end local index = math.random(#list_tips) return list_tips[index] end return nil end ------------------------------------------------------------------------------- ---Update tips ---@param message string function Form:updateTips(message) if not(self:isOpened()) then return end local navigate = User.getNavigate(self.classname) local time_tips = navigate["tips"] or game.tick if game.tick - time_tips > User.delay_tips then return end local message = self:getTips() if message == nil then return end local panel = self:getFramePanel("tips") panel.clear() GuiElement.add(panel, GuiLabel("tips"):caption(message)) local event_queue = User.getParameter("event_queue") or {} local event = {tick=game.tick, is_tips=true, classname=self.classname} event_queue[self.classname] = event if time_tips == game.tick then navigate["tips"] = game.tick User.setParameter("event_queue", event_queue) end end ------------------------------------------------------------------------------- ---Destroy tips function Form:destroyTips() if not(self:isOpened()) then return end local panel = self:getFramePanel("tips") panel.destroy() end ------------------------------------------------------------------------------- ---Update error ---@param event LuaEvent function Form:updateError(event) if not(self:isOpened()) then return end local panel = self:getFrameDeepPanel("error") panel.clear() GuiElement.add(panel, GuiLabel("message"):caption(event.message or "Unknown error"):color("red")) end ------------------------------------------------------------------------------- ---On update ---@param event LuaEvent function Form:onUpdate(event) end ------------------------------------------------------------------------------- ---Close dialog ---@param force boolean function Form:close(force) if not(self:isOpened()) and force ~= true then return end local flow_panel, content_panel, menu_panel = self:getPanel() User.setCloseForm(self.classname, flow_panel.location) self:onClose() flow_panel.destroy() if self.classname == "HMProductionPanel" then Player.setShortcutState(false) end end ------------------------------------------------------------------------------- ---On close dialog function Form:onClose() end