I recently learned about this design pattern where you have an integer ID for your "things" and then various arrays containing the "components" that make up those things. The pattern is sometimes called "struct of arrays" or "entity component system" (ECS). I'm trying to use this idea in a fledgling UI library I'm tinkering with. I'm using the slotmap
crate for the "arrays".
Maybe I need to forget about trait objects here, but they seem very nice for some things. I had a UI Widget
trait that had methods related to layout, rendering, and event handling. Eg:
trait Widget {
fn try_layout(&mut self, w: f32, h: f32) -> LayoutTry;
fn layout_decision(&mut self, w: f32, h: f32);
fn render(&self, rc: &RenderContext, ...)
...
}
Those layout methods implement a kind of "layout protocol". The VStack
struct, for example, implemented them to layout children widgets in a vertical stack. I'm tempted to keep these dynamic pieces around, even in the data oriented design. Something like:
widget_geometry: SlotMap<WidgetGeometry>, // location, size,
widget_tree: SecondaryMap<WidgetId, WidgetTreeInfo>, // parents, children
widget_layout: SecondaryMap<WidgetId, Box<dyn WidgetLayout>>
In effect the widget_layout
array would contain vtables for the layout functions. The weird thing is, what is self
for those functions? I supposed I could create a kind of proxy struct that contained only the WidgetId
(the slot map integer ID).
struct VStackId { id: WidgetId }
impl WidgetLayout for VStackId { .... }
So I'm wondering if anything has been written about this already. So I don't re-invent wheels here.
1 post - 1 participant