GUI introduction
Background history
"OldUI" UI Started as a 1:1 clone of Frontier, in 2008, implemented in C++.
"NewUI" was meant to move UI from C++ to Lua, so we don't need to re-compile the game for every change, and allo players to easily modify the game.
"PiGUI" was the second attempt at moving UI from OldUI and NewUI, uses the third party Imgui library, so we get a lot for free, but downside is it's not custom made for us.
Pioneer has at times 3 different UI systems, in the transitioning phase to PiGUI. Now (2021-05) NewUI is completely replaced by PiGUI, but some parts of OldUI still linger (F6,F7,F8 screens).
Getting started with UI
Some pointers on how to get started with PiGUI
Imgui
Start with downloading and compiling the stand alone Imgui C++ program. Launch the demo app, to see the possibilities it offers. There you can find all features in imgui.
Search the C++ source code for some string/sentence you saw in the demo ap, e.g. if you found a specific table interesting, search the table text in the source, to find the spot in the C++ source. Then you see the name of the function that makes the table.
Then search for the same name in pioneer's lua code. E.g. "git grep -i <function name>"
PiGUI
code example
Below is a snippet that if saved to a lua file placed anywhere in data/modules/ will draw a window on the WorldView screen.
-- Copyright © 2008-2021 Pioneer Developers. See AUTHORS.txt for details -- Licensed under the terms of the GPL v3. See licenses/GPL-3.txt --[[ data/pigui/modules/add_crime.lua Written for @impaktor as a tutorial on how to get started with pigui by @sturnclaw, extended by @impaktor --]] local Game = require 'Game' -- pigui is traditionally imported as 'ui' for simplicity. local ui = require 'pigui' -- gameView is needed to dispatch to our Hello World window local gameView = require 'pigui.views.game' -- we want all displayed text to be localized local lui = require 'Lang'.GetResource('ui-core') -- ui.WindowFlags is an acceleration structure to allow composing window flags -- once and reusing them with each call. local window_flags = ui.WindowFlags { -- We don't want to be able to collapse the window. -- "NoCollapse" } local amount = 1000 local Character = require "Character" -- Register this window as a Game-view module. It will be displayed when the -- player is in the World View. -- registerModule takes two parameters, the unique key of the module, and the -- module descriptor table. gameView.registerModule("Small example", { -- Pretty self explanatory, if this is true, draw() is called when the -- ship is in hyperspace as well as in normal space. ShowInHyperspace = true, -- Called once per frame while the module is active. The function is passed -- the module object (this table) and the frame delta time draw = function(self, deltaTime) -- ui.window takes three parameters: the window title, the window flags, -- and a function containing the body of the window. -- the window title is an IMGUI string ID - two windows cannot share -- the same ID at the same stack position. To work around this, -- everything after ## is not part of the title, but instead used to -- make the window ID unique. ui.window("Debug!##id43", window_flags, function() ui.text("State: " .. Game.player:GetFlightState()) if (ui.beginTabBar("mytabbar")) then if ui.beginTabItem("squares") then ui.text("test1") ui.endTabItem() end if ui.beginTabItem("BALLS!") then ui.text("test2") ui.endTabItem() end if ui.beginTabItem("Triangle") then ui.text("test3") ui.text("some more text") ui.endTabItem() end ui.endTabBar() end -- Give player mone if pressing the button if ui.button("Give money", Vector2(100, 0)) then Game.player:AddMoney(amount) end -- draws a horizontal line ui.separator() -- Reputation & kills if ui.collapsingHeader("Reputation & kills", {}) then Character.persistent.player.reputation = ui.sliderInt("Reputation", Character.persistent.player.reputation, 0, 512) ui.sameLine() ui.text(Character.persistent.player:GetReputationRating()) Character.persistent.player.killcount = ui.sliderInt("Kills", Character.persistent.player.killcount, 0, 6000) ui.sameLine() ui.text(Character.persistent.player:GetCombatRating()) end end) end })