diff --git a/res/content/base/package.json b/res/content/base/package.json index 249dd4ee..7da43458 100644 --- a/res/content/base/package.json +++ b/res/content/base/package.json @@ -1,6 +1,6 @@ { "id": "base", "title": "Base", - "version": "0.19", + "version": "0.20", "description": "basic content package" } diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 44e6e3f4..b6d7523d 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -42,7 +42,7 @@ function load_script(path, nocache) error("script '"..filename.."' not found in '"..packname.."'") end - local script, err = loadfile(file.resolve(path)) + local script, err = load(file.read(path), path) if script == nil then error(err) end diff --git a/src/constants.h b/src/constants.h index 56f54c7f..fffa9c22 100644 --- a/src/constants.h +++ b/src/constants.h @@ -2,10 +2,13 @@ #define SRC_CONSTANTS_H_ #include +#include #include "typedefs.h" const int ENGINE_VERSION_MAJOR = 0; -const int ENGINE_VERSION_MINOR = 19; +const int ENGINE_VERSION_MINOR = 20; +const bool ENGINE_VERSION_INDEV = true; +#define ENGINE_VERSION_STRING "0.20" const int BLOCK_AIR = 0; const int ITEM_EMPTY = 0; diff --git a/src/engine.cpp b/src/engine.cpp index 80d9114a..54ae6876 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -75,6 +75,9 @@ Engine::Engine(EngineSettings& settings, EnginePaths* paths) gui = std::make_unique(); if (settings.ui.language == "auto") { settings.ui.language = langs::locale_by_envlocale(platform::detect_locale(), paths->getResources()); + } + if (ENGINE_VERSION_INDEV) { + menus::create_version_label(this); } setLanguage(settings.ui.language); } diff --git a/src/frontend/gui/controls.cpp b/src/frontend/gui/controls.cpp index 1328b4dc..996226c2 100644 --- a/src/frontend/gui/controls.cpp +++ b/src/frontend/gui/controls.cpp @@ -36,6 +36,14 @@ std::wstring Label::getText() const { return text; } +void Label::setFontName(std::string name) { + this->fontName = name; +} + +const std::string& Label::getFontName() const { + return fontName; +} + void Label::draw(const GfxContext* pctx, Assets* assets) { if (supplier) { setText(supplier()); @@ -246,6 +254,25 @@ TextBox::TextBox(std::wstring placeholder, glm::vec4 padding) setHoverColor(glm::vec4(0.05f, 0.1f, 0.2f, 0.75f)); } +void TextBox::draw(const GfxContext* pctx, Assets* assets) { + Panel::draw(pctx, assets); + + font = assets->getFont(label->getFontName()); + + if (!isFocused()) + return; + + if (int((Window::time() - caretLastMove) * 2) % 2 == 0) { + auto batch = pctx->getBatch2D(); + batch->texture(nullptr); + batch->color = glm::vec4(1.0f); + + glm::vec2 lcoord = label->calcCoord(); + int width = font->calcWidth(input.substr(0, caret)); + batch->rect(lcoord.x + width, lcoord.y, 2, font->getLineHeight()); + } +} + void TextBox::drawBackground(const GfxContext* pctx, Assets* assets) { glm::vec2 coord = calcCoord(); @@ -279,11 +306,22 @@ void TextBox::drawBackground(const GfxContext* pctx, Assets* assets) { setScrollable(false); } -void TextBox::typed(unsigned int codepoint) { - input += std::wstring({(wchar_t)codepoint}); +void TextBox::paste(const std::wstring& text) { + if (caret >= input.length()) { + input += text; + } else { + auto left = input.substr(0, caret); + auto right = input.substr(caret); + input = left + text + right; + } + setCaret(caret + text.length()); validate(); } +void TextBox::typed(unsigned int codepoint) { + paste(std::wstring({(wchar_t)codepoint})); +} + bool TextBox::validate() { if (validator) { valid = validator(getText()); @@ -308,6 +346,7 @@ void TextBox::setOnEditStart(runnable oneditstart) { void TextBox::focus(GUI* gui) { Panel::focus(gui); if (onEditStart){ + setCaret(input.size()); onEditStart(); } } @@ -317,24 +356,60 @@ void TextBox::refresh() { label->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y)); } +void TextBox::clicked(GUI*, int button) { + +} + +void TextBox::mouseMove(GUI*, int x, int y) { + if (font == nullptr) + return; + glm::vec2 lcoord = label->calcCoord(); + uint offset = 0; + while (lcoord.x + font->calcWidth(input, offset) < x && offset <= input.length()) { + offset++; + } + setCaret(offset); +} + void TextBox::keyPressed(int key) { if (key == keycode::BACKSPACE) { - if (!input.empty()){ - input = input.substr(0, input.length()-1); + if (caret > 0 && input.length() > 0) { + if (caret > input.length()) { + caret = input.length(); + } + input = input.substr(0, caret-1) + input.substr(caret); + setCaret(caret-1); + validate(); + } + } else if (key == keycode::DELETE) { + if (caret < input.length()) { + input = input.substr(0, caret) + input.substr(caret + 1); validate(); } } else if (key == keycode::ENTER) { if (validate() && consumer) { consumer(label->getText()); } - defocus(); + defocus(); + } else if (key == keycode::LEFT) { + if (caret > 0) { + if (caret > input.length()) { + setCaret(input.length()-1); + } else { + setCaret(caret-1); + } + } + } else if (key == keycode::RIGHT) { + if (caret < input.length()) { + setCaret(caret+1); + caretLastMove = Window::time(); + } } // Pasting text from clipboard if (key == keycode::V && Events::pressed(keycode::LEFT_CONTROL)) { const char* text = Window::getClipboardText(); if (text) { - input += util::str2wstr_utf8(text); - validate(); + paste(util::str2wstr_utf8(text)); } } } @@ -355,6 +430,22 @@ void TextBox::setTextValidator(wstringchecker validator) { this->validator = validator; } +void TextBox::setFocusedColor(glm::vec4 color) { + this->focusedColor = color; +} + +glm::vec4 TextBox::getFocusedColor() const { + return focusedColor; +} + +void TextBox::setErrorColor(glm::vec4 color) { + this->invalidColor = color; +} + +glm::vec4 TextBox::getErrorColor() const { + return invalidColor; +} + std::wstring TextBox::getText() const { if (input.empty()) return placeholder; @@ -373,6 +464,15 @@ void TextBox::setPlaceholder(const std::wstring& placeholder) { this->placeholder = placeholder; } +uint TextBox::getCaret() const { + return caret; +} + +void TextBox::setCaret(uint position) { + this->caret = position; + caretLastMove = Window::time(); +} + // ============================== InputBindBox ================================ InputBindBox::InputBindBox(Binding& binding, glm::vec4 padding) : Panel(glm::vec2(100,32), padding, 0), diff --git a/src/frontend/gui/controls.h b/src/frontend/gui/controls.h index 1d0cb1ea..92a1a088 100644 --- a/src/frontend/gui/controls.h +++ b/src/frontend/gui/controls.h @@ -15,6 +15,7 @@ class Batch2D; class Assets; +class Font; namespace gui { class Label : public UINode { @@ -29,6 +30,9 @@ namespace gui { virtual void setText(std::wstring text); std::wstring getText() const; + virtual void setFontName(std::string name); + const std::string& getFontName() const; + virtual void draw(const GfxContext* pctx, Assets* assets) override; virtual void textSupplier(wstringsupplier supplier); @@ -105,12 +109,19 @@ namespace gui { wstringchecker validator = nullptr; runnable onEditStart = nullptr; bool valid = true; + /// @brief text input pointer, value may be greather than text length + uint caret = 0; + double caretLastMove = 0.0; + Font* font = nullptr; + + void paste(const std::wstring& text); public: TextBox(std::wstring placeholder, glm::vec4 padding=glm::vec4(4.0f)); virtual std::shared_ptr getAt(glm::vec2 pos, std::shared_ptr self) override; + virtual void draw(const GfxContext* pctx, Assets* assets) override; virtual void drawBackground(const GfxContext* pctx, Assets* assets) override; virtual void typed(unsigned int codepoint) override; virtual void keyPressed(int key) override; @@ -118,18 +129,26 @@ namespace gui { virtual void setTextConsumer(wstringconsumer consumer); virtual void setTextValidator(wstringchecker validator); virtual bool isFocuskeeper() const override {return true;} + virtual void setFocusedColor(glm::vec4 color); + virtual glm::vec4 getFocusedColor() const; + virtual void setErrorColor(glm::vec4 color); + virtual glm::vec4 getErrorColor() const; /* Get TextBox content text or placeholder if empty */ virtual std::wstring getText() const; /* Set TextBox content text */ virtual void setText(std::wstring value); virtual std::wstring getPlaceholder() const; virtual void setPlaceholder(const std::wstring&); + virtual uint getCaret() const; + virtual void setCaret(uint position); virtual bool validate(); virtual void setValid(bool valid); virtual bool isValid() const; virtual void setOnEditStart(runnable oneditstart); virtual void focus(GUI*) override; virtual void refresh() override; + virtual void clicked(GUI*, int button) override; + virtual void mouseMove(GUI*, int x, int y) override; }; class InputBindBox : public Panel { diff --git a/src/frontend/gui/gui_xml.cpp b/src/frontend/gui/gui_xml.cpp index 5a75e3ad..94a0dc97 100644 --- a/src/frontend/gui/gui_xml.cpp +++ b/src/frontend/gui/gui_xml.cpp @@ -228,6 +228,20 @@ static std::shared_ptr readTextBox(UiXmlReader& reader, xml::xmlelement ); textbox->setTextSupplier(supplier); } + if (element->has("focused-color")) { + textbox->setFocusedColor(element->attr("focused-color").asColor()); + } + if (element->has("error-color")) { + textbox->setErrorColor(element->attr("error-color").asColor()); + } + if (element->has("validator")) { + auto validator = scripting::create_wstring_validator( + reader.getEnvironment().getId(), + element->attr("validator").getText(), + reader.getFilename()+".lua" + ); + textbox->setTextValidator(validator); + } return textbox; } diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index c2fec154..1d97ec3c 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -380,18 +380,20 @@ void Hud::update(bool visible) { } glm::vec2 invSize = contentAccessPanel->getSize(); - contentAccessPanel->setVisible(inventoryOpen); + contentAccessPanel->setVisible(inventoryView != nullptr); contentAccessPanel->setSize(glm::vec2(invSize.x, Window::height)); contentAccess->setMinSize(glm::vec2(1, Window::height)); hotbarView->setVisible(visible); - for (int i = keycode::NUM_1; i <= keycode::NUM_9; i++) { - if (Events::jpressed(i)) { - player->setChosenSlot(i - keycode::NUM_1); + if (!gui->isFocusCaught() && !pause) { + for (int i = keycode::NUM_1; i <= keycode::NUM_9; i++) { + if (Events::jpressed(i)) { + player->setChosenSlot(i - keycode::NUM_1); + } + } + if (Events::jpressed(keycode::NUM_0)) { + player->setChosenSlot(9); } - } - if (Events::jpressed(keycode::NUM_0)) { - player->setChosenSlot(9); } if (!pause && !inventoryOpen && Events::scroll) { int slot = player->getChosenSlot(); @@ -436,7 +438,7 @@ void Hud::openInventory() { * @param blockinv block inventory. * In case of nullptr a new virtual inventory will be created */ -void Hud::openInventory(glm::ivec3 block, UiDocument* doc, std::shared_ptr blockinv) { +void Hud::openInventory(glm::ivec3 block, UiDocument* doc, std::shared_ptr blockinv, bool playerInventory) { if (isInventoryOpen()) { closeInventory(); } @@ -445,7 +447,11 @@ void Hud::openInventory(glm::ivec3 block, UiDocument* doc, std::shared_ptrinventories->createVirtual(blockUI->getSlotsCount()); } @@ -594,25 +600,30 @@ void Hud::draw(const GfxContext& ctx){ } if (inventoryOpen) { - float caWidth = contentAccess->getSize().x; + float caWidth = inventoryView ? contentAccess->getSize().x : 0.0f; contentAccessPanel->setCoord(glm::vec2(width-caWidth, 0)); - glm::vec2 invSize = inventoryView->getSize(); + glm::vec2 invSize = inventoryView ? inventoryView->getSize() : glm::vec2(); if (blockUI == nullptr) { - inventoryView->setCoord(glm::vec2( - glm::min(width/2-invSize.x/2, width-caWidth-10-invSize.x), - height/2-invSize.y/2 - )); + if (inventoryView) { + inventoryView->setCoord(glm::vec2( + glm::min(width/2-invSize.x/2, width-caWidth-10-invSize.x), + height/2-invSize.y/2 + )); + } } else { glm::vec2 blockInvSize = blockUI->getSize(); - int interval = 5; + float invwidth = glm::max(invSize.x, blockInvSize.x); + int interval = invSize.y > 0.0 ? 5 : 0; float totalHeight = invSize.y + blockInvSize.y + interval; - inventoryView->setCoord(glm::vec2( - glm::min(width/2-invSize.x/2, width-caWidth-10-invSize.x), - height/2+totalHeight/2-invSize.y - )); + if (inventoryView) { + inventoryView->setCoord(glm::vec2( + glm::min(width/2-invwidth/2, width-caWidth-10-invwidth), + height/2+totalHeight/2-invSize.y + )); + } blockUI->setCoord(glm::vec2( - glm::min(width/2-invSize.x/2, width-caWidth-10-invSize.x), + glm::min(width/2-invwidth/2, width-caWidth-10-invwidth), height/2-totalHeight/2 )); } diff --git a/src/frontend/hud.h b/src/frontend/hud.h index 5a5b8914..02e3e2bb 100644 --- a/src/frontend/hud.h +++ b/src/frontend/hud.h @@ -110,7 +110,7 @@ public: void setPause(bool pause); void openInventory(); - void openInventory(glm::ivec3 block, UiDocument* doc, std::shared_ptr blockInv); + void openInventory(glm::ivec3 block, UiDocument* doc, std::shared_ptr blockInv, bool playerInventory); void closeInventory(); void openPermanent(UiDocument* doc); diff --git a/src/frontend/menu.cpp b/src/frontend/menu.cpp index 1fd76916..aa679352 100644 --- a/src/frontend/menu.cpp +++ b/src/frontend/menu.cpp @@ -87,6 +87,20 @@ static std::shared_ptr