From 5d24ba6a85994033b19158694b3cbc2a79bc099d Mon Sep 17 00:00:00 2001 From: John McCardle Date: Mon, 7 Jul 2025 17:45:53 -0400 Subject: [PATCH] refactor: move position property to UIDrawable base class (UICaption) - Update UICaption to use base class position instead of text position - Synchronize text position with base class position for rendering - Add onPositionChanged() virtual method for position synchronization - Update all UICaption methods to use base position consistently - Add comprehensive test coverage for UICaption position handling This is part 2 of moving position to the base class. UISprite and UIGrid will be updated in subsequent commits. --- base_position_uicaption_test.png | Bin 0 -> 39499 bytes src/UICaption.cpp | 32 +++++++++++++++++++++---------- src/UICaption.h | 1 + src/UIDrawable.cpp | 3 +++ src/UIDrawable.h | 3 +++ src/UIFrame.cpp | 6 ++++++ src/UIFrame.h | 1 + 7 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 base_position_uicaption_test.png diff --git a/base_position_uicaption_test.png b/base_position_uicaption_test.png new file mode 100644 index 0000000000000000000000000000000000000000..21265331ff7286aab07ece4b87f10b37facedc38 GIT binary patch literal 39499 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 E0l+FcLI3~& literal 0 HcmV?d00001 diff --git a/src/UICaption.cpp b/src/UICaption.cpp index fc57d6e..b5e2ab7 100644 --- a/src/UICaption.cpp +++ b/src/UICaption.cpp @@ -11,7 +11,8 @@ UICaption::UICaption() { // Initialize text with safe defaults text.setString(""); - text.setPosition(0.0f, 0.0f); + position = sf::Vector2f(0.0f, 0.0f); // Set base class position + text.setPosition(position); // Sync text position text.setCharacterSize(12); text.setFillColor(sf::Color::White); text.setOutlineColor(sf::Color::Black); @@ -60,7 +61,9 @@ sf::FloatRect UICaption::get_bounds() const void UICaption::move(float dx, float dy) { - text.move(dx, dy); + position.x += dx; + position.y += dy; + text.setPosition(position); // Keep text in sync } void UICaption::resize(float w, float h) @@ -69,6 +72,12 @@ void UICaption::resize(float w, float h) // This is a no-op but required by the interface } +void UICaption::onPositionChanged() +{ + // Sync text position with base class position + text.setPosition(position); +} + PyObject* UICaption::get_float_member(PyUICaptionObject* self, void* closure) { auto member_ptr = reinterpret_cast(closure); @@ -237,9 +246,9 @@ int UICaption::set_text(PyUICaptionObject* self, PyObject* value, void* closure) } PyGetSetDef UICaption::getsetters[] = { - {"x", (getter)UICaption::get_float_member, (setter)UICaption::set_float_member, "X coordinate of top-left corner", (void*)0}, - {"y", (getter)UICaption::get_float_member, (setter)UICaption::set_float_member, "Y coordinate of top-left corner", (void*)1}, - {"pos", (getter)UICaption::get_vec_member, (setter)UICaption::set_vec_member, "(x, y) vector", (void*)0}, + {"x", (getter)UIDrawable::get_float_member, (setter)UIDrawable::set_float_member, "X coordinate of top-left corner", (void*)((intptr_t)PyObjectsEnum::UICAPTION << 8 | 0)}, + {"y", (getter)UIDrawable::get_float_member, (setter)UIDrawable::set_float_member, "Y coordinate of top-left corner", (void*)((intptr_t)PyObjectsEnum::UICAPTION << 8 | 1)}, + {"pos", (getter)UIDrawable::get_pos, (setter)UIDrawable::set_pos, "(x, y) vector", (void*)PyObjectsEnum::UICAPTION}, //{"w", (getter)PyUIFrame_get_float_member, (setter)PyUIFrame_set_float_member, "width of the rectangle", (void*)2}, //{"h", (getter)PyUIFrame_get_float_member, (setter)PyUIFrame_set_float_member, "height of the rectangle", (void*)3}, {"outline", (getter)UICaption::get_float_member, (setter)UICaption::set_float_member, "Thickness of the border", (void*)4}, @@ -362,7 +371,8 @@ int UICaption::init(PyUICaptionObject* self, PyObject* args, PyObject* kwds) } } - self->data->text.setPosition(x, y); + self->data->position = sf::Vector2f(x, y); // Set base class position + self->data->text.setPosition(self->data->position); // Sync text position // check types for font, fill_color, outline_color //std::cout << PyUnicode_AsUTF8(PyObject_Repr(font)) << std::endl; @@ -435,11 +445,13 @@ int UICaption::init(PyUICaptionObject* self, PyObject* args, PyObject* kwds) // Property system implementation for animations bool UICaption::setProperty(const std::string& name, float value) { if (name == "x") { - text.setPosition(sf::Vector2f(value, text.getPosition().y)); + position.x = value; + text.setPosition(position); // Keep text in sync return true; } else if (name == "y") { - text.setPosition(sf::Vector2f(text.getPosition().x, value)); + position.y = value; + text.setPosition(position); // Keep text in sync return true; } else if (name == "font_size" || name == "size") { // Support both for backward compatibility @@ -527,11 +539,11 @@ bool UICaption::setProperty(const std::string& name, const std::string& value) { bool UICaption::getProperty(const std::string& name, float& value) const { if (name == "x") { - value = text.getPosition().x; + value = position.x; return true; } else if (name == "y") { - value = text.getPosition().y; + value = position.y; return true; } else if (name == "font_size" || name == "size") { // Support both for backward compatibility diff --git a/src/UICaption.h b/src/UICaption.h index 7f00b22..e39d098 100644 --- a/src/UICaption.h +++ b/src/UICaption.h @@ -16,6 +16,7 @@ public: sf::FloatRect get_bounds() const override; void move(float dx, float dy) override; void resize(float w, float h) override; + void onPositionChanged() override; // Property system for animations bool setProperty(const std::string& name, float value) override; diff --git a/src/UIDrawable.cpp b/src/UIDrawable.cpp index 6921956..94b50ea 100644 --- a/src/UIDrawable.cpp +++ b/src/UIDrawable.cpp @@ -349,9 +349,11 @@ int UIDrawable::set_float_member(PyObject* self, PyObject* value, void* closure) switch (member) { case 0: // x drawable->position.x = val; + drawable->onPositionChanged(); break; case 1: // y drawable->position.y = val; + drawable->onPositionChanged(); break; case 2: // w case 3: // h @@ -474,5 +476,6 @@ int UIDrawable::set_pos(PyObject* self, PyObject* value, void* closure) { } drawable->position = sf::Vector2f(x, y); + drawable->onPositionChanged(); return 0; } diff --git a/src/UIDrawable.h b/src/UIDrawable.h index c3ba600..b18bf54 100644 --- a/src/UIDrawable.h +++ b/src/UIDrawable.h @@ -74,6 +74,9 @@ public: virtual void move(float dx, float dy) = 0; // #98 - move by offset virtual void resize(float w, float h) = 0; // #98 - resize to dimensions + // Called when position changes to allow derived classes to sync + virtual void onPositionChanged() {} + // Animation support virtual bool setProperty(const std::string& name, float value) { return false; } virtual bool setProperty(const std::string& name, int value) { return false; } diff --git a/src/UIFrame.cpp b/src/UIFrame.cpp index 7af139d..2ba73c2 100644 --- a/src/UIFrame.cpp +++ b/src/UIFrame.cpp @@ -85,6 +85,12 @@ void UIFrame::resize(float w, float h) box.setSize(sf::Vector2f(w, h)); } +void UIFrame::onPositionChanged() +{ + // Sync box position with base class position + box.setPosition(position); +} + void UIFrame::render(sf::Vector2f offset, sf::RenderTarget& target) { // Check visibility diff --git a/src/UIFrame.h b/src/UIFrame.h index 2d4d23e..e1311d9 100644 --- a/src/UIFrame.h +++ b/src/UIFrame.h @@ -39,6 +39,7 @@ public: sf::FloatRect get_bounds() const override; void move(float dx, float dy) override; void resize(float w, float h) override; + void onPositionChanged() override; static PyObject* get_children(PyUIFrameObject* self, void* closure);