Aller au contenu

Pattern GUI complet

Ce guide montre comment construire une GUI avec RitnLibGui et RitnLibGuiElement, en partant du cas le plus simple jusqu'au pattern complet utilisé dans RitnCharacters.

Exemple minimal

Pour une GUI simple (un frame + un bouton), tout peut tenir dans control.lua.

La classe

-- mon-mod/control.lua

MonGui = ritnlib.classFactory.newclass(RitnLibGui, function(self, event)
    -- mod_name + suffix du frame racine ("panel-frame-main" en jeu)
    RitnLibGui.init(self, event, "mon-mod", "frame-main")
    self.object_name = "MonGui"
    self.gui_name    = "panel"

    -- Actions autorisées : "type_normalisé-element_name"
    self.gui_action = {
        [self.gui_name] = {
            ["button-close"] = true,
        }
    }

    -- self.gui[1] = le conteneur, pas le frame racine
    self.gui    = { self.player.gui.center }
    self.content = {}
end)

function MonGui:create()
    -- Vérifie si la GUI existe déjà
    if self.gui[1]["panel-frame-main"] then return self end

    local frame = self.gui[1].add(
        RitnLibGuiElement("panel", "frame", "main"):vertical():get()
    )
    frame.add(
        RitnLibGuiElement("panel", "button", "close"):caption("Fermer"):get()
    )
    return self
end

function MonGui:action_close()
    local frame = self.gui[1]["panel-frame-main"]
    if frame then frame.destroy() end
    return self
end

L'interface remote

remote.add_interface("mon-mod", {
    gui_action_panel = function(action, event)
        if action == "button-close" then
            MonGui(event):action_close()
        end
    end,
})

Les handlers

script.on_event(defines.events.on_player_created, function(event)
    MonGui(event):create()
end)

script.on_event(defines.events.on_gui_click, function(event)
    MonGui(event):on_gui_click()
    -- parse "panel-button-close" → action = "button-close"
    -- → remote.call("mon-mod", "gui_action_panel", "button-close", event)
end)

Pattern complet — structure 3 fichiers

Pour une GUI plus complexe (liste, flows imbriqués, styles), il est recommandé de séparer en 3 fichiers comme dans RitnCharacters.

mon-mod/
├─ gui/mon-panel.lua        ← specs d'éléments + chemins
├─ classes/MonGui.lua       ← classe avec :create() et actions
└─ modules/storage.lua      ← remote.add_interface

gui/mon-panel.lua — specs et chemins

local function getElement(gui_name)
    return {
        frame = {
            main    = RitnLibGuiElement(gui_name, "frame", "main"):vertical():get(),
            submain = RitnLibGuiElement(gui_name, "frame", "submain"):vertical()
                        :style("inside_shallow_frame"):get(),
        },
        flow = {
            footer = RitnLibGuiElement(gui_name, "flow", "footer"):horizontal():get(),
        },
        list    = RitnLibGuiElement(gui_name, "list-box", "items"):get(),
        button  = {
            confirm = RitnLibGuiElement(gui_name, "button", "confirm"):caption("Valider"):get(),
            close   = RitnLibGuiElement(gui_name, "button", "close"):caption("Fermer"):get(),
        },
    }
end

local function getContent()
    return {
        frame  = {
            main    = { "frame-main" },
            submain = { "frame-main", "frame-submain" },
        },
        flow   = {
            footer = { "frame-main", "frame-submain", "flow-footer" },
        },
        list   = { "frame-main", "frame-submain", "listbox-items" },
        button = {
            confirm = { "frame-main", "frame-submain", "flow-footer", "button-confirm" },
            close   = { "frame-main", "frame-submain", "flow-footer", "button-close" },
        },
    }
end

return { getElement = getElement, getContent = getContent }

getContent décrit le chemin depuis self.gui[1] vers chaque élément. self:getElement("list") le parcourt en préfixant chaque étape avec gui_name .. "-".

classes/MonGui.lua

local fGui = require(ritnlib.defines.monmod.gui.panel)

MonGui = ritnlib.classFactory.newclass(RitnLibGui, function(self, event)
    RitnLibGui.init(self, event, ritnlib.defines.monmod.name, "frame-main")
    self.object_name = "MonGui"
    self.gui_name    = "panel"

    self.gui_action = {
        ["panel"] = {
            ["button-confirm"] = true,
            ["button-close"]   = true,
        }
    }

    self.gui     = { self.player.gui.center }
    self.content = fGui.getContent()
end)

function MonGui:create()
    if self.gui[1]["panel-frame-main"] then return self end

    local e = fGui.getElement(self.gui_name)
    local c = {}
    c.frame_main    = self.gui[1].add(e.frame.main)
    c.frame_submain = c.frame_main.add(e.frame.submain)
    c.list          = c.frame_submain.add(e.list)
    c.flow_footer   = c.frame_submain.add(e.flow.footer)
    c.btn_confirm   = c.flow_footer.add(e.button.confirm)
    c.btn_close     = c.flow_footer.add(e.button.close)

    -- Styles post-création
    RitnLibStyle(c.frame_main):padding(4)
    RitnLibStyle(c.list):horizontalStretch():maxHeight(400)
    RitnLibStyle(c.flow_footer):align("right")

    for _, item in pairs({ "Option A", "Option B", "Option C" }) do
        c.list.add_item(item)
    end
    return self
end

function MonGui:action_close()
    local frame = self.gui[1]["panel-frame-main"]
    if frame then frame.destroy() end
    return self
end

function MonGui:action_confirm()
    local list = self:getElement("list")
    if not list or list.selected_index == 0 then return self end
    self.player.player.print("Sélection : " .. list.get_item(list.selected_index))
    self:action_close()
    return self
end

modules/storage.lua

remote.add_interface("mon-mod", {
    ["gui_action_panel"] = function(action, event)
        if action == "button-confirm" then
            MonGui(event):action_confirm()
        elseif action == "button-close" then
            MonGui(event):action_close()
        end
    end,
})
return {}

Référence rapide

RitnLibGuiElement — nommage

RitnLibGuiElement(gui_name, type, name) génère le nom en jeu gui_name-type_normalisé-name :

Type passé Normalisé Exemple avec gui_name="panel"
"frame" "frame" "panel-frame-main"
"flow" "flow" "panel-flow-footer"
"button" / "sprite-button" "button" "panel-button-close"
"list-box" "listbox" "panel-listbox-items"
"drop-down" "dropdown" "panel-dropdown-x"
"text-box" "textbox" "panel-textbox-x"

Méthodes courantes

Méthode Rôle
:horizontal() / :vertical() Direction (frame, flow, line)
:caption(text) Texte affiché
:style(name) Style GUI Factorio
:tooltip(text) Infobulle
:visible(bool) Visibilité initiale
:enabled(bool) Actif/inactif
:get() Retourne le payload brut (à passer à parent.add(...))
:add(parent) Ajoute directement à parent, retourne le LuaGuiElement

Voir aussi