refactor: add GUI instance reference to UI nodes

This commit is contained in:
MihailRis 2025-03-07 18:19:56 +03:00
parent 74a94f869c
commit 4c48afbb90
70 changed files with 1133 additions and 832 deletions

View File

@ -19,13 +19,14 @@
#include "items/ItemDef.hpp" #include "items/ItemDef.hpp"
#include "Assets.hpp" #include "Assets.hpp"
#include "assetload_funcs.hpp" #include "assetload_funcs.hpp"
#include "engine/Engine.hpp"
namespace fs = std::filesystem; namespace fs = std::filesystem;
static debug::Logger logger("assets-loader"); static debug::Logger logger("assets-loader");
AssetsLoader::AssetsLoader(Assets* assets, const ResPaths* paths) AssetsLoader::AssetsLoader(Engine& engine, Assets& assets, const ResPaths* paths)
: assets(assets), paths(paths) { : engine(engine), assets(assets), paths(paths) {
addLoader(AssetType::SHADER, assetload::shader); addLoader(AssetType::SHADER, assetload::shader);
addLoader(AssetType::TEXTURE, assetload::texture); addLoader(AssetType::TEXTURE, assetload::texture);
addLoader(AssetType::FONT, assetload::font); addLoader(AssetType::FONT, assetload::font);
@ -73,7 +74,7 @@ void AssetsLoader::loadNext() {
aloader_func loader = getLoader(entry.tag); aloader_func loader = getLoader(entry.tag);
auto postfunc = auto postfunc =
loader(this, paths, entry.filename, entry.alias, entry.config); loader(this, paths, entry.filename, entry.alias, entry.config);
postfunc(assets); postfunc(&assets);
entries.pop(); entries.pop();
} catch (std::runtime_error& err) { } catch (std::runtime_error& err) {
logger.error() << err.what(); logger.error() << err.what();
@ -101,7 +102,7 @@ static void add_layouts(
AssetType::LAYOUT, AssetType::LAYOUT,
file.string(), file.string(),
name, name,
std::make_shared<LayoutCfg>(env) std::make_shared<LayoutCfg>(&loader.getEngine().getGUI(), env)
); );
} }
} }
@ -296,6 +297,10 @@ bool AssetsLoader::loadExternalTexture(
return false; return false;
} }
Engine& AssetsLoader::getEngine() {
return engine;
}
const ResPaths* AssetsLoader::getPaths() const { const ResPaths* AssetsLoader::getPaths() const {
return paths; return paths;
} }
@ -324,7 +329,7 @@ std::shared_ptr<Task> AssetsLoader::startTask(runnable onDone) {
std::make_shared<util::ThreadPool<aloader_entry, assetload::postfunc>>( std::make_shared<util::ThreadPool<aloader_entry, assetload::postfunc>>(
"assets-loader-pool", "assets-loader-pool",
[=]() { return std::make_shared<LoaderWorker>(this); }, [=]() { return std::make_shared<LoaderWorker>(this); },
[=](const assetload::postfunc& func) { func(assets); } [this](const assetload::postfunc& func) { func(&assets); }
); );
pool->setOnComplete(std::move(onDone)); pool->setOnComplete(std::move(onDone));
while (!entries.empty()) { while (!entries.empty()) {

View File

@ -18,6 +18,11 @@
class ResPaths; class ResPaths;
class AssetsLoader; class AssetsLoader;
class Content; class Content;
class Engine;
namespace gui {
class GUI;
}
struct AssetCfg { struct AssetCfg {
virtual ~AssetCfg() { virtual ~AssetCfg() {
@ -25,9 +30,10 @@ struct AssetCfg {
}; };
struct LayoutCfg : AssetCfg { struct LayoutCfg : AssetCfg {
gui::GUI* gui;
scriptenv env; scriptenv env;
LayoutCfg(scriptenv env) : env(std::move(env)) { LayoutCfg(gui::GUI* gui, scriptenv env) : gui(gui), env(std::move(env)) {
} }
}; };
@ -61,7 +67,8 @@ struct aloader_entry {
}; };
class AssetsLoader { class AssetsLoader {
Assets* assets; Engine& engine;
Assets& assets;
std::map<AssetType, aloader_func> loaders; std::map<AssetType, aloader_func> loaders;
std::queue<aloader_entry> entries; std::queue<aloader_entry> entries;
std::set<std::pair<AssetType, std::string>> enqueued; std::set<std::pair<AssetType, std::string>> enqueued;
@ -76,7 +83,7 @@ class AssetsLoader {
void processPreloadConfig(const io::path& file); void processPreloadConfig(const io::path& file);
void processPreloadConfigs(const Content* content); void processPreloadConfigs(const Content* content);
public: public:
AssetsLoader(Assets* assets, const ResPaths* paths); AssetsLoader(Engine& engine, Assets& assets, const ResPaths* paths);
void addLoader(AssetType tag, aloader_func func); void addLoader(AssetType tag, aloader_func func);
/// @brief Enqueue asset load /// @brief Enqueue asset load
@ -111,4 +118,6 @@ public:
const std::string& name, const std::string& name,
const std::vector<io::path>& alternatives const std::vector<io::path>& alternatives
); );
Engine& getEngine();
}; };

View File

@ -189,6 +189,7 @@ assetload::postfunc assetload::layout(
auto prefix = name.substr(0, pos); auto prefix = name.substr(0, pos);
assets->store( assets->store(
UiDocument::read( UiDocument::read(
*cfg->gui,
cfg->env, cfg->env,
name, name,
file, file,

View File

@ -50,8 +50,6 @@
static debug::Logger logger("engine"); static debug::Logger logger("engine");
namespace fs = std::filesystem;
static std::unique_ptr<ImageData> load_icon() { static std::unique_ptr<ImageData> load_icon() {
try { try {
auto file = "res:textures/misc/icon.png"; auto file = "res:textures/misc/icon.png";
@ -65,20 +63,21 @@ static std::unique_ptr<ImageData> load_icon() {
} }
Engine::Engine() = default; Engine::Engine() = default;
Engine::~Engine() = default;
static std::unique_ptr<Engine> engine; static std::unique_ptr<Engine> instance = nullptr;
Engine& Engine::getInstance() { Engine& Engine::getInstance() {
if (!engine) { if (!instance) {
engine = std::make_unique<Engine>(); instance = std::make_unique<Engine>();
} }
return *engine; return *instance;
} }
void Engine::initialize(CoreParameters coreParameters) { void Engine::initialize(CoreParameters coreParameters) {
params = std::move(coreParameters); params = std::move(coreParameters);
settingsHandler = std::make_unique<SettingsHandler>(settings); settingsHandler = std::make_unique<SettingsHandler>(settings);
interpreter = std::make_unique<cmd::CommandsInterpreter>(); cmd = std::make_unique<cmd::CommandsInterpreter>();
network = network::Network::create(settings.network); network = network::Network::create(settings.network);
logger.info() << "engine version: " << ENGINE_VERSION_STRING; logger.info() << "engine version: " << ENGINE_VERSION_STRING;
@ -97,7 +96,7 @@ void Engine::initialize(CoreParameters coreParameters) {
controller = std::make_unique<EngineController>(*this); controller = std::make_unique<EngineController>(*this);
if (!params.headless) { if (!params.headless) {
if (Window::initialize(&settings.display)){ if (!(input = Window::initialize(&settings.display))){
throw initialize_error("could not initialize window"); throw initialize_error("could not initialize window");
} }
time.set(Window::time()); time.set(Window::time());
@ -107,9 +106,9 @@ void Engine::initialize(CoreParameters coreParameters) {
} }
loadControls(); loadControls();
gui = std::make_unique<gui::GUI>(); gui = std::make_unique<gui::GUI>(*this);
if (ENGINE_DEBUG_BUILD) { if (ENGINE_DEBUG_BUILD) {
menus::create_version_label(*this); menus::create_version_label(*gui);
} }
} }
audio::initialize(!params.headless, settings.audio); audio::initialize(!params.headless, settings.audio);
@ -209,7 +208,7 @@ void Engine::nextFrame() {
: settings.display.framerate.get() : settings.display.framerate.get()
); );
Window::swapBuffers(); Window::swapBuffers();
Events::pollEvents(); input->pollEvents();
} }
void Engine::renderFrame() { void Engine::renderFrame() {
@ -229,7 +228,7 @@ void Engine::saveSettings() {
} }
} }
Engine::~Engine() { void Engine::close() {
saveSettings(); saveSettings();
logger.info() << "shutting down"; logger.info() << "shutting down";
if (screen) { if (screen) {
@ -238,7 +237,7 @@ Engine::~Engine() {
} }
content.reset(); content.reset();
assets.reset(); assets.reset();
interpreter.reset(); cmd.reset();
if (gui) { if (gui) {
gui.reset(); gui.reset();
logger.info() << "gui finished"; logger.info() << "gui finished";
@ -256,17 +255,14 @@ Engine::~Engine() {
} }
void Engine::terminate() { void Engine::terminate() {
engine.reset(); instance->close();
instance.reset();
} }
EngineController* Engine::getController() { EngineController* Engine::getController() {
return controller.get(); return controller.get();
} }
cmd::CommandsInterpreter* Engine::getCommandsInterpreter() {
return interpreter.get();
}
PacksManager Engine::createPacksManager(const io::path& worldFolder) { PacksManager Engine::createPacksManager(const io::path& worldFolder) {
PacksManager manager; PacksManager manager;
manager.setSources({ manager.setSources({
@ -286,7 +282,7 @@ void Engine::loadAssets() {
Shader::preprocessor->setPaths(resPaths.get()); Shader::preprocessor->setPaths(resPaths.get());
auto new_assets = std::make_unique<Assets>(); auto new_assets = std::make_unique<Assets>();
AssetsLoader loader(new_assets.get(), resPaths.get()); AssetsLoader loader(*this, *new_assets, resPaths.get());
AssetsLoader::addDefaults(loader, content.get()); AssetsLoader::addDefaults(loader, content.get());
// no need // no need
@ -376,7 +372,6 @@ void Engine::loadContent() {
load_configs(pack.folder); load_configs(pack.folder);
} }
content = contentBuilder.build(); content = contentBuilder.build();
interpreter->reset();
scripting::on_content_load(content.get()); scripting::on_content_load(content.get());
ContentLoader::loadScripts(*content); ContentLoader::loadScripts(*content);
@ -468,10 +463,6 @@ bool Engine::isQuitSignal() const {
return quitSignal; return quitSignal;
} }
gui::GUI* Engine::getGUI() {
return gui.get();
}
EngineSettings& Engine::getSettings() { EngineSettings& Engine::getSettings() {
return settings; return settings;
} }
@ -518,10 +509,6 @@ SettingsHandler& Engine::getSettingsHandler() {
return *settingsHandler; return *settingsHandler;
} }
network::Network& Engine::getNetwork() {
return *network;
}
Time& Engine::getTime() { Time& Engine::getTime() {
return time; return time;
} }

View File

@ -26,6 +26,7 @@ class ResPaths;
class EngineController; class EngineController;
class SettingsHandler; class SettingsHandler;
struct EngineSettings; struct EngineSettings;
class Input;
namespace gui { namespace gui {
class GUI; class GUI;
@ -66,8 +67,9 @@ class Engine : public util::ObjectsKeeper {
std::unique_ptr<Content> content; std::unique_ptr<Content> content;
std::unique_ptr<ResPaths> resPaths; std::unique_ptr<ResPaths> resPaths;
std::unique_ptr<EngineController> controller; std::unique_ptr<EngineController> controller;
std::unique_ptr<cmd::CommandsInterpreter> interpreter; std::unique_ptr<cmd::CommandsInterpreter> cmd;
std::unique_ptr<network::Network> network; std::unique_ptr<network::Network> network;
std::unique_ptr<Input> input;
std::vector<std::string> basePacks; std::vector<std::string> basePacks;
std::unique_ptr<gui::GUI> gui; std::unique_ptr<gui::GUI> gui;
PostRunnables postRunnables; PostRunnables postRunnables;
@ -87,6 +89,7 @@ public:
static Engine& getInstance(); static Engine& getInstance();
void initialize(CoreParameters coreParameters); void initialize(CoreParameters coreParameters);
void close();
static void terminate(); static void terminate();
@ -129,9 +132,6 @@ public:
/// @brief Get active assets storage instance /// @brief Get active assets storage instance
Assets* getAssets(); Assets* getAssets();
/// @brief Get main UI controller
gui::GUI* getGUI();
/// @brief Get writeable engine settings structure instance /// @brief Get writeable engine settings structure instance
EngineSettings& getSettings(); EngineSettings& getSettings();
@ -171,7 +171,6 @@ public:
void saveScreenshot(); void saveScreenshot();
EngineController* getController(); EngineController* getController();
cmd::CommandsInterpreter* getCommandsInterpreter();
PacksManager createPacksManager(const io::path& worldFolder); PacksManager createPacksManager(const io::path& worldFolder);
@ -179,11 +178,25 @@ public:
SettingsHandler& getSettingsHandler(); SettingsHandler& getSettingsHandler();
network::Network& getNetwork();
Time& getTime(); Time& getTime();
const CoreParameters& getCoreParameters() const; const CoreParameters& getCoreParameters() const;
bool isHeadless() const; bool isHeadless() const;
gui::GUI& getGUI() {
return *gui;
}
Input& getInput() {
return *input;
}
network::Network& getNetwork() {
return *network;
}
cmd::CommandsInterpreter& getCmd() {
return *cmd;
}
}; };

View File

@ -54,6 +54,7 @@ scriptenv UiDocument::getEnvironment() const {
} }
std::unique_ptr<UiDocument> UiDocument::read( std::unique_ptr<UiDocument> UiDocument::read(
gui::GUI& gui,
const scriptenv& penv, const scriptenv& penv,
const std::string& name, const std::string& name,
const io::path& file, const io::path& file,
@ -66,7 +67,7 @@ std::unique_ptr<UiDocument> UiDocument::read(
? scripting::create_doc_environment(scripting::get_root_environment(), name) ? scripting::create_doc_environment(scripting::get_root_environment(), name)
: scripting::create_doc_environment(penv, name); : scripting::create_doc_environment(penv, name);
gui::UiXmlReader reader(env); gui::UiXmlReader reader(gui, env);
auto view = reader.readXML(file.string(), *xmldoc->getRoot()); auto view = reader.readXML(file.string(), *xmldoc->getRoot());
view->setId("root"); view->setId("root");
uidocscript script {}; uidocscript script {};
@ -80,8 +81,7 @@ std::unique_ptr<UiDocument> UiDocument::read(
} }
std::shared_ptr<gui::UINode> UiDocument::readElement( std::shared_ptr<gui::UINode> UiDocument::readElement(
const io::path& file, const std::string& fileName gui::GUI& gui, const io::path& file, const std::string& fileName
) { ) {
auto document = read(nullptr, file.name(), file, fileName); return read(gui, nullptr, file.name(), file, fileName)->getRoot();
return document->getRoot();
} }

View File

@ -9,6 +9,7 @@
#include "io/fwd.hpp" #include "io/fwd.hpp"
namespace gui { namespace gui {
class GUI;
class UINode; class UINode;
} }
@ -45,12 +46,13 @@ public:
scriptenv getEnvironment() const; scriptenv getEnvironment() const;
static std::unique_ptr<UiDocument> read( static std::unique_ptr<UiDocument> read(
gui::GUI&,
const scriptenv& parent_env, const scriptenv& parent_env,
const std::string& name, const std::string& name,
const io::path& file, const io::path& file,
const std::string& fileName const std::string& fileName
); );
static std::shared_ptr<gui::UINode> readElement( static std::shared_ptr<gui::UINode> readElement(
const io::path& file, const std::string& fileName gui::GUI&, const io::path& file, const std::string& fileName
); );
}; };

View File

@ -35,8 +35,8 @@
using namespace gui; using namespace gui;
static std::shared_ptr<Label> create_label(wstringsupplier supplier) { static std::shared_ptr<Label> create_label(GUI& gui, wstringsupplier supplier) {
auto label = std::make_shared<Label>(L"-"); auto label = std::make_shared<Label>(gui, L"-");
label->textSupplier(std::move(supplier)); label->textSupplier(std::move(supplier));
return label; return label;
} }
@ -50,7 +50,10 @@ std::shared_ptr<UINode> create_debug_panel(
Player& player, Player& player,
bool allowDebugCheats bool allowDebugCheats
) { ) {
auto panel = std::make_shared<Panel>(glm::vec2(300, 200), glm::vec4(5.0f), 2.0f); auto& gui = engine.getGUI();
auto panel = std::make_shared<Panel>(
gui, glm::vec2(300, 200), glm::vec4(5.0f), 2.0f
);
panel->setId("hud.debug-panel"); panel->setId("hud.debug-panel");
panel->setPos(glm::vec2(10, 10)); panel->setPos(glm::vec2(10, 10));
@ -87,48 +90,48 @@ std::shared_ptr<UINode> create_debug_panel(
lastTotalUpload = totalUpload; lastTotalUpload = totalUpload;
}); });
panel->add(create_label([]() { return L"fps: "+fpsString;})); panel->add(create_label(gui, []() { return L"fps: "+fpsString;}));
panel->add(create_label([]() { panel->add(create_label(gui, []() {
return L"meshes: " + std::to_wstring(Mesh::meshesCount); return L"meshes: " + std::to_wstring(Mesh::meshesCount);
})); }));
panel->add(create_label([]() { panel->add(create_label(gui, []() {
int drawCalls = Mesh::drawCalls; int drawCalls = Mesh::drawCalls;
Mesh::drawCalls = 0; Mesh::drawCalls = 0;
return L"draw-calls: " + std::to_wstring(drawCalls); return L"draw-calls: " + std::to_wstring(drawCalls);
})); }));
panel->add(create_label([]() { panel->add(create_label(gui, []() {
return L"speakers: " + std::to_wstring(audio::count_speakers())+ return L"speakers: " + std::to_wstring(audio::count_speakers())+
L" streams: " + std::to_wstring(audio::count_streams()); L" streams: " + std::to_wstring(audio::count_streams());
})); }));
panel->add(create_label([]() { panel->add(create_label(gui, []() {
return L"lua-stack: " + std::to_wstring(scripting::get_values_on_stack()); return L"lua-stack: " + std::to_wstring(scripting::get_values_on_stack());
})); }));
panel->add(create_label([]() { return netSpeedString; })); panel->add(create_label(gui, []() { return netSpeedString; }));
panel->add(create_label([&engine]() { panel->add(create_label(gui, [&engine]() {
auto& settings = engine.getSettings(); auto& settings = engine.getSettings();
bool culling = settings.graphics.frustumCulling.get(); bool culling = settings.graphics.frustumCulling.get();
return L"frustum-culling: "+std::wstring(culling ? L"on" : L"off"); return L"frustum-culling: "+std::wstring(culling ? L"on" : L"off");
})); }));
panel->add(create_label([=]() { panel->add(create_label(gui, [=]() {
return L"particles: " + return L"particles: " +
std::to_wstring(ParticlesRenderer::visibleParticles) + std::to_wstring(ParticlesRenderer::visibleParticles) +
L" emitters: " + L" emitters: " +
std::to_wstring(ParticlesRenderer::aliveEmitters); std::to_wstring(ParticlesRenderer::aliveEmitters);
})); }));
panel->add(create_label([&]() { panel->add(create_label(gui, [&]() {
return L"chunks: "+std::to_wstring(level.chunks->size())+ return L"chunks: "+std::to_wstring(level.chunks->size())+
L" visible: "+std::to_wstring(ChunksRenderer::visibleChunks); L" visible: "+std::to_wstring(ChunksRenderer::visibleChunks);
})); }));
panel->add(create_label([&]() { panel->add(create_label(gui, [&]() {
return L"entities: "+std::to_wstring(level.entities->size())+L" next: "+ return L"entities: "+std::to_wstring(level.entities->size())+L" next: "+
std::to_wstring(level.entities->peekNextID()); std::to_wstring(level.entities->peekNextID());
})); }));
panel->add(create_label([&]() { panel->add(create_label(gui, [&]() {
return L"players: "+std::to_wstring(level.players->size())+L" local: "+ return L"players: "+std::to_wstring(level.players->size())+L" local: "+
std::to_wstring(player.getId()); std::to_wstring(player.getId());
})); }));
panel->add(create_label([&]() -> std::wstring { panel->add(create_label(gui, [&]() -> std::wstring {
const auto& vox = player.selection.vox; const auto& vox = player.selection.vox;
std::wstringstream stream; std::wstringstream stream;
stream << "r:" << vox.state.rotation << " s:" stream << "r:" << vox.state.rotation << " s:"
@ -141,7 +144,7 @@ std::shared_ptr<UINode> create_debug_panel(
L" "+stream.str(); L" "+stream.str();
} }
})); }));
panel->add(create_label([&]() -> std::wstring { panel->add(create_label(gui, [&]() -> std::wstring {
const auto& selection = player.selection; const auto& selection = player.selection;
const auto& vox = selection.vox; const auto& vox = selection.vox;
if (vox.id == BLOCK_VOID) { if (vox.id == BLOCK_VOID) {
@ -151,7 +154,7 @@ std::shared_ptr<UINode> create_debug_panel(
L" y: " + std::to_wstring(selection.actualPosition.y) + L" y: " + std::to_wstring(selection.actualPosition.y) +
L" z: " + std::to_wstring(selection.actualPosition.z); L" z: " + std::to_wstring(selection.actualPosition.z);
})); }));
panel->add(create_label([&]() { panel->add(create_label(gui, [&]() {
auto eid = player.getSelectedEntity(); auto eid = player.getSelectedEntity();
if (eid == ENTITY_NONE) { if (eid == ENTITY_NONE) {
return std::wstring {L"entity: -"}; return std::wstring {L"entity: -"};
@ -162,7 +165,7 @@ std::shared_ptr<UINode> create_debug_panel(
return std::wstring {L"entity: error (invalid UID)"}; return std::wstring {L"entity: error (invalid UID)"};
} }
})); }));
panel->add(create_label([&](){ panel->add(create_label(gui, [&](){
auto indices = level.content.getIndices(); auto indices = level.content.getIndices();
if (auto def = indices->blocks.get(player.selection.vox.id)) { if (auto def = indices->blocks.get(player.selection.vox.id)) {
return L"name: " + util::str2wstr_utf8(def->name); return L"name: " + util::str2wstr_utf8(def->name);
@ -170,23 +173,23 @@ std::shared_ptr<UINode> create_debug_panel(
return std::wstring {L"name: void"}; return std::wstring {L"name: void"};
} }
})); }));
panel->add(create_label([&](){ panel->add(create_label(gui, [&](){
return L"seed: "+std::to_wstring(level.getWorld()->getSeed()); return L"seed: "+std::to_wstring(level.getWorld()->getSeed());
})); }));
for (int ax = 0; ax < 3; ax++) { for (int ax = 0; ax < 3; ax++) {
auto sub = std::make_shared<Container>(glm::vec2(250, 27)); auto sub = std::make_shared<Container>(gui, glm::vec2(250, 27));
std::wstring str = L"x: "; std::wstring str = L"x: ";
str[0] += ax; str[0] += ax;
auto label = std::make_shared<Label>(str); auto label = std::make_shared<Label>(gui, str);
label->setMargin(glm::vec4(2, 3, 2, 3)); label->setMargin(glm::vec4(2, 3, 2, 3));
label->setSize(glm::vec2(20, 27)); label->setSize(glm::vec2(20, 27));
sub->add(label); sub->add(label);
sub->setColor(glm::vec4(0.0f)); sub->setColor(glm::vec4(0.0f));
// Coord input // Coord input
auto box = std::make_shared<TextBox>(L""); auto box = std::make_shared<TextBox>(gui, L"");
auto boxRef = box.get(); auto boxRef = box.get();
box->setTextSupplier([&player, ax]() { box->setTextSupplier([&player, ax]() {
return util::to_wstring(player.getPosition()[ax], 2); return util::to_wstring(player.getPosition()[ax], 2);
@ -212,7 +215,7 @@ std::shared_ptr<UINode> create_debug_panel(
panel->add(sub); panel->add(sub);
} }
auto& worldInfo = level.getWorld()->getInfo(); auto& worldInfo = level.getWorld()->getInfo();
panel->add(create_label([&](){ panel->add(create_label(gui, [&](){
int hour, minute, second; int hour, minute, second;
timeutil::from_value(worldInfo.daytime, hour, minute, second); timeutil::from_value(worldInfo.daytime, hour, minute, second);
@ -222,20 +225,20 @@ std::shared_ptr<UINode> create_debug_panel(
return L"time: "+timeString; return L"time: "+timeString;
})); }));
if (allowDebugCheats) { if (allowDebugCheats) {
auto bar = std::make_shared<TrackBar>(0.0f, 1.0f, 1.0f, 0.005f, 8); auto bar = std::make_shared<TrackBar>(gui, 0.0f, 1.0f, 1.0f, 0.005f, 8);
bar->setSupplier([&]() {return worldInfo.daytime;}); bar->setSupplier([&]() {return worldInfo.daytime;});
bar->setConsumer([&](double val) {worldInfo.daytime = val;}); bar->setConsumer([&](double val) {worldInfo.daytime = val;});
panel->add(bar); panel->add(bar);
} }
if (allowDebugCheats) { if (allowDebugCheats) {
auto bar = std::make_shared<TrackBar>(0.0f, 1.0f, 0.0f, 0.005f, 8); auto bar = std::make_shared<TrackBar>(gui, 0.0f, 1.0f, 0.0f, 0.005f, 8);
bar->setSupplier([&]() {return worldInfo.fog;}); bar->setSupplier([&]() {return worldInfo.fog;});
bar->setConsumer([&](double val) {worldInfo.fog = val;}); bar->setConsumer([&](double val) {worldInfo.fog = val;});
panel->add(bar); panel->add(bar);
} }
{ {
auto checkbox = std::make_shared<FullCheckBox>( auto checkbox = std::make_shared<FullCheckBox>(
L"Show Chunk Borders", glm::vec2(400, 24) gui, L"Show Chunk Borders", glm::vec2(400, 24)
); );
checkbox->setSupplier([=]() { checkbox->setSupplier([=]() {
return WorldRenderer::showChunkBorders; return WorldRenderer::showChunkBorders;
@ -247,7 +250,7 @@ std::shared_ptr<UINode> create_debug_panel(
} }
{ {
auto checkbox = std::make_shared<FullCheckBox>( auto checkbox = std::make_shared<FullCheckBox>(
L"Show Hitboxes", glm::vec2(400, 24) gui, L"Show Hitboxes", glm::vec2(400, 24)
); );
checkbox->setSupplier([=]() { checkbox->setSupplier([=]() {
return WorldRenderer::showEntitiesDebug; return WorldRenderer::showEntitiesDebug;
@ -259,7 +262,7 @@ std::shared_ptr<UINode> create_debug_panel(
} }
{ {
auto checkbox = std::make_shared<FullCheckBox>( auto checkbox = std::make_shared<FullCheckBox>(
L"Show Generator Minimap", glm::vec2(400, 24) gui, L"Show Generator Minimap", glm::vec2(400, 24)
); );
checkbox->setSupplier([=]() { checkbox->setSupplier([=]() {
return Hud::showGeneratorMinimap; return Hud::showGeneratorMinimap;

View File

@ -126,7 +126,7 @@ std::shared_ptr<InventoryView> Hud::createContentAccess() {
inventory->getSlot(player.getChosenSlot()).set(item); inventory->getSlot(player.getChosenSlot()).set(item);
}); });
InventoryBuilder builder; InventoryBuilder builder(gui);
builder.addGrid(8, itemsCount-1, glm::vec2(), glm::vec4(8, 8, 12, 8), true, slotLayout); builder.addGrid(8, itemsCount-1, glm::vec2(), glm::vec4(8, 8, 12, 8), true, slotLayout);
auto view = builder.build(); auto view = builder.build();
view->bind(accessInventory, &content); view->bind(accessInventory, &content);
@ -139,7 +139,7 @@ std::shared_ptr<InventoryView> Hud::createHotbar() {
auto& content = frontend.getLevel().content; auto& content = frontend.getLevel().content;
SlotLayout slotLayout(-1, glm::vec2(), false, false, nullptr, nullptr, nullptr); SlotLayout slotLayout(-1, glm::vec2(), false, false, nullptr, nullptr, nullptr);
InventoryBuilder builder; InventoryBuilder builder(gui);
builder.addGrid(10, 10, glm::vec2(), glm::vec4(4), true, slotLayout); builder.addGrid(10, 10, glm::vec2(), glm::vec4(4), true, slotLayout);
auto view = builder.build(); auto view = builder.build();
view->setId("hud.hotbar"); view->setId("hud.hotbar");
@ -153,8 +153,10 @@ static constexpr uint WORLDGEN_IMG_SIZE = 128U;
Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player) Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
: engine(engine), : engine(engine),
input(engine.getInput()),
assets(*engine.getAssets()), assets(*engine.getAssets()),
gui(*engine.getGUI()), gui(engine.getGUI()),
menu(*engine.getGUI().getMenu()),
frontend(frontend), frontend(frontend),
player(player), player(player),
debugImgWorldGen(std::make_unique<ImageData>( debugImgWorldGen(std::make_unique<ImageData>(
@ -163,7 +165,7 @@ Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
contentAccess = createContentAccess(); contentAccess = createContentAccess();
contentAccess->setId("hud.content-access"); contentAccess->setId("hud.content-access");
contentAccessPanel = std::make_shared<Panel>( contentAccessPanel = std::make_shared<Panel>(
contentAccess->getSize(), glm::vec4(0.0f), 0.0f gui, contentAccess->getSize(), glm::vec4(0.0f), 0.0f
); );
contentAccessPanel->setColor(glm::vec4()); contentAccessPanel->setColor(glm::vec4());
contentAccessPanel->add(contentAccess); contentAccessPanel->add(contentAccess);
@ -172,6 +174,7 @@ Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
hotbarView = createHotbar(); hotbarView = createHotbar();
darkOverlay = guiutil::create( darkOverlay = guiutil::create(
gui,
"<container size='4000' color='#00000080' z-index='-1' visible='false'/>" "<container size='4000' color='#00000080' z-index='-1' visible='false'/>"
); );
@ -183,13 +186,13 @@ Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
engine, frontend.getLevel(), player, allowDebugCheats engine, frontend.getLevel(), player, allowDebugCheats
); );
debugPanel->setZIndex(2); debugPanel->setZIndex(2);
gui.add(debugPanel);
gui.add(debugPanel);
gui.add(darkOverlay); gui.add(darkOverlay);
gui.add(hotbarView); gui.add(hotbarView);
gui.add(contentAccessPanel); gui.add(contentAccessPanel);
auto dplotter = std::make_shared<Plotter>(350, 250, 2000, 16); auto dplotter = std::make_shared<Plotter>(gui, 350, 250, 2000, 16);
dplotter->setGravity(Gravity::bottom_right); dplotter->setGravity(Gravity::bottom_right);
dplotter->setInteractive(false); dplotter->setInteractive(false);
add(HudElement(HudElementMode::PERMANENT, nullptr, dplotter, true)); add(HudElement(HudElementMode::PERMANENT, nullptr, dplotter, true));
@ -197,9 +200,10 @@ Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
assets.store(Texture::from(debugImgWorldGen.get()), DEBUG_WORLDGEN_IMAGE); assets.store(Texture::from(debugImgWorldGen.get()), DEBUG_WORLDGEN_IMAGE);
debugMinimap = guiutil::create( debugMinimap = guiutil::create(
"<image src='"+DEBUG_WORLDGEN_IMAGE+ gui,
"<image src='" + DEBUG_WORLDGEN_IMAGE +
"' pos='0' size='256' gravity='top-right' margin='0,20,0,0'/>" "' pos='0' size='256' gravity='top-right' margin='0,20,0,0'/>"
); );
add(HudElement(HudElementMode::PERMANENT, nullptr, debugMinimap, true)); add(HudElement(HudElementMode::PERMANENT, nullptr, debugMinimap, true));
} }
@ -223,11 +227,11 @@ void Hud::cleanup() {
} }
void Hud::processInput(bool visible) { void Hud::processInput(bool visible) {
auto menu = gui.getMenu(); if (!Window::isFocused() && !menu.hasOpenPage() && !isInventoryOpen()) {
if (!Window::isFocused() && !menu->hasOpenPage() && !isInventoryOpen()) {
setPause(true); setPause(true);
} }
if (!pause && visible && Events::jactive(BIND_HUD_INVENTORY)) { const auto& bindings = input.getBindings();
if (!pause && visible && bindings.jactive(BIND_HUD_INVENTORY)) {
if (inventoryOpen) { if (inventoryOpen) {
closeInventory(); closeInventory();
} else { } else {
@ -240,9 +244,10 @@ void Hud::processInput(bool visible) {
} }
void Hud::updateHotbarControl() { void Hud::updateHotbarControl() {
if (!inventoryOpen && Events::scroll) { int scroll = input.getScroll();
if (!inventoryOpen && scroll) {
int slot = player.getChosenSlot(); int slot = player.getChosenSlot();
slot = (slot - Events::scroll) % 10; slot = (slot - scroll) % 10;
if (slot < 0) { if (slot < 0) {
slot += 10; slot += 10;
} }
@ -253,11 +258,11 @@ void Hud::updateHotbarControl() {
i <= static_cast<int>(keycode::NUM_9); i <= static_cast<int>(keycode::NUM_9);
i++ i++
) { ) {
if (Events::jpressed(static_cast<keycode>(i))) { if (input.jpressed(static_cast<keycode>(i))) {
player.setChosenSlot(i - static_cast<int>(keycode::NUM_1)); player.setChosenSlot(i - static_cast<int>(keycode::NUM_1));
} }
} }
if (Events::jpressed(keycode::NUM_0)) { if (input.jpressed(keycode::NUM_0)) {
player.setChosenSlot(9); player.setChosenSlot(9);
} }
} }
@ -311,7 +316,6 @@ void Hud::updateWorldGenDebug() {
void Hud::update(bool visible) { void Hud::update(bool visible) {
const auto& chunks = *player.chunks; const auto& chunks = *player.chunks;
const auto& menu = gui.getMenu();
debugPanel->setVisible( debugPanel->setVisible(
debug && visible && !(inventoryOpen && inventoryView == nullptr) debug && visible && !(inventoryOpen && inventoryView == nullptr)
@ -320,13 +324,13 @@ void Hud::update(bool visible) {
if (!visible && inventoryOpen) { if (!visible && inventoryOpen) {
closeInventory(); closeInventory();
} }
if (pause && !menu->hasOpenPage()) { if (pause && !menu.hasOpenPage()) {
setPause(false); setPause(false);
} }
if (!gui.isFocusCaught()) { if (!gui.isFocusCaught()) {
processInput(visible); processInput(visible);
} }
if ((menu->hasOpenPage() || inventoryOpen) == Events::isCursorLocked()) { if ((menu.hasOpenPage() || inventoryOpen) == input.getCursor().locked) {
Events::toggleCursor(); Events::toggleCursor();
} }
@ -447,6 +451,7 @@ void Hud::showExchangeSlot() {
auto& content = level.content; auto& content = level.content;
exchangeSlotInv = level.inventories->createVirtual(1); exchangeSlotInv = level.inventories->createVirtual(1);
exchangeSlot = std::make_shared<SlotView>( exchangeSlot = std::make_shared<SlotView>(
gui,
SlotLayout(-1, glm::vec2(), false, false, nullptr, nullptr, nullptr) SlotLayout(-1, glm::vec2(), false, false, nullptr, nullptr, nullptr)
); );
exchangeSlot->bind(exchangeSlotInv->getId(), exchangeSlotInv->getSlot(0), &content); exchangeSlot->bind(exchangeSlotInv->getId(), exchangeSlotInv->getSlot(0), &content);
@ -590,11 +595,10 @@ void Hud::draw(const DrawContext& ctx){
const Viewport& viewport = ctx.getViewport(); const Viewport& viewport = ctx.getViewport();
const uint width = viewport.getWidth(); const uint width = viewport.getWidth();
const uint height = viewport.getHeight(); const uint height = viewport.getHeight();
auto menu = gui.getMenu();
bool is_menu_open = menu->hasOpenPage(); bool is_menu_open = menu.hasOpenPage();
darkOverlay->setVisible(is_menu_open); darkOverlay->setVisible(is_menu_open);
menu->setVisible(is_menu_open); menu.setVisible(is_menu_open);
updateElementsPosition(viewport); updateElementsPosition(viewport);
@ -663,7 +667,7 @@ void Hud::updateElementsPosition(const Viewport& viewport) {
} }
} }
if (exchangeSlot != nullptr) { if (exchangeSlot != nullptr) {
exchangeSlot->setPos(glm::vec2(Events::cursor)); exchangeSlot->setPos(input.getCursor().pos);
} }
hotbarView->setPos(glm::vec2(width/2, height-65)); hotbarView->setPos(glm::vec2(width/2, height-65));
hotbarView->setSelected(player.getChosenSlot()); hotbarView->setSelected(player.getChosenSlot());
@ -689,12 +693,11 @@ void Hud::setPause(bool pause) {
closeInventory(); closeInventory();
} }
const auto& menu = gui.getMenu(); if (!pause && menu.hasOpenPage()) {
if (!pause && menu->hasOpenPage()) { menu.reset();
menu->reset();
} }
if (pause && !menu->hasOpenPage()) { if (pause && !menu.hasOpenPage()) {
menu->setPage("pause"); menu.setPage("pause");
} }
} }
@ -730,9 +733,8 @@ void Hud::setDebugCheats(bool flag) {
void Hud::setAllowPause(bool flag) { void Hud::setAllowPause(bool flag) {
if (pause) { if (pause) {
auto menu = gui.getMenu();
setPause(false); setPause(false);
menu->setPage("pause", true); menu.setPage("pause", true);
} }
allowPause = flag; allowPause = flag;
} }

View File

@ -20,9 +20,11 @@ class UiDocument;
class DrawContext; class DrawContext;
class Viewport; class Viewport;
class ImageData; class ImageData;
class Input;
namespace gui { namespace gui {
class GUI; class GUI;
class Menu;
class UINode; class UINode;
class Panel; class Panel;
class Container; class Container;
@ -71,9 +73,11 @@ public:
class Hud : public util::ObjectsKeeper { class Hud : public util::ObjectsKeeper {
Engine& engine; Engine& engine;
Input& input;
Assets& assets; Assets& assets;
std::unique_ptr<Camera> uicamera;
gui::GUI& gui; gui::GUI& gui;
gui::Menu& menu;
std::unique_ptr<Camera> uicamera;
LevelFrontend& frontend; LevelFrontend& frontend;
Player& player; Player& player;

View File

@ -1,35 +1,35 @@
#include "menu.hpp" #include "menu.hpp"
#include "locale.hpp"
#include "UiDocument.hpp"
#include "screens/MenuScreen.hpp"
#include "delegates.hpp"
#include "engine/Engine.hpp"
#include "data/dv.hpp"
#include "interfaces/Task.hpp"
#include "io/engine_paths.hpp"
#include "graphics/ui/elements/Menu.hpp"
#include "graphics/ui/gui_util.hpp"
#include "graphics/ui/GUI.hpp"
#include "logic/scripting/scripting.hpp"
#include "settings.hpp"
#include "coders/commons.hpp"
#include "util/stringutil.hpp"
#include <filesystem> #include <filesystem>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "UiDocument.hpp"
#include "coders/commons.hpp"
#include "data/dv.hpp"
#include "delegates.hpp"
#include "engine/Engine.hpp"
#include "graphics/ui/GUI.hpp"
#include "graphics/ui/elements/Menu.hpp"
#include "graphics/ui/gui_util.hpp"
#include "interfaces/Task.hpp"
#include "io/engine_paths.hpp"
#include "locale.hpp"
#include "logic/scripting/scripting.hpp"
#include "screens/MenuScreen.hpp"
#include "settings.hpp"
#include "util/stringutil.hpp"
namespace fs = std::filesystem; namespace fs = std::filesystem;
using namespace gui; using namespace gui;
void menus::create_version_label(Engine& engine) { void menus::create_version_label(gui::GUI& gui) {
auto gui = engine.getGUI(); auto text = ENGINE_VERSION_STRING + " debug build";
auto text = ENGINE_VERSION_STRING+" debug build"; gui.add(guiutil::create(
gui->add(guiutil::create( gui,
"<label z-index='1000' color='#FFFFFF80' gravity='top-right' margin='4'>" "<label z-index='1000' color='#FFFFFF80' gravity='top-right' "
+text+ "margin='4'>" +
"</label>" text + "</label>"
)); ));
} }
@ -44,14 +44,16 @@ bool menus::call(Engine& engine, runnable func) {
engine.setScreen(std::make_shared<MenuScreen>(engine)); engine.setScreen(std::make_shared<MenuScreen>(engine));
// could not to find or read pack // could not to find or read pack
guiutil::alert( guiutil::alert(
engine, langs::get(L"error.pack-not-found")+L": "+ engine,
util::str2wstr_utf8(error.getPackId()) langs::get(L"error.pack-not-found") + L": " +
util::str2wstr_utf8(error.getPackId())
); );
return false; return false;
} catch (const assetload::error& error) { } catch (const assetload::error& error) {
engine.setScreen(std::make_shared<MenuScreen>(engine)); engine.setScreen(std::make_shared<MenuScreen>(engine));
guiutil::alert( guiutil::alert(
engine, langs::get(L"Assets Load Error", L"menu")+L":\n"+ engine,
langs::get(L"Assets Load Error", L"menu") + L":\n" +
util::str2wstr_utf8(error.what()) util::str2wstr_utf8(error.what())
); );
return false; return false;
@ -62,20 +64,27 @@ bool menus::call(Engine& engine, runnable func) {
} catch (const std::runtime_error& error) { } catch (const std::runtime_error& error) {
engine.setScreen(std::make_shared<MenuScreen>(engine)); engine.setScreen(std::make_shared<MenuScreen>(engine));
guiutil::alert( guiutil::alert(
engine, langs::get(L"Content Error", L"menu")+L":\n"+ engine,
langs::get(L"Content Error", L"menu") + L":\n" +
util::str2wstr_utf8(error.what()) util::str2wstr_utf8(error.what())
); );
return false; return false;
} }
} }
UiDocument* menus::show(Engine& engine, const std::string& name, std::vector<dv::value> args) { UiDocument* menus::show(
auto menu = engine.getGUI()->getMenu(); Engine& engine, const std::string& name, std::vector<dv::value> args
auto file = engine.getResPaths()->find("layouts/"+name+".xml"); ) {
auto fullname = "core:layouts/"+name; auto menu = engine.getGUI().getMenu();
auto file = engine.getResPaths()->find("layouts/" + name + ".xml");
auto fullname = "core:layouts/" + name;
auto documentPtr = UiDocument::read( auto documentPtr = UiDocument::read(
scripting::get_root_environment(), fullname, file, "core:layouts/"+name engine.getGUI(),
scripting::get_root_environment(),
fullname,
file,
"core:layouts/" + name
); );
auto document = documentPtr.get(); auto document = documentPtr.get();
engine.getAssets()->store(std::move(documentPtr), fullname); engine.getAssets()->store(std::move(documentPtr), fullname);
@ -85,18 +94,20 @@ UiDocument* menus::show(Engine& engine, const std::string& name, std::vector<dv:
return document; return document;
} }
void menus::show_process_panel(Engine& engine, const std::shared_ptr<Task>& task, const std::wstring& text) { void menus::show_process_panel(
Engine& engine, const std::shared_ptr<Task>& task, const std::wstring& text
) {
uint initialWork = task->getWorkTotal(); uint initialWork = task->getWorkTotal();
auto menu = engine.getGUI()->getMenu(); auto menu = engine.getGUI().getMenu();
menu->reset(); menu->reset();
auto doc = menus::show(engine, "process", { auto doc =
util::wstr2str_utf8(langs::get(text)) menus::show(engine, "process", {util::wstr2str_utf8(langs::get(text))});
}); std::dynamic_pointer_cast<Container>(doc->getRoot())
std::dynamic_pointer_cast<Container>(doc->getRoot())->listenInterval(0.01f, [=]() { ->listenInterval(0.01f, [=]() {
task->update(); task->update();
uint tasksDone = task->getWorkDone(); uint tasksDone = task->getWorkDone();
scripting::on_ui_progress(doc, tasksDone, initialWork); scripting::on_ui_progress(doc, tasksDone, initialWork);
}); });
} }

View File

@ -14,7 +14,7 @@ class UiDocument;
namespace menus { namespace menus {
/// @brief Create development version label at the top-right screen corner /// @brief Create development version label at the top-right screen corner
void create_version_label(Engine& engine); void create_version_label(gui::GUI& gui);
UiDocument* show( UiDocument* show(
Engine& engine, Engine& engine,

View File

@ -6,7 +6,7 @@
#include "core_defs.hpp" #include "core_defs.hpp"
#include "debug/Logger.hpp" #include "debug/Logger.hpp"
#include "engine/Engine.hpp" #include "engine/Engine.hpp"
#include "io/io.hpp" #include "frontend/ContentGfxCache.hpp"
#include "frontend/LevelFrontend.hpp" #include "frontend/LevelFrontend.hpp"
#include "frontend/hud.hpp" #include "frontend/hud.hpp"
#include "graphics/core/DrawContext.hpp" #include "graphics/core/DrawContext.hpp"
@ -17,8 +17,7 @@
#include "graphics/render/WorldRenderer.hpp" #include "graphics/render/WorldRenderer.hpp"
#include "graphics/ui/GUI.hpp" #include "graphics/ui/GUI.hpp"
#include "graphics/ui/elements/Menu.hpp" #include "graphics/ui/elements/Menu.hpp"
#include "graphics/ui/GUI.hpp" #include "io/io.hpp"
#include "frontend/ContentGfxCache.hpp"
#include "logic/LevelController.hpp" #include "logic/LevelController.hpp"
#include "logic/PlayerController.hpp" #include "logic/PlayerController.hpp"
#include "logic/scripting/scripting.hpp" #include "logic/scripting/scripting.hpp"
@ -43,12 +42,14 @@ LevelScreen::LevelScreen(
) )
: Screen(engine), : Screen(engine),
world(*levelPtr->getWorld()), world(*levelPtr->getWorld()),
postProcessing(std::make_unique<PostProcessing>()) { postProcessing(std::make_unique<PostProcessing>()),
gui(engine.getGUI()),
input(engine.getInput()) {
Level* level = levelPtr.get(); Level* level = levelPtr.get();
auto& settings = engine.getSettings(); auto& settings = engine.getSettings();
auto& assets = *engine.getAssets(); auto& assets = *engine.getAssets();
auto menu = engine.getGUI()->getMenu(); auto menu = engine.getGUI().getMenu();
menu->reset(); menu->reset();
auto player = level->players->get(localPlayer); auto player = level->players->get(localPlayer);
@ -57,10 +58,7 @@ LevelScreen::LevelScreen(
controller = controller =
std::make_unique<LevelController>(&engine, std::move(levelPtr), player); std::make_unique<LevelController>(&engine, std::move(levelPtr), player);
playerController = std::make_unique<PlayerController>( playerController = std::make_unique<PlayerController>(
settings, settings, *level, *player, *controller->getBlocksController()
*level,
*player,
*controller->getBlocksController()
); );
frontend = std::make_unique<LevelFrontend>( frontend = std::make_unique<LevelFrontend>(
@ -87,7 +85,7 @@ LevelScreen::LevelScreen(
keepAlive(settings.camera.fov.observe([=](double value) { keepAlive(settings.camera.fov.observe([=](double value) {
player->fpCamera->setFov(glm::radians(value)); player->fpCamera->setFov(glm::radians(value));
})); }));
keepAlive(Events::getBinding(BIND_CHUNKS_RELOAD).onactived.add([=](){ keepAlive(input.addCallback(BIND_CHUNKS_RELOAD, [=]() {
player->chunks->saveAndClear(); player->chunks->saveAndClear();
renderer->clear(); renderer->clear();
return false; return false;
@ -178,13 +176,14 @@ void LevelScreen::saveWorldPreview() {
void LevelScreen::updateHotkeys() { void LevelScreen::updateHotkeys() {
auto& settings = engine.getSettings(); auto& settings = engine.getSettings();
if (Events::jpressed(keycode::O)) {
if (input.jpressed(keycode::O)) {
settings.graphics.frustumCulling.toggle(); settings.graphics.frustumCulling.toggle();
} }
if (Events::jpressed(keycode::F1)) { if (input.jpressed(keycode::F1)) {
hudVisible = !hudVisible; hudVisible = !hudVisible;
} }
if (Events::jpressed(keycode::F3)) { if (input.jpressed(keycode::F3)) {
debug = !debug; debug = !debug;
hud->setDebug(debug); hud->setDebug(debug);
renderer->setDebug(debug); renderer->setDebug(debug);
@ -199,19 +198,16 @@ void LevelScreen::updateAudio() {
audio::get_channel("regular")->setPaused(paused); audio::get_channel("regular")->setPaused(paused);
audio::get_channel("ambient")->setPaused(paused); audio::get_channel("ambient")->setPaused(paused);
glm::vec3 velocity {}; glm::vec3 velocity {};
if (auto hitbox = player->getHitbox()) { if (auto hitbox = player->getHitbox()) {
velocity = hitbox->velocity; velocity = hitbox->velocity;
} }
audio::set_listener( audio::set_listener(
camera->position, camera->position, velocity, camera->dir, glm::vec3(0, 1, 0)
velocity,
camera->dir,
glm::vec3(0, 1, 0)
); );
} }
void LevelScreen::update(float delta) { void LevelScreen::update(float delta) {
auto& gui = *engine.getGUI(); auto& gui = engine.getGUI();
if (!gui.isFocusCaught()) { if (!gui.isFocusCaught()) {
updateHotkeys(); updateHotkeys();
@ -225,10 +221,10 @@ void LevelScreen::update(float delta) {
if (!paused) { if (!paused) {
world.updateTimers(delta); world.updateTimers(delta);
animator->update(delta); animator->update(delta);
playerController->update(delta, !inputLocked); playerController->update(delta, inputLocked ? nullptr : &engine.getInput());
} }
controller->update(glm::min(delta, 0.2f), paused); controller->update(glm::min(delta, 0.2f), paused);
playerController->postUpdate(delta, !inputLocked, paused); playerController->postUpdate(delta, inputLocked ? nullptr : &engine.getInput(), paused);
hud->update(hudVisible); hud->update(hudVisible);

View File

@ -16,6 +16,11 @@ class ContentPackRuntime;
class Decorator; class Decorator;
class Level; class Level;
class World; class World;
class Input;
namespace gui {
class GUI;
}
class LevelScreen : public Screen { class LevelScreen : public Screen {
World& world; World& world;
@ -27,6 +32,8 @@ class LevelScreen : public Screen {
std::unique_ptr<PostProcessing> postProcessing; std::unique_ptr<PostProcessing> postProcessing;
std::unique_ptr<Decorator> decorator; std::unique_ptr<Decorator> decorator;
std::unique_ptr<Hud> hud; std::unique_ptr<Hud> hud;
gui::GUI& gui;
Input& input;
void saveWorldPreview(); void saveWorldPreview();

View File

@ -13,7 +13,7 @@
MenuScreen::MenuScreen(Engine& engine) : Screen(engine) { MenuScreen::MenuScreen(Engine& engine) : Screen(engine) {
engine.resetContent(); engine.resetContent();
auto menu = engine.getGUI()->getMenu(); auto menu = engine.getGUI().getMenu();
menu->reset(); menu->reset();
menu->setPage("main"); menu->setPage("main");
@ -22,8 +22,7 @@ MenuScreen::MenuScreen(Engine& engine) : Screen(engine) {
uicamera->flipped = true; uicamera->flipped = true;
} }
MenuScreen::~MenuScreen() { MenuScreen::~MenuScreen() = default;
}
void MenuScreen::update(float delta) { void MenuScreen::update(float delta) {
} }

View File

@ -1,13 +1,15 @@
#include "GUI.hpp" #include "GUI.hpp"
#include "gui_util.hpp" #include <algorithm>
#include <iostream>
#include <utility>
#include "elements/UINode.hpp" #include "assets/Assets.hpp"
#include "elements/Label.hpp" #include "elements/Label.hpp"
#include "elements/Menu.hpp" #include "elements/Menu.hpp"
#include "elements/Panel.hpp" #include "elements/Panel.hpp"
#include "elements/UINode.hpp"
#include "assets/Assets.hpp" #include "engine/Engine.hpp"
#include "frontend/UiDocument.hpp" #include "frontend/UiDocument.hpp"
#include "frontend/locale.hpp" #include "frontend/locale.hpp"
#include "graphics/core/Batch2D.hpp" #include "graphics/core/Batch2D.hpp"
@ -15,31 +17,36 @@
#include "graphics/core/Shader.hpp" #include "graphics/core/Shader.hpp"
#include "graphics/core/Font.hpp" #include "graphics/core/Font.hpp"
#include "graphics/core/DrawContext.hpp" #include "graphics/core/DrawContext.hpp"
#include "graphics/core/Shader.hpp"
#include "gui_util.hpp"
#include "window/Camera.hpp"
#include "window/Events.hpp" #include "window/Events.hpp"
#include "window/Window.hpp" #include "window/Window.hpp"
#include "window/input.hpp" #include "window/input.hpp"
#include "window/Camera.hpp"
#include <algorithm> #include <algorithm>
#include <utility> #include <utility>
using namespace gui; using namespace gui;
GUI::GUI() GUI::GUI(Engine& engine)
: batch2D(std::make_unique<Batch2D>(1024)), : engine(engine),
container(std::make_shared<Container>(glm::vec2(1000))) { input(engine.getInput()),
batch2D(std::make_unique<Batch2D>(1024)),
container(std::make_shared<Container>(*this, glm::vec2(1000))) {
container->setId("root"); container->setId("root");
uicamera = std::make_unique<Camera>(glm::vec3(), Window::height); uicamera = std::make_unique<Camera>(glm::vec3(), Window::height);
uicamera->perspective = false; uicamera->perspective = false;
uicamera->flipped = true; uicamera->flipped = true;
menu = std::make_shared<Menu>(); menu = std::make_shared<Menu>(*this);
menu->setId("menu"); menu->setId("menu");
menu->setZIndex(10); menu->setZIndex(10);
container->add(menu); container->add(menu);
container->setScrollable(false); container->setScrollable(false);
tooltip = guiutil::create( tooltip = guiutil::create(
*this,
"<container color='#000000A0' interactive='false' z-index='999'>" "<container color='#000000A0' interactive='false' z-index='999'>"
"<label id='tooltip.label' pos='2' autoresize='true' multiline='true' text-wrap='false'></label>" "<label id='tooltip.label' pos='2' autoresize='true' multiline='true' text-wrap='false'></label>"
"</container>" "</container>"
@ -65,12 +72,15 @@ std::shared_ptr<Menu> GUI::getMenu() {
} }
void GUI::onAssetsLoad(Assets* assets) { void GUI::onAssetsLoad(Assets* assets) {
assets->store(std::make_unique<UiDocument>( assets->store(
"core:root", std::make_unique<UiDocument>(
uidocscript {}, "core:root",
std::dynamic_pointer_cast<gui::UINode>(container), uidocscript {},
nullptr std::dynamic_pointer_cast<gui::UINode>(container),
), "core:root"); nullptr
),
"core:root"
);
} }
void GUI::resetTooltip() { void GUI::resetTooltip() {
@ -79,11 +89,13 @@ void GUI::resetTooltip() {
} }
void GUI::updateTooltip(float delta) { void GUI::updateTooltip(float delta) {
if (hover == nullptr || !hover->isInside(Events::cursor)) { const auto& cursor = input.getCursor();
if (hover == nullptr || !hover->isInside(cursor.pos)) {
return resetTooltip(); return resetTooltip();
} }
if (tooltipTimer + delta >= hover->getTooltipDelay()) { if (tooltipTimer + delta >= hover->getTooltipDelay()) {
auto label = std::dynamic_pointer_cast<gui::Label>(get("tooltip.label")); auto label =
std::dynamic_pointer_cast<gui::Label>(get("tooltip.label"));
const auto& text = hover->getTooltip(); const auto& text = hover->getTooltip();
if (text.empty() && tooltip->isVisible()) { if (text.empty() && tooltip->isVisible()) {
return resetTooltip(); return resetTooltip();
@ -91,11 +103,11 @@ void GUI::updateTooltip(float delta) {
if (label && !text.empty()) { if (label && !text.empty()) {
tooltip->setVisible(true); tooltip->setVisible(true);
label->setText(langs::get(text)); label->setText(langs::get(text));
auto size = label->getSize()+glm::vec2(4.0f); auto size = label->getSize() + glm::vec2(4.0f);
auto pos = Events::cursor+glm::vec2(10.0f); auto pos = cursor.pos + glm::vec2(10.0f);
auto rootSize = container->getSize(); auto rootSize = container->getSize();
pos.x = glm::min(pos.x, rootSize.x-size.x); pos.x = glm::min(pos.x, rootSize.x - size.x);
pos.y = glm::min(pos.y, rootSize.y-size.y); pos.y = glm::min(pos.y, rootSize.y - size.y);
tooltip->setSize(size); tooltip->setSize(size);
tooltip->setPos(pos); tooltip->setPos(pos);
} }
@ -104,8 +116,8 @@ void GUI::updateTooltip(float delta) {
} }
/// @brief Mouse related input and logic handling /// @brief Mouse related input and logic handling
void GUI::actMouse(float delta) { void GUI::actMouse(float delta, const CursorState& cursor) {
float mouseDelta = glm::length(Events::delta); float mouseDelta = glm::length(cursor.delta);
doubleClicked = false; doubleClicked = false;
doubleClickTimer += delta + mouseDelta * 0.1f; doubleClickTimer += delta + mouseDelta * 0.1f;
@ -116,21 +128,21 @@ void GUI::actMouse(float delta) {
if (hover) { if (hover) {
hover->setHover(true); hover->setHover(true);
int scroll = Events::getScroll(); int scroll = input.getScroll();
if (scroll) { if (scroll) {
hover->scrolled(scroll); hover->scrolled(scroll);
} }
} }
this->hover = hover; this->hover = hover;
if (Events::jclicked(mousecode::BUTTON_1)) { if (input.jclicked(mousecode::BUTTON_1)) {
if (pressed == nullptr && this->hover) { if (pressed == nullptr && this->hover) {
pressed = hover; pressed = hover;
if (doubleClickTimer < doubleClickDelay) { if (doubleClickTimer < doubleClickDelay) {
pressed->doubleClick(this, Events::cursor.x, Events::cursor.y); pressed->doubleClick(cursor.pos.x, cursor.pos.y);
doubleClicked = true; doubleClicked = true;
} else { } else {
pressed->click(this, Events::cursor.x, Events::cursor.y); pressed->click(cursor.pos.x, cursor.pos.y);
} }
doubleClickTimer = 0.0f; doubleClickTimer = 0.0f;
if (focus && focus != pressed) { if (focus && focus != pressed) {
@ -138,7 +150,7 @@ void GUI::actMouse(float delta) {
} }
if (focus != pressed) { if (focus != pressed) {
focus = pressed; focus = pressed;
focus->onFocus(this); focus->onFocus();
return; return;
} }
} }
@ -146,22 +158,22 @@ void GUI::actMouse(float delta) {
focus->defocus(); focus->defocus();
focus = nullptr; focus = nullptr;
} }
} else if (!Events::clicked(mousecode::BUTTON_1) && pressed) { } else if (!input.clicked(mousecode::BUTTON_1) && pressed) {
pressed->mouseRelease(this, Events::cursor.x, Events::cursor.y); pressed->mouseRelease(cursor.pos.x, cursor.pos.y);
pressed = nullptr; pressed = nullptr;
} }
if (hover) { if (hover) {
for (mousecode code : MOUSECODES_ALL) { for (mousecode code : MOUSECODES_ALL) {
if (Events::jclicked(code)) { if (input.jclicked(code)) {
hover->clicked(this, code); hover->clicked(code);
} }
} }
} }
} }
void GUI::actFocused() { void GUI::actFocused() {
if (Events::jpressed(keycode::ESCAPE)) { if (input.jpressed(keycode::ESCAPE)) {
focus->defocus(); focus->defocus();
focus = nullptr; focus = nullptr;
return; return;
@ -173,12 +185,13 @@ void GUI::actFocused() {
focus->keyPressed(key); focus->keyPressed(key);
} }
if (!Events::isCursorLocked()) { const auto& cursor = input.getCursor();
if (Events::clicked(mousecode::BUTTON_1) && if (!cursor.locked) {
(Events::jclicked(mousecode::BUTTON_1) || Events::delta.x || Events::delta.y)) if (input.clicked(mousecode::BUTTON_1) &&
{ (input.jclicked(mousecode::BUTTON_1) || cursor.delta.x ||
cursor.delta.y)) {
if (!doubleClicked) { if (!doubleClicked) {
focus->mouseMove(this, Events::cursor.x, Events::cursor.y); focus->mouseMove(cursor.pos.x, cursor.pos.y);
} }
} }
} }
@ -190,15 +203,16 @@ void GUI::act(float delta, const Viewport& vp) {
auto prevfocus = focus; auto prevfocus = focus;
updateTooltip(delta); updateTooltip(delta);
const auto& cursor = input.getCursor();
if (!Events::isCursorLocked()) { if (!Events::isCursorLocked()) {
actMouse(delta); actMouse(delta, cursor);
} else { } else {
if (hover) { if (hover) {
hover->setHover(false); hover->setHover(false);
hover = nullptr; hover = nullptr;
} }
} }
if (focus) { if (focus) {
actFocused(); actFocused();
} }
@ -316,7 +330,7 @@ void GUI::setFocus(std::shared_ptr<UINode> node) {
} }
focus = std::move(node); focus = std::move(node);
if (focus) { if (focus) {
focus->onFocus(this); focus->onFocus();
} }
} }
@ -339,3 +353,7 @@ float GUI::getDoubleClickDelay() const {
void GUI::toggleDebug() { void GUI::toggleDebug() {
debug = !debug; debug = !debug;
} }
const Input& GUI::getInput() const {
return engine.getInput();
}

View File

@ -14,7 +14,9 @@ class DrawContext;
class Assets; class Assets;
class Camera; class Camera;
class Batch2D; class Batch2D;
class LineBatch; struct CursorState;
class Engine;
class Input;
/* /*
Some info about padding and margin. Some info about padding and margin.
@ -56,6 +58,8 @@ namespace gui {
/// @brief The main UI controller /// @brief The main UI controller
class GUI { class GUI {
Engine& engine;
Input& input;
std::unique_ptr<Batch2D> batch2D; std::unique_ptr<Batch2D> batch2D;
std::shared_ptr<Container> container; std::shared_ptr<Container> container;
std::shared_ptr<UINode> hover; std::shared_ptr<UINode> hover;
@ -76,12 +80,12 @@ namespace gui {
bool doubleClicked = false; bool doubleClicked = false;
bool debug = false; bool debug = false;
void actMouse(float delta); void actMouse(float delta, const CursorState& cursor);
void actFocused(); void actFocused();
void updateTooltip(float delta); void updateTooltip(float delta);
void resetTooltip(); void resetTooltip();
public: public:
GUI(); GUI(Engine& engine);
~GUI(); ~GUI();
void setPageLoader(PageLoaderFunc pageLoader); void setPageLoader(PageLoaderFunc pageLoader);
@ -152,5 +156,6 @@ namespace gui {
float getDoubleClickDelay() const; float getDoubleClickDelay() const;
void toggleDebug(); void toggleDebug();
const Input& getInput() const;
}; };
} }

View File

@ -26,12 +26,13 @@ namespace gui {
} }
protected: protected:
BasePanel( BasePanel(
GUI& gui,
glm::vec2 size, glm::vec2 size,
glm::vec4 padding = glm::vec4(0.0f), glm::vec4 padding = glm::vec4(0.0f),
float interval = 2.0f, float interval = 2.0f,
Orientation orientation = Orientation::vertical Orientation orientation = Orientation::vertical
) )
: Container(std::move(size)), : Container(gui, std::move(size)),
padding(std::move(padding)), padding(std::move(padding)),
interval(interval) { interval(interval) {
} }

View File

@ -3,17 +3,23 @@
#include <utility> #include <utility>
#include "Label.hpp" #include "Label.hpp"
#include "graphics/core/DrawContext.hpp"
#include "graphics/core/Batch2D.hpp" #include "graphics/core/Batch2D.hpp"
#include "graphics/core/DrawContext.hpp"
using namespace gui; using namespace gui;
Button::Button(const std::shared_ptr<UINode>& content, glm::vec4 padding) Button::Button(
: Panel(glm::vec2(), padding, 0) { GUI& gui, const std::shared_ptr<UINode>& content, glm::vec4 padding
)
: Panel(gui, glm::vec2(), padding, 0) {
glm::vec4 margin = getMargin(); glm::vec4 margin = getMargin();
setSize(content->getSize()+ setSize(
glm::vec2(padding[0]+padding[2]+margin[0]+margin[2], content->getSize() +
padding[1]+padding[3]+margin[1]+margin[3])); glm::vec2(
padding[0] + padding[2] + margin[0] + margin[2],
padding[1] + padding[3] + margin[1] + margin[3]
)
);
add(content); add(content);
setScrollable(false); setScrollable(false);
setHoverColor(glm::vec4(0.05f, 0.1f, 0.15f, 0.75f)); setHoverColor(glm::vec4(0.05f, 0.1f, 0.15f, 0.75f));
@ -22,15 +28,16 @@ Button::Button(const std::shared_ptr<UINode>& content, glm::vec4 padding)
} }
Button::Button( Button::Button(
GUI& gui,
const std::wstring& text, const std::wstring& text,
glm::vec4 padding, glm::vec4 padding,
const onaction& action, const onaction& action,
glm::vec2 size glm::vec2 size
) : Panel(size, padding, 0) )
{ : Panel(gui, size, padding, 0) {
if (size.y < 0.0f) { if (size.y < 0.0f) {
size = glm::vec2( size = glm::vec2(
glm::max(padding.x + padding.z + text.length()*8, size.x), glm::max(padding.x + padding.z + text.length() * 8, size.x),
glm::max(padding.y + padding.w + 16, size.y) glm::max(padding.y + padding.w + 16, size.y)
); );
} }
@ -41,9 +48,11 @@ Button::Button(
} }
setScrollable(false); setScrollable(false);
label = std::make_shared<Label>(text); label = std::make_shared<Label>(gui, text);
label->setAlign(Align::center); label->setAlign(Align::center);
label->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y)); label->setSize(
size - glm::vec2(padding.z + padding.x, padding.w + padding.y)
);
label->setInteractive(false); label->setInteractive(false);
add(label); add(label);
setHoverColor(glm::vec4(0.05f, 0.1f, 0.15f, 0.75f)); setHoverColor(glm::vec4(0.05f, 0.1f, 0.15f, 0.75f));
@ -73,7 +82,9 @@ Button* Button::textSupplier(wstringsupplier supplier) {
void Button::refresh() { void Button::refresh() {
Panel::refresh(); Panel::refresh();
if (label) { if (label) {
label->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y)); label->setSize(
size - glm::vec2(padding.z + padding.x, padding.w + padding.y)
);
} }
} }

View File

@ -9,13 +9,19 @@ namespace gui {
protected: protected:
std::shared_ptr<Label> label; std::shared_ptr<Label> label;
public: public:
Button(const std::shared_ptr<UINode>& content, Button(
glm::vec4 padding=glm::vec4(2.0f)); GUI& gui,
const std::shared_ptr<UINode>& content,
glm::vec4 padding = glm::vec4(2.0f)
);
Button(const std::wstring& text, Button(
glm::vec4 padding, GUI& gui,
const onaction& action, const std::wstring& text,
glm::vec2 size=glm::vec2(-1)); glm::vec4 padding,
const onaction& action,
glm::vec2 size = glm::vec2(-1)
);
virtual void drawBackground( virtual void drawBackground(
const DrawContext& pctx, const Assets& assets const DrawContext& pctx, const Assets& assets

View File

@ -4,7 +4,8 @@
#include "graphics/core/DrawContext.hpp" #include "graphics/core/DrawContext.hpp"
#include "graphics/core/Texture.hpp" #include "graphics/core/Texture.hpp"
gui::Canvas::Canvas(ImageFormat inFormat, glm::uvec2 inSize) : UINode(inSize) { gui::Canvas::Canvas(GUI& gui, ImageFormat inFormat, glm::uvec2 inSize)
: UINode(gui, inSize) {
auto data = std::make_shared<ImageData>(inFormat, inSize.x, inSize.y); auto data = std::make_shared<ImageData>(inFormat, inSize.x, inSize.y);
mTexture = Texture::from(data.get()); mTexture = Texture::from(data.get());
mData = std::move(data); mData = std::move(data);

View File

@ -9,7 +9,7 @@ class Texture;
namespace gui { namespace gui {
class Canvas final : public UINode { class Canvas final : public UINode {
public: public:
explicit Canvas(ImageFormat inFormat, glm::uvec2 inSize); explicit Canvas(GUI& gui, ImageFormat inFormat, glm::uvec2 inSize);
~Canvas() override = default; ~Canvas() override = default;

View File

@ -2,13 +2,14 @@
#include <utility> #include <utility>
#include "graphics/core/DrawContext.hpp"
#include "graphics/core/Batch2D.hpp"
#include "Label.hpp" #include "Label.hpp"
#include "graphics/core/Batch2D.hpp"
#include "graphics/core/DrawContext.hpp"
using namespace gui; using namespace gui;
CheckBox::CheckBox(bool checked) : UINode(glm::vec2(32.0f)), checked(checked) { CheckBox::CheckBox(GUI& gui, bool checked)
: UINode(gui, glm::vec2(32.0f)), checked(checked) {
setColor({0.0f, 0.0f, 0.0f, 0.5f}); setColor({0.0f, 0.0f, 0.0f, 0.5f});
setHoverColor({0.05f, 0.1f, 0.2f, 0.75f}); setHoverColor({0.05f, 0.1f, 0.2f, 0.75f});
} }
@ -24,7 +25,7 @@ void CheckBox::draw(const DrawContext& pctx, const Assets&) {
batch->rect(pos.x, pos.y, size.x, size.y); batch->rect(pos.x, pos.y, size.x, size.y);
} }
void CheckBox::mouseRelease(GUI*, int, int) { void CheckBox::mouseRelease(int, int) {
checked = !checked; checked = !checked;
if (consumer) { if (consumer) {
consumer(checked); consumer(checked);
@ -44,10 +45,12 @@ CheckBox* CheckBox::setChecked(bool flag) {
return this; return this;
} }
FullCheckBox::FullCheckBox(const std::wstring& text, glm::vec2 size, bool checked) FullCheckBox::FullCheckBox(
: Panel(size), GUI& gui, const std::wstring& text, glm::vec2 size, bool checked
checkbox(std::make_shared<CheckBox>(checked)), )
label(std::make_shared<Label>(text)) { : Panel(gui, size),
checkbox(std::make_shared<CheckBox>(gui, checked)),
label(std::make_shared<Label>(gui, text)) {
setColor(glm::vec4(0.0f)); setColor(glm::vec4(0.0f));
setOrientation(Orientation::horizontal); setOrientation(Orientation::horizontal);

View File

@ -2,8 +2,8 @@
#include <utility> #include <utility>
#include "Panel.hpp"
#include "Label.hpp" #include "Label.hpp"
#include "Panel.hpp"
namespace gui { namespace gui {
class CheckBox : public UINode { class CheckBox : public UINode {
@ -13,11 +13,12 @@ namespace gui {
boolconsumer consumer = nullptr; boolconsumer consumer = nullptr;
bool checked = false; bool checked = false;
public: public:
CheckBox(bool checked=false); explicit CheckBox(GUI& gui, bool checked = false);
virtual void draw(const DrawContext& pctx, const Assets& assets) override; virtual void draw(const DrawContext& pctx, const Assets& assets)
override;
virtual void mouseRelease(GUI*, int x, int y) override; virtual void mouseRelease(int x, int y) override;
virtual void setSupplier(boolsupplier supplier); virtual void setSupplier(boolsupplier supplier);
virtual void setConsumer(boolconsumer consumer); virtual void setConsumer(boolconsumer consumer);
@ -25,8 +26,7 @@ namespace gui {
virtual CheckBox* setChecked(bool flag); virtual CheckBox* setChecked(bool flag);
virtual bool isChecked() const { virtual bool isChecked() const {
if (supplier) if (supplier) return supplier();
return supplier();
return checked; return checked;
} }
}; };
@ -36,7 +36,12 @@ namespace gui {
std::shared_ptr<CheckBox> checkbox; std::shared_ptr<CheckBox> checkbox;
std::shared_ptr<Label> label; std::shared_ptr<Label> label;
public: public:
FullCheckBox(const std::wstring& text, glm::vec2 size, bool checked=false); explicit FullCheckBox(
GUI& gui,
const std::wstring& text,
glm::vec2 size,
bool checked = false
);
virtual void setSupplier(boolsupplier supplier) { virtual void setSupplier(boolsupplier supplier) {
checkbox->setSupplier(std::move(supplier)); checkbox->setSupplier(std::move(supplier));

View File

@ -8,7 +8,7 @@
using namespace gui; using namespace gui;
Container::Container(glm::vec2 size) : UINode(size) { Container::Container(GUI& gui, glm::vec2 size) : UINode(gui, size) {
actualLength = size.y; actualLength = size.y;
setColor(glm::vec4()); setColor(glm::vec4());
} }
@ -41,8 +41,8 @@ std::shared_ptr<UINode> Container::getAt(const glm::vec2& pos) {
return UINode::getAt(pos); return UINode::getAt(pos);
} }
void Container::mouseMove(GUI* gui, int x, int y) { void Container::mouseMove(int x, int y) {
UINode::mouseMove(gui, x, y); UINode::mouseMove(x, y);
if (!scrollable) { if (!scrollable) {
return; return;
} }
@ -65,8 +65,8 @@ void Container::mouseMove(GUI* gui, int x, int y) {
prevScrollY = y; prevScrollY = y;
} }
void Container::mouseRelease(GUI* gui, int x, int y) { void Container::mouseRelease(int x, int y) {
UINode::mouseRelease(gui, x, y); UINode::mouseRelease(x, y);
prevScrollY = -1; prevScrollY = -1;
} }

View File

@ -7,7 +7,7 @@
#include <vector> #include <vector>
namespace gui { namespace gui {
class Container : public UINode, public util::ObjectsKeeper { class Container : public UINode, public ::util::ObjectsKeeper {
int prevScrollY = -1; int prevScrollY = -1;
protected: protected:
std::vector<std::shared_ptr<UINode>> nodes; std::vector<std::shared_ptr<UINode>> nodes;
@ -22,7 +22,7 @@ namespace gui {
return prevScrollY != -1; return prevScrollY != -1;
} }
public: public:
Container(glm::vec2 size); Container(GUI& gui, glm::vec2 size);
virtual ~Container(); virtual ~Container();
virtual void act(float delta) override; virtual void act(float delta) override;
@ -44,8 +44,8 @@ namespace gui {
virtual void refresh() override; virtual void refresh() override;
void setScroll(int scroll); void setScroll(int scroll);
virtual void mouseMove(GUI*, int x, int y) override; virtual void mouseMove(int x, int y) override;
virtual void mouseRelease(GUI*, int x, int y) override; virtual void mouseRelease(int x, int y) override;
const std::vector<std::shared_ptr<UINode>>& getNodes() const; const std::vector<std::shared_ptr<UINode>>& getNodes() const;
}; };

View File

@ -2,16 +2,17 @@
#include <utility> #include <utility>
#include "graphics/core/DrawContext.hpp"
#include "graphics/core/Batch2D.hpp"
#include "graphics/core/Texture.hpp"
#include "graphics/core/Atlas.hpp"
#include "assets/Assets.hpp" #include "assets/Assets.hpp"
#include "graphics/core/Atlas.hpp"
#include "graphics/core/Batch2D.hpp"
#include "graphics/core/DrawContext.hpp"
#include "graphics/core/Texture.hpp"
#include "maths/UVRegion.hpp" #include "maths/UVRegion.hpp"
using namespace gui; using namespace gui;
Image::Image(std::string texture, glm::vec2 size) : UINode(size), texture(std::move(texture)) { Image::Image(GUI& gui, std::string texture, glm::vec2 size)
: UINode(gui, size), texture(std::move(texture)) {
setInteractive(false); setInteractive(false);
} }
@ -30,14 +31,16 @@ void Image::draw(const DrawContext& pctx, const Assets& assets) {
} else { } else {
auto atlasName = this->texture.substr(0, separator); auto atlasName = this->texture.substr(0, separator);
if (auto atlas = assets.get<Atlas>(atlasName)) { if (auto atlas = assets.get<Atlas>(atlasName)) {
if (auto region = atlas->getIf(this->texture.substr(separator+1))) { if (auto region =
atlas->getIf(this->texture.substr(separator + 1))) {
texture = atlas->getTexture(); texture = atlas->getTexture();
batch->texture(atlas->getTexture()); batch->texture(atlas->getTexture());
batch->setRegion(*region); batch->setRegion(*region);
if (autoresize) { if (autoresize) {
setSize(glm::vec2( setSize(glm::vec2(
texture->getWidth()*region->getWidth(), texture->getWidth() * region->getWidth(),
texture->getHeight()*region->getHeight())); texture->getHeight() * region->getHeight()
));
} }
} else { } else {
batch->texture(nullptr); batch->texture(nullptr);
@ -45,8 +48,17 @@ void Image::draw(const DrawContext& pctx, const Assets& assets) {
} }
} }
batch->rect( batch->rect(
pos.x, pos.y, size.x, size.y, pos.x,
0, 0, 0, UVRegion(), false, true, calcColor() pos.y,
size.x,
size.y,
0,
0,
0,
UVRegion(),
false,
true,
calcColor()
); );
} }

View File

@ -8,7 +8,7 @@ namespace gui {
std::string texture; std::string texture;
bool autoresize = false; bool autoresize = false;
public: public:
Image(std::string texture, glm::vec2 size=glm::vec2(32,32)); Image(GUI& gui, std::string texture, glm::vec2 size=glm::vec2(32,32));
virtual void draw(const DrawContext& pctx, const Assets& assets) override; virtual void draw(const DrawContext& pctx, const Assets& assets) override;

View File

@ -7,10 +7,10 @@
using namespace gui; using namespace gui;
InputBindBox::InputBindBox(Binding& binding, glm::vec4 padding) InputBindBox::InputBindBox(GUI& gui, Binding& binding, glm::vec4 padding)
: Panel(glm::vec2(100,32), padding, 0), : Panel(gui, glm::vec2(100,32), padding, 0),
binding(binding), binding(binding),
label(std::make_shared<Label>(L"")) { label(std::make_shared<Label>(gui, L"")) {
add(label); add(label);
setScrollable(false); setScrollable(false);
hoverColor = glm::vec4(0.05f, 0.1f, 0.2f, 0.75f); hoverColor = glm::vec4(0.05f, 0.1f, 0.2f, 0.75f);
@ -25,7 +25,7 @@ void InputBindBox::drawBackground(const DrawContext& pctx, const Assets&) {
label->setText(util::str2wstr_utf8(binding.text())); label->setText(util::str2wstr_utf8(binding.text()));
} }
void InputBindBox::clicked(GUI*, mousecode button) { void InputBindBox::clicked(mousecode button) {
if (isFocused()) { if (isFocused()) {
binding.reset(button); binding.reset(button);
defocus(); defocus();

View File

@ -11,14 +11,18 @@ namespace gui {
glm::vec4 focusedColor {0.1f, 0.15f, 0.35f, 0.75f}; glm::vec4 focusedColor {0.1f, 0.15f, 0.35f, 0.75f};
std::shared_ptr<Label> label; std::shared_ptr<Label> label;
public: public:
InputBindBox(Binding& binding, glm::vec4 padding=glm::vec4(6.0f)); explicit InputBindBox(
GUI& gui, Binding& binding, glm::vec4 padding = glm::vec4(6.0f)
);
virtual void drawBackground( virtual void drawBackground(
const DrawContext& pctx, const Assets& assets const DrawContext& pctx, const Assets& assets
) override; ) override;
virtual void clicked(GUI*, mousecode button) override; virtual void clicked(mousecode button) override;
virtual void keyPressed(keycode key) override; virtual void keyPressed(keycode key) override;
virtual bool isFocuskeeper() const override {return true;} virtual bool isFocuskeeper() const override {
return true;
}
}; };
} }

View File

@ -46,8 +46,8 @@ SlotLayout::SlotLayout(
shareFunc(std::move(shareFunc)), shareFunc(std::move(shareFunc)),
rightClick(std::move(rightClick)) {} rightClick(std::move(rightClick)) {}
InventoryBuilder::InventoryBuilder() { InventoryBuilder::InventoryBuilder(GUI& gui) : gui(gui) {
view = std::make_shared<InventoryView>(); view = std::make_shared<InventoryView>(gui);
} }
void InventoryBuilder::addGrid( void InventoryBuilder::addGrid(
@ -75,7 +75,8 @@ void InventoryBuilder::addGrid(
view->setSize(vsize); view->setSize(vsize);
if (addpanel) { if (addpanel) {
auto panel = std::make_shared<gui::Container>(glm::vec2(width, height)); auto panel =
std::make_shared<gui::Container>(gui, glm::vec2(width, height));
view->setColor(glm::vec4(0.122f, 0.122f, 0.122f, 0.878f)); view->setColor(glm::vec4(0.122f, 0.122f, 0.122f, 0.878f));
view->add(panel, pos); view->add(panel, pos);
} }
@ -106,8 +107,8 @@ std::shared_ptr<InventoryView> InventoryBuilder::build() {
} }
SlotView::SlotView( SlotView::SlotView(
SlotLayout layout GUI& gui, SlotLayout layout
) : UINode(glm::vec2(InventoryView::SLOT_SIZE)), ) : UINode(gui, glm::vec2(InventoryView::SLOT_SIZE)),
layout(std::move(layout)) layout(std::move(layout))
{ {
setColor(glm::vec4(0, 0, 0, 0.2f)); setColor(glm::vec4(0, 0, 0, 0.2f));
@ -347,11 +348,11 @@ void SlotView::performRightClick(ItemStack& stack, ItemStack& grabbed) {
} }
} }
void SlotView::clicked(gui::GUI* gui, mousecode button) { void SlotView::clicked(mousecode button) {
if (bound == nullptr) if (bound == nullptr)
return; return;
auto exchangeSlot = auto exchangeSlot =
std::dynamic_pointer_cast<SlotView>(gui->get(EXCHANGE_SLOT_NAME)); std::dynamic_pointer_cast<SlotView>(gui.get(EXCHANGE_SLOT_NAME));
if (exchangeSlot == nullptr) { if (exchangeSlot == nullptr) {
return; return;
} }
@ -368,8 +369,8 @@ void SlotView::clicked(gui::GUI* gui, mousecode button) {
} }
} }
void SlotView::onFocus(gui::GUI* gui) { void SlotView::onFocus() {
clicked(gui, mousecode::BUTTON_1); clicked(mousecode::BUTTON_1);
} }
const std::wstring& SlotView::getTooltip() const { const std::wstring& SlotView::getTooltip() const {
@ -398,7 +399,7 @@ ItemStack& SlotView::getStack() {
return *bound; return *bound;
} }
InventoryView::InventoryView() : Container(glm::vec2()) { InventoryView::InventoryView(GUI& gui) : Container(gui, glm::vec2()) {
setColor(glm::vec4(0, 0, 0, 0.0f)); setColor(glm::vec4(0, 0, 0, 0.0f));
} }
@ -419,7 +420,7 @@ std::shared_ptr<SlotView> InventoryView::addSlot(const SlotLayout& layout) {
} }
setSize(vsize); setSize(vsize);
auto slot = std::make_shared<SlotView>(layout); auto slot = std::make_shared<SlotView>(gui, layout);
if (!layout.background) { if (!layout.background) {
slot->setColor(glm::vec4()); slot->setColor(glm::vec4());
} }

View File

@ -86,15 +86,15 @@ namespace gui {
void refreshTooltip(const ItemStack& stack, const ItemDef& item); void refreshTooltip(const ItemStack& stack, const ItemDef& item);
public: public:
SlotView(SlotLayout layout); SlotView(GUI& gui, SlotLayout layout);
virtual void draw(const DrawContext& pctx, const Assets& assets) override; virtual void draw(const DrawContext& pctx, const Assets& assets) override;
void setHighlighted(bool flag); void setHighlighted(bool flag);
bool isHighlighted() const; bool isHighlighted() const;
virtual void clicked(gui::GUI*, mousecode) override; virtual void clicked(mousecode) override;
virtual void onFocus(gui::GUI*) override; virtual void onFocus() override;
virtual const std::wstring& getTooltip() const override; virtual const std::wstring& getTooltip() const override;
void bind( void bind(
@ -117,7 +117,7 @@ namespace gui {
std::vector<SlotView*> slots; std::vector<SlotView*> slots;
glm::vec2 origin {}; glm::vec2 origin {};
public: public:
InventoryView(); InventoryView(GUI& gui);
virtual ~InventoryView(); virtual ~InventoryView();
virtual void setPos(glm::vec2 pos) override; virtual void setPos(glm::vec2 pos) override;
@ -145,9 +145,10 @@ namespace gui {
}; };
class InventoryBuilder { class InventoryBuilder {
GUI& gui;
std::shared_ptr<InventoryView> view; std::shared_ptr<InventoryView> view;
public: public:
InventoryBuilder(); InventoryBuilder(GUI& gui);
/// @brief Add slots grid to inventory view /// @brief Add slots grid to inventory view
/// @param cols grid columns /// @param cols grid columns

View File

@ -83,8 +83,8 @@ void LabelCache::update(std::wstring_view text, bool multiline, bool wrap) {
} }
} }
Label::Label(const std::string& text, std::string fontName) Label::Label(GUI& gui, const std::string& text, std::string fontName)
: UINode(glm::vec2(text.length() * 8, 16)), : UINode(gui, glm::vec2(text.length() * 8, 16)),
text(util::str2wstr_utf8(text)), text(util::str2wstr_utf8(text)),
fontName(std::move(fontName)) fontName(std::move(fontName))
{ {
@ -93,8 +93,8 @@ Label::Label(const std::string& text, std::string fontName)
} }
Label::Label(const std::wstring& text, std::string fontName) Label::Label(GUI& gui, const std::wstring& text, std::string fontName)
: UINode(glm::vec2(text.length() * 8, 16)), : UINode(gui, glm::vec2(text.length() * 8, 16)),
text(text), text(text),
fontName(std::move(fontName)) fontName(std::move(fontName))
{ {

View File

@ -63,8 +63,8 @@ namespace gui {
std::unique_ptr<FontStylesScheme> styles; std::unique_ptr<FontStylesScheme> styles;
public: public:
Label(const std::string& text, std::string fontName=FONT_DEFAULT); Label(GUI& gui, const std::string& text, std::string fontName="normal");
Label(const std::wstring& text, std::string fontName=FONT_DEFAULT); Label(GUI& gui, const std::wstring& text, std::string fontName="normal");
virtual ~Label(); virtual ~Label();

View File

@ -5,7 +5,7 @@
using namespace gui; using namespace gui;
Menu::Menu() : Container(glm::vec2(1)){ Menu::Menu(GUI& gui) : Container(gui, glm::vec2(1)){
} }
bool Menu::has(const std::string& name) { bool Menu::has(const std::string& name) {

View File

@ -21,7 +21,7 @@ namespace gui {
std::unordered_map<std::string, supplier<std::shared_ptr<UINode>>> pageSuppliers; std::unordered_map<std::string, supplier<std::shared_ptr<UINode>>> pageSuppliers;
PageLoaderFunc pagesLoader = nullptr; PageLoaderFunc pagesLoader = nullptr;
public: public:
Menu(); explicit Menu(GUI& gui);
/// @brief Check menu have page or page supplier /// @brief Check menu have page or page supplier
/// @param name page name /// @param name page name

View File

@ -4,14 +4,12 @@
using namespace gui; using namespace gui;
Panel::Panel(glm::vec2 size, glm::vec4 padding, float interval) Panel::Panel(GUI& gui, glm::vec2 size, glm::vec4 padding, float interval)
: BasePanel(size, padding, interval, Orientation::vertical) : BasePanel(gui, size, padding, interval) {
{
setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.75f)); setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.75f));
} }
Panel::~Panel() { Panel::~Panel() = default;
}
void Panel::setMaxLength(int value) { void Panel::setMaxLength(int value) {
maxLength = value; maxLength = value;
@ -46,7 +44,7 @@ void Panel::fullRefresh() {
Container::fullRefresh(); Container::fullRefresh();
} }
void Panel::add(const std::shared_ptr<UINode> &node) { void Panel::add(const std::shared_ptr<UINode>& node) {
node->setResizing(true); node->setResizing(true);
Container::add(node); Container::add(node);
fullRefresh(); fullRefresh();
@ -80,7 +78,7 @@ void Panel::refresh() {
node->refresh(); node->refresh();
glm::vec2 nodeSize = node->getSize(); glm::vec2 nodeSize = node->getSize();
y += nodeSize.y + margin.w + interval; y += nodeSize.y + margin.w + interval;
maxw = fmax(maxw, ex+nodeSize.x+margin.z+padding.z); maxw = fmax(maxw, ex + nodeSize.x + margin.z + padding.z);
} }
actualLength = y + padding.w; actualLength = y + padding.w;
} else { } else {
@ -89,11 +87,13 @@ void Panel::refresh() {
glm::vec2 nodesize = node->getSize(); glm::vec2 nodesize = node->getSize();
const glm::vec4 margin = node->getMargin(); const glm::vec4 margin = node->getMargin();
x += margin.x; x += margin.x;
node->setPos(glm::vec2(x, y+margin.y)); node->setPos(glm::vec2(x, y + margin.y));
x += nodesize.x + margin.z + interval; x += nodesize.x + margin.z + interval;
node->refresh(); node->refresh();
maxh = fmax(maxh, y+margin.y+node->getSize().y+margin.w+padding.w); maxh = fmax(
maxh, y + margin.y + node->getSize().y + margin.w + padding.w
);
} }
actualLength = size.y; actualLength = size.y;
} }

View File

@ -1,15 +1,16 @@
#pragma once #pragma once
#include "commons.hpp"
#include "BasePanel.hpp" #include "BasePanel.hpp"
#include "commons.hpp"
namespace gui { namespace gui {
class Panel : public BasePanel { class Panel : public BasePanel {
public: public:
Panel( Panel(
GUI& gui,
glm::vec2 size, glm::vec2 size,
glm::vec4 padding=glm::vec4(0.0f), glm::vec4 padding = glm::vec4(2.0f),
float interval=2.0f float interval = 2.0f
); );
virtual ~Panel(); virtual ~Panel();

View File

@ -1,15 +1,16 @@
#pragma once #pragma once
#include <glm/glm.hpp>
#include <memory>
#include "UINode.hpp" #include "UINode.hpp"
#include "typedefs.hpp" #include "typedefs.hpp"
#include <memory>
class Assets; class Assets;
class DrawContext; class DrawContext;
namespace gui { namespace gui {
class Plotter : public gui::UINode { class Plotter : public UINode {
std::unique_ptr<int[]> points; std::unique_ptr<int[]> points;
float multiplier; float multiplier;
int index = 0; int index = 0;
@ -17,13 +18,18 @@ namespace gui {
int dmheight; int dmheight;
int labelsInterval; int labelsInterval;
public: public:
Plotter(uint width, uint height, float multiplier, int labelsInterval) Plotter(
: gui::UINode(glm::vec2(width, height)), GUI& gui,
multiplier(multiplier), uint width,
dmwidth(width-50), uint height,
dmheight(height), float multiplier,
labelsInterval(labelsInterval) int labelsInterval
{ )
: UINode(gui, glm::vec2(width, height)),
multiplier(multiplier),
dmwidth(width - 50),
dmheight(height),
labelsInterval(labelsInterval) {
points = std::make_unique<int[]>(dmwidth); points = std::make_unique<int[]>(dmwidth);
} }

View File

@ -2,15 +2,15 @@
using namespace gui; using namespace gui;
SplitBox::SplitBox(const glm::vec2& size, float splitPos, Orientation orientation) SplitBox::SplitBox(GUI& gui, const glm::vec2& size, float splitPos, Orientation orientation)
: BasePanel(size, glm::vec4(), 4.0f, orientation), splitPos(splitPos) { : BasePanel(gui, size, glm::vec4(), 4.0f, orientation), splitPos(splitPos) {
setCursor( setCursor(
orientation == Orientation::vertical ? CursorShape::NS_RESIZE orientation == Orientation::vertical ? CursorShape::NS_RESIZE
: CursorShape::EW_RESIZE : CursorShape::EW_RESIZE
); );
} }
void SplitBox::mouseMove(GUI*, int x, int y) { void SplitBox::mouseMove(int x, int y) {
auto pos = calcPos(); auto pos = calcPos();
auto size = getSize(); auto size = getSize();
@ -59,7 +59,7 @@ void SplitBox::refresh() {
} }
} }
void SplitBox::doubleClick(GUI*, int x, int y) { void SplitBox::doubleClick(int x, int y) {
if (nodes.size() < 2) { if (nodes.size() < 2) {
return; return;
} }

View File

@ -5,12 +5,12 @@
namespace gui { namespace gui {
class SplitBox : public BasePanel { class SplitBox : public BasePanel {
public: public:
SplitBox(const glm::vec2& size, float splitPos, Orientation orientation); SplitBox(GUI& gui, const glm::vec2& size, float splitPos, Orientation orientation);
virtual void mouseMove(GUI*, int x, int y) override; virtual void mouseMove(int x, int y) override;
virtual void refresh() override; virtual void refresh() override;
virtual void fullRefresh() override; virtual void fullRefresh() override;
virtual void doubleClick(GUI*, int x, int y) override; virtual void doubleClick(int x, int y) override;
private: private:
float splitPos; float splitPos;
}; };

View File

@ -4,9 +4,12 @@
#include <sstream> #include <sstream>
#include <utility> #include <utility>
#include "../GUI.hpp"
#include "../markdown.hpp"
#include "Label.hpp" #include "Label.hpp"
#include "assets/Assets.hpp" #include "assets/Assets.hpp"
#include "devtools/syntax_highlighting.hpp" #include "devtools/syntax_highlighting.hpp"
#include "engine/Engine.hpp"
#include "graphics/core/Batch2D.hpp" #include "graphics/core/Batch2D.hpp"
#include "graphics/core/DrawContext.hpp" #include "graphics/core/DrawContext.hpp"
#include "graphics/core/Font.hpp" #include "graphics/core/Font.hpp"
@ -186,8 +189,9 @@ namespace gui {
}; };
} }
TextBox::TextBox(std::wstring placeholder, glm::vec4 padding) TextBox::TextBox(GUI& gui, std::wstring placeholder, glm::vec4 padding)
: Container(glm::vec2(200, 32)), : Container(gui, glm::vec2(200, 32)),
inputEvents(gui.getInput()),
history(std::make_shared<ActionsHistory>()), history(std::make_shared<ActionsHistory>()),
historian(std::make_unique<TextBoxHistorian>(*this, *history)), historian(std::make_unique<TextBoxHistorian>(*this, *history)),
padding(padding), padding(padding),
@ -197,16 +201,21 @@ TextBox::TextBox(std::wstring placeholder, glm::vec4 padding)
setOnUpPressed(nullptr); setOnUpPressed(nullptr);
setOnDownPressed(nullptr); setOnDownPressed(nullptr);
setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.75f)); setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.75f));
label = std::make_shared<Label>(L"");
label->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y)); label = std::make_shared<Label>(gui, L"");
label->setSize(
size - glm::vec2(padding.z + padding.x, padding.w + padding.y)
);
label->setPos(glm::vec2( label->setPos(glm::vec2(
padding.x + LINE_NUMBERS_PANE_WIDTH * showLineNumbers, padding.y padding.x + LINE_NUMBERS_PANE_WIDTH * showLineNumbers, padding.y
)); ));
add(label); add(label);
lineNumbersLabel = std::make_shared<Label>(L""); lineNumbersLabel = std::make_shared<Label>(gui, L"");
lineNumbersLabel->setMultiline(true); lineNumbersLabel->setMultiline(true);
lineNumbersLabel->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y)); lineNumbersLabel->setSize(
size - glm::vec2(padding.z + padding.x, padding.w + padding.y)
);
lineNumbersLabel->setVerticalAlign(Align::top); lineNumbersLabel->setVerticalAlign(Align::top);
add(lineNumbersLabel); add(lineNumbersLabel);
@ -342,7 +351,7 @@ void TextBox::drawBackground(const DrawContext& pctx, const Assets&) {
batch->texture(nullptr); batch->texture(nullptr);
auto subctx = pctx.sub(); auto subctx = pctx.sub();
subctx.setScissors(glm::vec4(pos.x, pos.y-0.5, size.x, size.y+1)); subctx.setScissors(glm::vec4(pos.x, pos.y - 0.5, size.x, size.y + 1));
if (valid) { if (valid) {
if (isFocused() && !multiline) { if (isFocused() && !multiline) {
@ -371,7 +380,8 @@ void TextBox::refreshLabel() {
const auto& displayText = input.empty() && !hint.empty() ? hint : getText(); const auto& displayText = input.empty() && !hint.empty() ? hint : getText();
if (markup == "md") { if (markup == "md") {
auto [processedText, styles] = markdown::process(displayText, !focused || !editable); auto [processedText, styles] =
markdown::process(displayText, !focused || !editable);
label->setText(std::move(processedText)); label->setText(std::move(processedText));
label->setStyles(std::move(styles)); label->setStyles(std::move(styles));
} else { } else {
@ -386,7 +396,7 @@ void TextBox::refreshLabel() {
std::wstringstream ss; std::wstringstream ss;
int n = 1; int n = 1;
for (int i = 1; i <= label->getLinesNumber(); i++) { for (int i = 1; i <= label->getLinesNumber(); i++) {
if (!label->isFakeLine(i-1)) { if (!label->isFakeLine(i - 1)) {
ss << n; ss << n;
n++; n++;
} }
@ -402,11 +412,12 @@ void TextBox::refreshLabel() {
if (autoresize && font) { if (autoresize && font) {
auto size = getSize(); auto size = getSize();
int newy = glm::min(static_cast<int>(parent->getSize().y), int newy = glm::min(
static_cast<int>( static_cast<int>(parent->getSize().y),
label->getLinesNumber() * static_cast<int>(
label->getLineInterval() * label->getLinesNumber() * label->getLineInterval() *
font->getLineHeight()) + 1 font->getLineHeight()
) + 1
); );
if (newy != static_cast<int>(size.y)) { if (newy != static_cast<int>(size.y)) {
size.y = newy; size.y = newy;
@ -475,7 +486,7 @@ bool TextBox::eraseSelected() {
input.substr(selectionStart, selectionEnd - selectionStart), input.substr(selectionStart, selectionEnd - selectionStart),
true true
); );
erase(selectionStart, selectionEnd-selectionStart); erase(selectionStart, selectionEnd - selectionStart);
resetSelection(); resetSelection();
onInput(); onInput();
return true; return true;
@ -495,7 +506,7 @@ void TextBox::extendSelection(int index) {
size_t TextBox::getLineLength(uint line) const { size_t TextBox::getLineLength(uint line) const {
size_t position = label->getTextLineOffset(line); size_t position = label->getTextLineOffset(line);
size_t lineLength = label->getTextLineOffset(line+1)-position; size_t lineLength = label->getTextLineOffset(line + 1) - position;
if (lineLength == 0) { if (lineLength == 0) {
lineLength = label->getText().length() - position + 1; lineLength = label->getText().length() - position + 1;
} }
@ -593,9 +604,9 @@ bool TextBox::isAutoResize() const {
return autoresize; return autoresize;
} }
void TextBox::onFocus(GUI* gui) { void TextBox::onFocus() {
Container::onFocus(gui); Container::onFocus();
if (onEditStart){ if (onEditStart) {
setCaret(input.size()); setCaret(input.size());
onEditStart(); onEditStart();
resetSelection(); resetSelection();
@ -609,7 +620,9 @@ void TextBox::reposition() {
void TextBox::refresh() { void TextBox::refresh() {
Container::refresh(); Container::refresh();
label->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y)); label->setSize(
size - glm::vec2(padding.z + padding.x, padding.w + padding.y)
);
label->setPos(glm::vec2( label->setPos(glm::vec2(
padding.x + LINE_NUMBERS_PANE_WIDTH * showLineNumbers + textInitX - padding.x + LINE_NUMBERS_PANE_WIDTH * showLineNumbers + textInitX -
static_cast<int>(textOffset), static_cast<int>(textOffset),
@ -629,24 +642,27 @@ size_t TextBox::normalizeIndex(int index) {
/// @param y screen Y position /// @param y screen Y position
/// @return non-normalized character index /// @return non-normalized character index
int TextBox::calcIndexAt(int x, int y) const { int TextBox::calcIndexAt(int x, int y) const {
if (font == nullptr) if (font == nullptr) return 0;
return 0;
const auto& labelText = label->getText(); const auto& labelText = label->getText();
glm::vec2 lcoord = label->calcPos(); glm::vec2 lcoord = label->calcPos();
uint line = label->getLineByYOffset(y-lcoord.y); uint line = label->getLineByYOffset(y - lcoord.y);
line = std::min(line, label->getLinesNumber()-1); line = std::min(line, label->getLinesNumber() - 1);
size_t lineLength = getLineLength(line); size_t lineLength = getLineLength(line);
uint offset = 0; uint offset = 0;
while (lcoord.x + font->calcWidth(labelText, offset) < x && offset < lineLength-1) { while (lcoord.x + font->calcWidth(labelText, offset) < x &&
offset < lineLength - 1) {
offset++; offset++;
} }
return std::min(offset+label->getTextLineOffset(line), labelText.length()); return std::min(
offset + label->getTextLineOffset(line), labelText.length()
);
} }
static inline std::wstring get_alphabet(wchar_t c) { static inline std::wstring get_alphabet(wchar_t c) {
std::wstring alphabet {c}; std::wstring alphabet {c};
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') { if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') {
return L"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; return L"abcdefghijklmnopqrstuvwxyz_"
L"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
} else if (c >= '0' && c <= '9') { } else if (c >= '0' && c <= '9') {
return L"0123456789"; return L"0123456789";
} }
@ -674,23 +690,23 @@ void TextBox::tokenSelectAt(int index) {
} }
right++; right++;
} }
select(left+1, right); select(left + 1, right);
} }
void TextBox::doubleClick(GUI* gui, int x, int y) { void TextBox::doubleClick(int x, int y) {
UINode::doubleClick(gui, x, y); UINode::doubleClick(x, y);
tokenSelectAt(normalizeIndex(calcIndexAt(x, y)-1)); tokenSelectAt(normalizeIndex(calcIndexAt(x, y) - 1));
} }
void TextBox::click(GUI*, int x, int y) { void TextBox::click(int x, int y) {
int index = normalizeIndex(calcIndexAt(x, y)); int index = normalizeIndex(calcIndexAt(x, y));
selectionStart = index; selectionStart = index;
selectionEnd = index; selectionEnd = index;
selectionOrigin = index; selectionOrigin = index;
} }
void TextBox::mouseMove(GUI* gui, int x, int y) { void TextBox::mouseMove(int x, int y) {
Container::mouseMove(gui, x, y); Container::mouseMove(x, y);
if (isScrolling()) { if (isScrolling()) {
return; return;
} }
@ -701,7 +717,8 @@ void TextBox::mouseMove(GUI* gui, int x, int y) {
} }
void TextBox::resetMaxLocalCaret() { void TextBox::resetMaxLocalCaret() {
maxLocalCaret = caret - label->getTextLineOffset(label->getLineByTextIndex(caret)); maxLocalCaret =
caret - label->getTextLineOffset(label->getLineByTextIndex(caret));
} }
void TextBox::stepLeft(bool shiftPressed, bool breakSelection) { void TextBox::stepLeft(bool shiftPressed, bool breakSelection) {
@ -709,9 +726,9 @@ void TextBox::stepLeft(bool shiftPressed, bool breakSelection) {
size_t caret = breakSelection ? selectionStart : this->caret; size_t caret = breakSelection ? selectionStart : this->caret;
if (caret > 0) { if (caret > 0) {
if (caret > input.length()) { if (caret > input.length()) {
setCaret(input.length()-1); setCaret(input.length() - 1);
} else { } else {
setCaret(caret-1); setCaret(caret - 1);
} }
if (shiftPressed) { if (shiftPressed) {
if (selectionStart == selectionEnd) { if (selectionStart == selectionEnd) {
@ -732,7 +749,7 @@ void TextBox::stepRight(bool shiftPressed, bool breakSelection) {
uint previousCaret = this->caret; uint previousCaret = this->caret;
size_t caret = breakSelection ? selectionEnd : this->caret; size_t caret = breakSelection ? selectionEnd : this->caret;
if (caret < input.length()) { if (caret < input.length()) {
setCaret(caret+1); setCaret(caret + 1);
caretLastMove = Window::time(); caretLastMove = Window::time();
if (shiftPressed) { if (shiftPressed) {
if (selectionStart == selectionEnd) { if (selectionStart == selectionEnd) {
@ -753,9 +770,10 @@ void TextBox::stepDefaultDown(bool shiftPressed, bool breakSelection) {
uint previousCaret = this->caret; uint previousCaret = this->caret;
uint caret = breakSelection ? selectionEnd : this->caret; uint caret = breakSelection ? selectionEnd : this->caret;
uint caretLine = label->getLineByTextIndex(caret); uint caretLine = label->getLineByTextIndex(caret);
if (caretLine < label->getLinesNumber()-1) { if (caretLine < label->getLinesNumber() - 1) {
uint offset = std::min(size_t(maxLocalCaret), getLineLength(caretLine+1)-1); uint offset =
setCaret(label->getTextLineOffset(caretLine+1) + offset); std::min(size_t(maxLocalCaret), getLineLength(caretLine + 1) - 1);
setCaret(label->getTextLineOffset(caretLine + 1) + offset);
} else { } else {
setCaret(input.length()); setCaret(input.length());
} }
@ -774,8 +792,9 @@ void TextBox::stepDefaultUp(bool shiftPressed, bool breakSelection) {
uint caret = breakSelection ? selectionStart : this->caret; uint caret = breakSelection ? selectionStart : this->caret;
uint caretLine = label->getLineByTextIndex(caret); uint caretLine = label->getLineByTextIndex(caret);
if (caretLine > 0) { if (caretLine > 0) {
uint offset = std::min(size_t(maxLocalCaret), getLineLength(caretLine-1)-1); uint offset =
setCaret(label->getTextLineOffset(caretLine-1) + offset); std::min(size_t(maxLocalCaret), getLineLength(caretLine - 1) - 1);
setCaret(label->getTextLineOffset(caretLine - 1) + offset);
} else { } else {
setCaret(static_cast<size_t>(0)); setCaret(static_cast<size_t>(0));
} }
@ -805,7 +824,7 @@ void TextBox::onInput() {
} }
void TextBox::performEditingKeyboardEvents(keycode key) { void TextBox::performEditingKeyboardEvents(keycode key) {
bool shiftPressed = Events::pressed(keycode::LEFT_SHIFT); bool shiftPressed = gui.getInput().pressed(keycode::LEFT_SHIFT);
bool breakSelection = getSelectionLength() != 0 && !shiftPressed; bool breakSelection = getSelectionLength() != 0 && !shiftPressed;
if (key == keycode::BACKSPACE) { if (key == keycode::BACKSPACE) {
if (!eraseSelected() && caret > 0 && input.length() > 0) { if (!eraseSelected() && caret > 0 && input.length() > 0) {
@ -813,8 +832,8 @@ void TextBox::performEditingKeyboardEvents(keycode key) {
caret = input.length(); caret = input.length();
} }
historian->onErase(caret - 1, input.substr(caret - 1, 1)); historian->onErase(caret - 1, input.substr(caret - 1, 1));
input = input.substr(0, caret-1) + input.substr(caret); input = input.substr(0, caret - 1) + input.substr(caret);
setCaret(caret-1); setCaret(caret - 1);
if (validate()) { if (validate()) {
onInput(); onInput();
} }
@ -850,10 +869,11 @@ void TextBox::performEditingKeyboardEvents(keycode key) {
} }
void TextBox::keyPressed(keycode key) { void TextBox::keyPressed(keycode key) {
const auto& inputEvents = gui.getInput();
if (editable) { if (editable) {
performEditingKeyboardEvents(key); performEditingKeyboardEvents(key);
} }
if (Events::pressed(keycode::LEFT_CONTROL) && key != keycode::LEFT_CONTROL) { if (inputEvents.pressed(keycode::LEFT_CONTROL) && key != keycode::LEFT_CONTROL) {
if (controlCombinationsHandler) { if (controlCombinationsHandler) {
if (controlCombinationsHandler(static_cast<int>(key))) { if (controlCombinationsHandler(static_cast<int>(key))) {
return; return;
@ -871,7 +891,7 @@ void TextBox::keyPressed(keycode key) {
} }
// Paste text from clipboard // Paste text from clipboard
if (key == keycode::V && editable) { if (key == keycode::V && editable) {
const char* text = Window::getClipboardText(); const char* text = inputEvents.getClipboardText();
if (text) { if (text) {
historian->sync(); // flush buffer before combination historian->sync(); // flush buffer before combination
// Combine deleting selected text and pasing a clipboard content // Combine deleting selected text and pasing a clipboard content
@ -924,14 +944,14 @@ std::shared_ptr<UINode> TextBox::getAt(const glm::vec2& pos) {
return UINode::getAt(pos); return UINode::getAt(pos);
} }
void TextBox::setOnUpPressed(const runnable &callback) { void TextBox::setOnUpPressed(const runnable& callback) {
if (callback == nullptr) { if (callback == nullptr) {
onUpPressed = [this]() { onUpPressed = [this]() {
if (Events::pressed(keycode::LEFT_CONTROL)) { if (inputEvents.pressed(keycode::LEFT_CONTROL)) {
scrolled(1); scrolled(1);
return; return;
} }
bool shiftPressed = Events::pressed(keycode::LEFT_SHIFT); bool shiftPressed = inputEvents.pressed(keycode::LEFT_SHIFT);
bool breakSelection = getSelectionLength() != 0 && !shiftPressed; bool breakSelection = getSelectionLength() != 0 && !shiftPressed;
stepDefaultUp(shiftPressed, breakSelection); stepDefaultUp(shiftPressed, breakSelection);
}; };
@ -940,14 +960,14 @@ void TextBox::setOnUpPressed(const runnable &callback) {
} }
} }
void TextBox::setOnDownPressed(const runnable &callback) { void TextBox::setOnDownPressed(const runnable& callback) {
if (callback == nullptr) { if (callback == nullptr) {
onDownPressed = [this]() { onDownPressed = [this]() {
if (Events::pressed(keycode::LEFT_CONTROL)) { if (inputEvents.pressed(keycode::LEFT_CONTROL)) {
scrolled(-1); scrolled(-1);
return; return;
} }
bool shiftPressed = Events::pressed(keycode::LEFT_SHIFT); bool shiftPressed = inputEvents.pressed(keycode::LEFT_SHIFT);
bool breakSelection = getSelectionLength() != 0 && !shiftPressed; bool breakSelection = getSelectionLength() != 0 && !shiftPressed;
stepDefaultDown(shiftPressed, breakSelection); stepDefaultDown(shiftPressed, breakSelection);
}; };
@ -984,7 +1004,6 @@ glm::vec4 TextBox::getFocusedColor() const {
return focusedColor; return focusedColor;
} }
void TextBox::setTextColor(glm::vec4 color) { void TextBox::setTextColor(glm::vec4 color) {
this->textColor = color; this->textColor = color;
} }
@ -1002,8 +1021,7 @@ glm::vec4 TextBox::getErrorColor() const {
} }
const std::wstring& TextBox::getText() const { const std::wstring& TextBox::getText() const {
if (input.empty()) if (input.empty()) return placeholder;
return placeholder;
return input; return input;
} }
@ -1024,7 +1042,6 @@ void TextBox::setPlaceholder(const std::wstring& placeholder) {
this->placeholder = placeholder; this->placeholder = placeholder;
} }
const std::wstring& TextBox::getHint() const { const std::wstring& TextBox::getHint() const {
return hint; return hint;
} }
@ -1035,7 +1052,7 @@ void TextBox::setHint(const std::wstring& text) {
std::wstring TextBox::getSelection() const { std::wstring TextBox::getSelection() const {
const auto& text = label->getText(); const auto& text = label->getText();
return text.substr(selectionStart, selectionEnd-selectionStart); return text.substr(selectionStart, selectionEnd - selectionStart);
} }
size_t TextBox::getCaret() const { size_t TextBox::getCaret() const {
@ -1057,24 +1074,25 @@ void TextBox::setCaret(size_t position) {
uint line = rawTextCache.getLineByTextIndex(caret); uint line = rawTextCache.getLineByTextIndex(caret);
int offset = label->getLineYOffset(line) + getContentOffset().y; int offset = label->getLineYOffset(line) + getContentOffset().y;
uint lineHeight = font->getLineHeight()*label->getLineInterval(); uint lineHeight = font->getLineHeight() * label->getLineInterval();
if (scrollStep == 0) { if (scrollStep == 0) {
scrollStep = lineHeight; scrollStep = lineHeight;
} }
if (offset < 0) { if (offset < 0) {
scrolled(-glm::floor(offset / static_cast<double>(scrollStep)+0.5f)); scrolled(-glm::floor(offset / static_cast<double>(scrollStep) + 0.5f));
} else if (offset >= getSize().y) { } else if (offset >= getSize().y) {
offset -= getSize().y; offset -= getSize().y;
scrolled(-glm::ceil(offset / static_cast<double>(scrollStep)+0.5f)); scrolled(-glm::ceil(offset / static_cast<double>(scrollStep) + 0.5f));
} }
int lcaret = caret - rawTextCache.getTextLineOffset(line); int lcaret = caret - rawTextCache.getTextLineOffset(line);
int realoffset = int realoffset =
font->calcWidth(labelText, lcaret) - static_cast<int>(textOffset) + 2; font->calcWidth(labelText, lcaret) - static_cast<int>(textOffset) + 2;
if (realoffset-width > 0) { if (realoffset - width > 0) {
setTextOffset(textOffset + realoffset-width); setTextOffset(textOffset + realoffset - width);
} else if (realoffset < 0) { } else if (realoffset < 0) {
setTextOffset(std::max(textOffset + realoffset, static_cast<size_t>(0))); setTextOffset(std::max(textOffset + realoffset, static_cast<size_t>(0))
);
} }
} }

View File

@ -9,6 +9,7 @@ class ActionsHistory;
namespace gui { namespace gui {
class TextBoxHistorian; class TextBoxHistorian;
class TextBox : public Container { class TextBox : public Container {
const Input& inputEvents;
LabelCache rawTextCache; LabelCache rawTextCache;
std::shared_ptr<ActionsHistory> history; std::shared_ptr<ActionsHistory> history;
std::unique_ptr<TextBoxHistorian> historian; std::unique_ptr<TextBoxHistorian> historian;
@ -94,7 +95,8 @@ namespace gui {
void refreshSyntax(); void refreshSyntax();
public: public:
TextBox( explicit TextBox(
GUI& gui,
std::wstring placeholder, std::wstring placeholder,
glm::vec4 padding=glm::vec4(4.0f) glm::vec4 padding=glm::vec4(4.0f)
); );
@ -227,11 +229,11 @@ namespace gui {
virtual bool isShowLineNumbers() const; virtual bool isShowLineNumbers() const;
virtual void reposition() override; virtual void reposition() override;
virtual void onFocus(GUI*) override; virtual void onFocus() override;
virtual void refresh() override; virtual void refresh() override;
virtual void doubleClick(GUI*, int x, int y) override; virtual void doubleClick(int x, int y) override;
virtual void click(GUI*, int, int) override; virtual void click(int, int) override;
virtual void mouseMove(GUI*, int x, int y) override; virtual void mouseMove(int x, int y) override;
virtual bool isFocuskeeper() const override {return true;} virtual bool isFocuskeeper() const override {return true;}
virtual void draw(const DrawContext& pctx, const Assets& assets) override; virtual void draw(const DrawContext& pctx, const Assets& assets) override;
virtual void drawBackground(const DrawContext& pctx, const Assets& assets) override; virtual void drawBackground(const DrawContext& pctx, const Assets& assets) override;

View File

@ -9,12 +9,13 @@
using namespace gui; using namespace gui;
TrackBar::TrackBar( TrackBar::TrackBar(
GUI& gui,
double min, double min,
double max, double max,
double value, double value,
double step, double step,
int trackWidth int trackWidth
) : UINode(glm::vec2(26)), ) : UINode(gui, glm::vec2(26)),
min(min), min(min),
max(max), max(max),
value(value), value(value),
@ -54,7 +55,7 @@ void TrackBar::setSubConsumer(doubleconsumer consumer) {
this->subconsumer = std::move(consumer); this->subconsumer = std::move(consumer);
} }
void TrackBar::mouseMove(GUI*, int x, int) { void TrackBar::mouseMove(int x, int) {
glm::vec2 pos = calcPos(); glm::vec2 pos = calcPos();
value = x - trackWidth/2; value = x - trackWidth/2;
value -= pos.x; value -= pos.x;
@ -62,7 +63,7 @@ void TrackBar::mouseMove(GUI*, int x, int) {
value += min; value += min;
value = (value > max) ? max : value; value = (value > max) ? max : value;
value = (value < min) ? min : value; value = (value < min) ? min : value;
value = (int64_t)round(value / step) * step; value = static_cast<int64_t>(std::round(value / step)) * step;
if (consumer && !changeOnRelease) { if (consumer && !changeOnRelease) {
consumer(value); consumer(value);
@ -72,7 +73,7 @@ void TrackBar::mouseMove(GUI*, int x, int) {
} }
} }
void TrackBar::mouseRelease(GUI*, int, int) { void TrackBar::mouseRelease(int, int) {
if (consumer && changeOnRelease) { if (consumer && changeOnRelease) {
consumer(value); consumer(value);
} }

View File

@ -16,19 +16,22 @@ namespace gui {
int trackWidth; int trackWidth;
bool changeOnRelease = false; bool changeOnRelease = false;
public: public:
TrackBar(double min, TrackBar(
double max, GUI& gui,
double value, double min,
double step=1.0, double max,
int trackWidth=12); double value,
double step = 1.0,
int trackWidth = 12
);
virtual void draw(const DrawContext& pctx, const Assets& assets) override; virtual void draw(const DrawContext& pctx, const Assets& assets) override;
virtual void setSupplier(doublesupplier); virtual void setSupplier(doublesupplier);
virtual void setConsumer(doubleconsumer); virtual void setConsumer(doubleconsumer);
virtual void setSubConsumer(doubleconsumer); virtual void setSubConsumer(doubleconsumer);
virtual void mouseMove(GUI*, int x, int y) override; virtual void mouseMove(int x, int y) override;
virtual void mouseRelease(GUI*, int x, int y) override; virtual void mouseRelease(int x, int y) override;
virtual double getValue() const; virtual double getValue() const;
virtual double getMin() const; virtual double getMin() const;

View File

@ -8,7 +8,7 @@
using gui::UINode; using gui::UINode;
using gui::Align; using gui::Align;
UINode::UINode(glm::vec2 size) : size(size) { UINode::UINode(GUI& gui, glm::vec2 size) : gui(gui), size(size) {
} }
UINode::~UINode() { UINode::~UINode() {
@ -74,18 +74,18 @@ UINode* UINode::listenDoubleClick(const onaction& action) {
return this; return this;
} }
void UINode::click(GUI*, int, int) { void UINode::click(int, int) {
pressed = true; pressed = true;
} }
void UINode::doubleClick(GUI* gui, int x, int y) { void UINode::doubleClick(int x, int y) {
pressed = true; pressed = true;
if (isInside(glm::vec2(x, y))) { if (isInside(glm::vec2(x, y))) {
doubleClickCallbacks.notify(gui); doubleClickCallbacks.notify(gui);
} }
} }
void UINode::mouseRelease(GUI* gui, int x, int y) { void UINode::mouseRelease(int x, int y) {
pressed = false; pressed = false;
if (isInside(glm::vec2(x, y))) { if (isInside(glm::vec2(x, y))) {
actions.notify(gui); actions.notify(gui);

View File

@ -19,8 +19,8 @@ namespace gui {
class GUI; class GUI;
class Container; class Container;
using onaction = std::function<void(GUI*)>; using onaction = std::function<void(GUI&)>;
using onnumberchange = std::function<void(GUI*, double)>; using onnumberchange = std::function<void(GUI&, double)>;
class ActionsSet { class ActionsSet {
std::unique_ptr<std::vector<onaction>> callbacks; std::unique_ptr<std::vector<onaction>> callbacks;
@ -32,7 +32,7 @@ namespace gui {
callbacks->push_back(callback); callbacks->push_back(callback);
} }
void notify(GUI* gui) { void notify(GUI& gui) {
if (callbacks) { if (callbacks) {
for (auto& callback : *callbacks) { for (auto& callback : *callbacks) {
callback(gui); callback(gui);
@ -64,6 +64,9 @@ namespace gui {
/// @brief Base abstract class for all UI elements /// @brief Base abstract class for all UI elements
class UINode : public std::enable_shared_from_this<UINode> { class UINode : public std::enable_shared_from_this<UINode> {
protected:
GUI& gui;
private:
/// @brief element identifier used for direct access in UiDocument /// @brief element identifier used for direct access in UiDocument
std::string id = ""; std::string id = "";
/// @brief element enabled state /// @brief element enabled state
@ -118,7 +121,7 @@ namespace gui {
/// @brief cursor shape when mouse is over the element /// @brief cursor shape when mouse is over the element
CursorShape cursor = CursorShape::ARROW; CursorShape cursor = CursorShape::ARROW;
UINode(glm::vec2 size); UINode(GUI& gui, glm::vec2 size);
public: public:
virtual ~UINode(); virtual ~UINode();
@ -169,12 +172,12 @@ namespace gui {
virtual UINode* listenAction(const onaction &action); virtual UINode* listenAction(const onaction &action);
virtual UINode* listenDoubleClick(const onaction &action); virtual UINode* listenDoubleClick(const onaction &action);
virtual void onFocus(GUI*) {focused = true;} virtual void onFocus() {focused = true;}
virtual void doubleClick(GUI*, int x, int y); virtual void doubleClick(int x, int y);
virtual void click(GUI*, int x, int y); virtual void click(int x, int y);
virtual void clicked(GUI*, mousecode button) {} virtual void clicked(mousecode button) {}
virtual void mouseMove(GUI*, int x, int y) {}; virtual void mouseMove(int x, int y) {};
virtual void mouseRelease(GUI*, int x, int y); virtual void mouseRelease(int x, int y);
virtual void scrolled(int value); virtual void scrolled(int value);
bool isPressed() const; bool isPressed() const;

View File

@ -1,37 +1,36 @@
#include "gui_util.hpp" #include "gui_util.hpp"
#include "elements/Label.hpp"
#include "elements/Menu.hpp"
#include "elements/Button.hpp"
#include "elements/TextBox.hpp"
#include "gui_xml.hpp"
#include "logic/scripting/scripting.hpp"
#include "frontend/locale.hpp"
#include "util/stringutil.hpp"
#include "delegates.hpp"
#include "window/Events.hpp"
#include "engine/Engine.hpp"
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "delegates.hpp"
#include "elements/Button.hpp"
#include "elements/Label.hpp"
#include "elements/Menu.hpp"
#include "elements/TextBox.hpp"
#include "engine/Engine.hpp"
#include "frontend/locale.hpp"
#include "gui_xml.hpp"
#include "logic/scripting/scripting.hpp"
#include "util/stringutil.hpp"
using namespace gui; using namespace gui;
std::shared_ptr<gui::UINode> guiutil::create(const std::string& source, scriptenv env) { std::shared_ptr<gui::UINode> guiutil::create(
GUI& gui, const std::string& source, scriptenv env
) {
if (env == nullptr) { if (env == nullptr) {
env = scripting::get_root_environment(); env = scripting::get_root_environment();
} }
UiXmlReader reader(env); UiXmlReader reader(gui, env);
return reader.readXML("[string]", source); return reader.readXML("[string]", source);
} }
void guiutil::alert( void guiutil::alert(
Engine& engine, Engine& engine, const std::wstring& text, const runnable& on_hidden
const std::wstring& text,
const runnable& on_hidden
) { ) {
GUI& gui = engine.getGUI();
auto panel = std::make_shared<Panel>( auto panel = std::make_shared<Panel>(
gui,
glm::vec2( glm::vec2(
glm::min( glm::min(
static_cast<size_t>(650), static_cast<size_t>(650),
@ -44,7 +43,7 @@ void guiutil::alert(
); );
panel->setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.5f)); panel->setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.5f));
auto menuPtr = engine.getGUI()->getMenu(); auto menuPtr = gui.getMenu();
auto& menu = *menuPtr; auto& menu = *menuPtr;
runnable on_hidden_final = [on_hidden, &menu]() { runnable on_hidden_final = [on_hidden, &menu]() {
menu.removePage("<alert>"); menu.removePage("<alert>");
@ -55,24 +54,25 @@ void guiutil::alert(
} }
}; };
auto label = std::make_shared<Label>(text); auto label = std::make_shared<Label>(gui, text);
label->setMultiline(true); label->setMultiline(true);
label->setSize(glm::vec2(1, 24)); label->setSize(glm::vec2(1, 24));
label->setAutoResize(true); label->setAutoResize(true);
panel->add(label); panel->add(label);
panel->add(std::make_shared<Button>( panel->add(std::make_shared<Button>(
langs::get(L"Ok"), glm::vec4(10.f), gui,
[on_hidden_final](GUI*) { langs::get(L"Ok"),
on_hidden_final(); glm::vec4(10.f),
} [on_hidden_final](GUI&) { on_hidden_final(); }
)); ));
panel->refresh(); panel->refresh();
panel->keepAlive(Events::addKeyCallback(keycode::ENTER, [on_hidden_final](){ auto& input = engine.getInput();
panel->keepAlive(input.addKeyCallback(keycode::ENTER, [on_hidden_final]() {
on_hidden_final(); on_hidden_final();
return true; return true;
})); }));
panel->keepAlive(Events::addKeyCallback(keycode::ESCAPE, [on_hidden_final](){ panel->keepAlive(input.addKeyCallback(keycode::ESCAPE, [on_hidden_final]() {
on_hidden_final(); on_hidden_final();
return true; return true;
})); }));
@ -91,17 +91,25 @@ void guiutil::confirm(
if (yestext.empty()) yestext = langs::get(L"Yes"); if (yestext.empty()) yestext = langs::get(L"Yes");
if (notext.empty()) notext = langs::get(L"No"); if (notext.empty()) notext = langs::get(L"No");
auto container = std::make_shared<Container>(glm::vec2(5000, 5000)); auto& gui = engine.getGUI();
auto& input = engine.getInput();
auto container = std::make_shared<Container>(gui, glm::vec2(5000, 5000));
container->setColor(glm::vec4(0.05f, 0.05f, 0.05f, 0.7f)); container->setColor(glm::vec4(0.05f, 0.05f, 0.05f, 0.7f));
auto panel = std::make_shared<Panel>(glm::vec2(600, 200), glm::vec4(8.0f), 8.0f);
auto panel = std::make_shared<Panel>(
gui, glm::vec2(600, 200), glm::vec4(8.0f), 8.0f
);
panel->setGravity(Gravity::center_center); panel->setGravity(Gravity::center_center);
container->add(panel); container->add(panel);
panel->setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.5f)); panel->setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.5f));
panel->add(std::make_shared<Label>(text)); panel->add(std::make_shared<Label>(gui, text));
auto subpanel = std::make_shared<Panel>(glm::vec2(600, 53)); auto subpanel = std::make_shared<Panel>(gui, glm::vec2(600, 53));
subpanel->setColor(glm::vec4(0)); subpanel->setColor(glm::vec4(0));
auto menu = engine.getGUI()->getMenu(); auto menu = gui.getMenu();
runnable on_confirm_final = [on_confirm, menu]() { runnable on_confirm_final = [on_confirm, menu]() {
menu->removePage("<confirm>"); menu->removePage("<confirm>");
@ -121,20 +129,20 @@ void guiutil::confirm(
} }
}; };
subpanel->add(std::make_shared<Button>(yestext, glm::vec4(8.f), [=](GUI*){ subpanel->add(std::make_shared<Button>(gui, yestext, glm::vec4(8.f), [=](GUI&) {
on_confirm_final(); on_confirm_final();
})); }));
subpanel->add(std::make_shared<Button>(notext, glm::vec4(8.f), [=](GUI*){ subpanel->add(std::make_shared<Button>(gui, notext, glm::vec4(8.f), [=](GUI&) {
on_deny_final(); on_deny_final();
})); }));
panel->add(subpanel); panel->add(subpanel);
panel->keepAlive(Events::addKeyCallback(keycode::ENTER, [=](){ panel->keepAlive(input.addKeyCallback(keycode::ENTER, [=]() {
on_confirm_final(); on_confirm_final();
return true; return true;
})); }));
panel->keepAlive(Events::addKeyCallback(keycode::ESCAPE, [=](){ panel->keepAlive(input.addKeyCallback(keycode::ESCAPE, [=]() {
on_deny_final(); on_deny_final();
return true; return true;
})); }));
@ -145,21 +153,25 @@ void guiutil::confirm(
} }
void guiutil::confirm_with_memo( void guiutil::confirm_with_memo(
const std::shared_ptr<gui::Menu>& menu, Engine& engine,
const std::wstring& text, const std::wstring& text,
const std::wstring& memo, const std::wstring& memo,
const runnable& on_confirm, const runnable& on_confirm,
std::wstring yestext, std::wstring yestext,
std::wstring notext) { std::wstring notext
) {
auto& gui = engine.getGUI();
auto menu = gui.getMenu();
if (yestext.empty()) yestext = langs::get(L"Yes"); if (yestext.empty()) yestext = langs::get(L"Yes");
if (notext.empty()) notext = langs::get(L"No"); if (notext.empty()) notext = langs::get(L"No");
auto panel = std::make_shared<Panel>(glm::vec2(600, 500), glm::vec4(8.0f), 8.0f); auto panel = std::make_shared<Panel>(
gui, glm::vec2(600, 500), glm::vec4(8.0f), 8.0f
);
panel->setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.5f)); panel->setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.5f));
panel->add(std::make_shared<Label>(text)); panel->add(std::make_shared<Label>(gui, text));
auto textbox = std::make_shared<TextBox>(L""); auto textbox = std::make_shared<TextBox>(gui, L"");
textbox->setMultiline(true); textbox->setMultiline(true);
textbox->setTextWrapping(true); textbox->setTextWrapping(true);
textbox->setSize(glm::vec2(600, 300)); textbox->setSize(glm::vec2(600, 300));
@ -167,16 +179,15 @@ void guiutil::confirm_with_memo(
textbox->setEditable(false); textbox->setEditable(false);
panel->add(textbox); panel->add(textbox);
auto subpanel = std::make_shared<Panel>(glm::vec2(600, 53)); auto subpanel = std::make_shared<Panel>(gui, glm::vec2(600, 53));
subpanel->setColor(glm::vec4(0)); subpanel->setColor(glm::vec4(0));
subpanel->add(std::make_shared<Button>(yestext, glm::vec4(8.f), [=](GUI*){ subpanel->add(std::make_shared<Button>(gui, yestext, glm::vec4(8.f), [=](GUI&) {
if (on_confirm) if (on_confirm) on_confirm();
on_confirm();
menu->back(); menu->back();
})); }));
subpanel->add(std::make_shared<Button>(notext, glm::vec4(8.f), [=](GUI*){ subpanel->add(std::make_shared<Button>(gui, notext, glm::vec4(8.f), [=](GUI&) {
menu->back(); menu->back();
})); }));

View File

@ -1,38 +1,42 @@
#pragma once #pragma once
#include "GUI.hpp"
#include "typedefs.hpp"
#include "delegates.hpp"
#include <memory> #include <memory>
#include <string> #include <string>
#include "GUI.hpp"
#include "delegates.hpp"
#include "typedefs.hpp"
class Engine; class Engine;
namespace guiutil { namespace guiutil {
/// @brief Create element from XML /// @brief Create element from XML
/// @param source XML /// @param source XML
std::shared_ptr<gui::UINode> create(const std::string& source, scriptenv env=0); std::shared_ptr<gui::UINode> create(
gui::GUI& gui, const std::string& source, scriptenv env = 0
);
void alert( void alert(
Engine& engine, Engine& engine,
const std::wstring& text, const std::wstring& text,
const runnable& on_hidden=nullptr const runnable& on_hidden = nullptr
); );
void confirm( void confirm(
Engine& engine, Engine& engine,
const std::wstring& text, const std::wstring& text,
const runnable& on_confirm=nullptr, const runnable& on_confirm = nullptr,
const runnable& on_deny=nullptr, const runnable& on_deny = nullptr,
std::wstring yestext=L"", std::wstring yestext = L"",
std::wstring notext=L""); std::wstring notext = L""
);
void confirm_with_memo( void confirm_with_memo(
const std::shared_ptr<gui::Menu>& menu, Engine& engine,
const std::wstring& text, const std::wstring& text,
const std::wstring& memo, const std::wstring& memo,
const runnable& on_confirm=nullptr, const runnable& on_confirm = nullptr,
std::wstring yestext=L"", std::wstring yestext = L"",
std::wstring notext=L""); std::wstring notext = L""
);
} }

View File

@ -1,30 +1,31 @@
#include "gui_xml.hpp" #include "gui_xml.hpp"
#include "elements/Panel.hpp" #include <stdexcept>
#include "elements/Image.hpp" #include <utility>
#include "elements/Menu.hpp"
#include "GUI.hpp"
#include "elements/Button.hpp" #include "elements/Button.hpp"
#include "elements/Canvas.hpp" #include "elements/Canvas.hpp"
#include "elements/CheckBox.hpp" #include "elements/CheckBox.hpp"
#include "elements/TextBox.hpp" #include "elements/TextBox.hpp"
#include "elements/SplitBox.hpp" #include "elements/SplitBox.hpp"
#include "elements/TrackBar.hpp" #include "elements/TrackBar.hpp"
#include "elements/Image.hpp"
#include "elements/InputBindBox.hpp" #include "elements/InputBindBox.hpp"
#include "elements/InventoryView.hpp" #include "elements/InventoryView.hpp"
#include "GUI.hpp" #include "elements/Menu.hpp"
#include "elements/Panel.hpp"
#include "elements/TextBox.hpp"
#include "elements/TrackBar.hpp"
#include "engine/Engine.hpp" #include "engine/Engine.hpp"
#include "frontend/menu.hpp"
#include "frontend/locale.hpp" #include "frontend/locale.hpp"
#include "frontend/menu.hpp"
#include "items/Inventory.hpp" #include "items/Inventory.hpp"
#include "logic/scripting/scripting.hpp" #include "logic/scripting/scripting.hpp"
#include "maths/voxmaths.hpp" #include "maths/voxmaths.hpp"
#include "util/stringutil.hpp" #include "util/stringutil.hpp"
#include "window/Events.hpp" #include "window/Events.hpp"
#include <stdexcept>
#include <utility>
using namespace gui; using namespace gui;
static Align align_from_string(const std::string& str, Align def) { static Align align_from_string(const std::string& str, Align def) {
@ -80,7 +81,7 @@ static onaction create_action(
if (callback == nullptr) { if (callback == nullptr) {
return nullptr; return nullptr;
} }
return [callback](GUI*) {callback();}; return [callback](GUI&) { callback(); };
} }
/// @brief Read basic UINode properties /// @brief Read basic UINode properties
@ -152,9 +153,7 @@ static void read_uinode(
node.setAlign(align_from_string(alignName, node.getAlign())); node.setAlign(align_from_string(alignName, node.getAlign()));
if (element.has("gravity")) { if (element.has("gravity")) {
node.setGravity(gravity_from_string( node.setGravity(gravity_from_string(element.attr("gravity").getText()));
element.attr("gravity").getText()
));
} }
if (element.has("tooltip")) { if (element.has("tooltip")) {
@ -184,7 +183,9 @@ static void read_uinode(
} }
} }
static void read_container_impl(UiXmlReader& reader, const xml::xmlelement& element, Container& container) { static void read_container_impl(
UiXmlReader& reader, const xml::xmlelement& element, Container& container
) {
read_uinode(reader, element, container); read_uinode(reader, element, container);
if (element.has("scrollable")) { if (element.has("scrollable")) {
@ -194,8 +195,7 @@ static void read_container_impl(UiXmlReader& reader, const xml::xmlelement& elem
container.setScrollStep(element.attr("scroll-step").asInt()); container.setScrollStep(element.attr("scroll-step").asInt());
} }
for (auto& sub : element.getElements()) { for (auto& sub : element.getElements()) {
if (sub->isText()) if (sub->isText()) continue;
continue;
auto subnode = reader.readUINode(*sub); auto subnode = reader.readUINode(*sub);
if (subnode) { if (subnode) {
container.add(subnode); container.add(subnode);
@ -203,7 +203,9 @@ static void read_container_impl(UiXmlReader& reader, const xml::xmlelement& elem
} }
} }
void UiXmlReader::readUINode(UiXmlReader& reader, const xml::xmlelement& element, Container& container) { void UiXmlReader::readUINode(
UiXmlReader& reader, const xml::xmlelement& element, Container& container
) {
read_container_impl(reader, element, container); read_container_impl(reader, element, container);
} }
@ -225,8 +227,7 @@ static void read_base_panel_impl(
panel.setPadding(padding); panel.setPadding(padding);
glm::vec2 size = panel.getSize(); glm::vec2 size = panel.getSize();
panel.setSize(glm::vec2( panel.setSize(glm::vec2(
size.x + padding.x + padding.z, size.x + padding.x + padding.z, size.y + padding.y + padding.w
size.y + padding.y + padding.w
)); ));
} }
if (element.has("orientation")) { if (element.has("orientation")) {
@ -254,10 +255,15 @@ static void read_panel_impl(
if (element.has("min-length")) { if (element.has("min-length")) {
panel.setMinLength(element.attr("min-length").asInt()); panel.setMinLength(element.attr("min-length").asInt());
} }
if (element.has("orientation")) {
auto& oname = element.attr("orientation").getText();
if (oname == "horizontal") {
panel.setOrientation(Orientation::horizontal);
}
}
if (subnodes) { if (subnodes) {
for (auto& sub : element.getElements()) { for (auto& sub : element.getElements()) {
if (sub->isText()) if (sub->isText()) continue;
continue;
auto subnode = reader.readUINode(*sub); auto subnode = reader.readUINode(*sub);
if (subnode) { if (subnode) {
panel.add(subnode); panel.add(subnode);
@ -289,12 +295,12 @@ static std::shared_ptr<UINode> readLabel(
const UiXmlReader& reader, const xml::xmlelement& element const UiXmlReader& reader, const xml::xmlelement& element
) { ) {
std::wstring text = parse_inner_text(element, reader.getContext()); std::wstring text = parse_inner_text(element, reader.getContext());
auto label = std::make_shared<Label>(text); auto label = std::make_shared<Label>(reader.getGUI(), text);
read_uinode(reader, element, *label); read_uinode(reader, element, *label);
if (element.has("valign")) { if (element.has("valign")) {
label->setVerticalAlign( label->setVerticalAlign(align_from_string(
align_from_string(element.attr("valign").getText(), label->getVerticalAlign()) element.attr("valign").getText(), label->getVerticalAlign()
); ));
} }
if (element.has("supplier")) { if (element.has("supplier")) {
label->textSupplier(scripting::create_wstring_supplier( label->textSupplier(scripting::create_wstring_supplier(
@ -324,7 +330,7 @@ static std::shared_ptr<UINode> readLabel(
static std::shared_ptr<UINode> read_container( static std::shared_ptr<UINode> read_container(
UiXmlReader& reader, const xml::xmlelement& element UiXmlReader& reader, const xml::xmlelement& element
) { ) {
auto container = std::make_shared<Container>(glm::vec2()); auto container = std::make_shared<Container>(reader.getGUI(), glm::vec2());
read_container_impl(reader, element, *container); read_container_impl(reader, element, *container);
return container; return container;
} }
@ -337,8 +343,9 @@ static std::shared_ptr<UINode> read_split_box(
element.attr("orientation", "vertical").getText() == "horizontal" element.attr("orientation", "vertical").getText() == "horizontal"
? Orientation::horizontal ? Orientation::horizontal
: Orientation::vertical; : Orientation::vertical;
auto splitBox = auto splitBox = std::make_shared<SplitBox>(
std::make_shared<SplitBox>(glm::vec2(), splitPos, orientation); reader.getGUI(), glm::vec2(), splitPos, orientation
);
read_base_panel_impl(reader, element, *splitBox); read_base_panel_impl(reader, element, *splitBox);
for (auto& sub : element.getElements()) { for (auto& sub : element.getElements()) {
if (sub->isText()) if (sub->isText())
@ -355,7 +362,9 @@ static std::shared_ptr<UINode> read_panel(
UiXmlReader& reader, const xml::xmlelement& element UiXmlReader& reader, const xml::xmlelement& element
) { ) {
float interval = element.attr("interval", "2").asFloat(); float interval = element.attr("interval", "2").asFloat();
auto panel = std::make_shared<Panel>(glm::vec2(), glm::vec4(), interval); auto panel = std::make_shared<Panel>(
reader.getGUI(), glm::vec2(), glm::vec4(), interval
);
read_panel_impl(reader, element, *panel); read_panel_impl(reader, element, *panel);
return panel; return panel;
} }
@ -363,6 +372,7 @@ static std::shared_ptr<UINode> read_panel(
static std::shared_ptr<UINode> read_button( static std::shared_ptr<UINode> read_button(
UiXmlReader& reader, const xml::xmlelement& element UiXmlReader& reader, const xml::xmlelement& element
) { ) {
auto& gui = reader.getGUI();
glm::vec4 padding = element.attr("padding", "10").asVec4(); glm::vec4 padding = element.attr("padding", "10").asVec4();
std::shared_ptr<Button> button; std::shared_ptr<Button> button;
@ -370,14 +380,14 @@ static std::shared_ptr<UINode> read_button(
if (!elements.empty() && elements[0]->getTag() != "#") { if (!elements.empty() && elements[0]->getTag() != "#") {
auto inner = reader.readUINode(*elements.at(0)); auto inner = reader.readUINode(*elements.at(0));
if (inner != nullptr) { if (inner != nullptr) {
button = std::make_shared<Button>(inner, padding); button = std::make_shared<Button>(gui, inner, padding);
} else { } else {
button = std::make_shared<Button>(L"", padding, nullptr); button = std::make_shared<Button>(gui, L"", padding, nullptr);
} }
read_panel_impl(reader, element, *button, false); read_panel_impl(reader, element, *button, false);
} else { } else {
std::wstring text = parse_inner_text(element, reader.getContext()); std::wstring text = parse_inner_text(element, reader.getContext());
button = std::make_shared<Button>(text, padding, nullptr); button = std::make_shared<Button>(gui, text, padding, nullptr);
read_panel_impl(reader, element, *button, true); read_panel_impl(reader, element, *button, true);
} }
if (element.has("text-align")) { if (element.has("text-align")) {
@ -393,7 +403,9 @@ static std::shared_ptr<UINode> read_check_box(
) { ) {
auto text = parse_inner_text(element, reader.getContext()); auto text = parse_inner_text(element, reader.getContext());
bool checked = element.attr("checked", "false").asBool(); bool checked = element.attr("checked", "false").asBool();
auto checkbox = std::make_shared<FullCheckBox>(text, glm::vec2(32), checked); auto checkbox = std::make_shared<FullCheckBox>(
reader.getGUI(), text, glm::vec2(32), checked
);
read_panel_impl(reader, element, *checkbox); read_panel_impl(reader, element, *checkbox);
if (element.has("consumer")) { if (element.has("consumer")) {
@ -417,10 +429,13 @@ static std::shared_ptr<UINode> read_check_box(
static std::shared_ptr<UINode> read_text_box( static std::shared_ptr<UINode> read_text_box(
UiXmlReader& reader, const xml::xmlelement& element UiXmlReader& reader, const xml::xmlelement& element
) { ) {
auto placeholder = util::str2wstr_utf8(element.attr("placeholder", "").getText()); auto placeholder =
util::str2wstr_utf8(element.attr("placeholder", "").getText());
auto hint = util::str2wstr_utf8(element.attr("hint", "").getText()); auto hint = util::str2wstr_utf8(element.attr("hint", "").getText());
auto text = parse_inner_text(element, reader.getContext()); auto text = parse_inner_text(element, reader.getContext());
auto textbox = std::make_shared<TextBox>(placeholder, glm::vec4(0.0f)); auto textbox = std::make_shared<TextBox>(
reader.getGUI(), placeholder, glm::vec4(0.0f)
);
textbox->setHint(hint); textbox->setHint(hint);
read_container_impl(reader, element, *textbox); read_container_impl(reader, element, *textbox);
@ -429,8 +444,7 @@ static std::shared_ptr<UINode> read_text_box(
textbox->setPadding(padding); textbox->setPadding(padding);
glm::vec2 size = textbox->getSize(); glm::vec2 size = textbox->getSize();
textbox->setSize(glm::vec2( textbox->setSize(glm::vec2(
size.x + padding.x + padding.z, size.x + padding.x + padding.z, size.y + padding.y + padding.w
size.y + padding.y + padding.w
)); ));
} }
textbox->setText(text); textbox->setText(text);
@ -513,7 +527,7 @@ static std::shared_ptr<UINode> read_image(
const UiXmlReader& reader, const xml::xmlelement& element const UiXmlReader& reader, const xml::xmlelement& element
) { ) {
std::string src = element.attr("src", "").getText(); std::string src = element.attr("src", "").getText();
auto image = std::make_shared<Image>(src); auto image = std::make_shared<Image>(reader.getGUI(), src);
read_uinode(reader, element, *image); read_uinode(reader, element, *image);
return image; return image;
} }
@ -521,11 +535,12 @@ static std::shared_ptr<UINode> read_image(
static std::shared_ptr<UINode> read_canvas( static std::shared_ptr<UINode> read_canvas(
const UiXmlReader& reader, const xml::xmlelement& element const UiXmlReader& reader, const xml::xmlelement& element
) { ) {
auto size = glm::uvec2{32, 32}; auto size = glm::uvec2 {32, 32};
if (element.has("size")) { if (element.has("size")) {
size = element.attr("size").asVec2(); size = element.attr("size").asVec2();
} }
auto image = std::make_shared<Canvas>(ImageFormat::rgba8888, size); auto image =
std::make_shared<Canvas>(reader.getGUI(), ImageFormat::rgba8888, size);
read_uinode(reader, element, *image); read_uinode(reader, element, *image);
return image; return image;
} }
@ -540,19 +555,24 @@ static std::shared_ptr<UINode> read_track_bar(
float def = element.attr("value", "0.0").asFloat(); float def = element.attr("value", "0.0").asFloat();
float step = element.attr("step", "1.0").asFloat(); float step = element.attr("step", "1.0").asFloat();
int trackWidth = element.attr("track-width", "12").asInt(); int trackWidth = element.attr("track-width", "12").asInt();
auto bar = std::make_shared<TrackBar>(minv, maxv, def, step, trackWidth); auto bar = std::make_shared<TrackBar>(
reader.getGUI(), minv, maxv, def, step, trackWidth
);
read_uinode(reader, element, *bar); read_uinode(reader, element, *bar);
if (element.has("consumer")) { if (element.has("consumer")) {
bar->setConsumer(scripting::create_number_consumer( bar->setConsumer(scripting::create_number_consumer(
env, element.attr("consumer").getText(), file)); env, element.attr("consumer").getText(), file
));
} }
if (element.has("sub-consumer")) { if (element.has("sub-consumer")) {
bar->setSubConsumer(scripting::create_number_consumer( bar->setSubConsumer(scripting::create_number_consumer(
env, element.attr("sub-consumer").getText(), file)); env, element.attr("sub-consumer").getText(), file
));
} }
if (element.has("supplier")) { if (element.has("supplier")) {
bar->setSupplier(scripting::create_number_supplier( bar->setSupplier(scripting::create_number_supplier(
env, element.attr("supplier").getText(), file)); env, element.attr("supplier").getText(), file
));
} }
if (element.has("track-color")) { if (element.has("track-color")) {
bar->setTrackColor(element.attr("track-color").asColor()); bar->setTrackColor(element.attr("track-color").asColor());
@ -567,14 +587,11 @@ static std::shared_ptr<UINode> read_input_bind_box(
UiXmlReader& reader, const xml::xmlelement& element UiXmlReader& reader, const xml::xmlelement& element
) { ) {
auto bindname = element.attr("binding").getText(); auto bindname = element.attr("binding").getText();
auto found = Events::bindings.find(bindname); auto& found = Events::requireBinding(bindname);
if (found == Events::bindings.end()) {
throw std::runtime_error("binding does not exists "+util::quote(bindname));
}
glm::vec4 padding = element.attr("padding", "6").asVec4(); glm::vec4 padding = element.attr("padding", "6").asVec4();
auto bindbox = std::make_shared<InputBindBox>(found->second, padding); auto bindbox =
std::make_shared<InputBindBox>(reader.getGUI(), found, padding);
read_panel_impl(reader, element, *bindbox); read_panel_impl(reader, element, *bindbox);
return bindbox; return bindbox;
} }
@ -585,11 +602,12 @@ static slotcallback read_slot_func(
const std::string& attr const std::string& attr
) { ) {
auto consumer = scripting::create_int_array_consumer( auto consumer = scripting::create_int_array_consumer(
reader.getEnvironment(), reader.getEnvironment(), element.attr(attr).getText()
element.attr(attr).getText()
); );
return [=](uint slot, ItemStack&) { return [=](uint slot, ItemStack&) {
int args[] {int(view->getInventory()->getId()), int(slot)}; int args[] {
static_cast<int>(view->getInventory()->getId()),
static_cast<int>(slot)};
consumer(args, 2); consumer(args, 2);
}; };
} }
@ -601,7 +619,9 @@ static void readSlot(
bool itemSource = element.attr("item-source", "false").asBool(); bool itemSource = element.attr("item-source", "false").asBool();
bool taking = element.attr("taking", "true").asBool(); bool taking = element.attr("taking", "true").asBool();
bool placing = element.attr("placing", "true").asBool(); bool placing = element.attr("placing", "true").asBool();
SlotLayout layout(index, glm::vec2(), true, itemSource, nullptr, nullptr, nullptr); SlotLayout layout(
index, glm::vec2(), true, itemSource, nullptr, nullptr, nullptr
);
if (element.has("pos")) { if (element.has("pos")) {
layout.position = element.attr("pos").asVec2(); layout.position = element.attr("pos").asVec2();
} }
@ -612,7 +632,8 @@ static void readSlot(
layout.shareFunc = read_slot_func(view, reader, element, "sharefunc"); layout.shareFunc = read_slot_func(view, reader, element, "sharefunc");
} }
if (element.has("onrightclick")) { if (element.has("onrightclick")) {
layout.rightClick = read_slot_func(view, reader, element, "onrightclick"); layout.rightClick =
read_slot_func(view, reader, element, "onrightclick");
} }
layout.taking = taking; layout.taking = taking;
layout.placing = placing; layout.placing = placing;
@ -622,7 +643,9 @@ static void readSlot(
} }
static void readSlotsGrid( static void readSlotsGrid(
InventoryView* view, const UiXmlReader& reader, const xml::xmlelement& element InventoryView* view,
const UiXmlReader& reader,
const xml::xmlelement& element
) { ) {
int startIndex = element.attr("start-index", "0").asInt(); int startIndex = element.attr("start-index", "0").asInt();
int rows = element.attr("rows", "0").asInt(); int rows = element.attr("rows", "0").asInt();
@ -647,7 +670,9 @@ static void readSlotsGrid(
count = rows * cols; count = rows * cols;
} }
bool itemSource = element.attr("item-source", "false").asBool(); bool itemSource = element.attr("item-source", "false").asBool();
SlotLayout layout(-1, glm::vec2(), true, itemSource, nullptr, nullptr, nullptr); SlotLayout layout(
-1, glm::vec2(), true, itemSource, nullptr, nullptr, nullptr
);
if (element.has("pos")) { if (element.has("pos")) {
layout.position = element.attr("pos").asVec2(); layout.position = element.attr("pos").asVec2();
} }
@ -658,7 +683,8 @@ static void readSlotsGrid(
layout.shareFunc = read_slot_func(view, reader, element, "sharefunc"); layout.shareFunc = read_slot_func(view, reader, element, "sharefunc");
} }
if (element.has("onrightclick")) { if (element.has("onrightclick")) {
layout.rightClick = read_slot_func(view, reader, element, "onrightclick"); layout.rightClick =
read_slot_func(view, reader, element, "onrightclick");
} }
layout.padding = padding; layout.padding = padding;
layout.taking = taking; layout.taking = taking;
@ -674,7 +700,7 @@ static void readSlotsGrid(
slotLayout.index = startIndex + idx; slotLayout.index = startIndex + idx;
slotLayout.position += glm::vec2( slotLayout.position += glm::vec2(
padding + col * (slotSize + interval), padding + col * (slotSize + interval),
padding + (rows-row-1) * (slotSize + interval) padding + (rows - row - 1) * (slotSize + interval)
); );
auto slot = view->addSlot(slotLayout); auto slot = view->addSlot(slotLayout);
view->add(slot, slotLayout.position); view->add(slot, slotLayout.position);
@ -685,8 +711,8 @@ static void readSlotsGrid(
static std::shared_ptr<UINode> read_inventory( static std::shared_ptr<UINode> read_inventory(
UiXmlReader& reader, const xml::xmlelement& element UiXmlReader& reader, const xml::xmlelement& element
) { ) {
auto view = std::make_shared<InventoryView>(); auto view = std::make_shared<InventoryView>(reader.getGUI());
view->setColor(glm::vec4(0.122f, 0.122f, 0.122f, 0.878f)); // todo: fixme view->setColor(glm::vec4(0.122f, 0.122f, 0.122f, 0.878f)); // TODO: fixme
reader.addIgnore("slot"); reader.addIgnore("slot");
reader.addIgnore("slots-grid"); reader.addIgnore("slots-grid");
reader.readUINode(reader, element, *view); reader.readUINode(reader, element, *view);
@ -704,16 +730,15 @@ static std::shared_ptr<UINode> read_inventory(
static std::shared_ptr<UINode> read_page_box( static std::shared_ptr<UINode> read_page_box(
UiXmlReader& reader, const xml::xmlelement& element UiXmlReader& reader, const xml::xmlelement& element
) { ) {
auto menu = std::make_shared<Menu>(); auto& gui = reader.getGUI();
menu->setPageLoader( auto menu = std::make_shared<Menu>(gui);
Engine::getInstance().getGUI()->getMenu()->getPageLoader() menu->setPageLoader(gui.getMenu()->getPageLoader());
);
read_container_impl(reader, element, *menu); read_container_impl(reader, element, *menu);
return menu; return menu;
} }
UiXmlReader::UiXmlReader(const scriptenv& env) : env(env) { UiXmlReader::UiXmlReader(gui::GUI& gui, const scriptenv& env) : gui(gui), env(env) {
contextStack.emplace(""); contextStack.emplace("");
add("image", read_image); add("image", read_image);
add("canvas", read_canvas); add("canvas", read_canvas);
@ -742,16 +767,15 @@ void UiXmlReader::addIgnore(const std::string& tag) {
ignored.insert(tag); ignored.insert(tag);
} }
std::shared_ptr<UINode> UiXmlReader::readUINode(const xml::xmlelement& element) { std::shared_ptr<UINode> UiXmlReader::readUINode(const xml::xmlelement& element
) {
if (element.has("if")) { if (element.has("if")) {
const auto& cond = element.attr("if").getText(); const auto& cond = element.attr("if").getText();
if (cond.empty() || cond == "false" || cond == "nil") if (cond.empty() || cond == "false" || cond == "nil") return nullptr;
return nullptr;
} }
if (element.has("ifnot")) { if (element.has("ifnot")) {
const auto& cond = element.attr("ifnot").getText(); const auto& cond = element.attr("ifnot").getText();
if (!(cond.empty() || cond == "false" || cond == "nil")) if (!(cond.empty() || cond == "false" || cond == "nil")) return nullptr;
return nullptr;
} }
const std::string& tag = element.getTag(); const std::string& tag = element.getTag();
@ -760,7 +784,7 @@ std::shared_ptr<UINode> UiXmlReader::readUINode(const xml::xmlelement& element)
if (ignored.find(tag) != ignored.end()) { if (ignored.find(tag) != ignored.end()) {
return nullptr; return nullptr;
} }
throw std::runtime_error("unsupported element '"+tag+"'"); throw std::runtime_error("unsupported element '" + tag + "'");
} }
bool hascontext = element.has("context"); bool hascontext = element.has("context");
@ -775,8 +799,7 @@ std::shared_ptr<UINode> UiXmlReader::readUINode(const xml::xmlelement& element)
} }
std::shared_ptr<UINode> UiXmlReader::readXML( std::shared_ptr<UINode> UiXmlReader::readXML(
const std::string& filename, const std::string& filename, const std::string& source
const std::string& source
) { ) {
this->filename = filename; this->filename = filename;
auto document = xml::parse(filename, source); auto document = xml::parse(filename, source);
@ -784,8 +807,7 @@ std::shared_ptr<UINode> UiXmlReader::readXML(
} }
std::shared_ptr<UINode> UiXmlReader::readXML( std::shared_ptr<UINode> UiXmlReader::readXML(
const std::string& filename, const std::string& filename, const xml::xmlelement& root
const xml::xmlelement& root
) { ) {
this->filename = filename; this->filename = filename;
return readUINode(root); return readUINode(root);
@ -802,3 +824,7 @@ const std::string& UiXmlReader::getFilename() const {
const scriptenv& UiXmlReader::getEnvironment() const { const scriptenv& UiXmlReader::getEnvironment() const {
return env; return env;
} }
gui::GUI& UiXmlReader::getGUI() const {
return gui;
}

View File

@ -15,13 +15,14 @@ namespace gui {
std::shared_ptr<UINode>(UiXmlReader&, const xml::xmlelement&)>; std::shared_ptr<UINode>(UiXmlReader&, const xml::xmlelement&)>;
class UiXmlReader { class UiXmlReader {
gui::GUI& gui;
std::unordered_map<std::string, uinode_reader> readers; std::unordered_map<std::string, uinode_reader> readers;
std::unordered_set<std::string> ignored; std::unordered_set<std::string> ignored;
std::stack<std::string> contextStack; std::stack<std::string> contextStack;
std::string filename; std::string filename;
const scriptenv& env; const scriptenv& env;
public: public:
UiXmlReader(const scriptenv& env); UiXmlReader(gui::GUI& gui, const scriptenv& env);
void add(const std::string& tag, uinode_reader reader); void add(const std::string& tag, uinode_reader reader);
bool hasReader(const std::string& tag) const; bool hasReader(const std::string& tag) const;
@ -54,5 +55,6 @@ namespace gui {
const std::string& getContext() const; const std::string& getContext() const;
const scriptenv& getEnvironment() const; const scriptenv& getEnvironment() const;
const std::string& getFilename() const; const std::string& getFilename() const;
gui::GUI& getGUI() const;
}; };
} }

View File

@ -38,7 +38,7 @@ void EngineController::deleteWorld(const std::string& name) {
logger.info() << "deleting " << folder.string(); logger.info() << "deleting " << folder.string();
io::remove_all(folder); io::remove_all(folder);
if (!engine.isHeadless()) { if (!engine.isHeadless()) {
engine.getGUI()->getMenu()->back(); engine.getGUI().getMenu()->back();
} }
}; };
@ -109,7 +109,7 @@ static void show_convert_request(
text += util::str2wstr_utf8(line) + L"\n"; text += util::str2wstr_utf8(line) + L"\n";
} }
guiutil::confirm_with_memo( guiutil::confirm_with_memo(
engine.getGUI()->getMenu(), engine,
langs::get(message), langs::get(message),
text, text,
on_confirm, on_confirm,

View File

@ -4,9 +4,10 @@
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include "BlocksController.hpp"
#include "content/Content.hpp" #include "content/Content.hpp"
#include "core_defs.hpp" #include "core_defs.hpp"
#include "settings.hpp" #include "engine/Engine.hpp"
#include "items/Inventory.hpp" #include "items/Inventory.hpp"
#include "items/ItemDef.hpp" #include "items/ItemDef.hpp"
#include "items/ItemStack.hpp" #include "items/ItemStack.hpp"
@ -16,17 +17,15 @@
#include "objects/Players.hpp" #include "objects/Players.hpp"
#include "physics/Hitbox.hpp" #include "physics/Hitbox.hpp"
#include "physics/PhysicsSolver.hpp" #include "physics/PhysicsSolver.hpp"
#include "scripting/scripting.hpp"
#include "settings.hpp" #include "settings.hpp"
#include "voxels/Block.hpp" #include "voxels/Block.hpp"
#include "voxels/Chunks.hpp" #include "voxels/Chunks.hpp"
#include "voxels/voxel.hpp" #include "voxels/voxel.hpp"
#include "window/Camera.hpp" #include "window/Camera.hpp"
#include "window/Events.hpp"
#include "window/Window.hpp" #include "window/Window.hpp"
#include "window/input.hpp" #include "window/input.hpp"
#include "world/Level.hpp" #include "world/Level.hpp"
#include "BlocksController.hpp"
#include "scripting/scripting.hpp"
const float INTERACTION_RELOAD = 0.160f; const float INTERACTION_RELOAD = 0.160f;
const float STEPS_SPEED = 2.2f; const float STEPS_SPEED = 2.2f;
@ -40,9 +39,7 @@ const float RUN_ZOOM = 1.1f;
const float C_ZOOM = 0.1f; const float C_ZOOM = 0.1f;
const float CROUCH_SHIFT_Y = -0.2f; const float CROUCH_SHIFT_Y = -0.2f;
CameraControl::CameraControl( CameraControl::CameraControl(Player& player, const CameraSettings& settings)
Player& player, const CameraSettings& settings
)
: player(player), : player(player),
camera(player.fpCamera), camera(player.fpCamera),
settings(settings), settings(settings),
@ -70,7 +67,9 @@ void CameraControl::updateMouse(PlayerInput& input) {
(input.zoom ? settings.sensitivity.get() / 4.f (input.zoom ? settings.sensitivity.get() / 4.f
: settings.sensitivity.get()); : settings.sensitivity.get());
auto d = glm::degrees(Events::delta / (float)Window::height * sensitivity); auto d = glm::degrees(
input.delta / static_cast<float>(Window::height) * sensitivity
);
rotation.x -= d.x; rotation.x -= d.x;
rotation.y -= d.y; rotation.y -= d.y;
@ -147,15 +146,16 @@ void CameraControl::updateFovEffects(
// more extensible but uglier // more extensible but uglier
void CameraControl::switchCamera() { void CameraControl::switchCamera() {
const std::vector<std::shared_ptr<Camera>> playerCameras { const std::vector<std::shared_ptr<Camera>> playerCameras {
camera, player.tpCamera, player.spCamera camera, player.tpCamera, player.spCamera};
};
auto index = std::distance( auto index = std::distance(
playerCameras.begin(), playerCameras.begin(),
std::find_if( std::find_if(
playerCameras.begin(), playerCameras.begin(),
playerCameras.end(), playerCameras.end(),
[this](auto& ptr) { return ptr.get() == player.currentCamera.get(); } [this](auto& ptr) {
return ptr.get() == player.currentCamera.get();
}
) )
); );
if (static_cast<size_t>(index) != playerCameras.size()) { if (static_cast<size_t>(index) != playerCameras.size()) {
@ -205,8 +205,8 @@ void CameraControl::update(
tpCamera->front = camera->front; tpCamera->front = camera->front;
tpCamera->right = camera->right; tpCamera->right = camera->right;
} }
if (player.currentCamera == spCamera || if (player.currentCamera == spCamera || player.currentCamera == tpCamera ||
player.currentCamera == tpCamera || player.currentCamera == camera) { player.currentCamera == camera) {
player.currentCamera->setFov(glm::radians(settings.fov.get())); player.currentCamera->setFov(glm::radians(settings.fov.get()));
} }
} }
@ -239,10 +239,7 @@ void PlayerController::onFootstep(const Hitbox& hitbox) {
continue; continue;
} }
blocksController.onBlockInteraction( blocksController.onBlockInteraction(
&player, &player, glm::ivec3(x, y, z), def, BlockInteraction::step
glm::ivec3(x, y, z),
def,
BlockInteraction::step
); );
return; return;
} }
@ -265,9 +262,9 @@ void PlayerController::updateFootsteps(float delta) {
} }
} }
void PlayerController::update(float delta, bool input) { void PlayerController::update(float delta, const Input* inputEvents) {
if (input) { if (inputEvents) {
updateKeyboard(); updateKeyboard(*inputEvents);
player.updateSelectedEntity(); player.updateSelectedEntity();
} else { } else {
resetKeyboard(); resetKeyboard();
@ -275,7 +272,7 @@ void PlayerController::update(float delta, bool input) {
updatePlayer(delta); updatePlayer(delta);
} }
void PlayerController::postUpdate(float delta, bool input, bool pause) { void PlayerController::postUpdate(float delta, const Input* input, bool pause) {
if (!pause) { if (!pause) {
updateFootsteps(delta); updateFootsteps(delta);
} }
@ -287,23 +284,25 @@ void PlayerController::postUpdate(float delta, bool input, bool pause) {
player.postUpdate(); player.postUpdate();
camControl.update(this->input, pause ? 0.0f : delta, *player.chunks); camControl.update(this->input, pause ? 0.0f : delta, *player.chunks);
if (input) { if (input) {
updateInteraction(delta); updateInteraction(*input, delta);
} else { } else {
player.selection = {}; player.selection = {};
} }
} }
void PlayerController::updateKeyboard() { void PlayerController::updateKeyboard(const Input& inputEvents) {
input.moveForward = Events::active(BIND_MOVE_FORWARD); const auto& bindings = inputEvents.getBindings();
input.moveBack = Events::active(BIND_MOVE_BACK); input.moveForward = bindings.active(BIND_MOVE_FORWARD);
input.moveLeft = Events::active(BIND_MOVE_LEFT); input.moveBack = bindings.active(BIND_MOVE_BACK);
input.moveRight = Events::active(BIND_MOVE_RIGHT); input.moveLeft = bindings.active(BIND_MOVE_LEFT);
input.sprint = Events::active(BIND_MOVE_SPRINT); input.moveRight = bindings.active(BIND_MOVE_RIGHT);
input.shift = Events::active(BIND_MOVE_CROUCH); input.sprint = bindings.active(BIND_MOVE_SPRINT);
input.cheat = Events::active(BIND_MOVE_CHEAT); input.shift = bindings.active(BIND_MOVE_CROUCH);
input.jump = Events::active(BIND_MOVE_JUMP); input.cheat = bindings.active(BIND_MOVE_CHEAT);
input.zoom = Events::active(BIND_CAM_ZOOM); input.jump = bindings.active(BIND_MOVE_JUMP);
input.cameraMode = Events::jactive(BIND_CAM_MODE); input.zoom = bindings.active(BIND_CAM_ZOOM);
input.cameraMode = bindings.jactive(BIND_CAM_MODE);
input.delta = inputEvents.getCursor().delta;
} }
void PlayerController::resetKeyboard() { void PlayerController::resetKeyboard() {
@ -316,6 +315,7 @@ void PlayerController::resetKeyboard() {
input.shift = false; input.shift = false;
input.cheat = false; input.cheat = false;
input.jump = false; input.jump = false;
input.delta = {};
} }
void PlayerController::updatePlayer(float delta) { void PlayerController::updatePlayer(float delta) {
@ -328,18 +328,12 @@ static int determine_rotation(
if (def && def->rotatable) { if (def && def->rotatable) {
const std::string& name = def->rotations.name; const std::string& name = def->rotations.name;
if (name == "pipe") { if (name == "pipe") {
if (norm.x < 0.0f) if (norm.x < 0.0f) return BLOCK_DIR_WEST;
return BLOCK_DIR_WEST; if (norm.x > 0.0f) return BLOCK_DIR_EAST;
if (norm.x > 0.0f) if (norm.y > 0.0f) return BLOCK_DIR_UP;
return BLOCK_DIR_EAST; if (norm.y < 0.0f) return BLOCK_DIR_DOWN;
if (norm.y > 0.0f) if (norm.z > 0.0f) return BLOCK_DIR_NORTH;
return BLOCK_DIR_UP; if (norm.z < 0.0f) return BLOCK_DIR_SOUTH;
if (norm.y < 0.0f)
return BLOCK_DIR_DOWN;
if (norm.z > 0.0f)
return BLOCK_DIR_NORTH;
if (norm.z < 0.0f)
return BLOCK_DIR_SOUTH;
} else if (name == "pane") { } else if (name == "pane") {
if (abs(camDir.x) > abs(camDir.z)) { if (abs(camDir.x) > abs(camDir.z)) {
if (camDir.x > 0.0f) return BLOCK_DIR_EAST; if (camDir.x > 0.0f) return BLOCK_DIR_EAST;
@ -417,7 +411,9 @@ voxel* PlayerController::updateSelection(float maxDistance) {
return vox; return vox;
} }
void PlayerController::processRightClick(const Block& def, const Block& target) { void PlayerController::processRightClick(
const Block& def, const Block& target
) {
const auto& selection = player.selection; const auto& selection = player.selection;
auto& chunks = *player.chunks; auto& chunks = *player.chunks;
auto camera = player.fpCamera.get(); auto camera = player.fpCamera.get();
@ -427,8 +423,8 @@ void PlayerController::processRightClick(const Block& def, const Block& target)
if (!input.shift && target.rt.funcsset.oninteract) { if (!input.shift && target.rt.funcsset.oninteract) {
if (scripting::on_block_interact( if (scripting::on_block_interact(
&player, target, selection.actualPosition &player, target, selection.actualPosition
)) { )) {
return; return;
} }
} }
@ -443,7 +439,8 @@ void PlayerController::processRightClick(const Block& def, const Block& target)
if (def.obstacle) { if (def.obstacle) {
const auto& hitboxes = def.rt.hitboxes[state.rotation]; const auto& hitboxes = def.rt.hitboxes[state.rotation];
for (const AABB& blockAABB : hitboxes) { for (const AABB& blockAABB : hitboxes) {
if (level.entities->hasBlockingInside(blockAABB.translated(coord))) { if (level.entities->hasBlockingInside(blockAABB.translated(coord)
)) {
return; return;
} }
} }
@ -466,7 +463,7 @@ void PlayerController::processRightClick(const Block& def, const Block& target)
if (chosenBlock != vox->id && chosenBlock) { if (chosenBlock != vox->id && chosenBlock) {
if (!player.isInfiniteItems()) { if (!player.isInfiniteItems()) {
auto& slot = player.getInventory()->getSlot(player.getChosenSlot()); auto& slot = player.getInventory()->getSlot(player.getChosenSlot());
slot.setCount(slot.getCount()-1); slot.setCount(slot.getCount() - 1);
} }
blocksController.placeBlock( blocksController.placeBlock(
&player, def, state, coord.x, coord.y, coord.z &player, def, state, coord.x, coord.y, coord.z
@ -490,21 +487,22 @@ void PlayerController::updateEntityInteraction(
} }
} }
void PlayerController::updateInteraction(float delta) { void PlayerController::updateInteraction(const Input& inputEvents, float delta) {
auto indices = level.content.getIndices(); auto indices = level.content.getIndices();
const auto& selection = player.selection; const auto& selection = player.selection;
if (interactionTimer > 0.0f) { if (interactionTimer > 0.0f) {
interactionTimer -= delta; interactionTimer -= delta;
} }
bool xkey = Events::active(BIND_PLAYER_FAST_INTERACTOIN); const auto& bindings = inputEvents.getBindings();
bool xkey = bindings.active(BIND_PLAYER_FAST_INTERACTOIN);
float maxDistance = xkey ? 200.0f : 10.0f; float maxDistance = xkey ? 200.0f : 10.0f;
bool longInteraction = interactionTimer <= 0 || xkey; bool longInteraction = interactionTimer <= 0 || xkey;
bool lclick = Events::jactive(BIND_PLAYER_DESTROY) || bool lclick = bindings.jactive(BIND_PLAYER_DESTROY) ||
(longInteraction && Events::active(BIND_PLAYER_DESTROY)); (longInteraction && bindings.active(BIND_PLAYER_DESTROY));
bool lattack = Events::jactive(BIND_PLAYER_ATTACK); bool lattack = bindings.jactive(BIND_PLAYER_ATTACK);
bool rclick = Events::jactive(BIND_PLAYER_BUILD) || bool rclick = bindings.jactive(BIND_PLAYER_BUILD) ||
(longInteraction && Events::active(BIND_PLAYER_BUILD)); (longInteraction && bindings.active(BIND_PLAYER_BUILD));
if (lclick || rclick) { if (lclick || rclick) {
interactionTimer = INTERACTION_RELOAD; interactionTimer = INTERACTION_RELOAD;
} }
@ -527,8 +525,8 @@ void PlayerController::updateInteraction(float delta) {
auto iend = selection.position; auto iend = selection.position;
if (lclick && !input.shift && item.rt.funcsset.on_block_break_by) { if (lclick && !input.shift && item.rt.funcsset.on_block_break_by) {
if (scripting::on_item_break_block( if (scripting::on_item_break_block(
&player, item, iend.x, iend.y, iend.z &player, item, iend.x, iend.y, iend.z
)) { )) {
return; return;
} }
} }

View File

@ -7,6 +7,7 @@
#include "objects/Player.hpp" #include "objects/Player.hpp"
#include "util/Clock.hpp" #include "util/Clock.hpp"
class Input;
class Engine; class Engine;
class Camera; class Camera;
class Level; class Level;
@ -54,11 +55,11 @@ class PlayerController {
BlocksController& blocksController; BlocksController& blocksController;
float interactionTimer = 0.0f; float interactionTimer = 0.0f;
void updateKeyboard(); void updateKeyboard(const Input& inputEvents);
void resetKeyboard(); void resetKeyboard();
void updatePlayer(float delta); void updatePlayer(float delta);
void updateEntityInteraction(entityid_t eid, bool lclick, bool rclick); void updateEntityInteraction(entityid_t eid, bool lclick, bool rclick);
void updateInteraction(float delta); void updateInteraction(const Input& inputEvents, float delta);
float stepsTimer = 0.0f; float stepsTimer = 0.0f;
void onFootstep(const Hitbox& hitbox); void onFootstep(const Hitbox& hitbox);
@ -76,13 +77,13 @@ public:
/// @brief Called after blocks update if not paused /// @brief Called after blocks update if not paused
/// @param delta delta time /// @param delta delta time
/// @param input process user input /// @param inputEvents nullable window inputs
void update(float delta, bool input); void update(float delta, const Input* inputEvents);
/// @brief Called after whole level update /// @brief Called after whole level update
/// @param delta delta time /// @param delta delta time
/// @param input process user input /// @param inputEvents nullable window inputs
/// @param pause is game paused /// @param pause is game paused
void postUpdate(float delta, bool input, bool pause); void postUpdate(float delta, const Input* inputEvents, bool pause);
Player* getPlayer(); Player* getPlayer();
}; };

View File

@ -14,7 +14,7 @@ static int l_add_command(lua::State* L) {
lua::pushvalue(L, 3); lua::pushvalue(L, 3);
auto func = lua::create_lambda(L); auto func = lua::create_lambda(L);
try { try {
engine->getCommandsInterpreter()->getRepository()->add( engine->getCmd().getRepository()->add(
scheme, scheme,
description, description,
[func](auto, auto args, auto kwargs) { [func](auto, auto args, auto kwargs) {
@ -32,7 +32,7 @@ static int l_add_command(lua::State* L) {
static int l_execute(lua::State* L) { static int l_execute(lua::State* L) {
auto prompt = lua::require_string(L, 1); auto prompt = lua::require_string(L, 1);
try { try {
auto result = engine->getCommandsInterpreter()->execute(prompt); auto result = engine->getCmd().execute(prompt);
lua::pushvalue(L, result); lua::pushvalue(L, result);
return 1; return 1;
} catch (const parsing_error& err) { } catch (const parsing_error& err) {
@ -45,19 +45,18 @@ static int l_execute(lua::State* L) {
static int l_get(lua::State* L) { static int l_get(lua::State* L) {
auto name = lua::require_string(L, 1); auto name = lua::require_string(L, 1);
return lua::pushvalue(L, (*engine->getCommandsInterpreter())[name]); return lua::pushvalue(L, engine->getCmd()[name]);
} }
static int l_set(lua::State* L) { static int l_set(lua::State* L) {
auto name = lua::require_string(L, 1); auto name = lua::require_string(L, 1);
auto value = lua::tovalue(L, 2); auto value = lua::tovalue(L, 2);
(*engine->getCommandsInterpreter())[name] = value; engine->getCmd()[name] = value;
return 0; return 0;
} }
static int l_get_commands_list(lua::State* L) { static int l_get_commands_list(lua::State* L) {
auto interpreter = engine->getCommandsInterpreter(); auto repo = engine->getCmd().getRepository();
auto repo = interpreter->getRepository();
const auto& commands = repo->getCommands(); const auto& commands = repo->getCommands();
lua::createtable(L, commands.size(), 0); lua::createtable(L, commands.size(), 0);
@ -71,8 +70,7 @@ static int l_get_commands_list(lua::State* L) {
static int l_get_command_info(lua::State* L) { static int l_get_command_info(lua::State* L) {
auto name = lua::require_string(L, 1); auto name = lua::require_string(L, 1);
auto interpreter = engine->getCommandsInterpreter(); auto repo = engine->getCmd().getRepository();
auto repo = interpreter->getRepository();
auto command = repo->get(name); auto command = repo->get(name);
if (command == nullptr) { if (command == nullptr) {
return 0; return 0;

View File

@ -17,7 +17,6 @@
#include "logic/LevelController.hpp" #include "logic/LevelController.hpp"
#include "util/listutil.hpp" #include "util/listutil.hpp"
#include "util/platform.hpp" #include "util/platform.hpp"
#include "window/Events.hpp"
#include "world/Level.hpp" #include "world/Level.hpp"
#include "world/generator/WorldGenerator.hpp" #include "world/generator/WorldGenerator.hpp"

View File

@ -80,8 +80,9 @@ static int l_container_add(lua::State* L) {
} }
auto xmlsrc = lua::require_string(L, 2); auto xmlsrc = lua::require_string(L, 2);
try { try {
auto subnode = auto subnode = guiutil::create(
guiutil::create(xmlsrc, docnode.document->getEnvironment()); engine->getGUI(), xmlsrc, docnode.document->getEnvironment()
);
node->add(subnode); node->add(subnode);
UINode::getIndices(subnode, docnode.document->getMapWriteable()); UINode::getIndices(subnode, docnode.document->getMapWriteable());
} catch (const std::exception& err) { } catch (const std::exception& err) {
@ -93,7 +94,7 @@ static int l_container_add(lua::State* L) {
static int l_node_destruct(lua::State* L) { static int l_node_destruct(lua::State* L) {
auto docnode = get_document_node(L); auto docnode = get_document_node(L);
auto node = docnode.node; auto node = docnode.node;
engine->getGUI()->postRunnable([node]() { engine->getGUI().postRunnable([node]() {
auto parent = node->getParent(); auto parent = node->getParent();
if (auto container = dynamic_cast<Container*>(parent)) { if (auto container = dynamic_cast<Container*>(parent)) {
container->remove(node.get()); container->remove(node.get());
@ -651,7 +652,7 @@ static void p_set_focused(
const std::shared_ptr<UINode>& node, lua::State* L, int idx const std::shared_ptr<UINode>& node, lua::State* L, int idx
) { ) {
if (lua::toboolean(L, idx) && !node->isFocused()) { if (lua::toboolean(L, idx) && !node->isFocused()) {
engine->getGUI()->setFocus(node); engine->getGUI().setFocus(node);
} else if (node->isFocused()) { } else if (node->isFocused()) {
node->defocus(); node->defocus();
} }
@ -782,7 +783,7 @@ static int l_gui_get_locales_info(lua::State* L) {
} }
static int l_gui_getviewport(lua::State* L) { static int l_gui_getviewport(lua::State* L) {
return lua::pushvec2(L, engine->getGUI()->getContainer()->getSize()); return lua::pushvec2(L, engine->getGUI().getContainer()->getSize());
} }
static int l_gui_clear_markup(lua::State* L) { static int l_gui_clear_markup(lua::State* L) {
@ -845,6 +846,7 @@ static int l_gui_load_document(lua::State* L) {
auto args = lua::tovalue(L, 3); auto args = lua::tovalue(L, 3);
auto documentPtr = UiDocument::read( auto documentPtr = UiDocument::read(
engine->getGUI(),
scripting::get_root_environment(), scripting::get_root_environment(),
alias, alias,
filename, filename,

View File

@ -1,15 +1,15 @@
#include <filesystem> #include <filesystem>
#include "engine/Engine.hpp" #include "engine/Engine.hpp"
#include "io/io.hpp"
#include "frontend/hud.hpp" #include "frontend/hud.hpp"
#include "frontend/screens/Screen.hpp" #include "frontend/screens/Screen.hpp"
#include "graphics/ui/GUI.hpp" #include "graphics/ui/GUI.hpp"
#include "graphics/ui/elements/Container.hpp" #include "graphics/ui/elements/Container.hpp"
#include "io/io.hpp"
#include "libgui.hpp"
#include "util/stringutil.hpp" #include "util/stringutil.hpp"
#include "window/Events.hpp" #include "window/Events.hpp"
#include "window/input.hpp" #include "window/input.hpp"
#include "libgui.hpp"
namespace scripting { namespace scripting {
extern Hud* hud; extern Hud* hud;
@ -38,25 +38,25 @@ static int l_add_callback(lua::State* L) {
auto actual_callback = lua::create_simple_handler(L); auto actual_callback = lua::create_simple_handler(L);
observer_handler handler; observer_handler handler;
auto& gui = engine->getGUI();
auto& input = engine->getInput();
if (pos != std::string::npos) { if (pos != std::string::npos) {
std::string prefix = bindname.substr(0, pos); std::string prefix = bindname.substr(0, pos);
if (prefix == "key") { if (prefix == "key") {
auto key = input_util::keycode_from(bindname.substr(pos + 1)); auto key = input_util::keycode_from(bindname.substr(pos + 1));
handler = Events::addKeyCallback(key, actual_callback); handler = input.addKeyCallback(key, actual_callback);
} }
} }
auto callback = [=]() -> bool { auto callback = [&gui, actual_callback]() -> bool {
if (!scripting::engine->getGUI()->isFocusCaught()) { if (!gui.isFocusCaught()) {
return actual_callback(); return actual_callback();
} }
return false; return false;
}; };
if (handler == nullptr) { if (handler == nullptr) {
const auto& bind = Events::bindings.find(bindname); auto& bind = input.requireBinding(bindname);
if (bind == Events::bindings.end()) { handler = bind.onactived.add(callback);
throw std::runtime_error("unknown binding " + util::quote(bindname));
}
handler = bind->second.onactived.add(callback);
} }
if (hud) { if (hud) {
@ -64,7 +64,8 @@ static int l_add_callback(lua::State* L) {
return 0; return 0;
} else if (lua::gettop(L) >= 3) { } else if (lua::gettop(L) >= 3) {
auto node = get_document_node(L, 3); auto node = get_document_node(L, 3);
if (auto container = std::dynamic_pointer_cast<gui::Container>(node.node)) { if (auto container =
std::dynamic_pointer_cast<gui::Container>(node.node)) {
container->keepAlive(handler); container->keepAlive(handler);
return 0; return 0;
} }
@ -74,11 +75,11 @@ static int l_add_callback(lua::State* L) {
} }
static int l_get_mouse_pos(lua::State* L) { static int l_get_mouse_pos(lua::State* L) {
return lua::pushvec2(L, Events::cursor); return lua::pushvec2(L, engine->getInput().getCursor().pos);
} }
static int l_get_bindings(lua::State* L) { static int l_get_bindings(lua::State* L) {
auto& bindings = Events::bindings; const auto& bindings = engine->getInput().getBindings().getAll();
lua::createtable(L, bindings.size(), 0); lua::createtable(L, bindings.size(), 0);
int i = 0; int i = 0;
@ -92,25 +93,14 @@ static int l_get_bindings(lua::State* L) {
static int l_get_binding_text(lua::State* L) { static int l_get_binding_text(lua::State* L) {
auto bindname = lua::require_string(L, 1); auto bindname = lua::require_string(L, 1);
auto index = Events::bindings.find(bindname); const auto& bind = engine->getInput().requireBinding(bindname);
return lua::pushstring(L, bind.text());
if (index == Events::bindings.end()) {
throw std::runtime_error("unknown binding " + util::quote(bindname));
lua::pushstring(L, "");
} else {
lua::pushstring(L, index->second.text());
}
return 1;
} }
static int l_is_active(lua::State* L) { static int l_is_active(lua::State* L) {
auto bindname = lua::require_string(L, 1); auto bindname = lua::require_string(L, 1);
const auto& bind = Events::bindings.find(bindname); auto& bind = engine->getInput().requireBinding(bindname);
if (bind == Events::bindings.end()) { return lua::pushboolean(L, bind.active());
throw std::runtime_error("unknown binding " + util::quote(bindname));
}
return lua::pushboolean(L, bind->second.active());
} }
static int l_is_pressed(lua::State* L) { static int l_is_pressed(lua::State* L) {
@ -123,12 +113,11 @@ static int l_is_pressed(lua::State* L) {
auto name = code.substr(sep + 1); auto name = code.substr(sep + 1);
if (prefix == "key") { if (prefix == "key") {
return lua::pushboolean( return lua::pushboolean(
L, Events::pressed(static_cast<int>(input_util::keycode_from(name))) L, engine->getInput().pressed(input_util::keycode_from(name))
); );
} else if (prefix == "mouse") { } else if (prefix == "mouse") {
return lua::pushboolean( return lua::pushboolean(
L, L, engine->getInput().clicked(input_util::mousecode_from(name))
Events::clicked(static_cast<int>(input_util::mousecode_from(name)))
); );
} else { } else {
throw std::runtime_error("unknown input type " + util::quote(code)); throw std::runtime_error("unknown input type " + util::quote(code));
@ -140,9 +129,7 @@ static void reset_pack_bindings(const io::path& packFolder) {
auto bindsFile = configFolder / "bindings.toml"; auto bindsFile = configFolder / "bindings.toml";
if (io::is_regular_file(bindsFile)) { if (io::is_regular_file(bindsFile)) {
Events::loadBindings( Events::loadBindings(
bindsFile.string(), bindsFile.string(), io::read_string(bindsFile), BindType::REBIND
io::read_string(bindsFile),
BindType::REBIND
); );
} }
} }
@ -157,12 +144,8 @@ static int l_reset_bindings(lua::State*) {
static int l_set_enabled(lua::State* L) { static int l_set_enabled(lua::State* L) {
std::string bindname = lua::require_string(L, 1); std::string bindname = lua::require_string(L, 1);
bool enable = lua::toboolean(L, 2); bool enabled = lua::toboolean(L, 2);
const auto& bind = Events::bindings.find(bindname); engine->getInput().requireBinding(bindname).enabled = enabled;
if (bind == Events::bindings.end()) {
throw std::runtime_error("unknown binding " + util::quote(bindname));
}
Events::bindings[bindname].enable = enable;
return 0; return 0;
} }

View File

@ -6,13 +6,13 @@
using namespace scripting; using namespace scripting;
static int l_get(lua::State* L) { static int l_get(lua::State* L, network::Network& network) {
std::string url(lua::require_lstring(L, 1)); std::string url(lua::require_lstring(L, 1));
lua::pushvalue(L, 2); lua::pushvalue(L, 2);
auto onResponse = lua::create_lambda_nothrow(L); auto onResponse = lua::create_lambda_nothrow(L);
engine->getNetwork().get(url, [onResponse](std::vector<char> bytes) { network.get(url, [onResponse](std::vector<char> bytes) {
engine->postRunnable([=]() { engine->postRunnable([=]() {
onResponse({std::string(bytes.data(), bytes.size())}); onResponse({std::string(bytes.data(), bytes.size())});
}); });
@ -20,13 +20,13 @@ static int l_get(lua::State* L) {
return 0; return 0;
} }
static int l_get_binary(lua::State* L) { static int l_get_binary(lua::State* L, network::Network& network) {
std::string url(lua::require_lstring(L, 1)); std::string url(lua::require_lstring(L, 1));
lua::pushvalue(L, 2); lua::pushvalue(L, 2);
auto onResponse = lua::create_lambda_nothrow(L); auto onResponse = lua::create_lambda_nothrow(L);
engine->getNetwork().get(url, [onResponse](std::vector<char> bytes) { network.get(url, [onResponse](std::vector<char> bytes) {
auto buffer = std::make_shared<util::Buffer<ubyte>>( auto buffer = std::make_shared<util::Buffer<ubyte>>(
reinterpret_cast<const ubyte*>(bytes.data()), bytes.size() reinterpret_cast<const ubyte*>(bytes.data()), bytes.size()
); );
@ -37,7 +37,7 @@ static int l_get_binary(lua::State* L) {
return 0; return 0;
} }
static int l_post(lua::State* L) { static int l_post(lua::State* L, network::Network& network) {
std::string url(lua::require_lstring(L, 1)); std::string url(lua::require_lstring(L, 1));
auto data = lua::tovalue(L, 2); auto data = lua::tovalue(L, 2);
@ -61,12 +61,12 @@ static int l_post(lua::State* L) {
return 0; return 0;
} }
static int l_connect(lua::State* L) { static int l_connect(lua::State* L, network::Network& network) {
std::string address = lua::require_string(L, 1); std::string address = lua::require_string(L, 1);
int port = lua::tointeger(L, 2); int port = lua::tointeger(L, 2);
lua::pushvalue(L, 3); lua::pushvalue(L, 3);
auto callback = lua::create_lambda_nothrow(L); auto callback = lua::create_lambda_nothrow(L);
u64id_t id = engine->getNetwork().connect(address, port, [callback](u64id_t id) { u64id_t id = network.connect(address, port, [callback](u64id_t id) {
engine->postRunnable([=]() { engine->postRunnable([=]() {
callback({id}); callback({id});
}); });
@ -75,25 +75,25 @@ static int l_connect(lua::State* L) {
} }
static int l_close(lua::State* L) { static int l_close(lua::State* L, network::Network& network) {
u64id_t id = lua::tointeger(L, 1); u64id_t id = lua::tointeger(L, 1);
if (auto connection = engine->getNetwork().getConnection(id)) { if (auto connection = network.getConnection(id)) {
connection->close(true); connection->close(true);
} }
return 0; return 0;
} }
static int l_closeserver(lua::State* L) { static int l_closeserver(lua::State* L, network::Network& network) {
u64id_t id = lua::tointeger(L, 1); u64id_t id = lua::tointeger(L, 1);
if (auto server = engine->getNetwork().getServer(id)) { if (auto server = network.getServer(id)) {
server->close(); server->close();
} }
return 0; return 0;
} }
static int l_send(lua::State* L) { static int l_send(lua::State* L, network::Network& network) {
u64id_t id = lua::tointeger(L, 1); u64id_t id = lua::tointeger(L, 1);
auto connection = engine->getNetwork().getConnection(id); auto connection = network.getConnection(id);
if (connection == nullptr || if (connection == nullptr ||
connection->getState() == network::ConnectionState::CLOSED) { connection->getState() == network::ConnectionState::CLOSED) {
return 0; return 0;
@ -120,7 +120,7 @@ static int l_send(lua::State* L) {
return 0; return 0;
} }
static int l_recv(lua::State* L) { static int l_recv(lua::State* L, network::Network& network) {
u64id_t id = lua::tointeger(L, 1); u64id_t id = lua::tointeger(L, 1);
int length = lua::tointeger(L, 2); int length = lua::tointeger(L, 2);
auto connection = engine->getNetwork().getConnection(id); auto connection = engine->getNetwork().getConnection(id);
@ -149,19 +149,19 @@ static int l_recv(lua::State* L) {
return 1; return 1;
} }
static int l_available(lua::State* L) { static int l_available(lua::State* L, network::Network& network) {
u64id_t id = lua::tointeger(L, 1); u64id_t id = lua::tointeger(L, 1);
if (auto connection = engine->getNetwork().getConnection(id)) { if (auto connection = network.getConnection(id)) {
return lua::pushinteger(L, connection->available()); return lua::pushinteger(L, connection->available());
} }
return 0; return 0;
} }
static int l_open(lua::State* L) { static int l_open(lua::State* L, network::Network& network) {
int port = lua::tointeger(L, 1); int port = lua::tointeger(L, 1);
lua::pushvalue(L, 2); lua::pushvalue(L, 2);
auto callback = lua::create_lambda_nothrow(L); auto callback = lua::create_lambda_nothrow(L);
u64id_t id = engine->getNetwork().openServer(port, [callback](u64id_t id) { u64id_t id = network.openServer(port, [callback](u64id_t id) {
engine->postRunnable([=]() { engine->postRunnable([=]() {
callback({id}); callback({id});
}); });
@ -169,9 +169,9 @@ static int l_open(lua::State* L) {
return lua::pushinteger(L, id); return lua::pushinteger(L, id);
} }
static int l_is_alive(lua::State* L) { static int l_is_alive(lua::State* L, network::Network& network) {
u64id_t id = lua::tointeger(L, 1); u64id_t id = lua::tointeger(L, 1);
if (auto connection = engine->getNetwork().getConnection(id)) { if (auto connection = network.getConnection(id)) {
return lua::pushboolean( return lua::pushboolean(
L, L,
connection->getState() != network::ConnectionState::CLOSED || connection->getState() != network::ConnectionState::CLOSED ||
@ -181,9 +181,9 @@ static int l_is_alive(lua::State* L) {
return lua::pushboolean(L, false); return lua::pushboolean(L, false);
} }
static int l_is_connected(lua::State* L) { static int l_is_connected(lua::State* L, network::Network& network) {
u64id_t id = lua::tointeger(L, 1); u64id_t id = lua::tointeger(L, 1);
if (auto connection = engine->getNetwork().getConnection(id)) { if (auto connection = network.getConnection(id)) {
return lua::pushboolean( return lua::pushboolean(
L, connection->getState() == network::ConnectionState::CONNECTED L, connection->getState() == network::ConnectionState::CONNECTED
); );
@ -191,9 +191,9 @@ static int l_is_connected(lua::State* L) {
return lua::pushboolean(L, false); return lua::pushboolean(L, false);
} }
static int l_get_address(lua::State* L) { static int l_get_address(lua::State* L, network::Network& network) {
u64id_t id = lua::tointeger(L, 1); u64id_t id = lua::tointeger(L, 1);
if (auto connection = engine->getNetwork().getConnection(id)) { if (auto connection = network.getConnection(id)) {
lua::pushstring(L, connection->getAddress()); lua::pushstring(L, connection->getAddress());
lua::pushinteger(L, connection->getPort()); lua::pushinteger(L, connection->getPort());
return 2; return 2;
@ -201,47 +201,65 @@ static int l_get_address(lua::State* L) {
return 0; return 0;
} }
static int l_is_serveropen(lua::State* L) { static int l_is_serveropen(lua::State* L, network::Network& network) {
u64id_t id = lua::tointeger(L, 1); u64id_t id = lua::tointeger(L, 1);
if (auto server = engine->getNetwork().getServer(id)) { if (auto server = network.getServer(id)) {
return lua::pushboolean(L, server->isOpen()); return lua::pushboolean(L, server->isOpen());
} }
return lua::pushboolean(L, false); return lua::pushboolean(L, false);
} }
static int l_get_serverport(lua::State* L) { static int l_get_serverport(lua::State* L, network::Network& network) {
u64id_t id = lua::tointeger(L, 1); u64id_t id = lua::tointeger(L, 1);
if (auto server = engine->getNetwork().getServer(id)) { if (auto server = network.getServer(id)) {
return lua::pushinteger(L, server->getPort()); return lua::pushinteger(L, server->getPort());
} }
return 0; return 0;
} }
static int l_get_total_upload(lua::State* L) { static int l_get_total_upload(lua::State* L, network::Network& network) {
return lua::pushinteger(L, engine->getNetwork().getTotalUpload()); return lua::pushinteger(L, network.getTotalUpload());
} }
static int l_get_total_download(lua::State* L) { static int l_get_total_download(lua::State* L, network::Network& network) {
return lua::pushinteger(L, engine->getNetwork().getTotalDownload()); return lua::pushinteger(L, network.getTotalDownload());
} }
template <int(*func)(lua::State*, network::Network&)>
int wrap(lua_State* L) {
int result = 0;
try {
result = func(L, engine->getNetwork());
}
// transform exception with description into lua_error
catch (std::exception& e) {
luaL_error(L, e.what());
}
// Rethrow any other exception (lua error for example)
catch (...) {
throw;
}
return result;
}
const luaL_Reg networklib[] = { const luaL_Reg networklib[] = {
{"get", lua::wrap<l_get>}, {"get", wrap<l_get>},
{"get_binary", lua::wrap<l_get_binary>}, {"get_binary", wrap<l_get_binary>},
{"post", lua::wrap<l_post>}, {"post", wrap<l_post>},
{"get_total_upload", lua::wrap<l_get_total_upload>}, {"get_total_upload", wrap<l_get_total_upload>},
{"get_total_download", lua::wrap<l_get_total_download>}, {"get_total_download", wrap<l_get_total_download>},
{"__open", lua::wrap<l_open>}, {"__open", wrap<l_open>},
{"__closeserver", lua::wrap<l_closeserver>}, {"__closeserver", wrap<l_closeserver>},
{"__connect", lua::wrap<l_connect>}, {"__connect", wrap<l_connect>},
{"__close", lua::wrap<l_close>}, {"__close", wrap<l_close>},
{"__send", lua::wrap<l_send>}, {"__send", wrap<l_send>},
{"__recv", lua::wrap<l_recv>}, {"__recv", wrap<l_recv>},
{"__available", lua::wrap<l_available>}, {"__available", wrap<l_available>},
{"__is_alive", lua::wrap<l_is_alive>}, {"__is_alive", wrap<l_is_alive>},
{"__is_connected", lua::wrap<l_is_connected>}, {"__is_connected", wrap<l_is_connected>},
{"__get_address", lua::wrap<l_get_address>}, {"__get_address", wrap<l_get_address>},
{"__is_serveropen", lua::wrap<l_is_serveropen>}, {"__is_serveropen", wrap<l_is_serveropen>},
{"__get_serverport", lua::wrap<l_get_serverport>}, {"__get_serverport", wrap<l_get_serverport>},
{NULL, NULL} {NULL, NULL}
}; };

View File

@ -259,7 +259,7 @@ static int l_pack_request_writeable(lua::State* L) {
util::replaceAll(str, L"%{0}", util::str2wstr_utf8(packid)); util::replaceAll(str, L"%{0}", util::str2wstr_utf8(packid));
guiutil::confirm(*engine, str, [packid, handler]() { guiutil::confirm(*engine, str, [packid, handler]() {
handler({engine->getPaths().createWriteablePackDevice(packid)}); handler({engine->getPaths().createWriteablePackDevice(packid)});
engine->getGUI()->getMenu()->reset(); engine->getGUI().getMenu()->reset();
}); });
return 0; return 0;
} }

View File

@ -268,21 +268,21 @@ void scripting::on_world_load(LevelController* controller) {
lua::call_nothrow(L, 0, 0); lua::call_nothrow(L, 0, 0);
} }
for (auto& pack : scripting::engine->getAllContentPacks()) { for (auto& pack : Engine::getInstance().getAllContentPacks()) {
lua::emit_event(L, pack.id + ":.worldopen"); lua::emit_event(L, pack.id + ":.worldopen");
} }
} }
void scripting::on_world_tick() { void scripting::on_world_tick() {
auto L = lua::get_main_state(); auto L = lua::get_main_state();
for (auto& pack : scripting::engine->getAllContentPacks()) { for (auto& pack : Engine::getInstance().getAllContentPacks()) {
lua::emit_event(L, pack.id + ":.worldtick"); lua::emit_event(L, pack.id + ":.worldtick");
} }
} }
void scripting::on_world_save() { void scripting::on_world_save() {
auto L = lua::get_main_state(); auto L = lua::get_main_state();
for (auto& pack : scripting::engine->getAllContentPacks()) { for (auto& pack : Engine::getInstance().getAllContentPacks()) {
lua::emit_event(L, pack.id + ":.worldsave"); lua::emit_event(L, pack.id + ":.worldsave");
} }
if (lua::getglobal(L, "__vc_on_world_save")) { if (lua::getglobal(L, "__vc_on_world_save")) {
@ -292,7 +292,7 @@ void scripting::on_world_save() {
void scripting::on_world_quit() { void scripting::on_world_quit() {
auto L = lua::get_main_state(); auto L = lua::get_main_state();
for (auto& pack : scripting::engine->getAllContentPacks()) { for (auto& pack : Engine::getInstance().getAllContentPacks()) {
lua::emit_event(L, pack.id + ":.worldquit"); lua::emit_event(L, pack.id + ":.worldquit");
} }
if (lua::getglobal(L, "__vc_on_world_quit")) { if (lua::getglobal(L, "__vc_on_world_quit")) {
@ -308,7 +308,7 @@ void scripting::on_world_quit() {
void scripting::cleanup() { void scripting::cleanup() {
auto L = lua::get_main_state(); auto L = lua::get_main_state();
lua::requireglobal(L, "pack"); lua::requireglobal(L, "pack");
for (auto& pack : scripting::engine->getAllContentPacks()) { for (auto& pack : Engine::getInstance().getAllContentPacks()) {
lua::requirefield(L, "unload"); lua::requirefield(L, "unload");
lua::pushstring(L, pack.id); lua::pushstring(L, pack.id);
lua::call_nothrow(L, 1); lua::call_nothrow(L, 1);

View File

@ -44,7 +44,7 @@ void scripting::on_frontend_init(Hud* hud, WorldRenderer* renderer) {
lua::call_nothrow(L, 0, 0); lua::call_nothrow(L, 0, 0);
} }
for (auto& pack : engine->getAllContentPacks()) { for (auto& pack : Engine::getInstance().getAllContentPacks()) {
lua::emit_event( lua::emit_event(
lua::get_main_state(), lua::get_main_state(),
pack.id + ":.hudopen", pack.id + ":.hudopen",
@ -56,7 +56,7 @@ void scripting::on_frontend_init(Hud* hud, WorldRenderer* renderer) {
} }
void scripting::on_frontend_render() { void scripting::on_frontend_render() {
for (auto& pack : engine->getAllContentPacks()) { for (auto& pack : Engine::getInstance().getAllContentPacks()) {
lua::emit_event( lua::emit_event(
lua::get_main_state(), lua::get_main_state(),
pack.id + ":.hudrender", pack.id + ":.hudrender",
@ -67,7 +67,7 @@ void scripting::on_frontend_render() {
void scripting::on_frontend_close() { void scripting::on_frontend_close() {
auto L = lua::get_main_state(); auto L = lua::get_main_state();
for (auto& pack : engine->getAllContentPacks()) { for (auto& pack : Engine::getInstance().getAllContentPacks()) {
lua::emit_event( lua::emit_event(
L, L,
pack.id + ":.hudclose", pack.id + ":.hudclose",
@ -109,7 +109,7 @@ gui::PageLoaderFunc scripting::create_page_loader() {
auto func = lua::create_lambda(L); auto func = lua::create_lambda(L);
return [func](const std::string& name) -> std::shared_ptr<gui::UINode> { return [func](const std::string& name) -> std::shared_ptr<gui::UINode> {
auto docname = func({name}).asString(); auto docname = func({name}).asString();
return engine->getAssets()->require<UiDocument>(docname).getRoot(); return Engine::getInstance().getAssets()->require<UiDocument>(docname).getRoot();
}; };
} }
return nullptr; return nullptr;

View File

@ -260,7 +260,7 @@ std::unique_ptr<GeneratorScript> scripting::load_generator(
const io::path& file, const io::path& file,
const std::string& dirPath const std::string& dirPath
) { ) {
auto L = create_state(engine->getPaths(), StateType::GENERATOR); auto L = create_state(Engine::getInstance().getPaths(), StateType::GENERATOR);
return std::make_unique<LuaGeneratorScript>(L, def, file, dirPath); return std::make_unique<LuaGeneratorScript>(L, def, file, dirPath);
} }

View File

@ -18,16 +18,19 @@ struct Hitbox;
struct EngineSettings; struct EngineSettings;
struct PlayerInput { struct PlayerInput {
bool zoom : 1; struct {
bool cameraMode : 1; bool zoom : 1;
bool moveForward : 1; bool cameraMode : 1;
bool moveBack : 1; bool moveForward : 1;
bool moveRight : 1; bool moveBack : 1;
bool moveLeft : 1; bool moveRight : 1;
bool sprint : 1; bool moveLeft : 1;
bool shift : 1; bool sprint : 1;
bool cheat : 1; bool shift : 1;
bool jump : 1; bool cheat : 1;
bool jump : 1;
};
glm::vec2 delta;
}; };
struct CursorSelection { struct CursorSelection {

View File

@ -28,7 +28,6 @@ void Camera::rotate(float x, float y, float z) {
} }
glm::mat4 Camera::getProjection() const { glm::mat4 Camera::getProjection() const {
constexpr float epsilon = 1e-6f;
if (perspective) { if (perspective) {
return glm::perspective(fov * zoom, ar, near, far); return glm::perspective(fov * zoom, ar, near, far);
} else if (flipped) { } else if (flipped) {

View File

@ -28,7 +28,7 @@ glm::vec2 Events::cursor = {};
std::vector<uint> Events::codepoints; std::vector<uint> Events::codepoints;
std::vector<keycode> Events::pressedKeys; std::vector<keycode> Events::pressedKeys;
std::unordered_map<std::string, Binding> Events::bindings; Bindings Events::bindings {};
int Events::getScroll() { int Events::getScroll() {
return scroll; return scroll;
@ -86,9 +86,9 @@ void Events::pollEvents() {
pressedKeys.clear(); pressedKeys.clear();
glfwPollEvents(); glfwPollEvents();
for (auto& entry : bindings) { for (auto& entry : bindings.getAll()) {
auto& binding = entry.second; auto& binding = entry.second;
if (!binding.enable) { if (!binding.enabled) {
binding.state = false; binding.state = false;
continue; continue;
} }
@ -119,12 +119,15 @@ void Events::pollEvents() {
} }
} }
Binding& Events::getBinding(const std::string& name) { Binding* Events::getBinding(const std::string& name) {
const auto found = bindings.find(name); return bindings.get(name);
if (found == bindings.end()) { }
throw std::runtime_error("binding '" + name + "' does not exist");
Binding& Events::requireBinding(const std::string& name) {
if (const auto found = getBinding(name)) {
return *found;
} }
return found->second; throw std::runtime_error("binding '" + name + "' does not exist");
} }
void Events::bind(const std::string& name, inputtype type, keycode code) { void Events::bind(const std::string& name, inputtype type, keycode code) {
@ -136,31 +139,19 @@ void Events::bind(const std::string& name, inputtype type, mousecode code) {
} }
void Events::bind(const std::string& name, inputtype type, int code) { void Events::bind(const std::string& name, inputtype type, int code) {
bindings.try_emplace(name, Binding(type, code)); bindings.bind(name, type, code);
} }
void Events::rebind(const std::string& name, inputtype type, int code) { void Events::rebind(const std::string& name, inputtype type, int code) {
const auto& found = bindings.find(name); requireBinding(name) = Binding(type, code);
if (found == bindings.end()) {
throw std::runtime_error("binding '" + name + "' does not exist");
}
bindings[name] = Binding(type, code);
} }
bool Events::active(const std::string& name) { bool Events::active(const std::string& name) {
const auto& found = bindings.find(name); return bindings.active(name);
if (found == bindings.end()) {
return false;
}
return found->second.active();
} }
bool Events::jactive(const std::string& name) { bool Events::jactive(const std::string& name) {
const auto& found = bindings.find(name); return bindings.jactive(name);
if (found == bindings.end()) {
return false;
}
return found->second.jactive();
} }
void Events::setKey(int key, bool b) { void Events::setKey(int key, bool b) {
@ -198,7 +189,7 @@ observer_handler Events::addKeyCallback(keycode key, KeyCallback callback) {
std::string Events::writeBindings() { std::string Events::writeBindings() {
auto obj = dv::object(); auto obj = dv::object();
for (auto& entry : Events::bindings) { for (auto& entry : bindings.getAll()) {
const auto& binding = entry.second; const auto& binding = entry.second;
std::string value; std::string value;
switch (binding.type) { switch (binding.type) {
@ -253,9 +244,8 @@ void Events::loadBindings(
} }
void Events::enableBindings() { void Events::enableBindings() {
for (auto& entry : bindings) { for (auto& entry : bindings.getAll()) {
auto& binding = entry.second; entry.second.enabled = true;
binding.enable = true;
} }
} }

View File

@ -21,7 +21,7 @@ namespace Events {
extern glm::vec2 cursor; extern glm::vec2 cursor;
extern std::vector<uint> codepoints; extern std::vector<uint> codepoints;
extern std::vector<keycode> pressedKeys; extern std::vector<keycode> pressedKeys;
extern std::unordered_map<std::string, Binding> bindings; extern Bindings bindings;
void pollEvents(); void pollEvents();
@ -39,7 +39,8 @@ namespace Events {
void toggleCursor(); void toggleCursor();
Binding& getBinding(const std::string& name); Binding* getBinding(const std::string& name);
Binding& requireBinding(const std::string& name);
void bind(const std::string& name, inputtype type, keycode code); void bind(const std::string& name, inputtype type, keycode code);
void bind(const std::string& name, inputtype type, mousecode code); void bind(const std::string& name, inputtype type, mousecode code);
void bind(const std::string& name, inputtype type, int code); void bind(const std::string& name, inputtype type, int code);

View File

@ -175,7 +175,61 @@ static void glfw_error_callback(int error, const char* description) {
static GLFWcursor* standard_cursors[static_cast<int>(CursorShape::LAST) + 1] = {}; static GLFWcursor* standard_cursors[static_cast<int>(CursorShape::LAST) + 1] = {};
int Window::initialize(DisplaySettings* settings) { class GLFWInput : public Input {
public:
void pollEvents() override {
Events::pollEvents();
}
const char* getClipboardText() const override {
return glfwGetClipboardString(::window);
}
int getScroll() override {
return Events::getScroll();
}
Binding& requireBinding(const std::string& name) override {
return Events::requireBinding(name);
}
bool pressed(keycode keycode) const override {
return Events::pressed(keycode);
}
bool jpressed(keycode keycode) const override {
return Events::jpressed(keycode);
}
bool clicked(mousecode mousecode) const override {
return Events::clicked(mousecode);
}
bool jclicked(mousecode mousecode) const override {
return Events::jclicked(mousecode);
}
CursorState getCursor() const override {
return {
Events::isCursorLocked(),
Events::cursor,
Events::delta
};
}
Bindings& getBindings() override {
return Events::bindings;
}
const Bindings& getBindings() const override {
return Events::bindings;
}
observer_handler addKeyCallback(keycode key, KeyCallback callback) override {
return Events::addKeyCallback(key, std::move(callback));
}
};
static_assert(!std::is_abstract<GLFWInput>());
std::unique_ptr<Input> Window::initialize(DisplaySettings* settings) {
::settings = settings; ::settings = settings;
Window::width = settings->width.get(); Window::width = settings->width.get();
Window::height = settings->height.get(); Window::height = settings->height.get();
@ -190,7 +244,7 @@ int Window::initialize(DisplaySettings* settings) {
glfwSetErrorCallback(glfw_error_callback); glfwSetErrorCallback(glfw_error_callback);
if (glfwInit() == GLFW_FALSE) { if (glfwInit() == GLFW_FALSE) {
logger.error() << "failed to initialize GLFW"; logger.error() << "failed to initialize GLFW";
return -1; return nullptr;
} }
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
@ -209,7 +263,7 @@ int Window::initialize(DisplaySettings* settings) {
if (window == nullptr) { if (window == nullptr) {
logger.error() << "failed to create GLFW window"; logger.error() << "failed to create GLFW window";
glfwTerminate(); glfwTerminate();
return -1; return nullptr;
} }
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
@ -224,7 +278,7 @@ int Window::initialize(DisplaySettings* settings) {
} else { } else {
logger.error() << "failed to initialize GLEW:\n" logger.error() << "failed to initialize GLEW:\n"
<< glewGetErrorString(glewErr); << glewGetErrorString(glewErr);
return -1; return nullptr;
} }
} }
@ -283,7 +337,7 @@ int Window::initialize(DisplaySettings* settings) {
} }
standard_cursors[i] = glfwCreateStandardCursor(cursor); standard_cursors[i] = glfwCreateStandardCursor(cursor);
} }
return 0; return std::make_unique<GLFWInput>();
} }
void Window::clear() { void Window::clear() {
@ -467,10 +521,6 @@ std::unique_ptr<ImageData> Window::takeScreenshot() {
); );
} }
const char* Window::getClipboardText() {
return glfwGetClipboardString(window);
}
void Window::setClipboardText(const char* text) { void Window::setClipboardText(const char* text) {
glfwSetClipboardString(window, text); glfwSetClipboardString(window, text);
} }

View File

@ -9,13 +9,14 @@
#include "typedefs.hpp" #include "typedefs.hpp"
class ImageData; class ImageData;
class Input;
struct DisplaySettings; struct DisplaySettings;
namespace Window { namespace Window {
extern uint width; extern uint width;
extern uint height; extern uint height;
int initialize(DisplaySettings* settings); std::unique_ptr<Input> initialize(DisplaySettings* settings);
void terminate(); void terminate();
void viewport(int x, int y, int width, int height); void viewport(int x, int y, int width, int height);
@ -41,7 +42,6 @@ namespace Window {
void setBgColor(glm::vec3 color); void setBgColor(glm::vec3 color);
void setBgColor(glm::vec4 color); void setBgColor(glm::vec4 color);
double time(); double time();
const char* getClipboardText();
void setClipboardText(const char* text); void setClipboardText(const char* text);
DisplaySettings* getSettings(); DisplaySettings* getSettings();
void setIcon(const ImageData* image); void setIcon(const ImageData* image);

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <string> #include <string>
#include <glm/vec2.hpp>
#include "util/HandlersList.hpp" #include "util/HandlersList.hpp"
@ -143,7 +144,7 @@ struct Binding {
int code; int code;
bool state = false; bool state = false;
bool justChange = false; bool justChange = false;
bool enable = true; bool enabled = true;
Binding() = default; Binding() = default;
Binding(inputtype type, int code) : type(type), code(code) { Binding(inputtype type, int code) : type(type), code(code) {
@ -173,3 +174,77 @@ struct Binding {
return "<unknown input type>"; return "<unknown input type>";
} }
}; };
class Bindings {
std::unordered_map<std::string, Binding> bindings;
public:
bool active(const std::string& name) const {
const auto& found = bindings.find(name);
if (found == bindings.end()) {
return false;
}
return found->second.active();
}
bool jactive(const std::string& name) const {
const auto& found = bindings.find(name);
if (found == bindings.end()) {
return false;
}
return found->second.jactive();
}
Binding* get(const std::string& name) {
const auto found = bindings.find(name);
if (found == bindings.end()) {
return nullptr;
}
return &found->second;
}
void bind(const std::string& name, inputtype type, int code) {
bindings.try_emplace(name, Binding(type, code));
}
auto& getAll() {
return bindings;
}
};
struct CursorState {
bool locked = false;
glm::vec2 pos {};
glm::vec2 delta {};
};
class Input {
public:
virtual ~Input() = default;
virtual void pollEvents() = 0;
virtual const char* getClipboardText() const = 0;
virtual int getScroll() = 0;
virtual Binding& requireBinding(const std::string& name) = 0;
virtual bool pressed(keycode keycode) const = 0;
virtual bool jpressed(keycode keycode) const = 0;
virtual bool clicked(mousecode mousecode) const = 0;
virtual bool jclicked(mousecode mousecode) const = 0;
virtual CursorState getCursor() const = 0;
virtual Bindings& getBindings() = 0;
virtual const Bindings& getBindings() const = 0;
virtual observer_handler addKeyCallback(keycode key, KeyCallback callback) = 0;
observer_handler addCallback(const std::string& name, KeyCallback callback) {
return requireBinding(name).onactived.add(callback);
}
};