summaryrefslogtreecommitdiffstats
path: root/native/src/overlay/menu.rs
diff options
context:
space:
mode:
Diffstat (limited to 'native/src/overlay/menu.rs')
-rw-r--r--native/src/overlay/menu.rs116
1 files changed, 63 insertions, 53 deletions
diff --git a/native/src/overlay/menu.rs b/native/src/overlay/menu.rs
index c2df468e..f62dcb46 100644
--- a/native/src/overlay/menu.rs
+++ b/native/src/overlay/menu.rs
@@ -1,8 +1,15 @@
//! Build and show dropdown menus.
+use crate::container;
+use crate::event::{self, Event};
+use crate::layout;
+use crate::mouse;
+use crate::overlay;
+use crate::scrollable;
+use crate::text;
+use crate::touch;
use crate::{
- container, layout, mouse, overlay, scrollable, text, Clipboard, Container,
- Element, Event, Hasher, Layout, Length, Point, Rectangle, Scrollable, Size,
- Vector, Widget,
+ Clipboard, Container, Element, Hasher, Layout, Length, Padding, Point,
+ Rectangle, Scrollable, Size, Vector, Widget,
};
/// A list of selectable options.
@@ -13,7 +20,7 @@ pub struct Menu<'a, T, Renderer: self::Renderer> {
hovered_option: &'a mut Option<usize>,
last_selection: &'a mut Option<T>,
width: u16,
- padding: u16,
+ padding: Padding,
text_size: Option<u16>,
font: Renderer::Font,
style: <Renderer as self::Renderer>::Style,
@@ -26,9 +33,6 @@ where
{
/// Creates a new [`Menu`] with the given [`State`], a list of options, and
/// the message to produced when an option is selected.
- ///
- /// [`Menu`]: struct.Menu.html
- /// [`State`]: struct.State.html
pub fn new(
state: &'a mut State,
options: &'a [T],
@@ -41,7 +45,7 @@ where
hovered_option,
last_selection,
width: 0,
- padding: 0,
+ padding: Padding::ZERO,
text_size: None,
font: Default::default(),
style: Default::default(),
@@ -49,40 +53,30 @@ where
}
/// Sets the width of the [`Menu`].
- ///
- /// [`Menu`]: struct.Menu.html
pub fn width(mut self, width: u16) -> Self {
self.width = width;
self
}
- /// Sets the padding of the [`Menu`].
- ///
- /// [`Menu`]: struct.Menu.html
- pub fn padding(mut self, padding: u16) -> Self {
- self.padding = padding;
+ /// Sets the [`Padding`] of the [`Menu`].
+ pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
+ self.padding = padding.into();
self
}
/// Sets the text size of the [`Menu`].
- ///
- /// [`Menu`]: struct.Menu.html
pub fn text_size(mut self, text_size: u16) -> Self {
self.text_size = Some(text_size);
self
}
/// Sets the font of the [`Menu`].
- ///
- /// [`Menu`]: struct.Menu.html
pub fn font(mut self, font: Renderer::Font) -> Self {
self.font = font;
self
}
/// Sets the style of the [`Menu`].
- ///
- /// [`Menu`]: struct.Menu.html
pub fn style(
mut self,
style: impl Into<<Renderer as self::Renderer>::Style>,
@@ -97,8 +91,6 @@ where
/// The `target_height` will be used to display the menu either on top
/// of the target or under it, depending on the screen position and the
/// dimensions of the [`Menu`].
- ///
- /// [`Menu`]: struct.Menu.html
pub fn overlay<Message: 'a>(
self,
position: Point,
@@ -112,8 +104,6 @@ where
}
/// The local state of a [`Menu`].
-///
-/// [`Menu`]: struct.Menu.html
#[derive(Debug, Clone, Default)]
pub struct State {
scrollable: scrollable::State,
@@ -121,9 +111,6 @@ pub struct State {
impl State {
/// Creates a new [`State`] for a [`Menu`].
- ///
- /// [`State`]: struct.State.html
- /// [`Menu`]: struct.Menu.html
pub fn new() -> Self {
Self::default()
}
@@ -232,18 +219,18 @@ where
event: Event,
layout: Layout<'_>,
cursor_position: Point,
- messages: &mut Vec<Message>,
renderer: &Renderer,
- clipboard: Option<&dyn Clipboard>,
- ) {
+ clipboard: &mut dyn Clipboard,
+ messages: &mut Vec<Message>,
+ ) -> event::Status {
self.container.on_event(
event.clone(),
layout,
cursor_position,
- messages,
renderer,
clipboard,
- );
+ messages,
+ )
}
fn draw(
@@ -253,9 +240,13 @@ where
layout: Layout<'_>,
cursor_position: Point,
) -> Renderer::Output {
- let primitives =
- self.container
- .draw(renderer, defaults, layout, cursor_position);
+ let primitives = self.container.draw(
+ renderer,
+ defaults,
+ layout,
+ cursor_position,
+ &layout.bounds(),
+ );
renderer.decorate(
layout.bounds(),
@@ -270,7 +261,7 @@ struct List<'a, T, Renderer: self::Renderer> {
options: &'a [T],
hovered_option: &'a mut Option<usize>,
last_selection: &'a mut Option<T>,
- padding: u16,
+ padding: Padding,
text_size: Option<u16>,
font: Renderer::Font,
style: <Renderer as self::Renderer>::Style,
@@ -303,7 +294,7 @@ where
let size = {
let intrinsic = Size::new(
0.0,
- f32::from(text_size + self.padding * 2)
+ f32::from(text_size + self.padding.vertical())
* self.options.len() as f32,
);
@@ -329,10 +320,10 @@ where
event: Event,
layout: Layout<'_>,
cursor_position: Point,
- _messages: &mut Vec<Message>,
renderer: &Renderer,
- _clipboard: Option<&dyn Clipboard>,
- ) {
+ _clipboard: &mut dyn Clipboard,
+ _messages: &mut Vec<Message>,
+ ) -> event::Status {
match event {
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
let bounds = layout.bounds();
@@ -347,19 +338,42 @@ where
}
Event::Mouse(mouse::Event::CursorMoved { .. }) => {
let bounds = layout.bounds();
- let text_size =
- self.text_size.unwrap_or(renderer.default_size());
if bounds.contains(cursor_position) {
+ let text_size =
+ self.text_size.unwrap_or(renderer.default_size());
+
*self.hovered_option = Some(
((cursor_position.y - bounds.y)
- / f32::from(text_size + self.padding * 2))
+ / f32::from(text_size + self.padding.vertical()))
as usize,
);
}
}
+ Event::Touch(touch::Event::FingerPressed { .. }) => {
+ let bounds = layout.bounds();
+
+ if bounds.contains(cursor_position) {
+ let text_size =
+ self.text_size.unwrap_or(renderer.default_size());
+
+ *self.hovered_option = Some(
+ ((cursor_position.y - bounds.y)
+ / f32::from(text_size + self.padding.vertical()))
+ as usize,
+ );
+
+ if let Some(index) = *self.hovered_option {
+ if let Some(option) = self.options.get(index) {
+ *self.last_selection = Some(option.clone());
+ }
+ }
+ }
+ }
_ => {}
}
+
+ event::Status::Ignored
}
fn draw(
@@ -368,11 +382,13 @@ where
_defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ viewport: &Rectangle,
) -> Renderer::Output {
self::Renderer::draw(
renderer,
layout.bounds(),
cursor_position,
+ viewport,
self.options,
*self.hovered_option,
self.padding,
@@ -388,21 +404,16 @@ where
/// Your [renderer] will need to implement this trait before being
/// able to use a [`Menu`] in your user interface.
///
-/// [`Menu`]: struct.Menu.html
-/// [renderer]: ../../renderer/index.html
+/// [renderer]: crate::renderer
pub trait Renderer:
scrollable::Renderer + container::Renderer + text::Renderer
{
/// The [`Menu`] style supported by this renderer.
- ///
- /// [`Menu`]: struct.Menu.html
type Style: Default + Clone;
/// Decorates a the list of options of a [`Menu`].
///
/// This method can be used to draw a background for the [`Menu`].
- ///
- /// [`Menu`]: struct.Menu.html
fn decorate(
&mut self,
bounds: Rectangle,
@@ -412,15 +423,14 @@ pub trait Renderer:
) -> Self::Output;
/// Draws the list of options of a [`Menu`].
- ///
- /// [`Menu`]: struct.Menu.html
fn draw<T: ToString>(
&mut self,
bounds: Rectangle,
cursor_position: Point,
+ viewport: &Rectangle,
options: &[T],
hovered_option: Option<usize>,
- padding: u16,
+ padding: Padding,
text_size: u16,
font: Self::Font,
style: &<Self as Renderer>::Style,