diff --git a/doc/en/scripting/ui.md b/doc/en/scripting/ui.md index a88a80a6..771049c5 100644 --- a/doc/en/scripting/ui.md +++ b/doc/en/scripting/ui.md @@ -60,7 +60,13 @@ Common element methods: ## Containers -Common methods for containers (elements: container, panel, button, pagebox): +Common properties for containers (elements: container, panel, button, pagebox): + +| Name | Type | Read | Write | Description | +| ------ | ------ | ---- | ----- | --------------- | +| scroll | string | yes | yes | scroll contents | + +Common methods: | Method | Description | | ------------------------------- | -------------------------------------------------------------------------------------------- | diff --git a/doc/ru/scripting/ui.md b/doc/ru/scripting/ui.md index 107f5139..f9d9ab00 100644 --- a/doc/ru/scripting/ui.md +++ b/doc/ru/scripting/ui.md @@ -60,7 +60,13 @@ document["worlds-panel"]:clear() ## Контейнеры -Общие для контейнеров методы (элементы: container, panel, button, pagebox): +Свойства, относящиеся к контейнерам (элементы: container, panel, button, pagebox): + +| Название | Тип | Чтение | Запись | Описание | +| ------------- | ------ | ------ | ------ | ----------------------------------------- | +| scroll | string | да | да | прокрутка содержимого | + +Методы: | Метод | Описание | | ------------------------------- | ------------------------------------------------------------------------------------------- | diff --git a/res/layouts/console.xml.lua b/res/layouts/console.xml.lua index 891fb577..695408e1 100644 --- a/res/layouts/console.xml.lua +++ b/res/layouts/console.xml.lua @@ -87,6 +87,7 @@ end function build_files_list(filenames, selected) local files_list = document.filesList + files_list.scroll = 0 files_list:clear() for _, actual_filename in ipairs(filenames) do @@ -193,6 +194,7 @@ end function open_file_in_editor(filename, line, mutable) local editor = document.editor local source = file.read(filename):gsub('\t', ' ') + editor.scroll = 0 editor.text = source editor.focused = true if line then diff --git a/src/graphics/ui/elements/Container.cpp b/src/graphics/ui/elements/Container.cpp index 3fc25f66..63ddbc4f 100644 --- a/src/graphics/ui/elements/Container.cpp +++ b/src/graphics/ui/elements/Container.cpp @@ -226,6 +226,10 @@ void Container::refresh() { }); } +void Container::setScroll(int scroll) { + this->scroll = scroll; +} + const std::vector>& Container::getNodes() const { return nodes; } diff --git a/src/graphics/ui/elements/Container.hpp b/src/graphics/ui/elements/Container.hpp index f91fa915..2a5ca3e2 100644 --- a/src/graphics/ui/elements/Container.hpp +++ b/src/graphics/ui/elements/Container.hpp @@ -42,6 +42,7 @@ namespace gui { virtual int getScrollStep() const; virtual void setScrollStep(int step); virtual void refresh() override; + void setScroll(int scroll); virtual void mouseMove(GUI*, int x, int y) override; virtual void mouseRelease(GUI*, int x, int y) override; diff --git a/src/graphics/ui/elements/Label.cpp b/src/graphics/ui/elements/Label.cpp index 726785a8..fd8ac725 100644 --- a/src/graphics/ui/elements/Label.cpp +++ b/src/graphics/ui/elements/Label.cpp @@ -237,15 +237,30 @@ void Label::draw(const DrawContext& pctx, const Assets& assets) { textYOffset = pos.y-calcPos().y; totalLineHeight = lineHeight; + auto& viewport = pctx.getViewport(); + glm::vec4 bounds {0, 0, viewport.getWidth(), viewport.getHeight()}; + if (parent) { + auto ppos = parent->calcPos(); + auto psize = parent->getSize(); + bounds.x = std::max(bounds.x, ppos.x); + bounds.y = std::max(bounds.y, ppos.y); + bounds.z = std::min(bounds.z, ppos.x + psize.x); + bounds.w = std::min(bounds.w, ppos.y + psize.y); + } if (multiline) { + // todo: reduce loop range to the actual area for (size_t i = 0; i < cache.lines.size(); i++) { + float y = pos.y + i * totalLineHeight; + if (y + totalLineHeight < bounds.y || y > bounds.w) { + continue; + } auto& line = cache.lines[i]; size_t offset = line.offset; std::wstring_view view(text.c_str()+offset, text.length()-offset); if (i < cache.lines.size()-1) { view = std::wstring_view(text.c_str()+offset, cache.lines.at(i+1).offset-offset); } - font->draw(*batch, view, pos.x, pos.y + i * totalLineHeight, styles.get(), offset); + font->draw(*batch, view, pos.x, y, styles.get(), offset); } } else { font->draw(*batch, text, pos.x, pos.y, styles.get(), 0); diff --git a/src/logic/scripting/lua/libs/libgui.cpp b/src/logic/scripting/lua/libs/libgui.cpp index cc372f88..b40d4318 100644 --- a/src/logic/scripting/lua/libs/libgui.cpp +++ b/src/logic/scripting/lua/libs/libgui.cpp @@ -423,6 +423,13 @@ static int p_get_cursor(UINode* node, lua::State* L) { return lua::pushstring(L, to_string(node->getCursor())); } +static int p_get_scroll(UINode* node, lua::State* L) { + if (auto container = dynamic_cast(node)) { + return lua::pushnumber(L, container->getContentOffset().y); + } + return 0; +} + static int l_gui_getattr(lua::State* L) { auto docname = lua::require_string(L, 1); auto element = lua::require_string(L, 2); @@ -469,6 +476,7 @@ static int l_gui_getattr(lua::State* L) { {"min", p_get_min}, {"max", p_get_max}, {"step", p_get_step}, + {"scroll", p_get_scroll}, {"trackWidth", p_get_track_width}, {"trackColor", p_get_track_color}, {"textColor", p_get_text_color}, @@ -655,6 +663,13 @@ static void p_set_cursor(UINode* node, lua::State* L, int idx) { } } +static int p_set_scroll(UINode* node, lua::State* L, int idx) { + if (auto container = dynamic_cast(node)) { + container->setScroll(lua::tointeger(L, idx)); + } + return 0; +} + static int l_gui_setattr(lua::State* L) { auto docname = lua::require_string(L, 1); auto element = lua::require_string(L, 2); @@ -692,6 +707,7 @@ static int l_gui_setattr(lua::State* L) { {"min", p_set_min}, {"max", p_set_max}, {"step", p_set_step}, + {"scroll", p_set_scroll}, {"trackWidth", p_set_track_width}, {"trackColor", p_set_track_color}, {"textColor", p_set_text_color}, diff --git a/src/logic/scripting/lua/lua_extensions.cpp b/src/logic/scripting/lua/lua_extensions.cpp index 37ed5d01..399b6095 100644 --- a/src/logic/scripting/lua/lua_extensions.cpp +++ b/src/logic/scripting/lua/lua_extensions.cpp @@ -3,6 +3,9 @@ #include "libs/api_lua.hpp" #include "debug/Logger.hpp" +#include "logic/scripting/scripting.hpp" + +using namespace scripting; static debug::Logger logger("lua-debug"); @@ -28,13 +31,13 @@ const int MAX_DEPTH = 10; int l_debug_print(lua::State* L) { auto addIndentation = [](int depth) { - for (int i = 0; i < depth; ++i) std::cout << " "; + for (int i = 0; i < depth; ++i) *output_stream << " "; }; auto printHexData = [](const void* ptr, size_t size) { const auto* bytePtr = reinterpret_cast(ptr); for (size_t i = 0; i < size; ++i) { - std::cout << std::hex << std::setw(2) << std::setfill('0') + *output_stream << std::hex << std::setw(2) << std::setfill('0') << static_cast(bytePtr[i]) << ((i + 1) % 8 == 0 && i + 1 < size ? "\n" : " "); } @@ -43,20 +46,20 @@ int l_debug_print(lua::State* L) { auto printEscapedString = [](const char* str) { while (*str) { switch (*str) { - case '\\': std::cout << "\\\\"; break; - case '\"': std::cout << "\\\""; break; - case '\n': std::cout << "\\n"; break; - case '\t': std::cout << "\\t"; break; - case '\r': std::cout << "\\r"; break; - case '\b': std::cout << "\\b"; break; - case '\f': std::cout << "\\f"; break; + case '\\': *output_stream << "\\\\"; break; + case '\"': *output_stream << "\\\""; break; + case '\n': *output_stream << "\\n"; break; + case '\t': *output_stream << "\\t"; break; + case '\r': *output_stream << "\\r"; break; + case '\b': *output_stream << "\\b"; break; + case '\f': *output_stream << "\\f"; break; default: if (iscntrl(static_cast(*str))) { // Print other control characters in \xHH format - std::cout << "\\x" << std::hex << std::setw(2) << std::setfill('0') + *output_stream << "\\x" << std::hex << std::setw(2) << std::setfill('0') << static_cast(static_cast(*str)) << std::dec; } else { - std::cout << *str; + *output_stream << *str; } break; } @@ -68,80 +71,80 @@ int l_debug_print(lua::State* L) { int depth, bool is_key) { if (depth > MAX_DEPTH) { - std::cout << "{...}"; + *output_stream << "{...}"; return; } switch (lua::type(L, index)) { case LUA_TSTRING: if (is_key){ - std::cout << lua::tostring(L, index); + *output_stream << lua::tostring(L, index); }else{ - std::cout << "\""; + *output_stream << "\""; printEscapedString(lua::tostring(L, index)); - std::cout << "\""; + *output_stream << "\""; } break; case LUA_TBOOLEAN: - std::cout << (lua::toboolean(L, index) ? "true" : "false"); + *output_stream << (lua::toboolean(L, index) ? "true" : "false"); break; case LUA_TNUMBER: - std::cout << lua::tonumber(L, index); + *output_stream << lua::tonumber(L, index); break; case LUA_TTABLE: { bool is_list = lua::objlen(L, index) > 0, hadItems = false; int absTableIndex = index > 0 ? index : lua::gettop(L) + index + 1; - std::cout << "{"; + *output_stream << "{"; lua::pushnil(L); while (lua::next(L, absTableIndex) != 0) { if (hadItems) - std::cout << "," << '\n'; + *output_stream << "," << '\n'; else - std::cout << '\n'; + *output_stream << '\n'; addIndentation(depth + 1); if (!is_list) { debugPrint(-2, depth, true); - std::cout << " = "; + *output_stream << " = "; } debugPrint(-1, depth + 1, false); lua::pop(L, 1); hadItems = true; } - if (hadItems) std::cout << '\n'; + if (hadItems) *output_stream << '\n'; addIndentation(depth); - std::cout << "}"; + *output_stream << "}"; break; } case LUA_TFUNCTION: - std::cout << "function(0x" << std::hex + *output_stream << "function(0x" << std::hex << lua::topointer(L, index) << std::dec << ")"; break; case LUA_TUSERDATA: - std::cout << "userdata:\n"; + *output_stream << "userdata:\n"; printHexData(lua::topointer(L, index), lua::objlen(L, index)); break; case LUA_TLIGHTUSERDATA: - std::cout << "lightuserdata:\n"; + *output_stream << "lightuserdata:\n"; printHexData(lua::topointer(L, index), sizeof(void*)); break; case LUA_TNIL: - std::cout << "nil"; + *output_stream << "nil"; break; default: - std::cout << lua::type_name(L, lua::type(L, index)); + *output_stream << lua::type_name(L, lua::type(L, index)); break; } }; int n = lua::gettop(L); - std::cout << "debug.print(" << '\n'; + *output_stream << "debug.print(" << '\n'; for (int i = 1; i <= n; ++i) { addIndentation(1); debugPrint(i, 1, false); - if (i < n) std::cout << "," << '\n'; + if (i < n) *output_stream << "," << '\n'; } - std::cout << '\n' << ")" << std::endl; + *output_stream << '\n' << ")" << std::endl; lua::pop(L, n); return 0; }