From e1d30732df94137d5f6db7e08b8fed37a3595e86 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 11 Jan 2024 02:37:29 +0300 Subject: [PATCH] TextBox validation + minor refactor, fixes --- src/frontend/BlocksPreview.cpp | 12 +++++---- src/frontend/gui/controls.cpp | 41 +++++++++++++++++++++++++++++-- src/frontend/gui/controls.h | 9 +++++++ src/frontend/hud.cpp | 45 ++++++++++++++-------------------- src/frontend/menu.cpp | 28 +++++++-------------- src/graphics/Batch2D.cpp | 1 + src/graphics/Batch3D.cpp | 2 +- 7 files changed, 85 insertions(+), 53 deletions(-) diff --git a/src/frontend/BlocksPreview.cpp b/src/frontend/BlocksPreview.cpp index 87acd011..846afc4a 100644 --- a/src/frontend/BlocksPreview.cpp +++ b/src/frontend/BlocksPreview.cpp @@ -28,7 +28,7 @@ void BlocksPreview::begin(const Viewport* viewport) { shader->uniformMatrix("u_projview", glm::ortho(0.0f, float(viewport->getWidth()), 0.0f, float(viewport->getHeight()), - -1000.0f, 1000.0f) * + -100.0f, 100.0f) * glm::lookAt(glm::vec3(2, 2, 2), glm::vec3(0.0f), glm::vec3(0, 1, 0))); atlas->getTexture()->bind(); } @@ -42,15 +42,17 @@ void BlocksPreview::draw(const Block* def, int x, int y, int size, glm::vec4 tin x += 2; if (def->model == BlockModel::aabb) { - y += (1.0f - def->hitbox.size()).y * size * 0.5f; + x += (1.0f - def->hitbox.size()).x * size * 0.5f; + y += (1.0f - def->hitbox.size()).y * size * 0.25f; } glm::vec3 offset (x/float(width) * 2, y/float(height) * 2, 0.0f); shader->uniformMatrix("u_apply", glm::translate(glm::mat4(1.0f), offset)); + blockid_t id = def->rt.id; - const UVRegion texfaces[6]{ cache->getRegion(id, 0), cache->getRegion(id, 1), - cache->getRegion(id, 2), cache->getRegion(id, 3), - cache->getRegion(id, 4), cache->getRegion(id, 5)}; + const UVRegion texfaces[6]{cache->getRegion(id, 0), cache->getRegion(id, 1), + cache->getRegion(id, 2), cache->getRegion(id, 3), + cache->getRegion(id, 4), cache->getRegion(id, 5)}; switch (def->model) { case BlockModel::none: diff --git a/src/frontend/gui/controls.cpp b/src/frontend/gui/controls.cpp index b4445d2f..2f67c7f0 100644 --- a/src/frontend/gui/controls.cpp +++ b/src/frontend/gui/controls.cpp @@ -144,7 +144,19 @@ TextBox::TextBox(wstring placeholder, vec4 padding) void TextBox::drawBackground(Batch2D* batch, Assets* assets) { vec2 coord = calcCoord(); batch->texture(nullptr); - batch->color = (isfocused() ? focusedColor : (hover_ ? hoverColor : color_)); + + if (valid) { + if (isfocused()) { + batch->color = focusedColor; + } else if (hover_) { + batch->color = hoverColor; + } else { + batch->color = color_; + } + } else { + batch->color = invalidColor; + } + batch->rect(coord.x, coord.y, size_.x, size_.y); if (!focused_ && supplier) { input = supplier(); @@ -162,6 +174,24 @@ void TextBox::drawBackground(Batch2D* batch, Assets* assets) { void TextBox::typed(unsigned int codepoint) { input += wstring({(wchar_t)codepoint}); + validate(); +} + +bool TextBox::validate() { + if (validator) { + valid = validator(input); + } else { + valid = true; + } + return valid; +} + +void TextBox::setValid(bool valid) { + this->valid = valid; +} + +bool TextBox::isValid() const { + return valid; } void TextBox::keyPressed(int key) { @@ -169,10 +199,11 @@ void TextBox::keyPressed(int key) { case KEY_BACKSPACE: if (!input.empty()){ input = input.substr(0, input.length()-1); + validate(); } break; case KEY_ENTER: - if (consumer) { + if (validate() && consumer) { consumer(label->text()); } defocus(); @@ -183,6 +214,7 @@ void TextBox::keyPressed(int key) { const char* text = Window::getClipboardText(); if (text) { input += util::str2wstr_utf8(text); + validate(); } } } @@ -199,6 +231,10 @@ void TextBox::textConsumer(wstringconsumer consumer) { this->consumer = consumer; } +void TextBox::textValidator(wstringchecker validator) { + this->validator = validator; +} + wstring TextBox::text() const { if (input.empty()) return placeholder; @@ -297,6 +333,7 @@ void TrackBar::mouseMove(GUI*, int x, int y) { // ================================ CheckBox ================================== CheckBox::CheckBox(bool checked) : UINode(vec2(), vec2(32.0f)), checked_(checked) { color(vec4(0.0f, 0.0f, 0.0f, 0.5f)); + margin(vec4(0.0f, 0.0f, 5.0f, 0.0f)); } void CheckBox::draw(Batch2D* batch, Assets* assets) { diff --git a/src/frontend/gui/controls.h b/src/frontend/gui/controls.h index 4d710833..ebcec8e7 100644 --- a/src/frontend/gui/controls.h +++ b/src/frontend/gui/controls.h @@ -23,6 +23,8 @@ namespace gui { typedef std::function boolsupplier; typedef std::function boolconsumer; + typedef std::function wstringchecker; + class Label : public UINode { protected: std::wstring text_; @@ -71,11 +73,14 @@ namespace gui { protected: glm::vec4 hoverColor {0.05f, 0.1f, 0.2f, 0.75f}; glm::vec4 focusedColor {0.0f, 0.0f, 0.0f, 1.0f}; + glm::vec4 invalidColor {0.1f, 0.05f, 0.03f, 1.0f}; Label* label; std::wstring input; std::wstring placeholder; wstringsupplier supplier = nullptr; wstringconsumer consumer = nullptr; + wstringchecker validator = nullptr; + bool valid = true; public: TextBox(std::wstring placeholder, glm::vec4 padding=glm::vec4(2.0f)); @@ -87,8 +92,12 @@ namespace gui { virtual void keyPressed(int key) override; virtual void textSupplier(wstringsupplier supplier); virtual void textConsumer(wstringconsumer consumer); + virtual void textValidator(wstringchecker validator); virtual bool isfocuskeeper() const override {return true;} virtual std::wstring text() const; + virtual bool validate(); + virtual void setValid(bool valid); + virtual bool isValid() const; }; class InputBindBox : public Panel { diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index 832b61fd..635a9257 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -135,22 +135,14 @@ void HudRenderer::createDebugPanel(Engine* engine) { })); { TrackBar* bar = new TrackBar(0.0f, 1.0f, 1.0f, 0.005f, 8); - bar->supplier([=]() { - return level->world->daytime; - }); - bar->consumer([=](double val) { - level->world->daytime = val; - }); + bar->supplier([=]() {return level->world->daytime;}); + bar->consumer([=](double val) {level->world->daytime = val;}); panel->add(bar); } { TrackBar* bar = new TrackBar(0.0f, 1.0f, 0.0f, 0.005f, 8); - bar->supplier([=]() { - return WorldRenderer::fog; - }); - bar->consumer([=](double val) { - WorldRenderer::fog = val; - }); + bar->supplier([=]() {return WorldRenderer::fog;}); + bar->consumer([=](double val) {WorldRenderer::fog = val;}); panel->add(bar); } { @@ -159,7 +151,6 @@ void HudRenderer::createDebugPanel(Engine* engine) { checkpanel->orientation(Orientation::horizontal); CheckBox* checkbox = new CheckBox(); - checkbox->margin(vec4(0.0f, 0.0f, 5.0f, 0.0f)); checkbox->supplier([=]() { return engine->getSettings().debug.showChunkBorders; }); @@ -249,19 +240,25 @@ void HudRenderer::draw(const GfxContext& ctx){ const uint width = viewport.getWidth(); const uint height = viewport.getHeight(); - debugPanel->visible(level->player->debug); + Player* player = level->player; + debugPanel->visible(player->debug); uicamera->setFov(height); - Shader* uishader = assets->getShader("ui"); - uishader->use(); - uishader->uniformMatrix("u_projview", uicamera->getProjection()*uicamera->getView()); - auto batch = ctx.getBatch2D(); batch->begin(); - // Chosen block preview - batch->color = vec4(1.0f); + Shader* uishader = assets->getShader("ui"); + uishader->use(); + uishader->uniformMatrix("u_projview", uicamera->getProjection()*uicamera->getView()); + + // Draw selected item preview + hotbarView->setPosition(width-60, height-60); + hotbarView->setItems({player->getChosenItem()}); + hotbarView->actAndDraw(&ctx); + + // Crosshair + batch->begin(); if (Events::_cursor_locked && !level->player->debug) { batch->lineWidth(2); batch->line(width/2, height/2-6, width/2, height/2+6, 0.2f, 0.2f, 0.2f, 1.0f); @@ -270,20 +267,16 @@ void HudRenderer::draw(const GfxContext& ctx){ batch->line(width/2+5, height/2-5, width/2-5, height/2+5, 0.9f, 0.9f, 0.9f, 1.0f); } - Player* player = level->player; - hotbarView->setPosition(width-56, height-56); - hotbarView->setItems({player->getChosenItem()}); - hotbarView->actAndDraw(&ctx); - - uishader->use(); batch->begin(); if (pause) { + // draw fullscreen dark overlay batch->texture(nullptr); batch->color = vec4(0.0f, 0.0f, 0.0f, 0.5f); batch->rect(0, 0, width, height); } if (inventoryOpen) { + // draw content access panel (all available items) contentAccess->setPosition(viewport.getWidth()-contentAccess->getWidth(), 0); contentAccess->actAndDraw(&ctx); } diff --git a/src/frontend/menu.cpp b/src/frontend/menu.cpp index 5f88bf27..3301e164 100644 --- a/src/frontend/menu.cpp +++ b/src/frontend/menu.cpp @@ -277,6 +277,12 @@ void create_new_world_panel(Engine* engine, PagesControl* menu) { panel->add(label); TextBox* input = new TextBox(L"New World", vec4(6.0f)); + input->textValidator([=](const std::wstring& text) { + EnginePaths* paths = engine->getPaths(); + std::string textutf8 = util::wstr2str_utf8(text); + return util::is_valid_filename(text) && + !paths->isWorldNameUsed(textutf8); + }); panel->add(input); worldNameInput = input; } @@ -287,29 +293,15 @@ void create_new_world_panel(Engine* engine, PagesControl* menu) { panel->add(seedInput); } - vec4 basecolor = worldNameInput->color(); panel->add(create_button( L"Create World", vec4(10), vec4(1, 20, 1, 1), [=](GUI*) { + if (!worldNameInput->validate()) + return; + std::wstring name = worldNameInput->text(); std::string nameutf8 = util::wstr2str_utf8(name); EnginePaths* paths = engine->getPaths(); - // Basic validation - if (!util::is_valid_filename(name) || - paths->isWorldNameUsed(nameutf8)) { - // blink red two times - panel->listenInterval(0.1f, [worldNameInput, basecolor]() { - static bool flag = true; - if (flag) { - worldNameInput->color(vec4(0.3f, 0.0f, 0.0f, 0.5f)); - } else { - worldNameInput->color(basecolor); - } - flag = !flag; - }, 4); - return; - } - std::wstring seedstr = seedInput->text(); uint64_t seed = str2seed(seedstr); std::cout << "world seed: " << seed << std::endl; @@ -447,7 +439,6 @@ void create_settings_panel(Engine* engine, PagesControl* menu) { checkpanel->orientation(Orientation::horizontal); CheckBox* checkbox = new CheckBox(); - checkbox->margin(vec4(0.0f, 0.0f, 5.0f, 0.0f)); checkbox->supplier([=]() { return engine->getSettings().display.swapInterval != 0; }); @@ -466,7 +457,6 @@ void create_settings_panel(Engine* engine, PagesControl* menu) { checkpanel->orientation(Orientation::horizontal); CheckBox* checkbox = new CheckBox(); - checkbox->margin(vec4(0.0f, 0.0f, 5.0f, 0.0f)); checkbox->supplier([=]() { return engine->getSettings().graphics.backlight != 0; }); diff --git a/src/graphics/Batch2D.cpp b/src/graphics/Batch2D.cpp index f0c6b5b3..9dee8115 100644 --- a/src/graphics/Batch2D.cpp +++ b/src/graphics/Batch2D.cpp @@ -36,6 +36,7 @@ Batch2D::~Batch2D(){ void Batch2D::begin(){ _texture = nullptr; blank->bind(); + color = vec4(1.0f); } void Batch2D::vertex(float x, float y, diff --git a/src/graphics/Batch3D.cpp b/src/graphics/Batch3D.cpp index 1fda4c65..cf47dd2e 100644 --- a/src/graphics/Batch3D.cpp +++ b/src/graphics/Batch3D.cpp @@ -169,7 +169,7 @@ void Batch3D::xSprite(float w, float h, const UVRegion& uv, const vec4 tint, boo } void Batch3D::blockCube(const vec3 size, const UVRegion(&texfaces)[6], const vec4 tint, bool shading) { - vec3 coord = (1.0f - size) * -0.45f; + vec3 coord = (1.0f - size) * -0.5f; face(coord+vec3(0.0f, 0.0f, 0.0f), size.x, size.y, vec3(1, 0, 0), vec3(0, 1, 0), texfaces[5], (shading ? do_tint(0.8)*tint : tint)); face(coord+vec3(size.x, 0.0f, -size.z), size.x, size.y, vec3(-1, 0, 0), vec3(0, 1, 0), texfaces[4], (shading ? do_tint(0.8f)*tint : tint)); face(coord+vec3(0.0f, size.y, 0.0f), size.x, size.z, vec3(1, 0, 0), vec3(0, 0, -1), texfaces[3], (shading ? do_tint(1.0f)*tint : tint));