feat: Implement Phase A UI hierarchy foundations (closes #122, #102, #116, #118)

Parent-Child UI System (#122):
- Add parent weak_ptr to UIDrawable for hierarchy tracking
- Add setParent(), getParent(), removeFromParent() methods
- UICollection now tracks owner and sets parent on append/insert
- Auto-remove from old parent when adding to new collection

Global Position Property (#102):
- Add get_global_position() that walks up parent chain
- Expose as read-only 'global_position' property on all UI types
- Add UIDRAWABLE_PARENT_GETSETTERS macro for consistent bindings

Dirty Flag System (#116):
- Modify markDirty() to propagate up the parent chain
- Add isDirty() and clearDirty() methods for render optimization

Scene as Drawable (#118):
- Add position, visible, opacity properties to Scene
- Add setProperty()/getProperty() for animation support
- Apply scene transformations in PyScene::render()
- Fix lifecycle callbacks to clear errors when methods don't exist
- Add GameEngine::getScene() public accessor

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
John McCardle 2025-11-27 16:33:17 -05:00
commit e3d8f54d46
19 changed files with 988 additions and 67 deletions

View file

@ -5,6 +5,7 @@
#include "IndexTexture.h"
#include "Resources.h"
#include <list>
#include <memory>
#include "PyCallable.h"
#include "PyTexture.h"
@ -73,9 +74,28 @@ public:
// Name for finding elements
std::string name;
// Position in pixel coordinates (moved from derived classes)
sf::Vector2f position;
// Parent-child hierarchy (#122)
std::weak_ptr<UIDrawable> parent;
// Set the parent of this drawable (called by collections when adding)
void setParent(std::shared_ptr<UIDrawable> new_parent);
// Get the parent drawable (returns nullptr if no parent or expired)
std::shared_ptr<UIDrawable> getParent() const;
// Remove this drawable from its current parent's children
void removeFromParent();
// Get the global (screen) position by walking up the parent chain (#102)
sf::Vector2f get_global_position() const;
// Python API for parent/global_position
static PyObject* get_parent(PyObject* self, void* closure);
static PyObject* get_global_pos(PyObject* self, void* closure);
// New properties for Phase 1
bool visible = true; // #87 - visibility flag
@ -117,13 +137,20 @@ protected:
void updateRenderTexture();
public:
// Mark this drawable as needing redraw
void markDirty() { render_dirty = true; }
// Mark this drawable as needing redraw (#116 - propagates up parent chain)
void markDirty();
// Check if this drawable needs redraw
bool isDirty() const { return render_dirty; }
// Clear dirty flag (called after rendering)
void clearDirty() { render_dirty = false; }
};
typedef struct {
PyObject_HEAD
std::shared_ptr<std::vector<std::shared_ptr<UIDrawable>>> data;
std::weak_ptr<UIDrawable> owner; // #122: Parent drawable (for Frame.children, Grid.children)
} PyUICollectionObject;
typedef struct {