Created
June 18, 2019 14:49
-
-
Save raphlinus/25a64eb7ce4a4d2012944d4ff22130ea to your computer and use it in GitHub Desktop.
Very rough sketch of parent-owns widget scheme
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Sketch of new widget scheme for druid. Some pseudocode within. | |
| /// Base of a widget. | |
| /// | |
| /// Name should likely change, this name is chosen to express | |
| /// what's actually in it. | |
| pub struct Base<W: WidgetInner> { | |
| state: BaseState, | |
| inner: W, | |
| } | |
| /// Per-widget state. | |
| /// | |
| /// This mostly corresponds to state stored in a Vec in current druid | |
| /// `Ui` and `LayoutCtx`. | |
| pub struct BaseState { | |
| geom: Geometry, | |
| is_active: bool, | |
| is_hot: bool, | |
| is_focused: bool, | |
| // Rename to needs_anim_frame? | |
| is_animating: bool, | |
| needs_layout: bool, | |
| // Future: paint rect... | |
| } | |
| /// A trait expressing widget behavior and appearance. | |
| /// | |
| /// This is broadly similar to the existing Widget trait in druid. | |
| pub trait WidgetInner { | |
| fn paint(&mut self, paint_ctx: &mut PaintCtx, base_state: &BaseState, env: &Env); | |
| fn layout(&mut self, layout_ctx: &mut LayoutCtx, bc: &BoxConstraints, env: &Env) -> Geometry; | |
| fn event(&mut self, event: &Event, ctx, env) -> Option<Action>; | |
| /// Value in env is new value; delta can be used to recover old value. | |
| fn delta(&mut self, delta: &Delta, ctx, env); | |
| /// Send arbitrary data to a widget. | |
| /// | |
| /// Likely to be little-used. Path is used to route (when path matches exactly, widget | |
| /// can consume). | |
| fn poke(&mut self, &Any, ctx, env); | |
| } | |
| pub struct Env { | |
| path: Path, | |
| value: Value, | |
| // more stuff for looking up theme data etc. | |
| } | |
| pub enum Event { | |
| MouseEvent(...), | |
| KeyEvent(...), | |
| FocusChanged, | |
| ... | |
| } | |
| impl Base { | |
| pub fn paint(&mut self, paint_ctx: &mut PaintCtx, env: &Env) { | |
| if self.state.paint_rect.intersect(paint_ctx.rect) { | |
| self.inner.paint(paint_ctx, &self.state, env); | |
| } | |
| } | |
| pub fn layout(...) { | |
| // Note: could cache here, avoiding recursive call | |
| self.inner.layout(...); | |
| } | |
| pub fn delta(...) { | |
| if env.path.intersects(path) { | |
| self.inner.delta(...) | |
| } | |
| } | |
| pub fn event(...) -> Option<Action> { | |
| // use self.state.is_active etc to route | |
| } | |
| } | |
| struct TypicalContainer { | |
| // Note: dyn is only needed for heterogeneous children | |
| // | |
| // The path here is a *relative* path, to be joined | |
| children: Vec<(Path, Base<Box<dyn WidgetInner>>)>, | |
| } | |
| impl WidgetInner for TypicalContainer { | |
| fn paint(&mut self, ...) { | |
| for (path, child) in &mut self.children { | |
| // Note: because this is used so pervasively, maybe most `Base` methods | |
| // include a relative path to join as an extra arg; this would also reduce | |
| // the risk of accidentally forgetting to do so. | |
| let child_env = env.join_path(path); | |
| child.paint(paint_ctx, child_env); | |
| } | |
| } | |
| fn event(&mut self, ...) { | |
| for (path, child) in &mut self.children { | |
| let child_env = env.join_path(path); | |
| let action = child.event(ctx, event, child_env); | |
| if action.is_some() { | |
| return action; | |
| } | |
| } | |
| None | |
| } | |
| fn layout(&mut self, ...) { | |
| // call layout on children in arbitrary order | |
| } | |
| fn delta(...) { | |
| } | |
| fn poke(...) { | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment