From 31035345a8baf440b4cc0a5f0e68be3bfc51afc8 Mon Sep 17 00:00:00 2001 From: Artem Chernyshev Date: Sat, 4 Apr 2020 19:59:44 +0300 Subject: [PATCH] Fix several small issues 1. If using component without window it may lead to wrong layout. 2. CSS chain was not working for components nested into components. 3. Style scale was not passed to child contexts. 4. Implement number input type. 5. Fix absolute positioning (wasn't handling scroll correctly). --- samples/simple/styled.xml | 8 +++- src/extras/xhtml.h | 12 +++++ src/imvue.cpp | 8 ++-- src/imvue.h | 2 +- src/imvue_context.cpp | 1 + src/imvue_style.cpp | 9 ++-- tests/resources/dimensions.imv | 7 +++ tests/resources/dimensions.xml | 25 +++++++++++ tests/unit/style.cpp | 81 ++++++++++++++++++++++++++++++++++ 9 files changed, 143 insertions(+), 10 deletions(-) create mode 100644 tests/resources/dimensions.imv create mode 100644 tests/resources/dimensions.xml diff --git a/samples/simple/styled.xml b/samples/simple/styled.xml index 62a6be7..2dc03f6 100644 --- a/samples/simple/styled.xml +++ b/samples/simple/styled.xml @@ -136,7 +136,7 @@ margin-bottom: 2px; } - input[type="text"], input[type="password"] { + input[type="text"], input[type="password"], input[type="number"] { display: block; padding: 0.2em 0.5em; margin: 2px 2px 10px 2px; @@ -145,7 +145,7 @@ background-color: #222222; } - input[type="text"]:active, input[type="password"]:active { + input[type="text"]:active, input[type="password"]:active, input[type="number"]:active { margin-top: 0px; margin-left: 0px; margin-right: 0px; @@ -244,6 +244,10 @@ + + + + diff --git a/src/extras/xhtml.h b/src/extras/xhtml.h index 57ea0f8..202bdd4 100644 --- a/src/extras/xhtml.h +++ b/src/extras/xhtml.h @@ -210,6 +210,7 @@ namespace ImVue { , max(100.0f) , step(1.0f) , name(0) + , speed(1.0f) , mValue(0) , mModel(0) , mValueUpdated(false) @@ -377,6 +378,10 @@ namespace ImVue { break; case RANGE: changed = ImGui::SliderFloat(placeholder ? placeholder : "##slider", &mSliderValue, min, max, format ? format : "%.3f", step); + break; + case NUMBER: + changed = ImGui::DragFloat(placeholder ? placeholder : "##dragfloat", &mSliderValue, speed, min, max, format ? format : "%.3f", step); + break; default: // nothing break; @@ -427,6 +432,8 @@ namespace ImVue { mType = RADIO; } else if(ImStricmp(type, "range") == 0) { mType = RANGE; + } else if(ImStricmp(type, "number") == 0) { + mType = NUMBER; } if(mType == TEXT || mType == PASSWORD) { @@ -487,6 +494,8 @@ namespace ImVue { // radio only char* name; + // number only + float speed; private: void syncModel(bool write = false) @@ -515,6 +524,7 @@ namespace ImVue { case RADIO: (*mScriptState)[mModel] = mValue ? mValue : placeholder; break; + case NUMBER: case RANGE: (*mScriptState)[mModel] = mSliderValue; default: @@ -553,6 +563,7 @@ namespace ImVue { resetState(CHECKED); break; + case NUMBER: case RANGE: mSliderValue = object.as(); default: @@ -619,6 +630,7 @@ namespace ImVue { .attribute("max", &Input::max) .attribute("step", &Input::step) .attribute("format", &Input::format) + .attribute("speed", &Input::speed) .attribute("placeholder", &Input::placeholder); } diff --git a/src/imvue.cpp b/src/imvue.cpp index 76edfa7..702fd7c 100644 --- a/src/imvue.cpp +++ b/src/imvue.cpp @@ -197,7 +197,7 @@ namespace ImVue { res = builder->create(node, ctx, sctx, parent); } else { // then try to create a component - res = createComponent(node, ctx, sctx); + res = createComponent(node, ctx, sctx, parent); } if(res && sctx) { @@ -206,7 +206,7 @@ namespace ImVue { return res; } - Element* ComponentContainer::createComponent(rapidxml::xml_node<>* node, Context* ctx, ScriptState::Context* sctx) + Element* ComponentContainer::createComponent(rapidxml::xml_node<>* node, Context* ctx, ScriptState::Context* sctx, Element* parent) { ImU32 nodeID = ImHashStr(node->name()); if(mComponents.count(nodeID) == 0) { @@ -215,7 +215,7 @@ namespace ImVue { Component* component = mComponents[nodeID].create(); try { - component->configure(node, ctx, sctx, this); + component->configure(node, ctx, sctx, parent); } catch(...) { delete component; throw; @@ -343,7 +343,7 @@ namespace ImVue { , mData(data) { parseXML(tmpl.get()); - mFlags = mFlags | Element::COMPONENT; + mFlags = mFlags | Element::COMPONENT | Element::PSEUDO_ELEMENT; } Component::~Component() diff --git a/src/imvue.h b/src/imvue.h index d176426..1399631 100644 --- a/src/imvue.h +++ b/src/imvue.h @@ -150,7 +150,7 @@ namespace ImVue { /** * Creates component */ - Element* createComponent(rapidxml::xml_node<>* node, Context* ctx, ScriptState::Context* sctx); + Element* createComponent(rapidxml::xml_node<>* node, Context* ctx, ScriptState::Context* sctx, Element* parent); void parseXML(const char* data); diff --git a/src/imvue_context.cpp b/src/imvue_context.cpp index ecaf8b8..46388bd 100644 --- a/src/imvue_context.cpp +++ b/src/imvue_context.cpp @@ -195,6 +195,7 @@ namespace ImVue { Style* style = new Style(ctx->style); Context* child = createContext(ctx->factory, script, ctx->texture, ctx->fs, ctx->fontManager, style, ctx->userdata); child->parent = ctx; + child->scale = ctx->scale; return child; } } diff --git a/src/imvue_style.cpp b/src/imvue_style.cpp index a29aee3..af47aba 100644 --- a/src/imvue_style.cpp +++ b/src/imvue_style.cpp @@ -530,6 +530,7 @@ namespace ImVue { } else { pos = window->Pos; } + pos -= window->Scroll; break; } case CSS_POSITION_FIXED: @@ -1054,7 +1055,7 @@ namespace ImVue { ImGuiWindow* window = GetCurrentWindowNoDefault(); if(window){ Element* parent = e->getParent(); - while(parent && parent->display == CSS_DISPLAY_INLINE) { + while(parent && (parent->display == CSS_DISPLAY_INLINE || (parent->getFlags() & Element::PSEUDO_ELEMENT) != 0)) { parent = parent->getParent(); } @@ -1348,8 +1349,6 @@ namespace ImVue { if (code != CSS_OK) IMVUE_EXCEPTION(StyleError, "failed to append base stylesheet: %s", css_error_to_string(code)); - if(mParent) - mParent->appendSheets(ctx, false); appendSheets(ctx, true); return ctx; } @@ -1369,6 +1368,10 @@ namespace ImVue { void Style::appendSheets(css_select_ctx* ctx, bool scoped) { + if(mParent) { + mParent->appendSheets(ctx, false); + } + for(int i = 0; i < mSheets.size(); ++i) { if(mSheets[i].scoped && !scoped) { continue; diff --git a/tests/resources/dimensions.imv b/tests/resources/dimensions.imv new file mode 100644 index 0000000..ae1bdbe --- /dev/null +++ b/tests/resources/dimensions.imv @@ -0,0 +1,7 @@ + + + diff --git a/tests/resources/dimensions.xml b/tests/resources/dimensions.xml new file mode 100644 index 0000000..4ec6156 --- /dev/null +++ b/tests/resources/dimensions.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/tests/unit/style.cpp b/tests/unit/style.cpp index 594569f..b3934b7 100644 --- a/tests/unit/style.cpp +++ b/tests/unit/style.cpp @@ -4,6 +4,7 @@ #include "imvue_generated.h" #include "imvue_errors.h" #include "utils.h" +#include "extras/xhtml.h" #if defined(WITH_LUA) #include "lua/script.h" @@ -760,3 +761,83 @@ INSTANTIATE_TEST_CASE_P( #endif )); +#if defined(WITH_LUA) + +class TestStylesComponents : public ::testing::Test { + + public: + + TestStylesComponents() + : mDoc(0) + { + } + + ~TestStylesComponents() + { + if(mDoc) { + delete mDoc; + mDoc = 0; + } + } + + void SetUp() override + { + L = luaL_newstate(); + luaL_openlibs(L); + ImVue::registerBindings(L); + } + + void TearDown() override + { + if(mDoc) { + delete mDoc; + mDoc = 0; + } + lua_close(L); + } + + ImVue::Document& createDoc(const char* path) + { + if(mDoc) { + delete mDoc; + } + + ImVue::ElementFactory* factory = ImVue::createElementFactory(); + factory->element("test"); + + ImVue::Context* ctx = ImVue::createContext(factory, new ImVue::LuaScriptState(L)); + ImVue::Document doc(ctx); + char* data = ctx->fs->load(path); + try { + mDoc = new ImVue::Document(ctx); + mDoc->parse(data); + } catch(...) { + delete mDoc; + ImGui::MemFree(data); + throw; + } + ImGui::MemFree(data); + + return *mDoc; + } + + private: + ImVue::Document* mDoc; + lua_State* L; +}; + +TEST_F(TestStylesComponents, Dimensions) +{ + ImVue::Document& d = createDoc("dimensions.xml"); + ImVector els = d.getChildren("#check", true); + + ASSERT_GT(els.size(), 0); + + renderDocument(d); + + ImVue::HtmlContainer* div = els[0]; + EXPECT_EQ(div->computedSize.x, 300); + EXPECT_EQ(div->computedSize.y, 300); +} + +#endif