Custom widget to avoid stretching toplevel items
Avoids close button aligned way to right. And fixes offset for drag surface. But left aligns workspaces (need new container?).
This commit is contained in:
parent
9d2f2f68d0
commit
ec5dceeed2
5 changed files with 334 additions and 61 deletions
|
|
@ -205,22 +205,28 @@ pub(crate) fn toplevel_preview(toplevel: &Toplevel) -> cosmic::Element<Msg> {
|
|||
row![label]
|
||||
}
|
||||
.padding(4);
|
||||
column![
|
||||
close_button(Msg::CloseToplevel(toplevel.handle.clone())),
|
||||
widget::button(capture_image(toplevel.img.as_ref()))
|
||||
.selected(
|
||||
toplevel
|
||||
.info
|
||||
.state
|
||||
.contains(&zcosmic_toplevel_handle_v1::State::Activated)
|
||||
)
|
||||
.style(cosmic::theme::Button::Image)
|
||||
.on_press(Msg::ActivateToplevel(toplevel.handle.clone())),
|
||||
widget::button(label).on_press(Msg::ActivateToplevel(toplevel.handle.clone()))
|
||||
]
|
||||
.spacing(4)
|
||||
.align_items(iced::Alignment::Center)
|
||||
.width(iced::Length::Fill)
|
||||
crate::widgets::workspace_item(
|
||||
vec![
|
||||
close_button(Msg::CloseToplevel(toplevel.handle.clone())).into(),
|
||||
widget::button(capture_image(toplevel.img.as_ref()))
|
||||
.selected(
|
||||
toplevel
|
||||
.info
|
||||
.state
|
||||
.contains(&zcosmic_toplevel_handle_v1::State::Activated),
|
||||
)
|
||||
.style(cosmic::theme::Button::Image)
|
||||
.on_press(Msg::ActivateToplevel(toplevel.handle.clone()))
|
||||
.into(),
|
||||
widget::button(label)
|
||||
.on_press(Msg::ActivateToplevel(toplevel.handle.clone()))
|
||||
.into(),
|
||||
],
|
||||
Axis::Vertical,
|
||||
)
|
||||
//.spacing(4)
|
||||
//.align_items(iced::Alignment::Center)
|
||||
//.width(iced::Length::Fill)
|
||||
.into()
|
||||
}
|
||||
|
||||
|
|
@ -252,15 +258,16 @@ fn toplevel_previews<'a>(
|
|||
WorkspaceLayout::Vertical => (iced::Length::FillPortion(4), iced::Length::Fill),
|
||||
WorkspaceLayout::Horizontal => (iced::Length::Fill, iced::Length::FillPortion(4)),
|
||||
};
|
||||
row(toplevels
|
||||
let entries = toplevels
|
||||
.map(|t| toplevel_previews_entry(t, output))
|
||||
.collect())
|
||||
.width(width)
|
||||
.height(height)
|
||||
.spacing(16)
|
||||
.padding(12)
|
||||
.align_items(iced::Alignment::Center)
|
||||
.into()
|
||||
.collect();
|
||||
row(entries)
|
||||
.width(width)
|
||||
.height(height)
|
||||
.spacing(16)
|
||||
.padding(12)
|
||||
.align_items(iced::Alignment::Center)
|
||||
.into()
|
||||
}
|
||||
|
||||
fn capture_image(image: Option<&CaptureImage>) -> cosmic::Element<'_, Msg> {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
use cosmic::iced::{
|
||||
advanced::{layout, mouse, renderer, widget::Tree, Layout, Widget},
|
||||
advanced::{
|
||||
layout, mouse, overlay, renderer,
|
||||
widget::{tree, Id, Operation, OperationOutputWrapper, Tree},
|
||||
Clipboard, Layout, Shell, Widget,
|
||||
},
|
||||
event::{self, Event},
|
||||
Length, Rectangle,
|
||||
};
|
||||
use std::marker::PhantomData;
|
||||
|
|
@ -8,32 +13,28 @@ mod image_bg;
|
|||
pub use image_bg::image_bg;
|
||||
mod workspace_bar;
|
||||
pub use workspace_bar::workspace_bar;
|
||||
mod workspace_item;
|
||||
pub use workspace_item::workspace_item;
|
||||
mod mouse_interaction_wrapper;
|
||||
pub use mouse_interaction_wrapper::mouse_interaction_wrapper;
|
||||
|
||||
pub fn layout_wrapper<Msg, T: Widget<Msg, cosmic::Renderer>>(inner: T) -> LayoutWrapper<Msg, T> {
|
||||
trait Foo {}
|
||||
|
||||
pub fn layout_wrapper<'a, Msg, T: Into<cosmic::Element<'a, Msg>>>(
|
||||
inner: T,
|
||||
) -> LayoutWrapper<'a, Msg> {
|
||||
LayoutWrapper {
|
||||
inner,
|
||||
content: inner.into(),
|
||||
_msg: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LayoutWrapper<Msg, T: Widget<Msg, cosmic::Renderer>> {
|
||||
inner: T,
|
||||
pub struct LayoutWrapper<'a, Msg> {
|
||||
content: cosmic::Element<'a, Msg>,
|
||||
_msg: PhantomData<Msg>,
|
||||
}
|
||||
|
||||
impl<Msg, T: Widget<Msg, cosmic::Renderer>> Widget<Msg, cosmic::Renderer>
|
||||
for LayoutWrapper<Msg, T>
|
||||
{
|
||||
fn width(&self) -> Length {
|
||||
self.inner.width()
|
||||
}
|
||||
|
||||
fn height(&self) -> Length {
|
||||
self.inner.height()
|
||||
}
|
||||
|
||||
impl<'a, Msg> Widget<Msg, cosmic::Renderer> for LayoutWrapper<'a, Msg> {
|
||||
fn layout(
|
||||
&self,
|
||||
tree: &mut Tree,
|
||||
|
|
@ -41,32 +42,70 @@ impl<Msg, T: Widget<Msg, cosmic::Renderer>> Widget<Msg, cosmic::Renderer>
|
|||
limits: &layout::Limits,
|
||||
) -> layout::Node {
|
||||
dbg!(limits);
|
||||
dbg!(self.inner.layout(tree, renderer, limits))
|
||||
dbg!(self.content.as_widget().layout(tree, renderer, limits))
|
||||
}
|
||||
|
||||
fn draw(
|
||||
&self,
|
||||
state: &Tree,
|
||||
renderer: &mut cosmic::Renderer,
|
||||
theme: &cosmic::Theme,
|
||||
style: &renderer::Style,
|
||||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
self.inner
|
||||
.draw(state, renderer, theme, style, layout, cursor, viewport)
|
||||
}
|
||||
delegate::delegate! {
|
||||
to self.content.as_widget() {
|
||||
fn tag(&self) -> tree::Tag;
|
||||
fn state(&self) -> tree::State;
|
||||
fn children(&self) -> Vec<Tree>;
|
||||
fn width(&self) -> Length;
|
||||
fn height(&self) -> Length;
|
||||
fn operate(
|
||||
&self,
|
||||
tree: &mut Tree,
|
||||
layout: Layout<'_>,
|
||||
renderer: &cosmic::Renderer,
|
||||
operation: &mut dyn Operation<OperationOutputWrapper<Msg>>,
|
||||
);
|
||||
fn draw(
|
||||
&self,
|
||||
state: &Tree,
|
||||
renderer: &mut cosmic::Renderer,
|
||||
theme: &cosmic::Theme,
|
||||
style: &renderer::Style,
|
||||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
viewport: &Rectangle,
|
||||
);
|
||||
fn mouse_interaction(
|
||||
&self,
|
||||
_tree: &Tree,
|
||||
_layout: Layout<'_>,
|
||||
_cursor: mouse::Cursor,
|
||||
_viewport: &Rectangle,
|
||||
_renderer: &cosmic::Renderer,
|
||||
) -> mouse::Interaction;
|
||||
fn id(&self) -> Option<Id>;
|
||||
}
|
||||
|
||||
fn children(&self) -> Vec<Tree> {
|
||||
self.inner.children()
|
||||
to self.content.as_widget_mut() {
|
||||
fn diff(&mut self, tree: &mut Tree);
|
||||
fn on_event(
|
||||
&mut self,
|
||||
tree: &mut Tree,
|
||||
event: Event,
|
||||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
renderer: &cosmic::Renderer,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Msg>,
|
||||
viewport: &Rectangle,
|
||||
) -> event::Status;
|
||||
fn overlay<'b>(
|
||||
&'b mut self,
|
||||
tree: &'b mut Tree,
|
||||
layout: Layout<'_>,
|
||||
renderer: &cosmic::Renderer,
|
||||
) -> Option<overlay::Element<'b, Msg, cosmic::Renderer>>;
|
||||
fn set_id(&mut self, id: Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Msg: 'a, T: Widget<Msg, cosmic::Renderer> + 'a> From<LayoutWrapper<Msg, T>>
|
||||
for cosmic::Element<'a, Msg>
|
||||
{
|
||||
fn from(widget: LayoutWrapper<Msg, T>) -> Self {
|
||||
impl<'a, Msg: 'a> From<LayoutWrapper<'a, Msg>> for cosmic::Element<'a, Msg> {
|
||||
fn from(widget: LayoutWrapper<'a, Msg>) -> Self {
|
||||
cosmic::Element::new(widget)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use cosmic::iced::{
|
||||
advanced::{
|
||||
layout, mouse, overlay, renderer,
|
||||
widget::{tree, Operation, OperationOutputWrapper, Tree},
|
||||
widget::{tree, Id, Operation, OperationOutputWrapper, Tree},
|
||||
Clipboard, Layout, Shell, Widget,
|
||||
},
|
||||
event::{self, Event},
|
||||
|
|
@ -58,6 +58,7 @@ impl<'a, Msg> Widget<Msg, cosmic::Renderer> for MouseInteractionWrapper<'a, Msg>
|
|||
cursor: mouse::Cursor,
|
||||
viewport: &Rectangle,
|
||||
);
|
||||
fn id(&self) -> Option<Id>;
|
||||
}
|
||||
|
||||
to self.content.as_widget_mut() {
|
||||
|
|
@ -79,6 +80,7 @@ impl<'a, Msg> Widget<Msg, cosmic::Renderer> for MouseInteractionWrapper<'a, Msg>
|
|||
layout: Layout<'_>,
|
||||
renderer: &cosmic::Renderer,
|
||||
) -> Option<overlay::Element<'b, Msg, cosmic::Renderer>>;
|
||||
fn set_id(&mut self, id: Id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// Custom varian of row/column
|
||||
// Gives each child widget a maximim size on main axis of total/n
|
||||
|
||||
use cosmic::iced::{
|
||||
advanced::{
|
||||
|
|
|
|||
224
src/widgets/workspace_item.rs
Normal file
224
src/widgets/workspace_item.rs
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
// TODO rename
|
||||
// combine widgets
|
||||
|
||||
use cosmic::iced::{
|
||||
advanced::{
|
||||
layout::{self, flex::Axis},
|
||||
mouse, renderer,
|
||||
widget::{Operation, OperationOutputWrapper, Tree},
|
||||
Clipboard, Layout, Shell, Widget,
|
||||
},
|
||||
event::{self, Event},
|
||||
Length, Point, Rectangle, Size,
|
||||
};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// Duplicate of private methods
|
||||
trait AxisExt {
|
||||
fn main(&self, size: Size) -> f32;
|
||||
fn cross(&self, size: Size) -> f32;
|
||||
fn pack(&self, main: f32, cross: f32) -> (f32, f32);
|
||||
}
|
||||
|
||||
impl AxisExt for Axis {
|
||||
fn main(&self, size: Size) -> f32 {
|
||||
match self {
|
||||
Axis::Horizontal => size.width,
|
||||
Axis::Vertical => size.height,
|
||||
}
|
||||
}
|
||||
|
||||
fn cross(&self, size: Size) -> f32 {
|
||||
match self {
|
||||
Axis::Horizontal => size.height,
|
||||
Axis::Vertical => size.width,
|
||||
}
|
||||
}
|
||||
|
||||
fn pack(&self, main: f32, cross: f32) -> (f32, f32) {
|
||||
match self {
|
||||
Axis::Horizontal => (main, cross),
|
||||
Axis::Vertical => (cross, main),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn workspace_item<'a, Msg>(
|
||||
children: Vec<cosmic::Element<'a, Msg>>,
|
||||
axis: Axis,
|
||||
) -> WorkspaceItem<'a, Msg> {
|
||||
WorkspaceItem {
|
||||
axis,
|
||||
children,
|
||||
_msg: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WorkspaceItem<'a, Msg> {
|
||||
axis: Axis,
|
||||
children: Vec<cosmic::Element<'a, Msg>>,
|
||||
_msg: PhantomData<Msg>,
|
||||
}
|
||||
|
||||
impl<'a, Msg> Widget<Msg, cosmic::Renderer> for WorkspaceItem<'a, Msg> {
|
||||
fn width(&self) -> Length {
|
||||
Length::Fill
|
||||
}
|
||||
|
||||
fn height(&self) -> Length {
|
||||
// TODO Make depend on orientation or drop that option
|
||||
Length::Shrink
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&self,
|
||||
tree: &mut Tree,
|
||||
renderer: &cosmic::Renderer,
|
||||
limits: &layout::Limits,
|
||||
) -> layout::Node {
|
||||
let max_main = self.axis.main(limits.max());
|
||||
let max_cross = self.axis.cross(limits.max());
|
||||
|
||||
// XXX cleaner solution
|
||||
// Get layout of main widget, to set overall cross axis size
|
||||
let (max_width, max_height) = self.axis.pack(max_main, max_cross);
|
||||
let child_limits = layout::Limits::new(Size::ZERO, Size::new(max_width, max_height));
|
||||
let layout = self.children[1].layout(tree, renderer, &child_limits);
|
||||
|
||||
let max_cross = self.axis.cross(layout.size());
|
||||
|
||||
// XXX sill allocating maximum main axis?
|
||||
// - what was it doing before?
|
||||
let mut total_main = 0.0;
|
||||
let nodes = self
|
||||
.children
|
||||
.iter()
|
||||
.zip(tree.children.iter_mut())
|
||||
.map(|(child, tree)| {
|
||||
let (max_width, max_height) = self.axis.pack(max_main, max_cross);
|
||||
let child_limits =
|
||||
layout::Limits::new(Size::ZERO, Size::new(max_width, max_height));
|
||||
let mut layout = child.layout(tree, renderer, &child_limits);
|
||||
// Center on cross axis
|
||||
let cross = ((max_cross - self.axis.cross(layout.size())) / 2.).max(0.);
|
||||
let (x, y) = self.axis.pack(total_main, cross);
|
||||
layout.move_to(Point::new(x, y));
|
||||
total_main += self.axis.main(layout.size());
|
||||
layout
|
||||
})
|
||||
.collect();
|
||||
|
||||
let (total_width, total_height) = self.axis.pack(total_main, max_cross);
|
||||
let size = Size::new(total_width, total_height);
|
||||
layout::Node::with_children(size, nodes)
|
||||
}
|
||||
|
||||
fn operate(
|
||||
&self,
|
||||
tree: &mut Tree,
|
||||
layout: Layout<'_>,
|
||||
renderer: &cosmic::Renderer,
|
||||
operation: &mut dyn Operation<OperationOutputWrapper<Msg>>,
|
||||
) {
|
||||
operation.container(None, layout.bounds(), &mut |operation| {
|
||||
self.children
|
||||
.iter()
|
||||
.zip(&mut tree.children)
|
||||
.zip(layout.children())
|
||||
.for_each(|((child, state), layout)| {
|
||||
child
|
||||
.as_widget()
|
||||
.operate(state, layout, renderer, operation);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn on_event(
|
||||
&mut self,
|
||||
tree: &mut Tree,
|
||||
event: Event,
|
||||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
renderer: &cosmic::Renderer,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Msg>,
|
||||
viewport: &Rectangle,
|
||||
) -> event::Status {
|
||||
self.children
|
||||
.iter_mut()
|
||||
.zip(&mut tree.children)
|
||||
.zip(layout.children())
|
||||
.map(|((child, state), layout)| {
|
||||
child.as_widget_mut().on_event(
|
||||
state,
|
||||
event.clone(),
|
||||
layout,
|
||||
cursor,
|
||||
renderer,
|
||||
clipboard,
|
||||
shell,
|
||||
viewport,
|
||||
)
|
||||
})
|
||||
.fold(event::Status::Ignored, event::Status::merge)
|
||||
}
|
||||
|
||||
fn mouse_interaction(
|
||||
&self,
|
||||
tree: &Tree,
|
||||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
viewport: &Rectangle,
|
||||
renderer: &cosmic::Renderer,
|
||||
) -> mouse::Interaction {
|
||||
self.children
|
||||
.iter()
|
||||
.zip(&tree.children)
|
||||
.zip(layout.children())
|
||||
.map(|((child, state), layout)| {
|
||||
child
|
||||
.as_widget()
|
||||
.mouse_interaction(state, layout, cursor, viewport, renderer)
|
||||
})
|
||||
.max()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn draw(
|
||||
&self,
|
||||
tree: &Tree,
|
||||
renderer: &mut cosmic::Renderer,
|
||||
theme: &cosmic::Theme,
|
||||
style: &renderer::Style,
|
||||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
if let Some(viewport) = layout.bounds().intersection(viewport) {
|
||||
for ((child, state), layout) in self
|
||||
.children
|
||||
.iter()
|
||||
.zip(&tree.children)
|
||||
.zip(layout.children())
|
||||
{
|
||||
child
|
||||
.as_widget()
|
||||
.draw(state, renderer, theme, style, layout, cursor, &viewport);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn children(&self) -> Vec<Tree> {
|
||||
self.children.iter().map(Tree::new).collect()
|
||||
}
|
||||
|
||||
fn diff(&mut self, tree: &mut Tree) {
|
||||
tree.diff_children(&mut self.children);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Msg: 'static> From<WorkspaceItem<'a, Msg>> for cosmic::Element<'a, Msg> {
|
||||
fn from(widget: WorkspaceItem<'a, Msg>) -> Self {
|
||||
cosmic::Element::new(widget)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue