summaryrefslogtreecommitdiffstats
path: root/widget/src/combo_box.rs
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-08-30 04:31:21 +0200
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-08-30 04:31:21 +0200
commited3454301e663a7cb7d73cd56b57b188f4d14a2f (patch)
tree8118d1305c2eba3a1b45d04634cd0e8d050fc0fa /widget/src/combo_box.rs
parentc9bd48704dd9679c033dd0b8588e2744a3df44a0 (diff)
downloadiced-ed3454301e663a7cb7d73cd56b57b188f4d14a2f.tar.gz
iced-ed3454301e663a7cb7d73cd56b57b188f4d14a2f.tar.bz2
iced-ed3454301e663a7cb7d73cd56b57b188f4d14a2f.zip
Implement explicit text caching in the widget state tree
Diffstat (limited to 'widget/src/combo_box.rs')
-rw-r--r--widget/src/combo_box.rs167
1 files changed, 75 insertions, 92 deletions
diff --git a/widget/src/combo_box.rs b/widget/src/combo_box.rs
index 690ef27c..8c20ae8e 100644
--- a/widget/src/combo_box.rs
+++ b/widget/src/combo_box.rs
@@ -144,11 +144,6 @@ where
self
}
- /// Returns whether the [`ComboBox`] is currently focused or not.
- pub fn is_focused(&self) -> bool {
- self.state.is_focused()
- }
-
/// Sets the text sixe of the [`ComboBox`].
pub fn size(mut self, size: f32) -> Self {
self.text_input = self.text_input.size(size);
@@ -179,7 +174,6 @@ pub struct State<T>(RefCell<Inner<T>>);
#[derive(Debug, Clone)]
struct Inner<T> {
- text_input: text_input::State,
value: String,
options: Vec<T>,
option_matchers: Vec<String>,
@@ -216,7 +210,6 @@ where
);
Self(RefCell::new(Inner {
- text_input: text_input::State::new(),
value,
options,
option_matchers,
@@ -224,51 +217,12 @@ where
}))
}
- /// Focuses the [`ComboBox`].
- pub fn focused(self) -> Self {
- self.focus();
- self
- }
-
- /// Focuses the [`ComboBox`].
- pub fn focus(&self) {
- let mut inner = self.0.borrow_mut();
-
- inner.text_input.focus();
- }
-
- /// Unfocuses the [`ComboBox`].
- pub fn unfocus(&self) {
- let mut inner = self.0.borrow_mut();
-
- inner.text_input.unfocus();
- }
-
- /// Returns whether the [`ComboBox`] is currently focused or not.
- pub fn is_focused(&self) -> bool {
- let inner = self.0.borrow();
-
- inner.text_input.is_focused()
- }
-
fn value(&self) -> String {
let inner = self.0.borrow();
inner.value.clone()
}
- fn text_input_tree(&self) -> widget::Tree {
- let inner = self.0.borrow();
-
- inner.text_input_tree()
- }
-
- fn update_text_input(&self, tree: widget::Tree) {
- let mut inner = self.0.borrow_mut();
-
- inner.update_text_input(tree)
- }
-
fn with_inner<O>(&self, f: impl FnOnce(&Inner<T>) -> O) -> O {
let inner = self.0.borrow();
@@ -288,21 +242,6 @@ where
}
}
-impl<T> Inner<T> {
- fn text_input_tree(&self) -> widget::Tree {
- widget::Tree {
- tag: widget::tree::Tag::of::<text_input::State>(),
- state: widget::tree::State::new(self.text_input.clone()),
- children: vec![],
- }
- }
-
- fn update_text_input(&mut self, tree: widget::Tree) {
- self.text_input =
- tree.state.downcast_ref::<text_input::State>().clone();
- }
-}
-
impl<T> Filtered<T>
where
T: Clone,
@@ -366,10 +305,11 @@ where
fn layout(
&self,
+ tree: &widget::Tree,
renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
- self.text_input.layout(renderer, limits)
+ self.text_input.layout(tree, renderer, limits)
}
fn tag(&self) -> widget::tree::Tag {
@@ -385,6 +325,10 @@ where
})
}
+ fn children(&self) -> Vec<widget::Tree> {
+ vec![widget::Tree::new(&self.text_input as &dyn Widget<_, _>)]
+ }
+
fn on_event(
&mut self,
tree: &mut widget::Tree,
@@ -398,7 +342,13 @@ where
) -> event::Status {
let menu = tree.state.downcast_mut::<Menu<T>>();
- let started_focused = self.state.is_focused();
+ let started_focused = {
+ let text_input_state = tree.children[0]
+ .state
+ .downcast_ref::<text_input::State<Renderer::Paragraph>>();
+
+ text_input_state.is_focused()
+ };
// This is intended to check whether or not the message buffer was empty,
// since `Shell` does not expose such functionality.
let mut published_message_to_shell = false;
@@ -408,9 +358,8 @@ where
let mut local_shell = Shell::new(&mut local_messages);
// Provide it to the widget
- let mut tree = self.state.text_input_tree();
let mut event_status = self.text_input.on_event(
- &mut tree,
+ &mut tree.children[0],
event.clone(),
layout,
cursor,
@@ -419,7 +368,6 @@ where
&mut local_shell,
viewport,
);
- self.state.update_text_input(tree);
// Then finally react to them here
for message in local_messages {
@@ -450,7 +398,15 @@ where
shell.invalidate_layout();
}
- if self.state.is_focused() {
+ let is_focused = {
+ let text_input_state = tree.children[0]
+ .state
+ .downcast_ref::<text_input::State<Renderer::Paragraph>>();
+
+ text_input_state.is_focused()
+ };
+
+ if is_focused {
self.state.with_inner(|state| {
if !started_focused {
if let Some(on_option_hovered) = &mut self.on_option_hovered
@@ -589,9 +545,8 @@ where
published_message_to_shell = true;
// Unfocus the input
- let mut tree = state.text_input_tree();
let _ = self.text_input.on_event(
- &mut tree,
+ &mut tree.children[0],
Event::Mouse(mouse::Event::ButtonPressed(
mouse::Button::Left,
)),
@@ -602,21 +557,25 @@ where
&mut Shell::new(&mut vec![]),
viewport,
);
- state.update_text_input(tree);
}
});
- if started_focused
- && !self.state.is_focused()
- && !published_message_to_shell
- {
+ let is_focused = {
+ let text_input_state = tree.children[0]
+ .state
+ .downcast_ref::<text_input::State<Renderer::Paragraph>>();
+
+ text_input_state.is_focused()
+ };
+
+ if started_focused && !is_focused && !published_message_to_shell {
if let Some(message) = self.on_close.take() {
shell.publish(message);
}
}
// Focus changed, invalidate widget tree to force a fresh `view`
- if started_focused != self.state.is_focused() {
+ if started_focused != is_focused {
shell.invalidate_widgets();
}
@@ -625,20 +584,24 @@ where
fn mouse_interaction(
&self,
- _tree: &widget::Tree,
+ tree: &widget::Tree,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
- let tree = self.state.text_input_tree();
- self.text_input
- .mouse_interaction(&tree, layout, cursor, viewport, renderer)
+ self.text_input.mouse_interaction(
+ &tree.children[0],
+ layout,
+ cursor,
+ viewport,
+ renderer,
+ )
}
fn draw(
&self,
- _tree: &widget::Tree,
+ tree: &widget::Tree,
renderer: &mut Renderer,
theme: &Renderer::Theme,
_style: &renderer::Style,
@@ -646,16 +609,28 @@ where
cursor: mouse::Cursor,
_viewport: &Rectangle,
) {
- let selection = if self.state.is_focused() || self.selection.is_empty()
- {
+ let is_focused = {
+ let text_input_state = tree.children[0]
+ .state
+ .downcast_ref::<text_input::State<Renderer::Paragraph>>();
+
+ text_input_state.is_focused()
+ };
+
+ let selection = if is_focused || self.selection.is_empty() {
None
} else {
Some(&self.selection)
};
- let tree = self.state.text_input_tree();
- self.text_input
- .draw(&tree, renderer, theme, layout, cursor, selection);
+ self.text_input.draw(
+ &tree.children[0],
+ renderer,
+ theme,
+ layout,
+ cursor,
+ selection,
+ );
}
fn overlay<'b>(
@@ -664,14 +639,22 @@ where
layout: Layout<'_>,
_renderer: &Renderer,
) -> Option<overlay::Element<'b, Message, Renderer>> {
- let Menu {
- menu,
- filtered_options,
- hovered_option,
- ..
- } = tree.state.downcast_mut::<Menu<T>>();
+ let is_focused = {
+ let text_input_state = tree.children[0]
+ .state
+ .downcast_ref::<text_input::State<Renderer::Paragraph>>();
+
+ text_input_state.is_focused()
+ };
+
+ if is_focused {
+ let Menu {
+ menu,
+ filtered_options,
+ hovered_option,
+ ..
+ } = tree.state.downcast_mut::<Menu<T>>();
- if self.state.is_focused() {
let bounds = layout.bounds();
self.state.sync_filtered_options(filtered_options);