Checkpoint

Progress on tab focus
This commit is contained in:
Jonathan Johnson 2023-11-07 15:16:29 -08:00
parent 8a2dae3f76
commit 5e5d826267
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
12 changed files with 383 additions and 105 deletions

View file

@ -12,11 +12,12 @@ use kludgine::shapes::{Shape, StrokeOptions};
use kludgine::Kludgine;
use crate::graphics::Graphics;
use crate::styles::components::HighlightColor;
use crate::styles::components::{HighlightColor, VisualOrder};
use crate::styles::{ComponentDefaultvalue, ComponentDefinition, Styles};
use crate::value::Dynamic;
use crate::widget::{EventHandling, ManagedWidget, WidgetId, WidgetInstance};
use crate::window::{sealed, RunningWindow};
use crate::widget::{EventHandling, ManagedWidget, WidgetId, WidgetInstance, WidgetRef};
use crate::window::sealed::WindowCommand;
use crate::window::RunningWindow;
use crate::ConstraintLimit;
/// A context to an event function.
@ -48,11 +49,17 @@ impl<'context, 'window> EventContext<'context, 'window> {
/// parent widget needs to invoke events on a child widget. This is done by
/// creating an `EventContext` pointing to the child and calling the
/// appropriate function to invoke the event.
pub fn for_other<'child>(
pub fn for_other<'child, Widget>(
&'child mut self,
widget: ManagedWidget,
) -> EventContext<'child, 'window> {
EventContext::new(self.widget.for_other(widget), self.kludgine)
widget: &Widget,
) -> <Widget::Managed as MapManagedWidget<EventContext<'child, 'window>>>::Result
where
Widget: ManageWidget,
Widget::Managed: MapManagedWidget<EventContext<'child, 'window>>,
{
widget
.manage(self)
.map(|managed| EventContext::new(self.widget.for_other(&managed), self.kludgine))
}
/// Invokes [`Widget::hit_test()`](crate::widget::Widget::hit_test) on this
@ -145,11 +152,11 @@ impl<'context, 'window> EventContext<'context, 'window> {
pub(crate) fn hover(&mut self, location: Point<Px>) {
let changes = self.current_node.tree.hover(Some(&self.current_node));
for unhovered in changes.unhovered {
let mut context = self.for_other(unhovered.clone());
let mut context = self.for_other(&unhovered);
unhovered.lock().as_widget().unhover(&mut context);
}
for hover in changes.hovered {
let mut context = self.for_other(hover.clone());
let mut context = self.for_other(&hover);
hover.lock().as_widget().hover(location, &mut context);
}
}
@ -159,7 +166,7 @@ impl<'context, 'window> EventContext<'context, 'window> {
assert!(changes.hovered.is_empty());
for old_hover in changes.unhovered {
let mut old_hover_context = self.for_other(old_hover.clone());
let mut old_hover_context = self.for_other(&old_hover);
old_hover.lock().as_widget().unhover(&mut old_hover_context);
}
}
@ -170,7 +177,7 @@ impl<'context, 'window> EventContext<'context, 'window> {
let new = match self.current_node.tree.activate(active.as_ref()) {
Ok(old) => {
if let Some(old) = old {
let mut old_context = self.for_other(old.clone());
let mut old_context = self.for_other(&old);
old.lock().as_widget().deactivate(&mut old_context);
}
true
@ -182,7 +189,7 @@ impl<'context, 'window> EventContext<'context, 'window> {
active
.lock()
.as_widget()
.activate(&mut self.for_other(active.clone()));
.activate(&mut self.for_other(active));
}
self.pending_state.active = active;
}
@ -194,19 +201,19 @@ impl<'context, 'window> EventContext<'context, 'window> {
if focus
.lock()
.as_widget()
.accept_focus(&mut self.for_other(focus.clone()))
.accept_focus(&mut self.for_other(&focus))
{
break Some(focus);
} else if let Some(next_focus) = focus.next_focus() {
focus = next_focus;
} else {
break self.next_focus_after(focus);
break self.next_focus_after(focus, VisualOrder::left_to_right());
}
});
let new = match self.current_node.tree.focus(focus.as_ref()) {
Ok(old) => {
if let Some(old) = old {
let mut old_context = self.for_other(old.clone());
let mut old_context = self.for_other(&old);
old.lock().as_widget().blur(&mut old_context);
}
true
@ -215,26 +222,27 @@ impl<'context, 'window> EventContext<'context, 'window> {
};
if new {
if let Some(focus) = &focus {
focus
.lock()
.as_widget()
.focus(&mut self.for_other(focus.clone()));
focus.lock().as_widget().focus(&mut self.for_other(focus));
}
self.pending_state.focus = focus;
}
}
}
fn next_focus_after(&mut self, mut focus: ManagedWidget) -> Option<ManagedWidget> {
fn next_focus_after(
&mut self,
mut focus: ManagedWidget,
order: VisualOrder,
) -> Option<ManagedWidget> {
// First, look within the current focus for any focusable children.
let stop_at = focus.id();
if let Some(focus) = self.next_focus_within(&focus, None, stop_at) {
if let Some(focus) = self.next_focus_within(&focus, None, stop_at, order) {
return Some(focus);
}
// Now, look for the next widget in each hierarchy
let root = loop {
if let Some(focus) = self.next_focus_sibling(&focus, stop_at) {
if let Some(focus) = self.next_focus_sibling(&focus, stop_at, order) {
return Some(focus);
}
let Some(parent) = focus.parent() else {
@ -245,15 +253,16 @@ impl<'context, 'window> EventContext<'context, 'window> {
// We've exhausted a forward scan, we can now start searching the final
// parent, which is the root.
self.next_focus_within(&root, None, stop_at)
self.next_focus_within(&root, None, stop_at, order)
}
fn next_focus_sibling(
&mut self,
focus: &ManagedWidget,
stop_at: WidgetId,
order: VisualOrder,
) -> Option<ManagedWidget> {
self.next_focus_within(&focus.parent()?, Some(focus.id()), stop_at)
self.next_focus_within(&focus.parent()?, Some(focus.id()), stop_at, order)
}
/// Searches for the next focus inside of `focus`, returning `None` if
@ -264,21 +273,22 @@ impl<'context, 'window> EventContext<'context, 'window> {
focus: &ManagedWidget,
start_at: Option<WidgetId>,
stop_at: WidgetId,
order: VisualOrder,
) -> Option<ManagedWidget> {
let child_layouts = focus.child_layouts();
// TODO visually sort the layouts
let mut child_layouts = child_layouts.into_iter().peekable();
let mut children = focus
.visually_ordered_children(order)
.into_iter()
.peekable();
if let Some(start_at) = start_at {
// Skip all children up to `start_at`
while child_layouts.peek()?.0.id() != start_at {
child_layouts.next();
while children.peek()?.id() != start_at {
children.next();
}
// Skip `start_at`
child_layouts.next();
children.next();
}
for (child, _layout) in child_layouts {
for child in children {
// Ensure we haven't cycled completely.
if stop_at == child.id() {
break;
@ -287,16 +297,20 @@ impl<'context, 'window> EventContext<'context, 'window> {
if child
.lock()
.as_widget()
.accept_focus(&mut self.for_other(child.clone()))
.accept_focus(&mut self.for_other(&child))
{
return Some(child);
} else if let Some(focus) = self.next_focus_within(&child, None, stop_at) {
} else if let Some(focus) = self.next_focus_within(&child, None, stop_at, order) {
return Some(focus);
}
}
None
}
pub fn advance_focus(&mut self, direction: VisualOrder) {
self.pending_state.focus = self.next_focus_after(self.current_node.clone(), direction);
}
}
impl<'context, 'window> Deref for EventContext<'context, 'window> {
@ -362,19 +376,27 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> GraphicsContext<'context, 'window, '
/// Returns a new `GraphicsContext` that allows invoking graphics functions
/// for `widget`.
pub fn for_other<'child>(
pub fn for_other<'child, Widget>(
&'child mut self,
widget: ManagedWidget,
) -> GraphicsContext<'child, 'window, 'child, 'gfx, 'pass> {
let widget = self.widget.for_other(widget);
let layout = widget.last_layout().map_or_else(
|| Rect::from(self.graphics.clip_rect().size).into_signed(),
|rect| rect - self.graphics.region().origin,
);
GraphicsContext {
widget,
graphics: Exclusive::Owned(self.graphics.clipped_to(layout)),
}
widget: &Widget,
) -> <Widget::Managed as MapManagedWidget<
GraphicsContext<'child, 'window, 'child, 'gfx, 'pass>,
>>::Result
where
Widget: ManageWidget,
Widget::Managed: MapManagedWidget<GraphicsContext<'child, 'window, 'child, 'gfx, 'pass>>,
{
widget.manage(self).map(|widget| {
let widget = self.widget.for_other(&widget);
let layout = widget.last_layout().map_or_else(
|| Rect::from(self.graphics.clip_rect().size).into_signed(),
|rect| rect - self.graphics.region().origin,
);
GraphicsContext {
widget,
graphics: Exclusive::Owned(self.graphics.clipped_to(layout)),
}
})
}
/// Returns a new graphics context that renders to the `clip` rectangle.
@ -468,17 +490,18 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> LayoutContext<'context, 'window, 'cl
/// Returns a new `LayoutContext` that allows invoking layout functions for
/// `widget`.
pub fn for_other<'child, 'widget>(
pub fn for_other<'child, Widget>(
&'child mut self,
widget: ManagedWidget,
) -> LayoutContext<'child, 'window, 'child, 'gfx, 'pass>
widget: &Widget,
) -> <Widget::Managed as MapManagedWidget<LayoutContext<'child, 'window, 'child, 'gfx, 'pass>>>::Result
where
'widget: 'child,
Widget: ManageWidget,
Widget::Managed: MapManagedWidget<LayoutContext<'child, 'window, 'child, 'gfx, 'pass>>,
{
LayoutContext {
graphics: self.graphics.for_other(widget),
widget.manage(self).map(|widget| LayoutContext {
graphics: self.graphics.for_other(&widget),
persist_layout: self.persist_layout,
}
})
}
/// Invokes [`Widget::layout()`](crate::widget::Widget::layout) on this
@ -541,21 +564,21 @@ pub trait AsEventContext<'window> {
pushed_widget
.lock()
.as_widget()
.mounted(&mut context.for_other(pushed_widget.clone()));
.mounted(&mut context.for_other(&pushed_widget));
pushed_widget
}
/// Removes a widget from the hierarchy.
fn remove_child(&mut self, child: &ManagedWidget) {
let mut context = self.as_event_context();
child
.lock()
.as_widget()
.unmounted(&mut context.for_other(child));
context
.current_node
.tree
.remove_child(child, &context.current_node);
child
.lock()
.as_widget()
.unmounted(&mut context.for_other(child.clone()));
}
}
@ -616,16 +639,20 @@ impl<'context, 'window> WidgetContext<'context, 'window> {
}
/// Returns a new context representing `widget`.
pub fn for_other<'child>(
pub fn for_other<'child, Widget>(
&'child mut self,
widget: ManagedWidget,
) -> WidgetContext<'child, 'window> {
WidgetContext {
current_node: widget,
widget: &Widget,
) -> <Widget::Managed as MapManagedWidget<WidgetContext<'child, 'window>>>::Result
where
Widget: ManageWidget,
Widget::Managed: MapManagedWidget<WidgetContext<'child, 'window>>,
{
widget.manage(self).map(|current_node| WidgetContext {
current_node,
redraw_status: self.redraw_status,
window: &mut *self.window,
pending_state: self.pending_state.borrowed(),
}
})
}
pub(crate) fn parent(&self) -> Option<ManagedWidget> {
@ -792,14 +819,14 @@ impl<'context, 'window> WidgetContext<'context, 'window> {
}
pub(crate) struct WindowHandle {
kludgine: kludgine::app::WindowHandle<sealed::WindowCommand>,
kludgine: kludgine::app::WindowHandle<WindowCommand>,
redraw_status: RedrawStatus,
}
impl WindowHandle {
pub fn redraw(&self) {
if self.redraw_status.should_send_refresh() {
let _result = self.kludgine.send(sealed::WindowCommand::Redraw);
let _result = self.kludgine.send(WindowCommand::Redraw);
}
}
}
@ -880,3 +907,57 @@ impl RedrawStatus {
self.refresh_sent.store(false, Ordering::Release);
}
}
pub trait ManageWidget {
type Managed: MapManagedWidget<ManagedWidget>;
fn manage(&self, context: &WidgetContext<'_, '_>) -> Self::Managed;
}
impl ManageWidget for WidgetInstance {
type Managed = Option<ManagedWidget>;
fn manage(&self, context: &WidgetContext<'_, '_>) -> Self::Managed {
context.current_node.tree.widget(self.id())
}
}
impl ManageWidget for WidgetRef {
type Managed = Option<ManagedWidget>;
fn manage(&self, context: &WidgetContext<'_, '_>) -> Self::Managed {
match self {
WidgetRef::Unmounted(instance) => context.current_node.tree.widget(instance.id()),
WidgetRef::Mounted(instance) => Some(instance.clone()),
}
}
}
impl ManageWidget for ManagedWidget {
type Managed = Self;
fn manage(&self, _context: &WidgetContext<'_, '_>) -> Self::Managed {
self.clone()
}
}
pub trait MapManagedWidget<T> {
type Result;
fn map(self, map: impl FnOnce(ManagedWidget) -> T) -> Self::Result;
}
impl<T> MapManagedWidget<T> for Option<ManagedWidget> {
type Result = Option<T>;
fn map(self, map: impl FnOnce(ManagedWidget) -> T) -> Self::Result {
self.map(map)
}
}
impl<T> MapManagedWidget<T> for ManagedWidget {
type Result = T;
fn map(self, map: impl FnOnce(ManagedWidget) -> T) -> Self::Result {
map(self)
}
}

View file

@ -1,7 +1,8 @@
//! All style components supported by the built-in widgets.
use std::borrow::Cow;
use kludgine::figures::units::Lp;
use kludgine::figures::units::{Lp, Px};
use kludgine::figures::Rect;
use kludgine::Color;
use crate::animation::easings::{EaseInQuadradic, EaseOutQuadradic};
@ -160,3 +161,94 @@ impl ComponentDefinition for EasingOut {
EasingFunction::from(EaseOutQuadradic)
}
}
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct VisualOrder {
pub horizontal: HorizontalOrder,
pub vertical: VerticalOrder,
}
impl VisualOrder {
#[must_use]
pub const fn right_to_left() -> Self {
Self {
horizontal: HorizontalOrder::RightToLeft,
vertical: VerticalOrder::TopToBottom,
}
}
#[must_use]
pub const fn left_to_right() -> Self {
Self {
horizontal: HorizontalOrder::LeftToRight,
vertical: VerticalOrder::TopToBottom,
}
}
#[must_use]
pub fn rev(self) -> Self {
Self {
horizontal: self.horizontal.rev(),
vertical: self.vertical.rev(),
}
}
}
impl NamedComponent for VisualOrder {
fn name(&self) -> Cow<'_, ComponentName> {
Cow::Owned(ComponentName::named::<Global>("visual_order"))
}
}
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum HorizontalOrder {
LeftToRight,
RightToLeft,
}
impl HorizontalOrder {
#[must_use]
pub fn rev(self) -> Self {
match self {
Self::LeftToRight => Self::RightToLeft,
Self::RightToLeft => Self::LeftToRight,
}
}
pub fn sort_key(self, rect: &Rect<Px>) -> Px {
match self {
HorizontalOrder::LeftToRight => rect.origin.x,
HorizontalOrder::RightToLeft => -(rect.origin.x + rect.size.width),
}
}
}
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum VerticalOrder {
TopToBottom,
BottomToTop,
}
impl VerticalOrder {
#[must_use]
pub fn rev(self) -> Self {
match self {
Self::TopToBottom => VerticalOrder::BottomToTop,
Self::BottomToTop => VerticalOrder::TopToBottom,
}
}
pub fn max_px(self) -> Px {
match self {
VerticalOrder::TopToBottom => Px::MAX,
VerticalOrder::BottomToTop => Px::MIN,
}
}
pub fn smallest_px(self, a: Px, b: Px) -> Px {
match self {
VerticalOrder::TopToBottom => a.min(b),
VerticalOrder::BottomToTop => b.max(a),
}
}
}

View file

@ -5,6 +5,7 @@ use std::sync::{Arc, Mutex, PoisonError};
use kludgine::figures::units::Px;
use kludgine::figures::{Point, Rect};
use crate::styles::components::VisualOrder;
use crate::styles::{ComponentDefaultvalue, ComponentDefinition, ComponentType, Styles};
use crate::widget::{ManagedWidget, WidgetId, WidgetInstance};
@ -86,17 +87,63 @@ impl Tree {
}
}
pub(crate) fn child_layouts(&self, parent: WidgetId) -> Vec<(ManagedWidget, Rect<Px>)> {
pub(crate) fn visually_ordered_children(
&self,
parent: WidgetId,
order: VisualOrder,
) -> Vec<ManagedWidget> {
let data = self.data.lock().map_or_else(PoisonError::into_inner, |g| g);
data.nodes[&parent]
.children
.iter()
.filter_map(|id| {
data.nodes[id]
let node = &data.nodes[&parent];
let mut unordered = node.children.clone();
let mut ordered = Vec::<ManagedWidget>::with_capacity(unordered.len());
loop {
// Identify the next "row" of widgets by finding the top of a widget that is the closest to the origin of
let mut min_vertical = order.vertical.max_px();
let mut max_vertical = order.vertical.max_px();
let mut index = 0;
while index < unordered.len() {
let Some(layout) = &data.nodes[&unordered[index]].layout else {
unordered.remove(index);
continue;
};
let top = layout.origin.y;
let bottom = top + layout.size.height;
min_vertical = order.vertical.smallest_px(min_vertical, top);
max_vertical = order.vertical.smallest_px(min_vertical, bottom);
index += 1;
}
if unordered.is_empty() {
break;
}
// Find all widgets whose top is within the range found.
index = 0;
let row_base = ordered.len();
while index < unordered.len() {
let top_left = data.nodes[&unordered[index]]
.layout
.map(|layout| (data.widget(*id, self).expect("child still owned"), layout))
})
.collect()
.expect("all have layouts")
.origin;
if min_vertical <= top_left.y && top_left.y <= max_vertical {
ordered.push(
data.widget(unordered.remove(index), self)
.expect("widget is owned"),
);
} else {
index += 1;
}
}
ordered[row_base..].sort_unstable_by_key(|managed| {
order
.horizontal
.sort_key(&data.nodes[&managed.id()].layout.expect("all have layouts"))
});
}
ordered
}
pub(crate) fn hover(&self, new_hover: Option<&ManagedWidget>) -> HoverResults {

View file

@ -57,6 +57,8 @@ impl_all_tuples!(impl_with_clone);
pub trait ModifiersExt {
fn primary(&self) -> bool;
fn word_select(&self) -> bool;
fn possible_shortcut(&self) -> bool;
}
impl ModifiersExt for ModifiersState {
@ -79,6 +81,10 @@ impl ModifiersExt for ModifiersState {
fn word_select(&self) -> bool {
self.control_key()
}
fn possible_shortcut(&self) -> bool {
self.control_key() || self.alt_key() || self.super_key()
}
}
impl ModifiersExt for Modifiers {
@ -89,6 +95,10 @@ impl ModifiersExt for Modifiers {
fn word_select(&self) -> bool {
self.state().word_select()
}
fn possible_shortcut(&self) -> bool {
self.state().word_select()
}
}
pub struct Lazy<T> {

View file

@ -15,6 +15,7 @@ use kludgine::figures::units::{Px, UPx};
use kludgine::figures::{Point, Rect, Size};
use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContext};
use crate::styles::components::VisualOrder;
use crate::styles::Styles;
use crate::tree::Tree;
use crate::value::{IntoValue, Value};
@ -194,14 +195,14 @@ pub trait MakeWidget: Sized {
/// [`WidgetId`].
pub trait MakeWidgetWithId: Sized {
/// Returns a new [`WidgetInstance`] whose [`WidgetId`] is `id`.
fn make_with_id(self, id: PendingWidgetId) -> WidgetInstance;
fn make_with_id(self, id: WidgetTag) -> WidgetInstance;
}
impl<T> MakeWidgetWithId for T
where
T: Widget,
{
fn make_with_id(self, id: PendingWidgetId) -> WidgetInstance {
fn make_with_id(self, id: WidgetTag) -> WidgetInstance {
WidgetInstance::with_id(self, id)
}
}
@ -211,7 +212,7 @@ where
T: MakeWidgetWithId,
{
fn make_widget(self) -> WidgetInstance {
self.make_with_id(PendingWidgetId::unique())
self.make_with_id(WidgetTag::unique())
}
}
@ -267,7 +268,7 @@ pub struct WidgetInstance {
impl WidgetInstance {
/// Returns a new instance containing `widget` that is assigned the unique
/// `id` provided.
pub fn with_id<W>(widget: W, id: PendingWidgetId) -> Self
pub fn with_id<W>(widget: W, id: WidgetTag) -> Self
where
W: Widget,
{
@ -283,7 +284,7 @@ impl WidgetInstance {
where
W: Widget,
{
Self::with_id(widget, PendingWidgetId::unique())
Self::with_id(widget, WidgetTag::unique())
}
/// Returns the unique id of this widget instance.
@ -330,6 +331,11 @@ impl WidgetInstance {
self.next_focus.get()
}
}
impl AsRef<WidgetId> for WidgetInstance {
fn as_ref(&self) -> &WidgetId {
&self.id
}
}
impl Eq for WidgetInstance {}
@ -484,8 +490,14 @@ impl ManagedWidget {
self.tree.reset_child_layouts(self.id());
}
pub(crate) fn child_layouts(&self) -> Vec<(ManagedWidget, Rect<Px>)> {
self.tree.child_layouts(self.id())
pub(crate) fn visually_ordered_children(&self, order: VisualOrder) -> Vec<ManagedWidget> {
self.tree.visually_ordered_children(self.id(), order)
}
}
impl AsRef<WidgetId> for ManagedWidget {
fn as_ref(&self) -> &WidgetId {
self.widget.as_ref()
}
}
@ -631,6 +643,15 @@ impl WidgetRef {
}
}
impl AsRef<WidgetId> for WidgetRef {
fn as_ref(&self) -> &WidgetId {
match self {
WidgetRef::Unmounted(widget) => widget.as_ref(),
WidgetRef::Mounted(widget) => widget.as_ref(),
}
}
}
/// The unique id of a [`WidgetInstance`].
///
/// Each [`WidgetInstance`] is guaranteed to have a unique [`WidgetId`] across
@ -654,9 +675,17 @@ impl WidgetId {
/// assigned a given [`WidgetId`]. The contained [`WidgetId`] can be accessed
/// via [`id()`](Self::id), `Into<WidgetId>`, or `Deref`.
#[derive(Eq, PartialEq, Debug)]
pub struct PendingWidgetId(WidgetId);
pub struct WidgetTag(WidgetId);
impl WidgetTag {
/// Returns a unique tag and its contained id.
#[must_use]
pub fn new() -> (Self, WidgetId) {
let tag = Self::unique();
let id = *tag;
(tag, id)
}
impl PendingWidgetId {
/// Returns a newly allocated [`WidgetId`] that is guaranteed to be unique
/// for the lifetime of the application.
#[must_use]
@ -671,13 +700,13 @@ impl PendingWidgetId {
}
}
impl From<PendingWidgetId> for WidgetId {
fn from(value: PendingWidgetId) -> Self {
impl From<WidgetTag> for WidgetId {
fn from(value: WidgetTag) -> Self {
value.0
}
}
impl Deref for PendingWidgetId {
impl Deref for WidgetTag {
type Target = WidgetId;
fn deref(&self) -> &Self::Target {

View file

@ -47,7 +47,7 @@ impl Align {
);
let child = self.child.mounted(&mut context.as_event_context());
let content_size = context.for_other(child).layout(content_available);
let content_size = context.for_other(&child).layout(content_available);
let (left, right, width) = horizontal.measure(available_space.width, content_size.width);
let (top, bottom, height) = vertical.measure(available_space.height, content_size.height);
@ -128,7 +128,7 @@ impl FrameInfo {
impl Widget for Align {
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
let child = self.child.mounted(&mut context.as_event_context());
context.for_other(child).redraw();
context.for_other(&child).redraw();
}
fn layout(

View file

@ -49,7 +49,7 @@ impl Expand {
impl Widget for Expand {
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
let child = self.child.mounted(&mut context.as_event_context());
context.for_other(child).redraw();
context.for_other(&child).redraw();
}
fn layout(
@ -62,7 +62,7 @@ impl Widget for Expand {
ConstraintLimit::Known(available_space.height.max()),
);
let child = self.child.mounted(&mut context.as_event_context());
let size = context.for_other(child.clone()).layout(available_space);
let size = context.for_other(&child).layout(available_space);
context.set_child_layout(&child, Rect::from(size.into_signed()));
size
}

View file

@ -60,7 +60,7 @@ impl Resize {
impl Widget for Resize {
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
let child = self.child.mounted(&mut context.as_event_context());
context.for_other(child).redraw();
context.for_other(&child).redraw();
}
fn layout(
@ -83,7 +83,8 @@ impl Widget for Resize {
),
);
let child = self.child.mounted(&mut context.as_event_context());
context.for_other(child).layout(available_space)
// TODO set_child_layout
context.for_other(&child).layout(available_space)
}
}
}

View file

@ -12,7 +12,7 @@ use kludgine::shapes::Shape;
use kludgine::Color;
use crate::animation::{AnimationHandle, AnimationTarget, IntoAnimate, Spawn, ZeroToOne};
use crate::context::{AsEventContext, EventContext};
use crate::context::{AsEventContext, EventContext, LayoutContext};
use crate::styles::components::{EasingIn, EasingOut};
use crate::styles::{
ComponentDefinition, ComponentGroup, ComponentName, Dimension, NamedComponent,
@ -126,7 +126,7 @@ impl Widget for Scroll {
let visible_bottom_right = visible_rect.into_signed().extent();
let managed = self.contents.mounted(&mut context.as_event_context());
context.for_other(managed).redraw();
context.for_other(&managed).redraw();
if self.horizontal_bar.amount_hidden > 0 {
context.graphics.draw_shape(
@ -167,8 +167,8 @@ impl Widget for Scroll {
fn layout(
&mut self,
available_space: Size<crate::ConstraintLimit>,
context: &mut crate::context::LayoutContext<'_, '_, '_, '_, '_>,
available_space: Size<ConstraintLimit>,
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
) -> Size<UPx> {
let styles = context.query_styles(&[&ScrollBarThickness]);
self.bar_width = styles
@ -192,7 +192,7 @@ impl Widget for Scroll {
);
let managed = self.contents.mounted(&mut context.as_event_context());
let new_content_size = context
.for_other(managed.clone())
.for_other(&managed)
.layout(max_extents)
.into_signed();

View file

@ -132,7 +132,7 @@ impl Stack {
impl Widget for Stack {
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
for child in &self.synced_children {
context.for_other(child.clone()).redraw();
context.for_other(child).redraw();
}
}
@ -147,7 +147,7 @@ impl Widget for Stack {
available_space,
context.graphics.scale(),
|child_index, constraints, persist| {
let mut context = context.for_other(self.synced_children[child_index].clone());
let mut context = context.for_other(&self.synced_children[child_index]);
if !persist {
context = context.as_temporary();
}

View file

@ -31,7 +31,7 @@ impl Widget for Style {
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
let child = self.child.mounted(&mut context.as_event_context());
context.for_other(child).redraw();
context.for_other(&child).redraw();
}
fn layout(
@ -40,6 +40,6 @@ impl Widget for Style {
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
) -> Size<UPx> {
let child = self.child.mounted(&mut context.as_event_context());
context.for_other(child).layout(available_space)
context.for_other(&child).layout(available_space)
}
}

View file

@ -25,6 +25,7 @@ use crate::context::{
WidgetContext,
};
use crate::graphics::Graphics;
use crate::styles::components::VisualOrder;
use crate::tree::Tree;
use crate::utils::ModifiersExt;
use crate::widget::{EventHandling, ManagedWidget, Widget, WidgetInstance, HANDLED, IGNORED};
@ -316,6 +317,23 @@ where
window.set_needs_redraw();
}
}
KeyCode::Tab
if !window.modifiers().state().possible_shortcut()
&& input.state.is_pressed() =>
{
let direction = if window.modifiers().state().shift_key() {
VisualOrder::left_to_right().rev()
} else {
VisualOrder::left_to_right()
};
let target = self.root.tree.focused_widget().unwrap_or(self.root.id());
let target = self.root.tree.widget(target).expect("missing widget");
let mut target = EventContext::new(
WidgetContext::new(target, &self.redraw_status, &mut window),
kludgine,
);
target.advance_focus(direction);
}
_ => {}
}
}
@ -401,7 +419,7 @@ where
);
self.mouse_state.widget = None;
for widget in self.root.tree.widgets_at_point(location) {
let mut widget_context = context.for_other(widget.clone());
let mut widget_context = context.for_other(&widget);
let relative = location
- widget_context
.last_layout()
@ -527,7 +545,7 @@ fn recursively_handle_event(
match each_widget(context) {
HANDLED => Some(context.widget().clone()),
IGNORED => context.parent().and_then(|parent| {
recursively_handle_event(&mut context.for_other(parent), each_widget)
recursively_handle_event(&mut context.for_other(&parent), each_widget)
}),
}
}