[Bugfix] UIFrame: Child appearance changes don't invalidate parent's cached texture #225

Closed
opened 2026-01-22 15:48:56 +00:00 by john · 0 comments
Owner

Summary

When a Frame uses clip_children=True or cache_subtree=True, children are rendered to a RenderTexture. However, changes to child properties (color, text, sprite index, etc.) don't reliably invalidate the parent's cached texture.

Root Cause

The dirty propagation in UIDrawable::markContentDirty() (lines 909-919) has issues:

void UIDrawable::markContentDirty() {
    if (render_dirty) return;  // ← Early return if already dirty
    
    render_dirty = true;
    composite_dirty = true;
    
    auto p = parent.lock();
    if (p) {
        p->markContentDirty();  // ← Propagate up
    }
}

Issues

  1. Early return: If render_dirty is already true, propagation stops. Parent may not be notified.

  2. Weak pointer expiration: If parent.lock() returns nullptr (weak_ptr expired), propagation fails silently.

  3. No propagation for some setters: Not all property setters call markDirty(). Some call markCompositeDirty() which only propagates position changes, not content changes.

Symptoms

  • Change child Caption's text → parent texture not updated
  • Change child Frame's fill_color → parent texture not updated
  • Change child Sprite's sprite_index → parent texture not updated

Until something else triggers a full redraw.

Proposed Fix

  1. Remove or rethink the early return in markContentDirty()
  2. Audit all property setters to ensure they call appropriate dirty method
  3. Consider adding debug logging when parent.lock() fails
## Summary When a Frame uses `clip_children=True` or `cache_subtree=True`, children are rendered to a RenderTexture. However, changes to child properties (color, text, sprite index, etc.) don't reliably invalidate the parent's cached texture. ## Root Cause The dirty propagation in `UIDrawable::markContentDirty()` (lines 909-919) has issues: ```cpp void UIDrawable::markContentDirty() { if (render_dirty) return; // ← Early return if already dirty render_dirty = true; composite_dirty = true; auto p = parent.lock(); if (p) { p->markContentDirty(); // ← Propagate up } } ``` ### Issues 1. **Early return**: If `render_dirty` is already true, propagation stops. Parent may not be notified. 2. **Weak pointer expiration**: If `parent.lock()` returns nullptr (weak_ptr expired), propagation fails silently. 3. **No propagation for some setters**: Not all property setters call `markDirty()`. Some call `markCompositeDirty()` which only propagates position changes, not content changes. ## Symptoms - Change child Caption's text → parent texture not updated - Change child Frame's fill_color → parent texture not updated - Change child Sprite's sprite_index → parent texture not updated Until something else triggers a full redraw. ## Proposed Fix 1. Remove or rethink the early return in `markContentDirty()` 2. Audit all property setters to ensure they call appropriate dirty method 3. Consider adding debug logging when parent.lock() fails
john closed this issue 2026-01-23 03:56:05 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
john/McRogueFace#225
No description provided.