diff options
-rw-r--r-- | graphics/src/widget/pane_grid.rs | 60 | ||||
-rw-r--r-- | native/src/widget/pane_grid.rs | 34 | ||||
-rw-r--r-- | native/src/widget/pane_grid/content.rs | 77 | ||||
-rw-r--r-- | native/src/widget/pane_grid/title_bar.rs | 121 | ||||
-rw-r--r-- | wgpu/src/widget/pane_grid.rs | 16 |
5 files changed, 275 insertions, 33 deletions
diff --git a/graphics/src/widget/pane_grid.rs b/graphics/src/widget/pane_grid.rs index 7a840689..71b1658a 100644 --- a/graphics/src/widget/pane_grid.rs +++ b/graphics/src/widget/pane_grid.rs @@ -119,11 +119,63 @@ where fn draw_pane<Message>( &mut self, defaults: &Self::Defaults, - _title_bar: Option<&TitleBar<'_, Message, Self>>, - body: &Element<'_, Message, Self>, - layout: Layout<'_>, + title_bar: Option<(&TitleBar<'_, Message, Self>, Layout<'_>)>, + body: (&Element<'_, Message, Self>, Layout<'_>), + cursor_position: Point, + ) -> Self::Output { + let (body, body_layout) = body; + + let (body_primitive, body_interaction) = + body.draw(self, defaults, body_layout, cursor_position); + + if let Some((title_bar, title_bar_layout)) = title_bar { + let (title_bar_primitive, title_bar_interaction) = title_bar.draw( + self, + defaults, + title_bar_layout, + cursor_position, + ); + + ( + Primitive::Group { + primitives: vec![title_bar_primitive, body_primitive], + }, + if title_bar_interaction > body_interaction { + title_bar_interaction + } else { + body_interaction + }, + ) + } else { + (body_primitive, body_interaction) + } + } + + fn draw_title_bar<Message>( + &mut self, + defaults: &Self::Defaults, + style: &<Self as iced_native::container::Renderer>::Style, + title: (&Element<'_, Message, Self>, Layout<'_>), + controls: Option<(&Element<'_, Message, Self>, Layout<'_>)>, cursor_position: Point, ) -> Self::Output { - body.draw(self, defaults, layout, cursor_position) + let (title, title_layout) = title; + + let (title_primitive, _) = + title.draw(self, defaults, title_layout, cursor_position); + + if let Some((controls, controls_layout)) = controls { + let (controls_primitive, controls_interaction) = + controls.draw(self, defaults, controls_layout, cursor_position); + + ( + Primitive::Group { + primitives: vec![title_primitive, controls_primitive], + }, + controls_interaction, + ) + } else { + (title_primitive, mouse::Interaction::default()) + } } } diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs index 4c037ee9..bf9c76fd 100644 --- a/native/src/widget/pane_grid.rs +++ b/native/src/widget/pane_grid.rs @@ -29,8 +29,8 @@ pub use state::{Focus, State}; pub use title_bar::TitleBar; use crate::{ - keyboard, layout, mouse, Clipboard, Element, Event, Hasher, Layout, Length, - Point, Size, Widget, + container, keyboard, layout, mouse, row, Clipboard, Element, Event, Hasher, + Layout, Length, Point, Size, Widget, }; /// A collection of panes distributed using either vertical or horizontal splits @@ -86,7 +86,7 @@ use crate::{ /// [`PaneGrid`]: struct.PaneGrid.html /// [`State`]: struct.State.html #[allow(missing_debug_implementations)] -pub struct PaneGrid<'a, Message, Renderer> { +pub struct PaneGrid<'a, Message, Renderer: container::Renderer> { state: &'a mut state::Internal, pressed_modifiers: &'a mut keyboard::ModifiersState, elements: Vec<(Pane, Content<'a, Message, Renderer>)>, @@ -99,7 +99,10 @@ pub struct PaneGrid<'a, Message, Renderer> { 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> +where + Renderer: container::Renderer, +{ /// Creates a [`PaneGrid`] with the given [`State`] and view function. /// /// The view function will be called to display each [`Pane`] present in the @@ -362,7 +365,7 @@ pub struct KeyPressEvent { impl<'a, Message, Renderer> Widget<Message, Renderer> for PaneGrid<'a, Message, Renderer> where - Renderer: self::Renderer, + Renderer: self::Renderer + container::Renderer, { fn width(&self) -> Length { self.width @@ -604,7 +607,8 @@ where layout: Layout<'_>, cursor_position: Point, ) -> Renderer::Output { - renderer.draw( + self::Renderer::draw( + renderer, defaults, &self.elements, self.state.picked_pane(), @@ -636,7 +640,7 @@ where /// /// [`PaneGrid`]: struct.PaneGrid.html /// [renderer]: ../../renderer/index.html -pub trait Renderer: crate::Renderer + Sized { +pub trait Renderer: crate::Renderer + container::Renderer + Sized { /// Draws a [`PaneGrid`]. /// /// It receives: @@ -672,9 +676,17 @@ pub trait Renderer: crate::Renderer + Sized { fn draw_pane<Message>( &mut self, defaults: &Self::Defaults, - title_bar: Option<&TitleBar<'_, Message, Self>>, - body: &Element<'_, Message, Self>, - layout: Layout<'_>, + title_bar: Option<(&TitleBar<'_, Message, Self>, Layout<'_>)>, + body: (&Element<'_, Message, Self>, Layout<'_>), + cursor_position: Point, + ) -> Self::Output; + + fn draw_title_bar<Message>( + &mut self, + defaults: &Self::Defaults, + style: &Self::Style, + title: (&Element<'_, Message, Self>, Layout<'_>), + controls: Option<(&Element<'_, Message, Self>, Layout<'_>)>, cursor_position: Point, ) -> Self::Output; } @@ -682,7 +694,7 @@ pub trait Renderer: crate::Renderer + Sized { impl<'a, Message, Renderer> From<PaneGrid<'a, Message, Renderer>> for Element<'a, Message, Renderer> where - Renderer: 'a + self::Renderer, + Renderer: 'a + self::Renderer + row::Renderer, Message: 'a, { fn from( diff --git a/native/src/widget/pane_grid/content.rs b/native/src/widget/pane_grid/content.rs index e1374c82..a30b0e7d 100644 --- a/native/src/widget/pane_grid/content.rs +++ b/native/src/widget/pane_grid/content.rs @@ -1,16 +1,20 @@ +use crate::container; use crate::layout; use crate::pane_grid::{self, TitleBar}; -use crate::{Clipboard, Element, Event, Hasher, Layout, Point}; +use crate::{Clipboard, Element, Event, Hasher, Layout, Point, Size}; /// The content of a [`Pane`]. /// /// [`Pane`]: struct.Pane.html -pub struct Content<'a, Message, Renderer> { +pub struct Content<'a, Message, Renderer: container::Renderer> { title_bar: Option<TitleBar<'a, Message, Renderer>>, body: Element<'a, Message, Renderer>, } -impl<'a, Message, Renderer> Content<'a, Message, Renderer> { +impl<'a, Message, Renderer> Content<'a, Message, Renderer> +where + Renderer: container::Renderer, +{ pub fn new(body: impl Into<Element<'a, Message, Renderer>>) -> Self { Self { title_bar: None, @@ -29,7 +33,7 @@ impl<'a, Message, Renderer> Content<'a, Message, Renderer> { impl<'a, Message, Renderer> Content<'a, Message, Renderer> where - Renderer: pane_grid::Renderer, + Renderer: pane_grid::Renderer + container::Renderer, { pub fn draw( &self, @@ -38,13 +42,25 @@ where layout: Layout<'_>, cursor_position: Point, ) -> Renderer::Output { - renderer.draw_pane( - defaults, - self.title_bar.as_ref(), - &self.body, - layout, - cursor_position, - ) + if let Some(title_bar) = &self.title_bar { + let mut children = layout.children(); + let title_bar_layout = children.next().unwrap(); + let body_layout = children.next().unwrap(); + + renderer.draw_pane( + defaults, + Some((title_bar, title_bar_layout)), + (&self.body, body_layout), + cursor_position, + ) + } else { + renderer.draw_pane( + defaults, + None, + (&self.body, layout), + cursor_position, + ) + } } pub(crate) fn is_over_drag_target( @@ -60,7 +76,34 @@ where renderer: &Renderer, limits: &layout::Limits, ) -> layout::Node { - self.body.layout(renderer, limits) + if let Some(title_bar) = &self.title_bar { + let max_size = limits.max(); + + let title_bar_layout = title_bar + .layout(renderer, &layout::Limits::new(Size::ZERO, max_size)); + + let title_bar_size = title_bar_layout.size(); + + let mut body_layout = self.body.layout( + renderer, + &layout::Limits::new( + Size::ZERO, + Size::new( + max_size.width, + max_size.height - title_bar_size.height, + ), + ), + ); + + body_layout.move_to(Point::new(0.0, title_bar_size.height)); + + layout::Node::with_children( + max_size, + vec![title_bar_layout, body_layout], + ) + } else { + self.body.layout(renderer, limits) + } } pub(crate) fn on_event( @@ -86,3 +129,13 @@ where self.body.hash_layout(state); } } + +impl<'a, T, Message, Renderer> From<T> for Content<'a, Message, Renderer> +where + T: Into<Element<'a, Message, Renderer>>, + Renderer: pane_grid::Renderer + container::Renderer, +{ + fn from(element: T) -> Self { + Self::new(element) + } +} diff --git a/native/src/widget/pane_grid/title_bar.rs b/native/src/widget/pane_grid/title_bar.rs index fa868a20..1fd06411 100644 --- a/native/src/widget/pane_grid/title_bar.rs +++ b/native/src/widget/pane_grid/title_bar.rs @@ -1,6 +1,119 @@ -use crate::Element; +use crate::container; +use crate::layout; +use crate::pane_grid; +use crate::{Element, Layout, Point, Size}; -pub struct TitleBar<'a, Message, Renderer> { - title: String, - buttons: Option<Element<'a, Message, Renderer>>, +pub struct TitleBar<'a, Message, Renderer: container::Renderer> { + title: Element<'a, Message, Renderer>, + controls: Option<Element<'a, Message, Renderer>>, + padding: u16, + style: Renderer::Style, +} + +impl<'a, Message, Renderer> TitleBar<'a, Message, Renderer> +where + Renderer: container::Renderer, +{ + pub fn new(title: impl Into<Element<'a, Message, Renderer>>) -> Self { + Self { + title: title.into(), + controls: None, + padding: 0, + style: Renderer::Style::default(), + } + } + + pub fn controls( + mut self, + controls: impl Into<Element<'a, Message, Renderer>>, + ) -> Self { + self.controls = Some(controls.into()); + self + } + + /// Sets the padding of the [`TitleBar`]. + /// + /// [`TitleBar`]: struct.TitleBar.html + pub fn padding(mut self, units: u16) -> Self { + self.padding = units; + self + } +} + +impl<'a, Message, Renderer> TitleBar<'a, Message, Renderer> +where + Renderer: pane_grid::Renderer, +{ + pub fn draw( + &self, + renderer: &mut Renderer, + defaults: &Renderer::Defaults, + layout: Layout<'_>, + cursor_position: Point, + ) -> Renderer::Output { + if let Some(controls) = &self.controls { + let mut children = layout.children(); + let title_layout = children.next().unwrap(); + let controls_layout = children.next().unwrap(); + + renderer.draw_title_bar( + defaults, + &self.style, + (&self.title, title_layout), + Some((controls, controls_layout)), + cursor_position, + ) + } else { + renderer.draw_title_bar( + defaults, + &self.style, + (&self.title, layout), + None, + cursor_position, + ) + } + } + + pub(crate) fn layout( + &self, + renderer: &Renderer, + limits: &layout::Limits, + ) -> layout::Node { + let padding = f32::from(self.padding); + let limits = limits.pad(padding); + + let mut node = if let Some(controls) = &self.controls { + let max_size = limits.max(); + + let title_layout = self + .title + .layout(renderer, &layout::Limits::new(Size::ZERO, max_size)); + + let title_size = title_layout.size(); + + let mut controls_layout = controls.layout( + renderer, + &layout::Limits::new( + Size::ZERO, + Size::new( + max_size.width - title_size.width, + max_size.height, + ), + ), + ); + + controls_layout.move_to(Point::new(title_size.width, 0.0)); + + layout::Node::with_children( + max_size, + vec![title_layout, controls_layout], + ) + } else { + self.title.layout(renderer, &limits) + }; + + node.move_to(Point::new(padding, padding)); + + node + } } diff --git a/wgpu/src/widget/pane_grid.rs b/wgpu/src/widget/pane_grid.rs index d9fec026..3c47b562 100644 --- a/wgpu/src/widget/pane_grid.rs +++ b/wgpu/src/widget/pane_grid.rs @@ -11,8 +11,8 @@ use crate::Renderer; pub use iced_native::pane_grid::{ - Axis, Configuration, Content, Direction, DragEvent, Focus, KeyPressEvent, - Node, Pane, ResizeEvent, Split, State, + Axis, Configuration, Direction, DragEvent, Focus, KeyPressEvent, Node, + Pane, ResizeEvent, Split, State, }; /// A collection of panes distributed using either vertical or horizontal splits @@ -22,3 +22,15 @@ pub use iced_native::pane_grid::{ /// /// This is an alias of an `iced_native` pane grid with an `iced_wgpu::Renderer`. pub type PaneGrid<'a, Message> = iced_native::PaneGrid<'a, Message, Renderer>; + +/// The content of a [`Pane`]. +/// +/// [`Pane`]: struct.Pane.html +pub type Content<'a, Message> = + iced_native::pane_grid::Content<'a, Message, Renderer>; + +/// The title bar of a [`Pane`]. +/// +/// [`Pane`]: struct.Pane.html +pub type TitleBar<'a, Message> = + iced_native::pane_grid::TitleBar<'a, Message, Renderer>; |