Skip to content

Commit

Permalink
Initial window focus
Browse files Browse the repository at this point in the history
  • Loading branch information
ecton committed Nov 6, 2023
1 parent 0f6d383 commit fbf6134
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 92 deletions.
3 changes: 2 additions & 1 deletion examples/gameui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ fn main() -> gooey::Result {
}
})
.make_widget();
let input_id = input.id();

Expand::new(Stack::rows(children![
Expand::new(Stack::columns(children![
Expand All @@ -47,6 +48,6 @@ fn main() -> gooey::Result {
])),
input.clone(),
]))
.with_next_focus(input)
.with_next_focus(input_id)
.run()
}
36 changes: 30 additions & 6 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ impl<'context, 'window> EventContext<'context, 'window> {

pub(crate) fn apply_pending_state(&mut self) {
let active = self.pending_state.active.clone();
if self.current_node.tree.active_widget() != active.as_ref().map(|active| active.id) {
if self.current_node.tree.active_widget() != active.as_ref().map(ManagedWidget::id) {
let new = match self.current_node.tree.activate(active.as_ref()) {
Ok(old) => {
if let Some(old) = old {
Expand All @@ -178,17 +178,32 @@ impl<'context, 'window> EventContext<'context, 'window> {
Err(_) => false,
};
if new {
if let Some(active) = active {
if let Some(active) = &active {
active
.lock()
.as_widget()
.activate(&mut self.for_other(active.clone()));
}
self.pending_state.active = active;
}
}

let focus = self.pending_state.focus.clone();
if self.current_node.tree.focused_widget() != focus.as_ref().map(|focus| focus.id) {
if self.current_node.tree.focused_widget() != focus.as_ref().map(ManagedWidget::id) {
let focus = focus.and_then(|mut focus| loop {
if focus
.lock()
.as_widget()
.accept_focus(&mut self.for_other(focus.clone()))
{
break Some(focus);
} else if let Some(next_focus) = focus.next_focus() {
focus = next_focus;
} else {
// TODO visually scan the tree for the "next" widget.
break None;
}
});
let new = match self.current_node.tree.focus(focus.as_ref()) {
Ok(old) => {
if let Some(old) = old {
Expand All @@ -200,12 +215,13 @@ impl<'context, 'window> EventContext<'context, 'window> {
Err(_) => false,
};
if new {
if let Some(focus) = focus {
if let Some(focus) = &focus {
focus
.lock()
.as_widget()
.focus(&mut self.for_other(focus.clone()));
}
self.pending_state.focus = focus;
}
}
}
Expand Down Expand Up @@ -324,6 +340,14 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> GraphicsContext<'context, 'window, '
}
}

impl Drop for GraphicsContext<'_, '_, '_, '_, '_> {
fn drop(&mut self) {
if matches!(self.widget.pending_state, PendingState::Owned(_)) {
self.as_event_context().apply_pending_state();
}
}
}

impl<'context, 'window, 'clip, 'gfx, 'pass> Deref
for GraphicsContext<'context, 'window, 'clip, 'gfx, 'pass>
{
Expand Down Expand Up @@ -497,11 +521,11 @@ impl<'context, 'window> WidgetContext<'context, 'window> {
focus: current_node
.tree
.focused_widget()
.map(|id| current_node.tree.widget(id)),
.and_then(|id| current_node.tree.widget(id)),
active: current_node
.tree
.active_widget()
.map(|id| current_node.tree.widget(id)),
.and_then(|id| current_node.tree.widget(id)),
}),
current_node,
redraw_status,
Expand Down
113 changes: 63 additions & 50 deletions src/tree.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::collections::HashMap;
use std::fmt::Debug;
use std::mem;
use std::sync::atomic::{self, AtomicU64};
use std::sync::{Arc, Mutex, PoisonError};

use alot::{LotId, Lots};
use kludgine::figures::units::Px;
use kludgine::figures::{Point, Rect};

Expand All @@ -21,46 +22,54 @@ impl Tree {
parent: Option<&ManagedWidget>,
) -> ManagedWidget {
let mut data = self.data.lock().map_or_else(PoisonError::into_inner, |g| g);
let id = WidgetId(data.nodes.push(Node {
widget: widget.clone(),
children: Vec::new(),
parent: parent.map(|parent| parent.id),
layout: None,
styles: None,
}));
let id = widget.id();
data.nodes.insert(
id,
Node {
widget: widget.clone(),
children: Vec::new(),
parent: parent.map(ManagedWidget::id),
layout: None,
styles: None,
},
);
if let Some(parent) = parent {
let parent = &mut data.nodes[parent.id.0];
let parent = data.nodes.get_mut(&parent.id()).expect("missing parent");
parent.children.push(id);
}
ManagedWidget {
id,
widget,
tree: self.clone(),
}
}

pub fn remove_child(&self, child: &ManagedWidget, parent: &ManagedWidget) {
let mut data = self.data.lock().map_or_else(PoisonError::into_inner, |g| g);
data.remove_child(child.id, parent.id);
data.remove_child(child.id(), parent.id());
}

pub(crate) fn set_layout(&self, widget: WidgetId, rect: Rect<Px>) {
let mut data = self.data.lock().map_or_else(PoisonError::into_inner, |g| g);
rect.extents();
data.nodes[widget.0].layout = Some(rect);

data.render_order.push(widget);
let mut children_to_offset = data.nodes[widget.0].children.clone();
let node = data.nodes.get_mut(&widget).expect("missing widget");
node.layout = Some(rect);
let mut children_to_offset = node.children.clone();
while let Some(child) = children_to_offset.pop() {
if let Some(layout) = &mut data.nodes[child.0].layout {
if let Some(layout) = data
.nodes
.get_mut(&child)
.and_then(|child| child.layout.as_mut())
{
layout.origin += rect.origin;
children_to_offset.extend(data.nodes[child.0].children.iter().copied());
children_to_offset.extend(data.nodes[&child].children.iter().copied());
}
}
}

pub(crate) fn layout(&self, widget: WidgetId) -> Option<Rect<Px>> {
let data = self.data.lock().map_or_else(PoisonError::into_inner, |g| g);
data.nodes[widget.0].layout
data.nodes[&widget].layout
}

pub(crate) fn reset_render_order(&self) {
Expand All @@ -70,20 +79,20 @@ impl Tree {

pub(crate) fn reset_child_layouts(&self, parent: WidgetId) {
let mut data = self.data.lock().map_or_else(PoisonError::into_inner, |g| g);
let children = data.nodes[parent.0].children.clone();
let children = data.nodes[&parent].children.clone();
for child in children {
data.nodes[child.0].layout = None;
data.nodes.get_mut(&child).expect("missing widget").layout = None;
}
}

pub(crate) fn hover(&self, new_hover: Option<&ManagedWidget>) -> HoverResults {
let mut data = self.data.lock().map_or_else(PoisonError::into_inner, |g| g);
let hovered = new_hover
.map(|new_hover| data.widget_hierarchy(new_hover.id, self))
.map(|new_hover| data.widget_hierarchy(new_hover.id(), self))
.unwrap_or_default();
let unhovered = match data.update_tracked_widget(new_hover, self, |data| &mut data.hover) {
Ok(Some(old_hover)) => {
let mut old_hovered = data.widget_hierarchy(old_hover.id, self);
let mut old_hovered = data.widget_hierarchy(old_hover.id(), self);
// For any widgets that were shared, remove them, as they don't
// need to have their events fired again.
let mut new_index = 0;
Expand Down Expand Up @@ -111,7 +120,7 @@ impl Tree {
data.update_tracked_widget(new_active, self, |data| &mut data.active)
}

pub fn widget(&self, id: WidgetId) -> ManagedWidget {
pub fn widget(&self, id: WidgetId) -> Option<ManagedWidget> {
let data = self.data.lock().map_or_else(PoisonError::into_inner, |g| g);
data.widget(id, self)
}
Expand All @@ -137,7 +146,7 @@ impl Tree {
if hovered == id {
return true;
}
search = data.nodes[hovered.0].parent;
search = data.nodes[&hovered].parent;
}

false
Expand All @@ -154,11 +163,10 @@ impl Tree {
let data = self.data.lock().map_or_else(PoisonError::into_inner, |g| g);
let mut hits = Vec::new();
for id in data.render_order.iter().rev() {
if let Some(last_rendered) = data.nodes[id.0].layout {
if let Some(last_rendered) = data.nodes[id].layout {
if last_rendered.contains(point) {
hits.push(ManagedWidget {
id: *id,
widget: data.nodes[id.0].widget.clone(),
widget: data.nodes[id].widget.clone(),
tree: self.clone(),
});
}
Expand All @@ -169,12 +177,12 @@ impl Tree {

pub(crate) fn parent(&self, id: WidgetId) -> Option<WidgetId> {
let data = self.data.lock().map_or_else(PoisonError::into_inner, |g| g);
data.nodes[id.0].parent
data.nodes.get(&id).expect("missing widget").parent
}

pub(crate) fn attach_styles(&self, id: WidgetId, styles: Styles) {
let mut data = self.data.lock().map_or_else(PoisonError::into_inner, |g| g);
data.nodes[id.0].styles = Some(styles);
data.nodes.get_mut(&id).expect("missing widget").styles = Some(styles);
}

pub fn query_styles(
Expand All @@ -185,7 +193,7 @@ impl Tree {
self.data
.lock()
.map_or_else(PoisonError::into_inner, |g| g)
.query_styles(perspective.id, query)
.query_styles(perspective.id(), query)
}

pub fn query_style<Component: ComponentDefinition>(
Expand All @@ -196,7 +204,7 @@ impl Tree {
self.data
.lock()
.map_or_else(PoisonError::into_inner, |g| g)
.query_style(perspective.id, component)
.query_style(perspective.id(), component)
}
}

Expand All @@ -207,25 +215,24 @@ pub(crate) struct HoverResults {

#[derive(Default)]
struct TreeData {
nodes: Lots<Node>,
nodes: HashMap<WidgetId, Node>,
active: Option<WidgetId>,
focus: Option<WidgetId>,
hover: Option<WidgetId>,
render_order: Vec<WidgetId>,
}

impl TreeData {
fn widget(&self, id: WidgetId, tree: &Tree) -> ManagedWidget {
ManagedWidget {
id,
widget: self.nodes[id.0].widget.clone(),
fn widget(&self, id: WidgetId, tree: &Tree) -> Option<ManagedWidget> {
Some(ManagedWidget {
widget: self.nodes.get(&id)?.widget.clone(),
tree: tree.clone(),
}
})
}

fn remove_child(&mut self, child: WidgetId, parent: WidgetId) {
let removed_node = self.nodes.remove(child.0).expect("widget already removed");
let parent = &mut self.nodes[parent.0];
let removed_node = self.nodes.remove(&child).expect("widget already removed");
let parent = self.nodes.get_mut(&parent).expect("missing widget");
let index = parent
.children
.iter()
Expand All @@ -236,16 +243,16 @@ impl TreeData {
let mut detached_nodes = removed_node.children;

while let Some(node) = detached_nodes.pop() {
let mut node = self.nodes.remove(node.0).expect("detached node missing");
let mut node = self.nodes.remove(&node).expect("detached node missing");
detached_nodes.append(&mut node.children);
}
}

pub(crate) fn widget_hierarchy(&self, mut widget: WidgetId, tree: &Tree) -> Vec<ManagedWidget> {
let mut hierarchy = Vec::new();
loop {
hierarchy.push(self.widget(widget, tree));
let Some(parent) = self.nodes[widget.0].parent else {
while let Some(managed) = self.widget(widget, tree) {
hierarchy.push(managed);
let Some(parent) = self.nodes[&widget].parent else {
break;
};
widget = parent;
Expand All @@ -263,13 +270,12 @@ impl TreeData {
property: impl FnOnce(&mut Self) -> &mut Option<WidgetId>,
) -> Result<Option<ManagedWidget>, ()> {
match (
mem::replace(property(self), new_widget.map(|w| w.id)),
mem::replace(property(self), new_widget.map(ManagedWidget::id)),
new_widget,
) {
(Some(old_widget), Some(new_widget)) if old_widget == new_widget.id => Err(()),
(Some(old_widget), Some(new_widget)) if old_widget == new_widget.id() => Err(()),
(Some(old_widget), _) => Ok(Some(ManagedWidget {
id: old_widget,
widget: self.nodes[old_widget.0].widget.clone(),
widget: self.nodes[&old_widget].widget.clone(),
tree: tree.clone(),
})),
(None, _) => Ok(None),
Expand All @@ -284,7 +290,7 @@ impl TreeData {
let mut query = query.iter().map(|n| n.name()).collect::<Vec<_>>();
let mut resolved = Styles::new();
while !query.is_empty() {
let node = &self.nodes[perspective.0];
let node = &self.nodes[&perspective];
if let Some(styles) = &node.styles {
query.retain(|name| {
if let Some(component) = styles.get(name) {
Expand All @@ -308,7 +314,7 @@ impl TreeData {
) -> Component::ComponentType {
let name = query.name();
loop {
let node = &self.nodes[perspective.0];
let node = &self.nodes[&perspective];
if let Some(styles) = &node.styles {
if let Some(component) = styles.get(&name) {
let Ok(value) =
Expand All @@ -334,5 +340,12 @@ pub struct Node {
pub styles: Option<Styles>,
}

#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub struct WidgetId(LotId);
#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash)]
pub struct WidgetId(u64);

impl WidgetId {
pub fn unique() -> Self {
static COUNTER: AtomicU64 = AtomicU64::new(0);
Self(COUNTER.fetch_add(1, atomic::Ordering::Acquire))
}
}
2 changes: 1 addition & 1 deletion src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ impl<T> Value<T> {
}

/// Returns a clone of the currently stored value.
pub fn get(&mut self) -> T
pub fn get(&self) -> T
where
T: Clone,
{
Expand Down
Loading

0 comments on commit fbf6134

Please sign in to comment.