From a11bcf5af0be26671ba90097c64021014ab2092d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 4 Jun 2020 07:13:38 +0200 Subject: [PATCH 01/16] Draft first-class `TitleBar` in `pane_grid` --- examples/pane_grid/src/main.rs | 2 +- glow/src/widget/pane_grid.rs | 4 +- graphics/src/widget/pane_grid.rs | 17 ++- native/src/lib.rs | 4 +- native/src/widget/pane_grid.rs | 46 ++++++-- native/src/widget/pane_grid/configuration.rs | 30 +++++ native/src/widget/pane_grid/content.rs | 112 ++++++++++++++----- native/src/widget/pane_grid/state.rs | 21 ++-- native/src/widget/pane_grid/title_bar.rs | 6 + wgpu/src/widget/pane_grid.rs | 4 +- 10 files changed, 190 insertions(+), 56 deletions(-) create mode 100644 native/src/widget/pane_grid/configuration.rs create mode 100644 native/src/widget/pane_grid/title_bar.rs diff --git a/examples/pane_grid/src/main.rs b/examples/pane_grid/src/main.rs index b4bbd68f..4f081b48 100644 --- a/examples/pane_grid/src/main.rs +++ b/examples/pane_grid/src/main.rs @@ -97,7 +97,7 @@ impl Sandbox for Example { let pane_grid = PaneGrid::new(&mut self.panes, |pane, content, focus| { - content.view(pane, focus, total_panes) + pane_grid::Content::new(content.view(pane, focus, total_panes)) }) .width(Length::Fill) .height(Length::Fill) diff --git a/glow/src/widget/pane_grid.rs b/glow/src/widget/pane_grid.rs index 6f437df7..d9fec026 100644 --- a/glow/src/widget/pane_grid.rs +++ b/glow/src/widget/pane_grid.rs @@ -11,8 +11,8 @@ use crate::Renderer; pub use iced_native::pane_grid::{ - Axis, Content, Direction, DragEvent, Focus, KeyPressEvent, Node, Pane, - ResizeEvent, Split, State, + Axis, Configuration, Content, Direction, DragEvent, Focus, KeyPressEvent, + Node, Pane, ResizeEvent, Split, State, }; /// A collection of panes distributed using either vertical or horizontal splits diff --git a/graphics/src/widget/pane_grid.rs b/graphics/src/widget/pane_grid.rs index 56af683d..7a840689 100644 --- a/graphics/src/widget/pane_grid.rs +++ b/graphics/src/widget/pane_grid.rs @@ -14,8 +14,8 @@ use iced_native::pane_grid; use iced_native::{Element, Layout, Point, Rectangle, Vector}; pub use iced_native::pane_grid::{ - Axis, Direction, DragEvent, Focus, KeyPressEvent, Pane, ResizeEvent, Split, - State, + Axis, Configuration, Content, Direction, DragEvent, Focus, KeyPressEvent, + Pane, ResizeEvent, Split, State, TitleBar, }; /// A collection of panes distributed using either vertical or horizontal splits @@ -34,7 +34,7 @@ where fn draw( &mut self, defaults: &Self::Defaults, - content: &[(Pane, Element<'_, Message, Self>)], + content: &[(Pane, Content<'_, Message, Self>)], dragging: Option, resizing: Option, layout: Layout<'_>, @@ -115,4 +115,15 @@ where }, ) } + + fn draw_pane( + &mut self, + defaults: &Self::Defaults, + _title_bar: Option<&TitleBar<'_, Message, Self>>, + body: &Element<'_, Message, Self>, + layout: Layout<'_>, + cursor_position: Point, + ) -> Self::Output { + body.draw(self, defaults, layout, cursor_position) + } } diff --git a/native/src/lib.rs b/native/src/lib.rs index b67ff2a1..86046f63 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -30,8 +30,8 @@ //! [`Widget`]: widget/trait.Widget.html //! [`UserInterface`]: struct.UserInterface.html //! [renderer]: renderer/index.html -#![deny(missing_docs)] -#![deny(missing_debug_implementations)] +//#![deny(missing_docs)] +//#![deny(missing_debug_implementations)] #![deny(unused_results)] #![forbid(unsafe_code)] #![forbid(rust_2018_idioms)] diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs index 076ae76f..4c037ee9 100644 --- a/native/src/widget/pane_grid.rs +++ b/native/src/widget/pane_grid.rs @@ -9,20 +9,24 @@ //! [`pane_grid` example]: https://github.com/hecrj/iced/tree/0.1/examples/pane_grid //! [`PaneGrid`]: struct.PaneGrid.html mod axis; +mod configuration; mod content; mod direction; mod node; mod pane; mod split; mod state; +mod title_bar; pub use axis::Axis; +pub use configuration::Configuration; pub use content::Content; pub use direction::Direction; pub use node::Node; pub use pane::Pane; pub use split::Split; pub use state::{Focus, State}; +pub use title_bar::TitleBar; use crate::{ keyboard, layout, mouse, Clipboard, Element, Event, Hasher, Layout, Length, @@ -70,10 +74,10 @@ use crate::{ /// /// let pane_grid = /// PaneGrid::new(&mut state, |pane, state, focus| { -/// match state { +/// pane_grid::Content::new(match state { /// PaneState::SomePane => Text::new("This is some pane"), /// PaneState::AnotherKindOfPane => Text::new("This is another kind of pane"), -/// }.into() +/// }) /// }) /// .on_drag(Message::PaneDragged) /// .on_resize(Message::PaneResized); @@ -85,7 +89,7 @@ use crate::{ pub struct PaneGrid<'a, Message, Renderer> { state: &'a mut state::Internal, pressed_modifiers: &'a mut keyboard::ModifiersState, - elements: Vec<(Pane, Element<'a, Message, Renderer>)>, + elements: Vec<(Pane, Content<'a, Message, Renderer>)>, width: Length, height: Length, spacing: u16, @@ -110,7 +114,7 @@ impl<'a, Message, Renderer> PaneGrid<'a, Message, Renderer> { Pane, &'a mut T, Option, - ) -> Element<'a, Message, Renderer>, + ) -> Content<'a, Message, Renderer>, ) -> Self { let elements = { let action = state.internal.action(); @@ -416,12 +420,15 @@ where }, ); - if let Some(((pane, _), _)) = clicked_region.next() { + if let Some(((pane, content), layout)) = + clicked_region.next() + { match &self.on_drag { Some(on_drag) - if self - .pressed_modifiers - .matches(self.modifier_keys) => + if content.is_over_drag_target( + layout, + cursor_position, + ) => { self.state.pick_pane(pane); @@ -576,7 +583,7 @@ where { self.elements.iter_mut().zip(layout.children()).for_each( |((_, pane), layout)| { - pane.widget.on_event( + pane.on_event( event.clone(), layout, cursor_position, @@ -645,12 +652,31 @@ pub trait Renderer: crate::Renderer + Sized { fn draw( &mut self, defaults: &Self::Defaults, - content: &[(Pane, Element<'_, Message, Self>)], + content: &[(Pane, Content<'_, Message, Self>)], dragging: Option, resizing: Option, layout: Layout<'_>, cursor_position: Point, ) -> Self::Output; + + /// Draws a [`Pane`]. + /// + /// It receives: + /// - the [`TitleBar`] of the [`Pane`], if any + /// - the [`Content`] of the [`Pane`] + /// - the [`Layout`] of the [`Pane`] and its elements + /// - the cursor position + /// + /// [`Pane`]: struct.Pane.html + /// [`Layout`]: ../layout/struct.Layout.html + fn draw_pane( + &mut self, + defaults: &Self::Defaults, + title_bar: Option<&TitleBar<'_, Message, Self>>, + body: &Element<'_, Message, Self>, + layout: Layout<'_>, + cursor_position: Point, + ) -> Self::Output; } impl<'a, Message, Renderer> From> diff --git a/native/src/widget/pane_grid/configuration.rs b/native/src/widget/pane_grid/configuration.rs new file mode 100644 index 00000000..1fed98b7 --- /dev/null +++ b/native/src/widget/pane_grid/configuration.rs @@ -0,0 +1,30 @@ +use crate::pane_grid::Axis; + +/// The arrangement of a [`PaneGrid`]. +/// +/// [`PaneGrid`]: struct.PaneGrid.html +#[derive(Debug, Clone)] +pub enum Configuration { + /// A split of the available space. + Split { + /// The direction of the split. + axis: Axis, + + /// The ratio of the split in [0.0, 1.0]. + ratio: f32, + + /// The left/top [`Content`] of the split. + /// + /// [`Configuration`]: enum.Node.html + a: Box>, + + /// The right/bottom [`Content`] of the split. + /// + /// [`Configuration`]: enum.Node.html + b: Box>, + }, + /// A [`Pane`]. + /// + /// [`Pane`]: struct.Pane.html + Pane(T), +} diff --git a/native/src/widget/pane_grid/content.rs b/native/src/widget/pane_grid/content.rs index 8822083e..e1374c82 100644 --- a/native/src/widget/pane_grid/content.rs +++ b/native/src/widget/pane_grid/content.rs @@ -1,30 +1,88 @@ -use crate::pane_grid::Axis; +use crate::layout; +use crate::pane_grid::{self, TitleBar}; +use crate::{Clipboard, Element, Event, Hasher, Layout, Point}; -/// The content of a [`PaneGrid`]. +/// The content of a [`Pane`]. /// -/// [`PaneGrid`]: struct.PaneGrid.html -#[derive(Debug, Clone)] -pub enum Content { - /// A split of the available space. - Split { - /// The direction of the split. - axis: Axis, - - /// The ratio of the split in [0.0, 1.0]. - ratio: f32, - - /// The left/top [`Content`] of the split. - /// - /// [`Content`]: enum.Node.html - a: Box>, - - /// The right/bottom [`Content`] of the split. - /// - /// [`Content`]: enum.Node.html - b: Box>, - }, - /// A [`Pane`]. - /// - /// [`Pane`]: struct.Pane.html - Pane(T), +/// [`Pane`]: struct.Pane.html +pub struct Content<'a, Message, Renderer> { + title_bar: Option>, + body: Element<'a, Message, Renderer>, +} + +impl<'a, Message, Renderer> Content<'a, Message, Renderer> { + pub fn new(body: impl Into>) -> Self { + Self { + title_bar: None, + body: body.into(), + } + } + + pub fn title_bar( + mut self, + title_bar: TitleBar<'a, Message, Renderer>, + ) -> Self { + self.title_bar = Some(title_bar); + self + } +} + +impl<'a, Message, Renderer> Content<'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 { + renderer.draw_pane( + defaults, + self.title_bar.as_ref(), + &self.body, + layout, + cursor_position, + ) + } + + pub(crate) fn is_over_drag_target( + &self, + _layout: Layout<'_>, + _cursor_position: Point, + ) -> bool { + false + } + + pub(crate) fn layout( + &self, + renderer: &Renderer, + limits: &layout::Limits, + ) -> layout::Node { + self.body.layout(renderer, limits) + } + + pub(crate) fn on_event( + &mut self, + event: Event, + layout: Layout<'_>, + cursor_position: Point, + messages: &mut Vec, + renderer: &Renderer, + clipboard: Option<&dyn Clipboard>, + ) { + self.body.on_event( + event, + layout, + cursor_position, + messages, + renderer, + clipboard, + ) + } + + pub(crate) fn hash_layout(&self, state: &mut Hasher) { + self.body.hash_layout(state); + } } diff --git a/native/src/widget/pane_grid/state.rs b/native/src/widget/pane_grid/state.rs index 4b13fb8e..943120e3 100644 --- a/native/src/widget/pane_grid/state.rs +++ b/native/src/widget/pane_grid/state.rs @@ -1,6 +1,6 @@ use crate::{ keyboard, - pane_grid::{Axis, Content, Direction, Node, Pane, Split}, + pane_grid::{Axis, Configuration, Direction, Node, Pane, Split}, Hasher, Point, Rectangle, Size, }; @@ -53,18 +53,21 @@ impl State { /// [`State`]: struct.State.html /// [`Pane`]: struct.Pane.html pub fn new(first_pane_state: T) -> (Self, Pane) { - (Self::with_content(Content::Pane(first_pane_state)), Pane(0)) + ( + Self::with_configuration(Configuration::Pane(first_pane_state)), + Pane(0), + ) } - /// Creates a new [`State`] with the given [`Content`]. + /// Creates a new [`State`] with the given [`Configuration`]. /// /// [`State`]: struct.State.html - /// [`Content`]: enum.Content.html - pub fn with_content(content: impl Into>) -> Self { + /// [`Configuration`]: enum.Configuration.html + pub fn with_configuration(config: impl Into>) -> Self { let mut panes = HashMap::new(); let (layout, last_id) = - Self::distribute_content(&mut panes, content.into(), 0); + Self::distribute_content(&mut panes, config.into(), 0); State { panes, @@ -274,11 +277,11 @@ impl State { fn distribute_content( panes: &mut HashMap, - content: Content, + content: Configuration, next_id: usize, ) -> (Node, usize) { match content { - Content::Split { axis, ratio, a, b } => { + Configuration::Split { axis, ratio, a, b } => { let (a, next_id) = Self::distribute_content(panes, *a, next_id); let (b, next_id) = Self::distribute_content(panes, *b, next_id); @@ -293,7 +296,7 @@ impl State { next_id + 1, ) } - Content::Pane(state) => { + Configuration::Pane(state) => { let id = Pane(next_id); let _ = panes.insert(id, state); diff --git a/native/src/widget/pane_grid/title_bar.rs b/native/src/widget/pane_grid/title_bar.rs new file mode 100644 index 00000000..fa868a20 --- /dev/null +++ b/native/src/widget/pane_grid/title_bar.rs @@ -0,0 +1,6 @@ +use crate::Element; + +pub struct TitleBar<'a, Message, Renderer> { + title: String, + buttons: Option>, +} diff --git a/wgpu/src/widget/pane_grid.rs b/wgpu/src/widget/pane_grid.rs index 6f437df7..d9fec026 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, Content, Direction, DragEvent, Focus, KeyPressEvent, Node, Pane, - ResizeEvent, Split, State, + Axis, Configuration, Content, Direction, DragEvent, Focus, KeyPressEvent, + Node, Pane, ResizeEvent, Split, State, }; /// A collection of panes distributed using either vertical or horizontal splits From 4e1e0e0890b83fb1c4c4406791e3aa63bba58a93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Fri, 5 Jun 2020 06:52:07 +0200 Subject: [PATCH 02/16] Draft drawing logic for `Content` and `TitleBar` --- graphics/src/widget/pane_grid.rs | 60 ++++++++++- native/src/widget/pane_grid.rs | 34 ++++--- native/src/widget/pane_grid/content.rs | 77 ++++++++++++--- native/src/widget/pane_grid/title_bar.rs | 121 ++++++++++++++++++++++- 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( &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 { - body.draw(self, defaults, layout, cursor_position) + 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( + &mut self, + defaults: &Self::Defaults, + style: &::Style, + title: (&Element<'_, Message, Self>, Layout<'_>), + controls: Option<(&Element<'_, Message, Self>, Layout<'_>)>, + cursor_position: Point, + ) -> Self::Output { + 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 Option + '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 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( &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( + &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> 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>, 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>) -> 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 for Content<'a, Message, Renderer> +where + T: Into>, + 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>, +pub struct TitleBar<'a, Message, Renderer: container::Renderer> { + title: Element<'a, Message, Renderer>, + controls: Option>, + padding: u16, + style: Renderer::Style, +} + +impl<'a, Message, Renderer> TitleBar<'a, Message, Renderer> +where + Renderer: container::Renderer, +{ + pub fn new(title: impl Into>) -> Self { + Self { + title: title.into(), + controls: None, + padding: 0, + style: Renderer::Style::default(), + } + } + + pub fn controls( + mut self, + controls: impl Into>, + ) -> 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>; From e8e656b3300093e384771a6083e25e9395bbeb50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Fri, 5 Jun 2020 14:00:31 +0200 Subject: [PATCH 03/16] Implement `Layout::position` --- native/src/layout.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/native/src/layout.rs b/native/src/layout.rs index 4a3ab94a..93d95e17 100644 --- a/native/src/layout.rs +++ b/native/src/layout.rs @@ -34,7 +34,14 @@ impl<'a> Layout<'a> { } } - /// Gets the bounds of the [`Layout`]. + /// Returns the position of the [`Layout`]. + /// + /// [`Layout`]: struct.Layout.html + pub fn position(&self) -> Point { + self.position + } + + /// Returns the bounds of the [`Layout`]. /// /// The returned [`Rectangle`] describes the position and size of a /// [`Node`]. From 4dc5bffdfbfb09a017f35c12b484301fcf044876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Fri, 5 Jun 2020 14:02:29 +0200 Subject: [PATCH 04/16] Draft draggable and graphics logic for `TitleBar` --- graphics/src/widget/container.rs | 33 +++++--- graphics/src/widget/pane_grid.rs | 78 ++++++++++++++--- native/src/renderer/null.rs | 21 ++++- native/src/widget/pane_grid.rs | 30 ++++--- native/src/widget/pane_grid/content.rs | 60 +++++++++++-- native/src/widget/pane_grid/state.rs | 16 ++-- native/src/widget/pane_grid/title_bar.rs | 103 +++++++++++++++++++---- 7 files changed, 268 insertions(+), 73 deletions(-) diff --git a/graphics/src/widget/container.rs b/graphics/src/widget/container.rs index 070cb48b..576062d4 100644 --- a/graphics/src/widget/container.rs +++ b/graphics/src/widget/container.rs @@ -39,20 +39,10 @@ where let (content, mouse_interaction) = content.draw(self, &defaults, content_layout, cursor_position); - if style.background.is_some() || style.border_width > 0 { - let quad = Primitive::Quad { - bounds, - background: style - .background - .unwrap_or(Background::Color(Color::TRANSPARENT)), - border_radius: style.border_radius, - border_width: style.border_width, - border_color: style.border_color, - }; - + if let Some(background) = background(bounds, &style) { ( Primitive::Group { - primitives: vec![quad, content], + primitives: vec![background, content], }, mouse_interaction, ) @@ -61,3 +51,22 @@ where } } } + +pub(crate) fn background( + bounds: Rectangle, + style: &container::Style, +) -> Option { + if style.background.is_none() && style.border_width > 0 { + return None; + } + + Some(Primitive::Quad { + bounds, + background: style + .background + .unwrap_or(Background::Color(Color::TRANSPARENT)), + border_radius: style.border_radius, + border_width: style.border_width, + border_color: style.border_color, + }) +} diff --git a/graphics/src/widget/pane_grid.rs b/graphics/src/widget/pane_grid.rs index 71b1658a..27b4f211 100644 --- a/graphics/src/widget/pane_grid.rs +++ b/graphics/src/widget/pane_grid.rs @@ -35,7 +35,7 @@ where &mut self, defaults: &Self::Defaults, content: &[(Pane, Content<'_, Message, Self>)], - dragging: Option, + dragging: Option<(Pane, Point)>, resizing: Option, layout: Layout<'_>, cursor_position: Point, @@ -63,32 +63,40 @@ where mouse_interaction = new_mouse_interaction; } - if Some(*id) == dragging { - dragged_pane = Some((i, layout)); + if let Some((dragging, origin)) = dragging { + if *id == dragging { + dragged_pane = Some((i, layout, origin)); + } } primitive }) .collect(); - let primitives = if let Some((index, layout)) = dragged_pane { + let primitives = if let Some((index, layout, origin)) = dragged_pane { let pane = panes.remove(index); let bounds = layout.bounds(); + if let Primitive::Group { primitives } = &pane { + panes.push( + primitives.first().cloned().unwrap_or(Primitive::None), + ); + } + // TODO: Fix once proper layering is implemented. // This is a pretty hacky way to achieve layering. let clip = Primitive::Clip { bounds: Rectangle { - x: cursor_position.x - bounds.width / 2.0, - y: cursor_position.y - bounds.height / 2.0, + x: cursor_position.x - origin.x, + y: cursor_position.y - origin.y, width: bounds.width + 0.5, height: bounds.height + 0.5, }, offset: Vector::new(0, 0), content: Box::new(Primitive::Translate { translation: Vector::new( - cursor_position.x - bounds.x - bounds.width / 2.0, - cursor_position.y - bounds.y - bounds.height / 2.0, + cursor_position.x - bounds.x - origin.x, + cursor_position.y - bounds.y - origin.y, ), content: Box::new(pane), }), @@ -119,48 +127,77 @@ where fn draw_pane( &mut self, defaults: &Self::Defaults, + bounds: Rectangle, + style_sheet: &Self::Style, title_bar: Option<(&TitleBar<'_, Message, Self>, Layout<'_>)>, body: (&Element<'_, Message, Self>, Layout<'_>), cursor_position: Point, ) -> Self::Output { + let style = style_sheet.style(); let (body, body_layout) = body; let (body_primitive, body_interaction) = body.draw(self, defaults, body_layout, cursor_position); + let background = crate::widget::container::background(bounds, &style); + if let Some((title_bar, title_bar_layout)) = title_bar { + let show_controls = bounds.contains(cursor_position); + let is_over_draggable = + title_bar.is_over_draggable(title_bar_layout, cursor_position); + let (title_bar_primitive, title_bar_interaction) = title_bar.draw( self, defaults, title_bar_layout, cursor_position, + show_controls, ); ( Primitive::Group { - primitives: vec![title_bar_primitive, body_primitive], + primitives: vec![ + background.unwrap_or(Primitive::None), + title_bar_primitive, + body_primitive, + ], }, - if title_bar_interaction > body_interaction { + if is_over_draggable { + mouse::Interaction::Grab + } else if title_bar_interaction > body_interaction { title_bar_interaction } else { body_interaction }, ) } else { - (body_primitive, body_interaction) + ( + if let Some(background) = background { + Primitive::Group { + primitives: vec![background, body_primitive], + } + } else { + body_primitive + }, + body_interaction, + ) } } fn draw_title_bar( &mut self, defaults: &Self::Defaults, - style: &::Style, + bounds: Rectangle, + style_sheet: &Self::Style, title: (&Element<'_, Message, Self>, Layout<'_>), controls: Option<(&Element<'_, Message, Self>, Layout<'_>)>, cursor_position: Point, ) -> Self::Output { + let style = style_sheet.style(); let (title, title_layout) = title; + let background = crate::widget::container::background(bounds, &style); + let (title_primitive, _) = title.draw(self, defaults, title_layout, cursor_position); @@ -170,12 +207,25 @@ where ( Primitive::Group { - primitives: vec![title_primitive, controls_primitive], + primitives: vec![ + background.unwrap_or(Primitive::None), + title_primitive, + controls_primitive, + ], }, controls_interaction, ) } else { - (title_primitive, mouse::Interaction::default()) + ( + if let Some(background) = background { + Primitive::Group { + primitives: vec![background, title_primitive], + } + } else { + title_primitive + }, + mouse::Interaction::default(), + ) } } } diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs index b8695b9c..29df3e14 100644 --- a/native/src/renderer/null.rs +++ b/native/src/renderer/null.rs @@ -1,7 +1,7 @@ use crate::{ - button, checkbox, column, progress_bar, radio, row, scrollable, slider, - text, text_input, Color, Element, Font, HorizontalAlignment, Layout, Point, - Rectangle, Renderer, Size, VerticalAlignment, + button, checkbox, column, container, progress_bar, radio, row, scrollable, + slider, text, text_input, Color, Element, Font, HorizontalAlignment, + Layout, Point, Rectangle, Renderer, Size, VerticalAlignment, }; /// A renderer that does nothing. @@ -226,3 +226,18 @@ impl progress_bar::Renderer for Null { ) { } } + +impl container::Renderer for Null { + type Style = (); + + fn draw( + &mut self, + _defaults: &Self::Defaults, + _bounds: Rectangle, + _cursor_position: Point, + _style: &Self::Style, + _content: &Element<'_, Message, Self>, + _content_layout: Layout<'_>, + ) { + } +} diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs index bf9c76fd..c0c3839e 100644 --- a/native/src/widget/pane_grid.rs +++ b/native/src/widget/pane_grid.rs @@ -30,7 +30,7 @@ pub use title_bar::TitleBar; use crate::{ container, keyboard, layout, mouse, row, Clipboard, Element, Event, Hasher, - Layout, Length, Point, Size, Widget, + Layout, Length, Point, Rectangle, Size, Widget, }; /// A collection of panes distributed using either vertical or horizontal splits @@ -427,17 +427,18 @@ where clicked_region.next() { match &self.on_drag { - Some(on_drag) - if content.is_over_drag_target( - layout, - cursor_position, - ) => - { - self.state.pick_pane(pane); + Some(on_drag) => { + if let Some(origin) = + content.drag_origin(layout, cursor_position) + { + self.state.pick_pane(pane, origin); - messages.push(on_drag(DragEvent::Picked { - pane: *pane, - })); + messages.push(on_drag(DragEvent::Picked { + pane: *pane, + })); + } else { + self.state.focus(pane); + } } _ => { self.state.focus(pane); @@ -448,7 +449,7 @@ where } } 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 { @@ -657,7 +658,7 @@ pub trait Renderer: crate::Renderer + container::Renderer + Sized { &mut self, defaults: &Self::Defaults, content: &[(Pane, Content<'_, Message, Self>)], - dragging: Option, + dragging: Option<(Pane, Point)>, resizing: Option, layout: Layout<'_>, cursor_position: Point, @@ -676,6 +677,8 @@ pub trait Renderer: crate::Renderer + container::Renderer + Sized { fn draw_pane( &mut self, defaults: &Self::Defaults, + bounds: Rectangle, + style: &Self::Style, title_bar: Option<(&TitleBar<'_, Message, Self>, Layout<'_>)>, body: (&Element<'_, Message, Self>, Layout<'_>), cursor_position: Point, @@ -684,6 +687,7 @@ pub trait Renderer: crate::Renderer + container::Renderer + Sized { fn draw_title_bar( &mut self, defaults: &Self::Defaults, + bounds: Rectangle, style: &Self::Style, title: (&Element<'_, Message, Self>, Layout<'_>), controls: Option<(&Element<'_, Message, Self>, Layout<'_>)>, diff --git a/native/src/widget/pane_grid/content.rs b/native/src/widget/pane_grid/content.rs index a30b0e7d..843dcec4 100644 --- a/native/src/widget/pane_grid/content.rs +++ b/native/src/widget/pane_grid/content.rs @@ -1,7 +1,7 @@ use crate::container; use crate::layout; use crate::pane_grid::{self, TitleBar}; -use crate::{Clipboard, Element, Event, Hasher, Layout, Point, Size}; +use crate::{Clipboard, Element, Event, Hasher, Layout, Point, Size, Vector}; /// The content of a [`Pane`]. /// @@ -9,6 +9,7 @@ use crate::{Clipboard, Element, Event, Hasher, Layout, Point, Size}; pub struct Content<'a, Message, Renderer: container::Renderer> { title_bar: Option>, body: Element<'a, Message, Renderer>, + style: Renderer::Style, } impl<'a, Message, Renderer> Content<'a, Message, Renderer> @@ -19,6 +20,7 @@ where Self { title_bar: None, body: body.into(), + style: Renderer::Style::default(), } } @@ -29,6 +31,14 @@ where self.title_bar = Some(title_bar); self } + + /// Sets the style of the [`TitleBar`]. + /// + /// [`TitleBar`]: struct.TitleBar.html + pub fn style(mut self, style: impl Into) -> Self { + self.style = style.into(); + self + } } impl<'a, Message, Renderer> Content<'a, Message, Renderer> @@ -49,6 +59,8 @@ where renderer.draw_pane( defaults, + layout.bounds(), + &self.style, Some((title_bar, title_bar_layout)), (&self.body, body_layout), cursor_position, @@ -56,6 +68,8 @@ where } else { renderer.draw_pane( defaults, + layout.bounds(), + &self.style, None, (&self.body, layout), cursor_position, @@ -63,12 +77,25 @@ where } } - pub(crate) fn is_over_drag_target( + pub fn drag_origin( &self, - _layout: Layout<'_>, - _cursor_position: Point, - ) -> bool { - false + layout: Layout<'_>, + cursor_position: Point, + ) -> Option { + if let Some(title_bar) = &self.title_bar { + let mut children = layout.children(); + let title_bar_layout = children.next().unwrap(); + + if title_bar.is_over_draggable(title_bar_layout, cursor_position) { + let position = layout.position(); + + Some(cursor_position - Vector::new(position.x, position.y)) + } else { + None + } + } else { + None + } } pub(crate) fn layout( @@ -115,14 +142,31 @@ where renderer: &Renderer, clipboard: Option<&dyn Clipboard>, ) { + let body_layout = if let Some(title_bar) = &mut self.title_bar { + let mut children = layout.children(); + + title_bar.on_event( + event.clone(), + children.next().unwrap(), + cursor_position, + messages, + renderer, + clipboard, + ); + + children.next().unwrap() + } else { + layout + }; + self.body.on_event( event, - layout, + body_layout, cursor_position, messages, renderer, clipboard, - ) + ); } pub(crate) fn hash_layout(&self, state: &mut Hasher) { diff --git a/native/src/widget/pane_grid/state.rs b/native/src/widget/pane_grid/state.rs index 943120e3..a8431dec 100644 --- a/native/src/widget/pane_grid/state.rs +++ b/native/src/widget/pane_grid/state.rs @@ -313,13 +313,14 @@ pub struct Internal { action: Action, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum Action { Idle { focus: Option, }, Dragging { pane: Pane, + origin: Point, }, Resizing { split: Split, @@ -334,7 +335,7 @@ impl Action { Action::Idle { focus } | Action::Resizing { focus, .. } => { focus.map(|pane| (pane, Focus::Idle)) } - Action::Dragging { pane } => Some((*pane, Focus::Dragging)), + Action::Dragging { pane, .. } => Some((*pane, Focus::Dragging)), } } } @@ -351,9 +352,9 @@ impl Internal { } } - pub fn picked_pane(&self) -> Option { + pub fn picked_pane(&self) -> Option<(Pane, Point)> { match self.action { - Action::Dragging { pane } => Some(pane), + Action::Dragging { pane, origin } => Some((pane, origin)), _ => None, } } @@ -385,8 +386,11 @@ impl Internal { self.action = Action::Idle { focus: Some(*pane) }; } - pub fn pick_pane(&mut self, pane: &Pane) { - self.action = Action::Dragging { pane: *pane }; + pub fn pick_pane(&mut self, pane: &Pane, origin: Point) { + self.action = Action::Dragging { + pane: *pane, + origin, + }; } pub fn pick_split(&mut self, split: &Split, axis: Axis) { diff --git a/native/src/widget/pane_grid/title_bar.rs b/native/src/widget/pane_grid/title_bar.rs index 1fd06411..dc96dcbf 100644 --- a/native/src/widget/pane_grid/title_bar.rs +++ b/native/src/widget/pane_grid/title_bar.rs @@ -1,7 +1,7 @@ use crate::container; use crate::layout; use crate::pane_grid; -use crate::{Element, Layout, Point, Size}; +use crate::{Clipboard, Element, Event, Layout, Point, Size}; pub struct TitleBar<'a, Message, Renderer: container::Renderer> { title: Element<'a, Message, Renderer>, @@ -38,6 +38,14 @@ where self.padding = units; self } + + /// Sets the style of the [`TitleBar`]. + /// + /// [`TitleBar`]: struct.TitleBar.html + pub fn style(mut self, style: impl Into) -> Self { + self.style = style.into(); + self + } } impl<'a, Message, Renderer> TitleBar<'a, Message, Renderer> @@ -50,30 +58,63 @@ where defaults: &Renderer::Defaults, layout: Layout<'_>, cursor_position: Point, + show_controls: bool, ) -> Renderer::Output { + let mut children = layout.children(); + let padded = children.next().unwrap(); + if let Some(controls) = &self.controls { - let mut children = layout.children(); + let mut children = padded.children(); let title_layout = children.next().unwrap(); let controls_layout = children.next().unwrap(); renderer.draw_title_bar( defaults, + layout.bounds(), &self.style, (&self.title, title_layout), - Some((controls, controls_layout)), + if show_controls { + Some((controls, controls_layout)) + } else { + None + }, cursor_position, ) } else { renderer.draw_title_bar( defaults, + layout.bounds(), &self.style, - (&self.title, layout), + (&self.title, padded), None, cursor_position, ) } } + pub fn is_over_draggable( + &self, + layout: Layout<'_>, + cursor_position: Point, + ) -> bool { + if layout.bounds().contains(cursor_position) { + let mut children = layout.children(); + let padded = children.next().unwrap(); + + if self.controls.is_some() { + let mut children = padded.children(); + let _ = children.next().unwrap(); + let controls_layout = children.next().unwrap(); + + !controls_layout.bounds().contains(cursor_position) + } else { + true + } + } else { + false + } + } + pub(crate) fn layout( &self, renderer: &Renderer, @@ -82,38 +123,66 @@ where let padding = f32::from(self.padding); let limits = limits.pad(padding); - let mut node = if let Some(controls) = &self.controls { + let node = if let Some(controls) = &self.controls { let max_size = limits.max(); - let title_layout = self - .title + let mut controls_layout = controls .layout(renderer, &layout::Limits::new(Size::ZERO, max_size)); - let title_size = title_layout.size(); + let controls_size = controls_layout.size(); + let space_before_controls = max_size.width - controls_size.width; - let mut controls_layout = controls.layout( + let mut title_layout = self.title.layout( renderer, &layout::Limits::new( Size::ZERO, - Size::new( - max_size.width - title_size.width, - max_size.height, - ), + Size::new(space_before_controls, max_size.height), ), ); - controls_layout.move_to(Point::new(title_size.width, 0.0)); + title_layout.move_to(Point::new(padding, padding)); + controls_layout + .move_to(Point::new(space_before_controls + padding, padding)); + + let title_size = title_layout.size(); + let height = title_size.height.max(controls_size.height); layout::Node::with_children( - max_size, + Size::new(max_size.width, height), vec![title_layout, controls_layout], ) } else { self.title.layout(renderer, &limits) }; - node.move_to(Point::new(padding, padding)); + layout::Node::with_children(node.size().pad(padding), vec![node]) + } - node + pub(crate) fn on_event( + &mut self, + event: Event, + layout: Layout<'_>, + cursor_position: Point, + messages: &mut Vec, + renderer: &Renderer, + clipboard: Option<&dyn Clipboard>, + ) { + if let Some(controls) = &mut self.controls { + let mut children = layout.children(); + let padded = children.next().unwrap(); + + let mut children = padded.children(); + let _ = children.next(); + let controls_layout = children.next().unwrap(); + + controls.on_event( + event, + controls_layout, + cursor_position, + messages, + renderer, + clipboard, + ); + } } } From 3cfe6e428be22fdbf715f1f28caec0c802fd069e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 10 Jun 2020 16:27:28 +0200 Subject: [PATCH 05/16] Lay out title text dynamically in `TitleBar` --- graphics/src/widget/pane_grid.rs | 30 ++++++-- native/src/renderer/null.rs | 48 ++++++++++++- native/src/widget/pane_grid.rs | 17 +++-- native/src/widget/pane_grid/content.rs | 6 +- native/src/widget/pane_grid/title_bar.rs | 90 ++++++++++++++++-------- 5 files changed, 144 insertions(+), 47 deletions(-) diff --git a/graphics/src/widget/pane_grid.rs b/graphics/src/widget/pane_grid.rs index 27b4f211..ec607c47 100644 --- a/graphics/src/widget/pane_grid.rs +++ b/graphics/src/widget/pane_grid.rs @@ -8,10 +8,15 @@ //! //! [`pane_grid` example]: https://github.com/hecrj/iced/tree/0.1/examples/pane_grid //! [`PaneGrid`]: type.PaneGrid.html -use crate::{Backend, Primitive, Renderer}; +use crate::backend::{self, Backend}; +use crate::{Primitive, Renderer}; use iced_native::mouse; use iced_native::pane_grid; -use iced_native::{Element, Layout, Point, Rectangle, Vector}; +use iced_native::text; +use iced_native::{ + Element, HorizontalAlignment, Layout, Point, Rectangle, Vector, + VerticalAlignment, +}; pub use iced_native::pane_grid::{ Axis, Configuration, Content, Direction, DragEvent, Focus, KeyPressEvent, @@ -29,7 +34,7 @@ pub type PaneGrid<'a, Message, Backend> = impl pane_grid::Renderer for Renderer where - B: Backend, + B: Backend + backend::Text, { fn draw( &mut self, @@ -189,17 +194,28 @@ where defaults: &Self::Defaults, bounds: Rectangle, style_sheet: &Self::Style, - title: (&Element<'_, Message, Self>, Layout<'_>), + title: &str, + title_size: u16, + title_font: Self::Font, + title_bounds: Rectangle, controls: Option<(&Element<'_, Message, Self>, Layout<'_>)>, cursor_position: Point, ) -> Self::Output { let style = style_sheet.style(); - let (title, title_layout) = title; let background = crate::widget::container::background(bounds, &style); - let (title_primitive, _) = - title.draw(self, defaults, title_layout, cursor_position); + let (title_primitive, _) = text::Renderer::draw( + self, + defaults, + title_bounds, + title, + title_size, + title_font, + None, + HorizontalAlignment::Left, + VerticalAlignment::Top, + ); if let Some((controls, controls_layout)) = controls { let (controls_primitive, controls_interaction) = diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs index 29df3e14..d6a8e18f 100644 --- a/native/src/renderer/null.rs +++ b/native/src/renderer/null.rs @@ -1,7 +1,8 @@ use crate::{ - button, checkbox, column, container, progress_bar, radio, row, scrollable, - slider, text, text_input, Color, Element, Font, HorizontalAlignment, - Layout, Point, Rectangle, Renderer, Size, VerticalAlignment, + button, checkbox, column, container, pane_grid, progress_bar, radio, row, + scrollable, slider, text, text_input, Color, Element, Font, + HorizontalAlignment, Layout, Point, Rectangle, Renderer, Size, + VerticalAlignment, }; /// A renderer that does nothing. @@ -241,3 +242,44 @@ impl container::Renderer for Null { ) { } } + +impl pane_grid::Renderer for Null { + fn draw( + &mut self, + _defaults: &Self::Defaults, + _content: &[(pane_grid::Pane, pane_grid::Content<'_, Message, Self>)], + _dragging: Option<(pane_grid::Pane, Point)>, + _resizing: Option, + _layout: Layout<'_>, + _cursor_position: Point, + ) { + } + + fn draw_pane( + &mut self, + _defaults: &Self::Defaults, + _bounds: Rectangle, + _style: &Self::Style, + _title_bar: Option<( + &pane_grid::TitleBar<'_, Message, Self>, + Layout<'_>, + )>, + _body: (&Element<'_, Message, Self>, Layout<'_>), + _cursor_position: Point, + ) { + } + + fn draw_title_bar( + &mut self, + _defaults: &Self::Defaults, + _bounds: Rectangle, + _style: &Self::Style, + _title: &str, + _title_size: u16, + _title_font: Self::Font, + _title_bounds: Rectangle, + _controls: Option<(&Element<'_, Message, Self>, Layout<'_>)>, + _cursor_position: Point, + ) { + } +} diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs index 8fb6c20c..a3282ed7 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::{ - container, keyboard, layout, mouse, row, Clipboard, Element, Event, Hasher, - Layout, Length, Point, Rectangle, Size, Widget, + container, keyboard, layout, mouse, row, text, Clipboard, Element, Event, + Hasher, Layout, Length, Point, Rectangle, 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: container::Renderer> { +pub struct PaneGrid<'a, Message, Renderer: self::Renderer> { state: &'a mut state::Internal, pressed_modifiers: &'a mut keyboard::ModifiersState, elements: Vec<(Pane, Content<'a, Message, Renderer>)>, @@ -101,7 +101,7 @@ pub struct PaneGrid<'a, Message, Renderer: container::Renderer> { impl<'a, Message, Renderer> PaneGrid<'a, Message, Renderer> where - Renderer: container::Renderer, + Renderer: self::Renderer, { /// Creates a [`PaneGrid`] with the given [`State`] and view function. /// @@ -646,7 +646,9 @@ where /// /// [`PaneGrid`]: struct.PaneGrid.html /// [renderer]: ../../renderer/index.html -pub trait Renderer: crate::Renderer + container::Renderer + Sized { +pub trait Renderer: + crate::Renderer + container::Renderer + text::Renderer + Sized +{ /// Draws a [`PaneGrid`]. /// /// It receives: @@ -694,7 +696,10 @@ pub trait Renderer: crate::Renderer + container::Renderer + Sized { defaults: &Self::Defaults, bounds: Rectangle, style: &Self::Style, - title: (&Element<'_, Message, Self>, Layout<'_>), + title: &str, + title_size: u16, + title_font: Self::Font, + title_bounds: Rectangle, controls: Option<(&Element<'_, Message, Self>, Layout<'_>)>, cursor_position: Point, ) -> Self::Output; diff --git a/native/src/widget/pane_grid/content.rs b/native/src/widget/pane_grid/content.rs index 843dcec4..55fa4c60 100644 --- a/native/src/widget/pane_grid/content.rs +++ b/native/src/widget/pane_grid/content.rs @@ -6,7 +6,7 @@ use crate::{Clipboard, Element, Event, Hasher, Layout, Point, Size, Vector}; /// The content of a [`Pane`]. /// /// [`Pane`]: struct.Pane.html -pub struct Content<'a, Message, Renderer: container::Renderer> { +pub struct Content<'a, Message, Renderer: pane_grid::Renderer> { title_bar: Option>, body: Element<'a, Message, Renderer>, style: Renderer::Style, @@ -14,7 +14,7 @@ pub struct Content<'a, Message, Renderer: container::Renderer> { impl<'a, Message, Renderer> Content<'a, Message, Renderer> where - Renderer: container::Renderer, + Renderer: pane_grid::Renderer, { pub fn new(body: impl Into>) -> Self { Self { @@ -43,7 +43,7 @@ where impl<'a, Message, Renderer> Content<'a, Message, Renderer> where - Renderer: pane_grid::Renderer + container::Renderer, + Renderer: pane_grid::Renderer, { pub fn draw( &self, diff --git a/native/src/widget/pane_grid/title_bar.rs b/native/src/widget/pane_grid/title_bar.rs index dc96dcbf..bdf87c17 100644 --- a/native/src/widget/pane_grid/title_bar.rs +++ b/native/src/widget/pane_grid/title_bar.rs @@ -1,10 +1,10 @@ -use crate::container; use crate::layout; use crate::pane_grid; -use crate::{Clipboard, Element, Event, Layout, Point, Size}; +use crate::{Clipboard, Element, Event, Layout, Point, Rectangle, Size}; -pub struct TitleBar<'a, Message, Renderer: container::Renderer> { - title: Element<'a, Message, Renderer>, +pub struct TitleBar<'a, Message, Renderer: pane_grid::Renderer> { + title: String, + title_size: Option, controls: Option>, padding: u16, style: Renderer::Style, @@ -12,17 +12,29 @@ pub struct TitleBar<'a, Message, Renderer: container::Renderer> { impl<'a, Message, Renderer> TitleBar<'a, Message, Renderer> where - Renderer: container::Renderer, + Renderer: pane_grid::Renderer, { - pub fn new(title: impl Into>) -> Self { + pub fn new(title: impl Into) -> Self { Self { title: title.into(), + title_size: None, controls: None, padding: 0, style: Renderer::Style::default(), } } + /// Sets the size of the title of the [`TitleBar`]. + /// + /// [`TitleBar`]: struct.Text.html + pub fn title_size(mut self, size: u16) -> Self { + self.title_size = Some(size); + self + } + + /// Sets the controls of the [`TitleBar`]. + /// + /// [`TitleBar`]: struct.TitleBar.html pub fn controls( mut self, controls: impl Into>, @@ -68,24 +80,38 @@ where let title_layout = children.next().unwrap(); let controls_layout = children.next().unwrap(); + let (title_bounds, controls) = if show_controls { + (title_layout.bounds(), Some((controls, controls_layout))) + } else { + ( + Rectangle { + width: padded.bounds().width, + ..title_layout.bounds() + }, + None, + ) + }; + renderer.draw_title_bar( defaults, layout.bounds(), &self.style, - (&self.title, title_layout), - if show_controls { - Some((controls, controls_layout)) - } else { - None - }, + &self.title, + self.title_size.unwrap_or(Renderer::DEFAULT_SIZE), + Renderer::Font::default(), + title_bounds, + controls, cursor_position, ) } else { - renderer.draw_title_bar( + renderer.draw_title_bar::<()>( defaults, layout.bounds(), &self.style, - (&self.title, padded), + &self.title, + self.title_size.unwrap_or(Renderer::DEFAULT_SIZE), + Renderer::Font::default(), + padded.bounds(), None, cursor_position, ) @@ -122,39 +148,47 @@ where ) -> layout::Node { let padding = f32::from(self.padding); let limits = limits.pad(padding); + let max_size = limits.max(); - let node = if let Some(controls) = &self.controls { - let max_size = limits.max(); + let title_size = self.title_size.unwrap_or(Renderer::DEFAULT_SIZE); + let title_font = Renderer::Font::default(); + let (title_width, title_height) = renderer.measure( + &self.title, + title_size, + title_font, + Size::new(f32::INFINITY, max_size.height), + ); + + let mut node = if let Some(controls) = &self.controls { let mut controls_layout = controls .layout(renderer, &layout::Limits::new(Size::ZERO, max_size)); let controls_size = controls_layout.size(); let space_before_controls = max_size.width - controls_size.width; - let mut title_layout = self.title.layout( - renderer, - &layout::Limits::new( - Size::ZERO, - Size::new(space_before_controls, max_size.height), - ), - ); - - title_layout.move_to(Point::new(padding, padding)); - controls_layout - .move_to(Point::new(space_before_controls + padding, padding)); + let mut title_layout = layout::Node::new(Size::new( + title_width.min(space_before_controls), + title_height, + )); let title_size = title_layout.size(); let height = title_size.height.max(controls_size.height); + title_layout + .move_to(Point::new(0.0, (height - title_size.height) / 2.0)); + controls_layout.move_to(Point::new(space_before_controls, 0.0)); + layout::Node::with_children( Size::new(max_size.width, height), vec![title_layout, controls_layout], ) } else { - self.title.layout(renderer, &limits) + layout::Node::new(Size::new(title_width, title_height)) }; + node.move_to(Point::new(padding, padding)); + layout::Node::with_children(node.size().pad(padding), vec![node]) } From 072ec69d53d2708d8fd1693151bcec7305efccf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 10 Jun 2020 16:29:23 +0200 Subject: [PATCH 06/16] Expose `Content` and `TitleBar` in `iced_glow` --- glow/src/widget/pane_grid.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/glow/src/widget/pane_grid.rs b/glow/src/widget/pane_grid.rs index d9fec026..3c47b562 100644 --- a/glow/src/widget/pane_grid.rs +++ b/glow/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>; From 733ec6b2eafd3e7267409e49f2e6cf497f7c7074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 8 Jul 2020 11:48:16 +0200 Subject: [PATCH 07/16] Fix default text size in `TitleBar` --- native/src/widget/pane_grid/title_bar.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/native/src/widget/pane_grid/title_bar.rs b/native/src/widget/pane_grid/title_bar.rs index bdf87c17..cf5f0a59 100644 --- a/native/src/widget/pane_grid/title_bar.rs +++ b/native/src/widget/pane_grid/title_bar.rs @@ -97,7 +97,7 @@ where layout.bounds(), &self.style, &self.title, - self.title_size.unwrap_or(Renderer::DEFAULT_SIZE), + self.title_size.unwrap_or(renderer.default_size()), Renderer::Font::default(), title_bounds, controls, @@ -109,7 +109,7 @@ where layout.bounds(), &self.style, &self.title, - self.title_size.unwrap_or(Renderer::DEFAULT_SIZE), + self.title_size.unwrap_or(renderer.default_size()), Renderer::Font::default(), padded.bounds(), None, @@ -150,7 +150,7 @@ where let limits = limits.pad(padding); let max_size = limits.max(); - let title_size = self.title_size.unwrap_or(Renderer::DEFAULT_SIZE); + let title_size = self.title_size.unwrap_or(renderer.default_size()); let title_font = Renderer::Font::default(); let (title_width, title_height) = renderer.measure( From e3cd947437cad1a53715b77b63e6c7a348de97c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 9 Jul 2020 05:26:11 +0200 Subject: [PATCH 08/16] Write documentation for new `PaneGrid` API --- graphics/src/widget/pane_grid.rs | 6 ++--- native/src/lib.rs | 4 +-- native/src/widget/pane_grid.rs | 22 ++++++++++++--- native/src/widget/pane_grid/content.rs | 34 ++++++++++++++++-------- native/src/widget/pane_grid/title_bar.rs | 22 +++++++++++++-- 5 files changed, 66 insertions(+), 22 deletions(-) diff --git a/graphics/src/widget/pane_grid.rs b/graphics/src/widget/pane_grid.rs index ec607c47..c8d9625b 100644 --- a/graphics/src/widget/pane_grid.rs +++ b/graphics/src/widget/pane_grid.rs @@ -148,8 +148,8 @@ where if let Some((title_bar, title_bar_layout)) = title_bar { let show_controls = bounds.contains(cursor_position); - let is_over_draggable = - title_bar.is_over_draggable(title_bar_layout, cursor_position); + let is_over_pick_area = + title_bar.is_over_pick_area(title_bar_layout, cursor_position); let (title_bar_primitive, title_bar_interaction) = title_bar.draw( self, @@ -167,7 +167,7 @@ where body_primitive, ], }, - if is_over_draggable { + if is_over_pick_area { mouse::Interaction::Grab } else if title_bar_interaction > body_interaction { title_bar_interaction diff --git a/native/src/lib.rs b/native/src/lib.rs index 86046f63..b67ff2a1 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -30,8 +30,8 @@ //! [`Widget`]: widget/trait.Widget.html //! [`UserInterface`]: struct.UserInterface.html //! [renderer]: renderer/index.html -//#![deny(missing_docs)] -//#![deny(missing_debug_implementations)] +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] #![deny(unused_results)] #![forbid(unsafe_code)] #![forbid(rust_2018_idioms)] diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs index 21788e6a..5313e993 100644 --- a/native/src/widget/pane_grid.rs +++ b/native/src/widget/pane_grid.rs @@ -30,7 +30,7 @@ pub use title_bar::TitleBar; use crate::{ container, keyboard, layout, mouse, row, text, Clipboard, Element, Event, - Hasher, Layout, Length, Point, Rectangle, Size, Widget, + Hasher, Layout, Length, Point, Rectangle, Size, Vector, Widget, }; /// A collection of panes distributed using either vertical or horizontal splits @@ -273,9 +273,12 @@ where if let Some(((pane, content), layout)) = clicked_region.next() { match &self.on_drag { Some(on_drag) => { - if let Some(origin) = - content.drag_origin(layout, cursor_position) - { + if content.can_be_picked_at(layout, cursor_position) { + let pane_position = layout.position(); + + let origin = cursor_position + - Vector::new(pane_position.x, pane_position.y); + self.state.pick_pane(pane, origin); messages @@ -693,6 +696,17 @@ pub trait Renderer: cursor_position: Point, ) -> Self::Output; + /// Draws a [`TitleBar`]. + /// + /// It receives: + /// - the bounds, style of the [`TitleBar`] + /// - the style of the [`TitleBar`] + /// - the title of the [`TitleBar`] with its size, font, and bounds + /// - the controls of the [`TitleBar`] with their [`Layout`+, if any + /// - the cursor position + /// + /// [`TitleBar`]: struct.TitleBar.html + /// [`Layout`]: ../layout/struct.Layout.html fn draw_title_bar( &mut self, defaults: &Self::Defaults, diff --git a/native/src/widget/pane_grid/content.rs b/native/src/widget/pane_grid/content.rs index 55fa4c60..1f5ce640 100644 --- a/native/src/widget/pane_grid/content.rs +++ b/native/src/widget/pane_grid/content.rs @@ -1,11 +1,12 @@ use crate::container; use crate::layout; use crate::pane_grid::{self, TitleBar}; -use crate::{Clipboard, Element, Event, Hasher, Layout, Point, Size, Vector}; +use crate::{Clipboard, Element, Event, Hasher, Layout, Point, Size}; /// The content of a [`Pane`]. /// /// [`Pane`]: struct.Pane.html +#[allow(missing_debug_implementations)] pub struct Content<'a, Message, Renderer: pane_grid::Renderer> { title_bar: Option>, body: Element<'a, Message, Renderer>, @@ -16,6 +17,9 @@ impl<'a, Message, Renderer> Content<'a, Message, Renderer> where Renderer: pane_grid::Renderer, { + /// Creates a new [`Content`] with the provided body. + /// + /// [`Content`]: struct.Content.html pub fn new(body: impl Into>) -> Self { Self { title_bar: None, @@ -24,6 +28,10 @@ where } } + /// Sets the [`TitleBar`] of this [`Content`]. + /// + /// [`TitleBar`]: struct.TitleBar.html + /// [`Content`]: struct.Content.html pub fn title_bar( mut self, title_bar: TitleBar<'a, Message, Renderer>, @@ -45,6 +53,11 @@ impl<'a, Message, Renderer> Content<'a, Message, Renderer> where Renderer: pane_grid::Renderer, { + /// Draws the [`Content`] with the provided [`Renderer`] and [`Layout`]. + /// + /// [`Content`]: struct.Content.html + /// [`Renderer`]: trait.Renderer.html + /// [`Layout`]: ../layout/struct.Layout.html pub fn draw( &self, renderer: &mut Renderer, @@ -77,24 +90,23 @@ where } } - pub fn drag_origin( + /// Returns whether the [`Content`] with the given [`Layout`] can be picked + /// at the provided cursor position. + /// + /// [`Content`]: struct.Content.html + /// [`Layout`]: ../layout/struct.Layout.html + pub fn can_be_picked_at( &self, layout: Layout<'_>, cursor_position: Point, - ) -> Option { + ) -> bool { if let Some(title_bar) = &self.title_bar { let mut children = layout.children(); let title_bar_layout = children.next().unwrap(); - if title_bar.is_over_draggable(title_bar_layout, cursor_position) { - let position = layout.position(); - - Some(cursor_position - Vector::new(position.x, position.y)) - } else { - None - } + title_bar.is_over_pick_area(title_bar_layout, cursor_position) } else { - None + false } } diff --git a/native/src/widget/pane_grid/title_bar.rs b/native/src/widget/pane_grid/title_bar.rs index cf5f0a59..775c8a8f 100644 --- a/native/src/widget/pane_grid/title_bar.rs +++ b/native/src/widget/pane_grid/title_bar.rs @@ -2,6 +2,10 @@ use crate::layout; use crate::pane_grid; use crate::{Clipboard, Element, Event, Layout, Point, Rectangle, Size}; +/// The title bar of a [`Pane`]. +/// +/// [`Pane`]: struct.Pane.html +#[allow(missing_debug_implementations)] pub struct TitleBar<'a, Message, Renderer: pane_grid::Renderer> { title: String, title_size: Option, @@ -14,6 +18,9 @@ impl<'a, Message, Renderer> TitleBar<'a, Message, Renderer> where Renderer: pane_grid::Renderer, { + /// Cretes a new [`TitleBar`] with the given title. + /// + /// [`TitleBar`]: struct.TitleBar.html pub fn new(title: impl Into) -> Self { Self { title: title.into(), @@ -26,7 +33,7 @@ where /// Sets the size of the title of the [`TitleBar`]. /// - /// [`TitleBar`]: struct.Text.html + /// [`TitleBar`]: struct.TitleBar.html pub fn title_size(mut self, size: u16) -> Self { self.title_size = Some(size); self @@ -64,6 +71,11 @@ impl<'a, Message, Renderer> TitleBar<'a, Message, Renderer> where Renderer: pane_grid::Renderer, { + /// Draws the [`TitleBar`] with the provided [`Renderer`] and [`Layout`]. + /// + /// [`TitleBar`]: struct.TitleBar.html + /// [`Renderer`]: trait.Renderer.html + /// [`Layout`]: ../layout/struct.Layout.html pub fn draw( &self, renderer: &mut Renderer, @@ -118,7 +130,13 @@ where } } - pub fn is_over_draggable( + /// Returns whether the mouse cursor is over the pick area of the + /// [`TitleBar`] or not. + /// + /// The whole [`TitleBar`] is a pick area, except its controls. + /// + /// [`TitleBar`]: struct.TitleBar.html + pub fn is_over_pick_area( &self, layout: Layout<'_>, cursor_position: Point, From 2334c7d1d558818ae469a4cf629eb2ba82eaa4dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 9 Jul 2020 05:28:19 +0200 Subject: [PATCH 09/16] Stop tracking `pressed_modifiers` in `PaneGrid` --- native/src/widget/pane_grid.rs | 5 ----- native/src/widget/pane_grid/state.rs | 3 --- 2 files changed, 8 deletions(-) diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs index 5313e993..24cf5094 100644 --- a/native/src/widget/pane_grid.rs +++ b/native/src/widget/pane_grid.rs @@ -88,7 +88,6 @@ use crate::{ #[allow(missing_debug_implementations)] pub struct PaneGrid<'a, Message, Renderer: self::Renderer> { state: &'a mut state::Internal, - pressed_modifiers: &'a mut keyboard::ModifiersState, elements: Vec<(Pane, Content<'a, Message, Renderer>)>, width: Length, height: Length, @@ -143,7 +142,6 @@ where Self { state: &mut state.internal, - pressed_modifiers: &mut state.modifiers, elements, width: Length::Fill, height: Length::Fill, @@ -558,9 +556,6 @@ where } } } - keyboard::Event::ModifiersChanged(modifiers) => { - *self.pressed_modifiers = modifiers; - } _ => {} } } diff --git a/native/src/widget/pane_grid/state.rs b/native/src/widget/pane_grid/state.rs index 3f0accc1..e1585968 100644 --- a/native/src/widget/pane_grid/state.rs +++ b/native/src/widget/pane_grid/state.rs @@ -1,5 +1,4 @@ use crate::{ - keyboard, pane_grid::{Axis, Configuration, Direction, Node, Pane, Split}, Hasher, Point, Rectangle, Size, }; @@ -25,7 +24,6 @@ use std::collections::HashMap; pub struct State { pub(super) panes: HashMap, pub(super) internal: Internal, - pub(super) modifiers: keyboard::ModifiersState, } /// The current focus of a [`Pane`]. @@ -76,7 +74,6 @@ impl State { last_id, action: Action::Idle { focus: None }, }, - modifiers: keyboard::ModifiersState::default(), } } From ad19c1628d89edb6490a8b586eecd1d72ae60459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 9 Jul 2020 05:33:44 +0200 Subject: [PATCH 10/16] Fix docs of `modifiers_keys` in `PaneGrid` --- native/src/widget/pane_grid.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs index 24cf5094..6b9d5f2f 100644 --- a/native/src/widget/pane_grid.rs +++ b/native/src/widget/pane_grid.rs @@ -182,8 +182,7 @@ where /// Sets the modifier keys of the [`PaneGrid`]. /// - /// The modifier keys will need to be pressed to trigger dragging, and key - /// events. + /// The modifier keys will need to be pressed to trigger key events. /// /// The default modifier key is `Ctrl`. /// From 2f02ca3248bee529ebde7901375784dc9971eaf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 9 Jul 2020 05:42:28 +0200 Subject: [PATCH 11/16] Fix layout of a `TitleBar` without controls --- native/src/widget/pane_grid/title_bar.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/src/widget/pane_grid/title_bar.rs b/native/src/widget/pane_grid/title_bar.rs index 775c8a8f..c74c9e20 100644 --- a/native/src/widget/pane_grid/title_bar.rs +++ b/native/src/widget/pane_grid/title_bar.rs @@ -202,7 +202,7 @@ where vec![title_layout, controls_layout], ) } else { - layout::Node::new(Size::new(title_width, title_height)) + layout::Node::new(Size::new(max_size.width, title_height)) }; node.move_to(Point::new(padding, padding)); From ef553cd12456a3fd70df26c936953887a78a1bba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 9 Jul 2020 05:44:48 +0200 Subject: [PATCH 12/16] Stop drawing pane background when dragged --- graphics/src/widget/pane_grid.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/graphics/src/widget/pane_grid.rs b/graphics/src/widget/pane_grid.rs index c8d9625b..8ec5c547 100644 --- a/graphics/src/widget/pane_grid.rs +++ b/graphics/src/widget/pane_grid.rs @@ -82,12 +82,6 @@ where let pane = panes.remove(index); let bounds = layout.bounds(); - if let Primitive::Group { primitives } = &pane { - panes.push( - primitives.first().cloned().unwrap_or(Primitive::None), - ); - } - // TODO: Fix once proper layering is implemented. // This is a pretty hacky way to achieve layering. let clip = Primitive::Clip { From 1319c25f20a274d163d8009805b6fd3bb55ac88a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 9 Jul 2020 06:27:12 +0200 Subject: [PATCH 13/16] Respect `TitleBar` text color style when drawing --- graphics/src/widget/pane_grid.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/graphics/src/widget/pane_grid.rs b/graphics/src/widget/pane_grid.rs index 8ec5c547..aa8a3f7c 100644 --- a/graphics/src/widget/pane_grid.rs +++ b/graphics/src/widget/pane_grid.rs @@ -9,6 +9,7 @@ //! [`pane_grid` example]: https://github.com/hecrj/iced/tree/0.1/examples/pane_grid //! [`PaneGrid`]: type.PaneGrid.html use crate::backend::{self, Backend}; +use crate::defaults; use crate::{Primitive, Renderer}; use iced_native::mouse; use iced_native::pane_grid; @@ -197,11 +198,17 @@ where ) -> Self::Output { let style = style_sheet.style(); + let defaults = Self::Defaults { + text: defaults::Text { + color: style.text_color.unwrap_or(defaults.text.color), + }, + }; + let background = crate::widget::container::background(bounds, &style); let (title_primitive, _) = text::Renderer::draw( self, - defaults, + &defaults, title_bounds, title, title_size, @@ -212,8 +219,12 @@ where ); if let Some((controls, controls_layout)) = controls { - let (controls_primitive, controls_interaction) = - controls.draw(self, defaults, controls_layout, cursor_position); + let (controls_primitive, controls_interaction) = controls.draw( + self, + &defaults, + controls_layout, + cursor_position, + ); ( Primitive::Group { From 67f4c9aea3a04aca765943f3314fd191f6d9c81f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 9 Jul 2020 06:27:38 +0200 Subject: [PATCH 14/16] Add a `TitleBar` to `pane_grid` example --- examples/pane_grid/src/main.rs | 46 ++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/examples/pane_grid/src/main.rs b/examples/pane_grid/src/main.rs index 069e2f59..cc4a45af 100644 --- a/examples/pane_grid/src/main.rs +++ b/examples/pane_grid/src/main.rs @@ -97,7 +97,16 @@ impl Sandbox for Example { let pane_grid = PaneGrid::new(&mut self.panes, |pane, content, focus| { - pane_grid::Content::new(content.view(pane, focus, total_panes)) + let title_bar = + pane_grid::TitleBar::new(format!("Pane {}", content.id)) + .padding(10) + .style(style::TitleBar { focus }); + + pane_grid::Content::new(content.view(pane, total_panes)) + .title_bar(title_bar) + .style(style::Pane { + is_focused: focus.is_some(), + }) }) .width(Length::Fill) .height(Length::Fill) @@ -155,15 +164,14 @@ impl Content { fn view( &mut self, pane: pane_grid::Pane, - focus: Option, total_panes: usize, ) -> Element { let Content { - id, scroll, split_horizontally, split_vertically, close, + .. } = self; let button = |state, label, message, style| { @@ -209,7 +217,6 @@ impl Content { .width(Length::Fill) .spacing(10) .align_items(Align::Center) - .push(Text::new(format!("Pane {}", id)).size(30)) .push(controls); Container::new(content) @@ -217,15 +224,12 @@ impl Content { .height(Length::Fill) .padding(5) .center_y() - .style(style::Pane { - is_focused: focus.is_some(), - }) .into() } } mod style { - use iced::{button, container, Background, Color, Vector}; + use iced::{button, container, pane_grid, Background, Color, Vector}; const SURFACE: Color = Color::from_rgb( 0xF2 as f32 / 255.0, @@ -245,6 +249,25 @@ mod style { 0xC4 as f32 / 255.0, ); + pub struct TitleBar { + pub focus: Option, + } + + impl container::StyleSheet for TitleBar { + fn style(&self) -> container::Style { + let pane = Pane { + is_focused: self.focus.is_some(), + } + .style(); + + container::Style { + text_color: Some(Color::WHITE), + background: Some(pane.border_color.into()), + ..Default::default() + } + } + } + pub struct Pane { pub is_focused: bool, } @@ -254,9 +277,10 @@ mod style { container::Style { background: Some(Background::Color(SURFACE)), border_width: 2, - border_color: Color { - a: if self.is_focused { 1.0 } else { 0.3 }, - ..Color::BLACK + border_color: if self.is_focused { + Color::BLACK + } else { + Color::from_rgb(0.7, 0.7, 0.7) }, ..Default::default() } From 6820eea9cee75922f33ce7050e0e868f0749c83e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 9 Jul 2020 06:29:54 +0200 Subject: [PATCH 15/16] Simplify style of `pane_grid` example --- examples/pane_grid/src/main.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/examples/pane_grid/src/main.rs b/examples/pane_grid/src/main.rs index cc4a45af..09c33613 100644 --- a/examples/pane_grid/src/main.rs +++ b/examples/pane_grid/src/main.rs @@ -97,16 +97,15 @@ impl Sandbox for Example { let pane_grid = PaneGrid::new(&mut self.panes, |pane, content, focus| { + let is_focused = focus.is_some(); let title_bar = pane_grid::TitleBar::new(format!("Pane {}", content.id)) .padding(10) - .style(style::TitleBar { focus }); + .style(style::TitleBar { is_focused }); pane_grid::Content::new(content.view(pane, total_panes)) .title_bar(title_bar) - .style(style::Pane { - is_focused: focus.is_some(), - }) + .style(style::Pane { is_focused }) }) .width(Length::Fill) .height(Length::Fill) @@ -229,7 +228,7 @@ impl Content { } mod style { - use iced::{button, container, pane_grid, Background, Color, Vector}; + use iced::{button, container, Background, Color, Vector}; const SURFACE: Color = Color::from_rgb( 0xF2 as f32 / 255.0, @@ -250,13 +249,13 @@ mod style { ); pub struct TitleBar { - pub focus: Option, + pub is_focused: bool, } impl container::StyleSheet for TitleBar { fn style(&self) -> container::Style { let pane = Pane { - is_focused: self.focus.is_some(), + is_focused: self.is_focused, } .style(); From 3c5921f30c17bcbe0af74a30b6a256a3fa03515c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 9 Jul 2020 07:05:57 +0200 Subject: [PATCH 16/16] Update `pane_grid` GIFs --- examples/pane_grid/README.md | 4 ++-- native/src/widget/pane_grid.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/pane_grid/README.md b/examples/pane_grid/README.md index 3653fc5b..a4cfcb7d 100644 --- a/examples/pane_grid/README.md +++ b/examples/pane_grid/README.md @@ -15,8 +15,8 @@ This example showcases the `PaneGrid` widget, which features: The __[`main`]__ file contains all the code of the example. diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs index 6b9d5f2f..c472d043 100644 --- a/native/src/widget/pane_grid.rs +++ b/native/src/widget/pane_grid.rs @@ -36,7 +36,7 @@ use crate::{ /// A collection of panes distributed using either vertical or horizontal splits /// to completely fill the space available. /// -/// [![Pane grid - Iced](https://thumbs.gfycat.com/MixedFlatJellyfish-small.gif)](https://gfycat.com/mixedflatjellyfish) +/// [![Pane grid - Iced](https://thumbs.gfycat.com/FrailFreshAiredaleterrier-small.gif)](https://gfycat.com/frailfreshairedaleterrier) /// /// This distribution of space is common in tiling window managers (like /// [`awesome`](https://awesomewm.org/), [`i3`](https://i3wm.org/), or even