Remove focus concept from `pane_grid`
This commit is contained in:
parent
d0402d072d
commit
5681c83d3c
|
@ -11,6 +11,7 @@ pub fn main() -> iced::Result {
|
||||||
struct Example {
|
struct Example {
|
||||||
panes: pane_grid::State<Content>,
|
panes: pane_grid::State<Content>,
|
||||||
panes_created: usize,
|
panes_created: usize,
|
||||||
|
focus: Option<pane_grid::Pane>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
@ -33,6 +34,7 @@ impl Sandbox for Example {
|
||||||
Example {
|
Example {
|
||||||
panes,
|
panes,
|
||||||
panes_created: 1,
|
panes_created: 1,
|
||||||
|
focus: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +54,7 @@ impl Sandbox for Example {
|
||||||
self.panes_created += 1;
|
self.panes_created += 1;
|
||||||
}
|
}
|
||||||
Message::SplitFocused(axis) => {
|
Message::SplitFocused(axis) => {
|
||||||
if let Some(pane) = self.panes.active() {
|
if let Some(pane) = self.focus {
|
||||||
let _ = self.panes.split(
|
let _ = self.panes.split(
|
||||||
axis,
|
axis,
|
||||||
&pane,
|
&pane,
|
||||||
|
@ -63,11 +65,11 @@ impl Sandbox for Example {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::FocusAdjacent(direction) => {
|
Message::FocusAdjacent(direction) => {
|
||||||
if let Some(pane) = self.panes.active() {
|
if let Some(pane) = self.focus {
|
||||||
if let Some(adjacent) =
|
if let Some(adjacent) =
|
||||||
self.panes.adjacent(&pane, direction)
|
self.panes.adjacent(&pane, direction)
|
||||||
{
|
{
|
||||||
self.panes.focus(&adjacent);
|
self.focus = Some(adjacent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,7 +87,7 @@ impl Sandbox for Example {
|
||||||
let _ = self.panes.close(&pane);
|
let _ = self.panes.close(&pane);
|
||||||
}
|
}
|
||||||
Message::CloseFocused => {
|
Message::CloseFocused => {
|
||||||
if let Some(pane) = self.panes.active() {
|
if let Some(pane) = self.focus {
|
||||||
let _ = self.panes.close(&pane);
|
let _ = self.panes.close(&pane);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,11 +95,12 @@ impl Sandbox for Example {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&mut self) -> Element<Message> {
|
fn view(&mut self) -> Element<Message> {
|
||||||
|
let focus = self.focus;
|
||||||
let total_panes = self.panes.len();
|
let total_panes = self.panes.len();
|
||||||
|
|
||||||
let pane_grid =
|
let pane_grid = PaneGrid::new(&mut self.panes, |pane, content| {
|
||||||
PaneGrid::new(&mut self.panes, |pane, content, focus| {
|
let is_focused = focus == Some(pane);
|
||||||
let is_focused = focus.is_some();
|
|
||||||
let title_bar =
|
let title_bar =
|
||||||
pane_grid::TitleBar::new(format!("Pane {}", content.id))
|
pane_grid::TitleBar::new(format!("Pane {}", content.id))
|
||||||
.padding(10)
|
.padding(10)
|
||||||
|
@ -111,8 +114,7 @@ impl Sandbox for Example {
|
||||||
.height(Length::Fill)
|
.height(Length::Fill)
|
||||||
.spacing(10)
|
.spacing(10)
|
||||||
.on_drag(Message::Dragged)
|
.on_drag(Message::Dragged)
|
||||||
.on_resize(10, Message::Resized)
|
.on_resize(10, Message::Resized);
|
||||||
.on_key_press(handle_hotkey);
|
|
||||||
|
|
||||||
Container::new(pane_grid)
|
Container::new(pane_grid)
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
|
|
|
@ -73,7 +73,7 @@ use crate::{
|
||||||
/// let (mut state, _) = pane_grid::State::new(PaneState::SomePane);
|
/// let (mut state, _) = pane_grid::State::new(PaneState::SomePane);
|
||||||
///
|
///
|
||||||
/// let pane_grid =
|
/// let pane_grid =
|
||||||
/// PaneGrid::new(&mut state, |pane, state, focus| {
|
/// PaneGrid::new(&mut state, |pane, state| {
|
||||||
/// pane_grid::Content::new(match state {
|
/// pane_grid::Content::new(match state {
|
||||||
/// PaneState::SomePane => Text::new("This is some pane"),
|
/// PaneState::SomePane => Text::new("This is some pane"),
|
||||||
/// PaneState::AnotherKindOfPane => Text::new("This is another kind of pane"),
|
/// PaneState::AnotherKindOfPane => Text::new("This is another kind of pane"),
|
||||||
|
@ -92,10 +92,8 @@ pub struct PaneGrid<'a, Message, Renderer: self::Renderer> {
|
||||||
width: Length,
|
width: Length,
|
||||||
height: Length,
|
height: Length,
|
||||||
spacing: u16,
|
spacing: u16,
|
||||||
modifier_keys: keyboard::ModifiersState,
|
|
||||||
on_drag: Option<Box<dyn Fn(DragEvent) -> Message + 'a>>,
|
on_drag: Option<Box<dyn Fn(DragEvent) -> Message + 'a>>,
|
||||||
on_resize: Option<(u16, Box<dyn Fn(ResizeEvent) -> Message + 'a>)>,
|
on_resize: Option<(u16, Box<dyn Fn(ResizeEvent) -> Message + 'a>)>,
|
||||||
on_key_press: Option<Box<dyn Fn(KeyPressEvent) -> Option<Message> + 'a>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, Renderer> PaneGrid<'a, Message, Renderer>
|
impl<'a, Message, Renderer> PaneGrid<'a, Message, Renderer>
|
||||||
|
@ -112,31 +110,13 @@ where
|
||||||
/// [`Pane`]: struct.Pane.html
|
/// [`Pane`]: struct.Pane.html
|
||||||
pub fn new<T>(
|
pub fn new<T>(
|
||||||
state: &'a mut State<T>,
|
state: &'a mut State<T>,
|
||||||
view: impl Fn(
|
view: impl Fn(Pane, &'a mut T) -> Content<'a, Message, Renderer>,
|
||||||
Pane,
|
|
||||||
&'a mut T,
|
|
||||||
Option<Focus>,
|
|
||||||
) -> Content<'a, Message, Renderer>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let elements = {
|
let elements = {
|
||||||
let action = state.internal.action();
|
|
||||||
let current_focus = action.focus();
|
|
||||||
|
|
||||||
state
|
state
|
||||||
.panes
|
.panes
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.map(move |(pane, pane_state)| {
|
.map(move |(pane, pane_state)| (*pane, view(*pane, pane_state)))
|
||||||
let focus = match current_focus {
|
|
||||||
Some((focused_pane, focus))
|
|
||||||
if *pane == focused_pane =>
|
|
||||||
{
|
|
||||||
Some(focus)
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
(*pane, view(*pane, pane_state, focus))
|
|
||||||
})
|
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -146,13 +126,8 @@ where
|
||||||
width: Length::Fill,
|
width: Length::Fill,
|
||||||
height: Length::Fill,
|
height: Length::Fill,
|
||||||
spacing: 0,
|
spacing: 0,
|
||||||
modifier_keys: keyboard::ModifiersState {
|
|
||||||
control: true,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
on_drag: None,
|
on_drag: None,
|
||||||
on_resize: None,
|
on_resize: None,
|
||||||
on_key_press: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,21 +155,6 @@ where
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the modifier keys of the [`PaneGrid`].
|
|
||||||
///
|
|
||||||
/// The modifier keys will need to be pressed to trigger key events.
|
|
||||||
///
|
|
||||||
/// The default modifier key is `Ctrl`.
|
|
||||||
///
|
|
||||||
/// [`PaneGrid`]: struct.PaneGrid.html
|
|
||||||
pub fn modifier_keys(
|
|
||||||
mut self,
|
|
||||||
modifier_keys: keyboard::ModifiersState,
|
|
||||||
) -> Self {
|
|
||||||
self.modifier_keys = modifier_keys;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enables the drag and drop interactions of the [`PaneGrid`], which will
|
/// Enables the drag and drop interactions of the [`PaneGrid`], which will
|
||||||
/// use the provided function to produce messages.
|
/// use the provided function to produce messages.
|
||||||
///
|
///
|
||||||
|
@ -225,31 +185,6 @@ where
|
||||||
self.on_resize = Some((leeway, Box::new(f)));
|
self.on_resize = Some((leeway, Box::new(f)));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Captures hotkey interactions with the [`PaneGrid`], using the provided
|
|
||||||
/// function to produce messages.
|
|
||||||
///
|
|
||||||
/// The function will be called when:
|
|
||||||
/// - a [`Pane`] is focused
|
|
||||||
/// - a key is pressed
|
|
||||||
/// - all the modifier keys are pressed
|
|
||||||
///
|
|
||||||
/// If the function returns `None`, the key press event will be discarded
|
|
||||||
/// without producing any message.
|
|
||||||
///
|
|
||||||
/// This method is particularly useful to implement hotkey interactions.
|
|
||||||
/// For instance, you can use it to enable splitting, swapping, or resizing
|
|
||||||
/// panes by pressing combinations of keys.
|
|
||||||
///
|
|
||||||
/// [`PaneGrid`]: struct.PaneGrid.html
|
|
||||||
/// [`Pane`]: struct.Pane.html
|
|
||||||
pub fn on_key_press<F>(mut self, f: F) -> Self
|
|
||||||
where
|
|
||||||
F: 'a + Fn(KeyPressEvent) -> Option<Message>,
|
|
||||||
{
|
|
||||||
self.on_key_press = Some(Box::new(f));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, Renderer> PaneGrid<'a, Message, Renderer>
|
impl<'a, Message, Renderer> PaneGrid<'a, Message, Renderer>
|
||||||
|
@ -280,13 +215,9 @@ where
|
||||||
|
|
||||||
messages
|
messages
|
||||||
.push(on_drag(DragEvent::Picked { pane: *pane }));
|
.push(on_drag(DragEvent::Picked { pane: *pane }));
|
||||||
} else {
|
|
||||||
self.state.focus(pane);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {}
|
||||||
self.state.focus(pane);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -495,17 +426,10 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// TODO: Encode cursor availability in the type system
|
|
||||||
if cursor_position.x > 0.0 && cursor_position.y > 0.0 {
|
|
||||||
self.state.unfocus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mouse::Event::ButtonReleased(mouse::Button::Left) => {
|
mouse::Event::ButtonReleased(mouse::Button::Left) => {
|
||||||
if let Some((pane, _)) = self.state.picked_pane() {
|
if let Some((pane, _)) = self.state.picked_pane() {
|
||||||
self.state.focus(&pane);
|
|
||||||
|
|
||||||
if let Some(on_drag) = &self.on_drag {
|
if let Some(on_drag) = &self.on_drag {
|
||||||
let mut dropped_region = self
|
let mut dropped_region = self
|
||||||
.elements
|
.elements
|
||||||
|
@ -527,8 +451,10 @@ where
|
||||||
|
|
||||||
messages.push(on_drag(event));
|
messages.push(on_drag(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.state.idle();
|
||||||
} else if self.state.picked_split().is_some() {
|
} else if self.state.picked_split().is_some() {
|
||||||
self.state.drop_split();
|
self.state.idle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mouse::Event::CursorMoved { .. } => {
|
mouse::Event::CursorMoved { .. } => {
|
||||||
|
@ -536,31 +462,6 @@ where
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
Event::Keyboard(keyboard_event) => {
|
|
||||||
match keyboard_event {
|
|
||||||
keyboard::Event::KeyPressed {
|
|
||||||
modifiers,
|
|
||||||
key_code,
|
|
||||||
} => {
|
|
||||||
if let Some(on_key_press) = &self.on_key_press {
|
|
||||||
// TODO: Discard when event is captured
|
|
||||||
if let Some(_) = self.state.active_pane() {
|
|
||||||
if modifiers.matches(self.modifier_keys) {
|
|
||||||
if let Some(message) =
|
|
||||||
on_key_press(KeyPressEvent {
|
|
||||||
key_code,
|
|
||||||
modifiers,
|
|
||||||
})
|
|
||||||
{
|
|
||||||
messages.push(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ impl<T> State<T> {
|
||||||
internal: Internal {
|
internal: Internal {
|
||||||
layout,
|
layout,
|
||||||
last_id,
|
last_id,
|
||||||
action: Action::Idle { focus: None },
|
action: Action::Idle,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,45 +122,10 @@ impl<T> State<T> {
|
||||||
&self.internal.layout
|
&self.internal.layout
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the focused [`Pane`] of the [`State`], if there is one.
|
|
||||||
///
|
|
||||||
/// [`Pane`]: struct.Pane.html
|
|
||||||
/// [`State`]: struct.State.html
|
|
||||||
pub fn focused(&self) -> Option<Pane> {
|
|
||||||
self.internal.focused_pane()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the active [`Pane`] of the [`State`], if there is one.
|
|
||||||
///
|
|
||||||
/// A [`Pane`] is active if it is focused and is __not__ being dragged.
|
|
||||||
///
|
|
||||||
/// [`Pane`]: struct.Pane.html
|
|
||||||
/// [`State`]: struct.State.html
|
|
||||||
pub fn active(&self) -> Option<Pane> {
|
|
||||||
self.internal.active_pane()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the adjacent [`Pane`] of another [`Pane`] in the given
|
/// Returns the adjacent [`Pane`] of another [`Pane`] in the given
|
||||||
/// direction, if there is one.
|
/// direction, if there is one.
|
||||||
///
|
///
|
||||||
/// ## Example
|
|
||||||
/// You can combine this with [`State::active`] to find the pane that is
|
|
||||||
/// adjacent to the current active one, and then swap them. For instance:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use iced_native::pane_grid;
|
|
||||||
/// #
|
|
||||||
/// # let (mut state, _) = pane_grid::State::new(());
|
|
||||||
/// #
|
|
||||||
/// if let Some(active) = state.active() {
|
|
||||||
/// if let Some(adjacent) = state.adjacent(&active, pane_grid::Direction::Right) {
|
|
||||||
/// state.swap(&active, &adjacent);
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`Pane`]: struct.Pane.html
|
/// [`Pane`]: struct.Pane.html
|
||||||
/// [`State::active`]: struct.State.html#method.active
|
|
||||||
pub fn adjacent(&self, pane: &Pane, direction: Direction) -> Option<Pane> {
|
pub fn adjacent(&self, pane: &Pane, direction: Direction) -> Option<Pane> {
|
||||||
let regions = self
|
let regions = self
|
||||||
.internal
|
.internal
|
||||||
|
@ -194,20 +159,6 @@ impl<T> State<T> {
|
||||||
Some(*pane)
|
Some(*pane)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Focuses the given [`Pane`].
|
|
||||||
///
|
|
||||||
/// [`Pane`]: struct.Pane.html
|
|
||||||
pub fn focus(&mut self, pane: &Pane) {
|
|
||||||
self.internal.focus(pane);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unfocuses the current focused [`Pane`].
|
|
||||||
///
|
|
||||||
/// [`Pane`]: struct.Pane.html
|
|
||||||
pub fn unfocus(&mut self) {
|
|
||||||
self.internal.unfocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Splits the given [`Pane`] into two in the given [`Axis`] and
|
/// Splits the given [`Pane`] into two in the given [`Axis`] and
|
||||||
/// initializing the new [`Pane`] with the provided internal state.
|
/// initializing the new [`Pane`] with the provided internal state.
|
||||||
///
|
///
|
||||||
|
@ -236,7 +187,6 @@ impl<T> State<T> {
|
||||||
node.split(new_split, axis, new_pane);
|
node.split(new_split, axis, new_pane);
|
||||||
|
|
||||||
let _ = self.panes.insert(new_pane, state);
|
let _ = self.panes.insert(new_pane, state);
|
||||||
self.focus(&new_pane);
|
|
||||||
|
|
||||||
Some((new_pane, new_split))
|
Some((new_pane, new_split))
|
||||||
}
|
}
|
||||||
|
@ -281,8 +231,7 @@ impl<T> State<T> {
|
||||||
///
|
///
|
||||||
/// [`Pane`]: struct.Pane.html
|
/// [`Pane`]: struct.Pane.html
|
||||||
pub fn close(&mut self, pane: &Pane) -> Option<T> {
|
pub fn close(&mut self, pane: &Pane) -> Option<T> {
|
||||||
if let Some(sibling) = self.internal.layout.remove(pane) {
|
if let Some(_) = self.internal.layout.remove(pane) {
|
||||||
self.focus(&sibling);
|
|
||||||
self.panes.remove(pane)
|
self.panes.remove(pane)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -329,52 +278,12 @@ pub struct Internal {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
Idle {
|
Idle,
|
||||||
focus: Option<Pane>,
|
Dragging { pane: Pane, origin: Point },
|
||||||
},
|
Resizing { split: Split, axis: Axis },
|
||||||
Dragging {
|
|
||||||
pane: Pane,
|
|
||||||
origin: Point,
|
|
||||||
focus: Option<Pane>,
|
|
||||||
},
|
|
||||||
Resizing {
|
|
||||||
split: Split,
|
|
||||||
axis: Axis,
|
|
||||||
focus: Option<Pane>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Action {
|
|
||||||
pub fn focus(&self) -> Option<(Pane, Focus)> {
|
|
||||||
match self {
|
|
||||||
Action::Idle { focus } | Action::Resizing { focus, .. } => {
|
|
||||||
focus.map(|pane| (pane, Focus::Idle))
|
|
||||||
}
|
|
||||||
Action::Dragging { pane, .. } => Some((*pane, Focus::Dragging)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Internal {
|
impl Internal {
|
||||||
pub fn action(&self) -> Action {
|
|
||||||
self.action
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn focused_pane(&self) -> Option<Pane> {
|
|
||||||
match self.action {
|
|
||||||
Action::Idle { focus } => focus,
|
|
||||||
Action::Dragging { focus, .. } => focus,
|
|
||||||
Action::Resizing { focus, .. } => focus,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn active_pane(&self) -> Option<Pane> {
|
|
||||||
match self.action {
|
|
||||||
Action::Idle { focus } => focus,
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn picked_pane(&self) -> Option<(Pane, Point)> {
|
pub fn picked_pane(&self) -> Option<(Pane, Point)> {
|
||||||
match self.action {
|
match self.action {
|
||||||
Action::Dragging { pane, origin, .. } => Some((pane, origin)),
|
Action::Dragging { pane, origin, .. } => Some((pane, origin)),
|
||||||
|
@ -405,17 +314,10 @@ impl Internal {
|
||||||
self.layout.split_regions(spacing, size)
|
self.layout.split_regions(spacing, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn focus(&mut self, pane: &Pane) {
|
|
||||||
self.action = Action::Idle { focus: Some(*pane) };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pick_pane(&mut self, pane: &Pane, origin: Point) {
|
pub fn pick_pane(&mut self, pane: &Pane, origin: Point) {
|
||||||
let focus = self.focused_pane();
|
|
||||||
|
|
||||||
self.action = Action::Dragging {
|
self.action = Action::Dragging {
|
||||||
pane: *pane,
|
pane: *pane,
|
||||||
origin,
|
origin,
|
||||||
focus,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,26 +328,14 @@ impl Internal {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let focus = self.action.focus().map(|(pane, _)| pane);
|
|
||||||
|
|
||||||
self.action = Action::Resizing {
|
self.action = Action::Resizing {
|
||||||
split: *split,
|
split: *split,
|
||||||
axis,
|
axis,
|
||||||
focus,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drop_split(&mut self) {
|
pub fn idle(&mut self) {
|
||||||
match self.action {
|
self.action = Action::Idle;
|
||||||
Action::Resizing { focus, .. } => {
|
|
||||||
self.action = Action::Idle { focus };
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unfocus(&mut self) {
|
|
||||||
self.action = Action::Idle { focus: None };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hash_layout(&self, hasher: &mut Hasher) {
|
pub fn hash_layout(&self, hasher: &mut Hasher) {
|
||||||
|
|
Loading…
Reference in New Issue