Fixes a systemic bug where Python tp_getset property setters bypassed the
render cache dirty flag system (#144). The animation/C++ setProperty() path
had correct dirty propagation, but direct Python property assignments
(e.g. frame.x = 50, caption.text = "Hello") did not invalidate the parent
Frame's render cache when clip_children or cache_subtree was enabled.
Changes by file:
- UIDrawable.cpp: Add markCompositeDirty() to set_float_member (x/y),
set_pos, set_grid_pos; add markDirty() for w/h resize
- UICaption.cpp: Add markDirty() to set_text, set_color_member,
set_float_member (outline/font_size); markCompositeDirty() for position
- UICollection.cpp: Add markContentDirty() on owner in append, remove,
pop, insert, extend, setitem, and slice assignment/deletion
- UISprite.cpp: Add markDirty() to scale/sprite_index/texture setters;
markCompositeDirty() to position setters
- UICircle.cpp: Add markDirty() to radius/fill_color/outline_color/outline;
markCompositeDirty() to center setter
- UILine.cpp: Add markDirty() to start/end/color/thickness setters
- UIArc.cpp: Add markDirty() to radius/angles/color/thickness setters;
markCompositeDirty() to center setter
- UIGrid.cpp: Add markDirty() to center/zoom/camera_rotation/fill_color/
size/perspective/fov setters
Closes#288, closes#289, closes#290, closes#291
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace ~230 occurrences of PyObject_GetAttrString(McRFPy_API::mcrf_module, "TypeName")
with direct &mcrfpydef::PyXxxType references across 32 source files.
Each PyObject_GetAttrString call returns a new reference. When used inline
in PyObject_IsInstance(), that reference was immediately leaked. When used
for tp_alloc, the reference required careful Py_DECREF management that was
often missing on error paths.
Direct type references are compile-time constants that never need reference
counting, eliminating ~230 potential leak sites and removing ~100 lines of
Py_DECREF/Py_XDECREF cleanup code.
Also adds extractDrawable() helper in UICollection.cpp to replace repeated
8-way type-check-and-extract chains with a single function call.
Closes#267, closes#268
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
UIDrawables placed in a Grid's children collection now have:
- grid_pos: Position in tile coordinates (get/set)
- grid_size: Size in tile coordinates (get/set)
Raises RuntimeError if accessed when parent is not a Grid.
UIGrid only gets grid_pos (grid_size conflicts with existing property).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
McRogueFace needs to accept callable objects (properties on C++ objects)
and also support subclassing (getattr on user objects). Only direct
properties were supported previously, now shadowing a callback by name
will allow custom objects to "just work".
- Added CallbackCache struct and is_python_subclass flag to UIDrawable.h
- Created metaclass for tracking class-level callback changes
- Updated all UI type init functions to detect subclasses
- Modified PyScene.cpp event dispatch to try subclass methods
BREAKING CHANGE: Constructor keyword argument renamed from `click` to
`on_click` for all UIDrawable types (Frame, Caption, Sprite, Grid, Line,
Circle, Arc).
Before: Frame(pos=(0,0), size=(100,100), click=handler)
After: Frame(pos=(0,0), size=(100,100), on_click=handler)
The property name was already `on_click` - this makes the constructor
kwarg match, completing the callback naming standardization from #139.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add cache_subtree property on Frame for opt-in RenderTexture caching
- Add PyTexture::from_rendered() factory for runtime texture creation
- Add snapshot= parameter to Sprite for creating sprites from Frame content
- Implement content_dirty vs composite_dirty distinction:
- markContentDirty(): content changed, invalidate self and ancestors
- markCompositeDirty(): position changed, ancestors need recomposite only
- Update all UIDrawable position setters to use markCompositeDirty()
- Add quick exit workaround for cleanup segfaults
Benchmark: deep_nesting_cached is 3.7x faster (0.09ms vs 0.35ms)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Breaking change: callback property standardized to on_* pattern.
- `drawable.click` → `drawable.on_click`
Updated all C++ bindings (8 files) and Python test usages.
Note: src/scripts changes tracked separately (in .gitignore).
This establishes the naming pattern for future callbacks:
on_click, on_enter, on_exit, on_move, on_key, etc.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
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>
Implement new UIDrawable-derived classes for vector graphics:
- UILine: Thick line segments using sf::ConvexShape for proper thickness
- Properties: start, end, color, thickness
- Supports click detection along the line
- UICircle: Filled and outlined circles using sf::CircleShape
- Properties: radius, center, fill_color, outline_color, outline
- Full property system for animations
- UIArc: Arc segments for orbital paths and partial circles
- Properties: center, radius, start_angle, end_angle, color, thickness
- Uses sf::VertexArray with TriangleStrip for smooth rendering
- Supports arbitrary angle spans including negative (reverse) arcs
All primitives integrate with the Python API through mcrfpy module:
- Added to PyObjectsEnum for type identification
- Full getter/setter support for all properties
- Added to UICollection for scene management
- Support for visibility, opacity, z_index, name, and click handling
closes#128, closes#129🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>