Compute panes
regions and focus on click
This commit is contained in:
parent
b6926d9ab4
commit
d7f32d47ba
@ -12,6 +12,7 @@ pub fn main() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct Launcher {
|
struct Launcher {
|
||||||
panes: panes::State<Example>,
|
panes: panes::State<Example>,
|
||||||
}
|
}
|
||||||
@ -36,8 +37,6 @@ impl Application for Launcher {
|
|||||||
let (clock, _) = Clock::new();
|
let (clock, _) = Clock::new();
|
||||||
let (panes, _) = panes::State::new(Example::Clock(clock));
|
let (panes, _) = panes::State::new(Example::Clock(clock));
|
||||||
|
|
||||||
dbg!(&panes);
|
|
||||||
|
|
||||||
(Self { panes }, Command::none())
|
(Self { panes }, Command::none())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,6 +60,8 @@ impl Application for Launcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbg!(self);
|
||||||
|
|
||||||
Command::none()
|
Command::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
layout, Clipboard, Element, Event, Hasher, Layout, Length, Point, Size,
|
input::{mouse, ButtonState},
|
||||||
Widget,
|
layout, Clipboard, Element, Event, Hasher, Layout, Length, Point,
|
||||||
|
Rectangle, Size, Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -8,7 +9,7 @@ use std::collections::HashMap;
|
|||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Panes<'a, Message, Renderer> {
|
pub struct Panes<'a, Message, Renderer> {
|
||||||
state: &'a mut Internal,
|
state: &'a mut Internal,
|
||||||
elements: Vec<Element<'a, Message, Renderer>>,
|
elements: Vec<(Pane, Element<'a, Message, Renderer>)>,
|
||||||
width: Length,
|
width: Length,
|
||||||
height: Length,
|
height: Length,
|
||||||
}
|
}
|
||||||
@ -21,7 +22,7 @@ impl<'a, Message, Renderer> Panes<'a, Message, Renderer> {
|
|||||||
let elements = state
|
let elements = state
|
||||||
.panes
|
.panes
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.map(|(pane, state)| view(*pane, state))
|
.map(|(pane, state)| (*pane, view(*pane, state)))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@ -71,15 +72,67 @@ where
|
|||||||
let limits = limits.width(self.width).height(self.height);
|
let limits = limits.width(self.width).height(self.height);
|
||||||
let size = limits.resolve(Size::ZERO);
|
let size = limits.resolve(Size::ZERO);
|
||||||
|
|
||||||
|
let regions = self.state.layout.regions(size);
|
||||||
|
|
||||||
let children = self
|
let children = self
|
||||||
.elements
|
.elements
|
||||||
.iter()
|
.iter()
|
||||||
.map(|element| element.layout(renderer, &limits))
|
.filter_map(|(pane, element)| {
|
||||||
|
let region = regions.get(pane)?;
|
||||||
|
let size = Size::new(region.width, region.height);
|
||||||
|
|
||||||
|
let mut node =
|
||||||
|
element.layout(renderer, &layout::Limits::new(size, size));
|
||||||
|
|
||||||
|
node.move_to(Point::new(region.x, region.y));
|
||||||
|
|
||||||
|
Some(node)
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
layout::Node::with_children(size, children)
|
layout::Node::with_children(size, children)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_event(
|
||||||
|
&mut self,
|
||||||
|
event: Event,
|
||||||
|
layout: Layout<'_>,
|
||||||
|
cursor_position: Point,
|
||||||
|
messages: &mut Vec<Message>,
|
||||||
|
renderer: &Renderer,
|
||||||
|
clipboard: Option<&dyn Clipboard>,
|
||||||
|
) {
|
||||||
|
match event {
|
||||||
|
Event::Mouse(mouse::Event::Input {
|
||||||
|
button: mouse::Button::Left,
|
||||||
|
state: ButtonState::Pressed,
|
||||||
|
}) => {
|
||||||
|
let mut clicked_region =
|
||||||
|
self.elements.iter().zip(layout.children()).filter(
|
||||||
|
|(_, layout)| layout.bounds().contains(cursor_position),
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(((pane, _), _)) = clicked_region.next() {
|
||||||
|
self.state.focused_pane = Some(*pane);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.elements.iter_mut().zip(layout.children()).for_each(
|
||||||
|
|((_, pane), layout)| {
|
||||||
|
pane.widget.on_event(
|
||||||
|
event.clone(),
|
||||||
|
layout,
|
||||||
|
cursor_position,
|
||||||
|
messages,
|
||||||
|
renderer,
|
||||||
|
clipboard,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
@ -98,7 +151,7 @@ where
|
|||||||
self.height.hash(state);
|
self.height.hash(state);
|
||||||
self.state.layout.hash(state);
|
self.state.layout.hash(state);
|
||||||
|
|
||||||
for element in &self.elements {
|
for (_, element) in &self.elements {
|
||||||
element.hash_layout(state);
|
element.hash_layout(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -161,11 +214,7 @@ impl<T> State<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn split_vertically(&mut self, pane: &Pane, state: T) -> Option<Pane> {
|
pub fn split_vertically(&mut self, pane: &Pane, state: T) -> Option<Pane> {
|
||||||
let new_pane = Pane(self.internal.last_pane.checked_add(1)?);
|
self.split(Split::Vertical, pane, state)
|
||||||
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
Some(new_pane)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn split_horizontally(
|
pub fn split_horizontally(
|
||||||
@ -173,9 +222,22 @@ impl<T> State<T> {
|
|||||||
pane: &Pane,
|
pane: &Pane,
|
||||||
state: T,
|
state: T,
|
||||||
) -> Option<Pane> {
|
) -> Option<Pane> {
|
||||||
let new_pane = Pane(self.internal.last_pane.checked_add(1)?);
|
self.split(Split::Horizontal, pane, state)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO
|
fn split(&mut self, kind: Split, pane: &Pane, state: T) -> Option<Pane> {
|
||||||
|
let node = self.internal.layout.find(pane)?;
|
||||||
|
|
||||||
|
let new_pane = {
|
||||||
|
self.internal.last_pane = self.internal.last_pane.checked_add(1)?;
|
||||||
|
|
||||||
|
Pane(self.internal.last_pane)
|
||||||
|
};
|
||||||
|
|
||||||
|
node.split(kind, new_pane);
|
||||||
|
|
||||||
|
let _ = self.panes.insert(new_pane, state);
|
||||||
|
self.internal.focused_pane = Some(new_pane);
|
||||||
|
|
||||||
Some(new_pane)
|
Some(new_pane)
|
||||||
}
|
}
|
||||||
@ -192,12 +254,120 @@ enum Node {
|
|||||||
Pane(Pane),
|
Pane(Pane),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Node {
|
||||||
|
pub fn find(&mut self, pane: &Pane) -> Option<&mut Node> {
|
||||||
|
match self {
|
||||||
|
Node::Split { a, b, .. } => {
|
||||||
|
if let Some(node) = a.find(pane) {
|
||||||
|
Some(node)
|
||||||
|
} else {
|
||||||
|
b.find(pane)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Node::Pane(p) => {
|
||||||
|
if p == pane {
|
||||||
|
Some(self)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn split(&mut self, kind: Split, new_pane: Pane) {
|
||||||
|
*self = Node::Split {
|
||||||
|
kind,
|
||||||
|
ratio: 500_000,
|
||||||
|
a: Box::new(self.clone()),
|
||||||
|
b: Box::new(Node::Pane(new_pane)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn regions(&self, size: Size) -> HashMap<Pane, Rectangle> {
|
||||||
|
let mut regions = HashMap::new();
|
||||||
|
|
||||||
|
self.compute_regions(
|
||||||
|
&Rectangle {
|
||||||
|
x: 0.0,
|
||||||
|
y: 0.0,
|
||||||
|
width: size.width,
|
||||||
|
height: size.height,
|
||||||
|
},
|
||||||
|
&mut regions,
|
||||||
|
);
|
||||||
|
|
||||||
|
regions
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_regions(
|
||||||
|
&self,
|
||||||
|
current: &Rectangle,
|
||||||
|
regions: &mut HashMap<Pane, Rectangle>,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
Node::Split { kind, ratio, a, b } => {
|
||||||
|
let ratio = *ratio as f32 / 1_000_000.0;
|
||||||
|
let (region_a, region_b) = kind.apply(current, ratio);
|
||||||
|
|
||||||
|
a.compute_regions(®ion_a, regions);
|
||||||
|
b.compute_regions(®ion_b, regions);
|
||||||
|
}
|
||||||
|
Node::Pane(pane) => {
|
||||||
|
let _ = regions.insert(*pane, *current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Hash)]
|
#[derive(Debug, Clone, Copy, Hash)]
|
||||||
enum Split {
|
enum Split {
|
||||||
Horizontal,
|
Horizontal,
|
||||||
Vertical,
|
Vertical,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Split {
|
||||||
|
pub fn apply(
|
||||||
|
&self,
|
||||||
|
rectangle: &Rectangle,
|
||||||
|
ratio: f32,
|
||||||
|
) -> (Rectangle, Rectangle) {
|
||||||
|
match self {
|
||||||
|
Split::Horizontal => {
|
||||||
|
let width_left = rectangle.width * ratio;
|
||||||
|
let width_right = rectangle.width - width_left;
|
||||||
|
|
||||||
|
(
|
||||||
|
Rectangle {
|
||||||
|
width: width_left,
|
||||||
|
..*rectangle
|
||||||
|
},
|
||||||
|
Rectangle {
|
||||||
|
x: rectangle.x + width_left,
|
||||||
|
width: width_right,
|
||||||
|
..*rectangle
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Split::Vertical => {
|
||||||
|
let height_top = rectangle.height * ratio;
|
||||||
|
let height_bottom = rectangle.height - height_top;
|
||||||
|
|
||||||
|
(
|
||||||
|
Rectangle {
|
||||||
|
height: height_top,
|
||||||
|
..*rectangle
|
||||||
|
},
|
||||||
|
Rectangle {
|
||||||
|
x: rectangle.x + height_top,
|
||||||
|
height: height_bottom,
|
||||||
|
..*rectangle
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The renderer of some [`Panes`].
|
/// The renderer of some [`Panes`].
|
||||||
///
|
///
|
||||||
/// Your [renderer] will need to implement this trait before being
|
/// Your [renderer] will need to implement this trait before being
|
||||||
@ -218,7 +388,7 @@ pub trait Renderer: crate::Renderer + Sized {
|
|||||||
fn draw<Message>(
|
fn draw<Message>(
|
||||||
&mut self,
|
&mut self,
|
||||||
defaults: &Self::Defaults,
|
defaults: &Self::Defaults,
|
||||||
content: &[Element<'_, Message, Self>],
|
content: &[(Pane, Element<'_, Message, Self>)],
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
) -> Self::Output;
|
) -> Self::Output;
|
||||||
|
@ -5,7 +5,7 @@ impl panes::Renderer for Renderer {
|
|||||||
fn draw<Message>(
|
fn draw<Message>(
|
||||||
&mut self,
|
&mut self,
|
||||||
defaults: &Self::Defaults,
|
defaults: &Self::Defaults,
|
||||||
content: &[Element<'_, Message, Self>],
|
content: &[(panes::Pane, Element<'_, Message, Self>)],
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
) -> Self::Output {
|
) -> Self::Output {
|
||||||
@ -16,9 +16,9 @@ impl panes::Renderer for Renderer {
|
|||||||
primitives: content
|
primitives: content
|
||||||
.iter()
|
.iter()
|
||||||
.zip(layout.children())
|
.zip(layout.children())
|
||||||
.map(|(child, layout)| {
|
.map(|((_, pane), layout)| {
|
||||||
let (primitive, new_mouse_cursor) =
|
let (primitive, new_mouse_cursor) =
|
||||||
child.draw(self, defaults, layout, cursor_position);
|
pane.draw(self, defaults, layout, cursor_position);
|
||||||
|
|
||||||
if new_mouse_cursor > mouse_cursor {
|
if new_mouse_cursor > mouse_cursor {
|
||||||
mouse_cursor = new_mouse_cursor;
|
mouse_cursor = new_mouse_cursor;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user