Custom widget for sidebar; closing workspace
Need custom widget currently to distribute space correctly.
This commit is contained in:
parent
df81bd4e4c
commit
a3e3bec885
4 changed files with 317 additions and 11 deletions
12
src/main.rs
12
src/main.rs
|
|
@ -47,6 +47,7 @@ use std::{
|
|||
|
||||
mod view;
|
||||
mod wayland;
|
||||
mod widgets;
|
||||
|
||||
// Include `pid` in mime. Want to drag between our surfaces, but not another
|
||||
// process, if we use Wayland object ids.
|
||||
|
|
@ -489,7 +490,16 @@ impl Application for App {
|
|||
}
|
||||
}
|
||||
}
|
||||
Msg::CloseWorkspace(_workspace_handle) => {}
|
||||
Msg::CloseWorkspace(_workspace_handle) => {
|
||||
// XXX close specific workspace
|
||||
if let WorkspaceAmount::Static(n) = &mut self.conf.workspace_config.workspace_amount
|
||||
{
|
||||
*n -= 1;
|
||||
self.conf
|
||||
.cosmic_comp_config
|
||||
.set("workspaces", &self.conf.workspace_config);
|
||||
}
|
||||
}
|
||||
Msg::CloseToplevel(toplevel_handle) => {
|
||||
// TODO confirmation?
|
||||
if let Some(toplevel_manager) = self.toplevel_manager.as_ref() {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use cosmic::{
|
|||
cctk,
|
||||
iced::{
|
||||
self,
|
||||
advanced::layout::flex::Axis,
|
||||
widget::{column, row},
|
||||
},
|
||||
widget,
|
||||
|
|
@ -67,15 +68,13 @@ pub(crate) fn workspace_item<'a>(
|
|||
workspace: &'a Workspace,
|
||||
output: &wl_output::WlOutput,
|
||||
) -> cosmic::Element<'a, Msg> {
|
||||
let image = capture_image(workspace.img_for_output.get(output));
|
||||
column![
|
||||
close_button(Msg::CloseWorkspace(workspace.handle.clone())),
|
||||
widget::button(column![
|
||||
capture_image(workspace.img_for_output.get(output)),
|
||||
widget::text(&workspace.name)
|
||||
])
|
||||
.selected(workspace.is_active)
|
||||
.style(cosmic::theme::Button::Image)
|
||||
.on_press(Msg::ActivateWorkspace(workspace.handle.clone())),
|
||||
widget::button(column![image, widget::text(&workspace.name)])
|
||||
.selected(workspace.is_active)
|
||||
.style(cosmic::theme::Button::Image)
|
||||
.on_press(Msg::ActivateWorkspace(workspace.handle.clone())),
|
||||
]
|
||||
.height(iced::Length::Fill)
|
||||
.into()
|
||||
|
|
@ -126,10 +125,11 @@ fn workspaces_sidebar<'a>(
|
|||
.into(),
|
||||
);
|
||||
}
|
||||
let sidebar_entries_container: cosmic::Element<'_, _> = match layout {
|
||||
WorkspaceLayout::Vertical => column(sidebar_entries).into(),
|
||||
WorkspaceLayout::Horizontal => row(sidebar_entries).into(),
|
||||
let axis = match layout {
|
||||
WorkspaceLayout::Vertical => Axis::Vertical,
|
||||
WorkspaceLayout::Horizontal => Axis::Horizontal,
|
||||
};
|
||||
let sidebar_entries_container = crate::widgets::workspace_bar(sidebar_entries, axis);
|
||||
widget::container(sidebar_entries_container)
|
||||
.width(iced::Length::Fill)
|
||||
.height(iced::Length::Fill)
|
||||
|
|
|
|||
69
src/widgets/mod.rs
Normal file
69
src/widgets/mod.rs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
use cosmic::iced::{
|
||||
self,
|
||||
advanced::{layout, mouse, renderer, widget::Tree, Layout, Widget},
|
||||
Length, Rectangle,
|
||||
};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
mod workspace_bar;
|
||||
pub use workspace_bar::workspace_bar;
|
||||
|
||||
pub fn layout_wrapper<Msg, T: Widget<Msg, cosmic::Renderer>>(inner: T) -> LayoutWrapper<Msg, T> {
|
||||
LayoutWrapper {
|
||||
inner,
|
||||
_msg: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LayoutWrapper<Msg, T: Widget<Msg, cosmic::Renderer>> {
|
||||
inner: T,
|
||||
_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()
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&self,
|
||||
tree: &mut Tree,
|
||||
renderer: &cosmic::Renderer,
|
||||
limits: &layout::Limits,
|
||||
) -> layout::Node {
|
||||
dbg!(limits);
|
||||
dbg!(self.inner.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)
|
||||
}
|
||||
|
||||
fn children(&self) -> Vec<Tree> {
|
||||
self.inner.children()
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
cosmic::Element::new(widget)
|
||||
}
|
||||
}
|
||||
227
src/widgets/workspace_bar.rs
Normal file
227
src/widgets/workspace_bar.rs
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
// Custom varian of row/column
|
||||
|
||||
use cosmic::iced::{
|
||||
self,
|
||||
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_bar<'a, Msg>(
|
||||
children: Vec<cosmic::Element<'a, Msg>>,
|
||||
axis: Axis,
|
||||
) -> WorkspaceBar<'a, Msg> {
|
||||
WorkspaceBar {
|
||||
axis,
|
||||
children,
|
||||
_msg: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WorkspaceBar<'a, Msg> {
|
||||
axis: Axis,
|
||||
children: Vec<cosmic::Element<'a, Msg>>,
|
||||
_msg: PhantomData<Msg>,
|
||||
}
|
||||
|
||||
impl<'a, Msg> Widget<Msg, cosmic::Renderer> for WorkspaceBar<'a, Msg> {
|
||||
fn width(&self) -> Length {
|
||||
Length::Shrink
|
||||
}
|
||||
|
||||
fn height(&self) -> Length {
|
||||
Length::Shrink
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&self,
|
||||
tree: &mut Tree,
|
||||
renderer: &cosmic::Renderer,
|
||||
limits: &layout::Limits,
|
||||
) -> layout::Node {
|
||||
/*
|
||||
layout::flex::resolve(
|
||||
layout::flex::Axis::Vertical,
|
||||
renderer,
|
||||
&limits,
|
||||
iced::Padding::ZERO,
|
||||
0.0, // spacing
|
||||
iced::Alignment::Start,
|
||||
&self.children,
|
||||
&mut tree.children,
|
||||
)
|
||||
*/
|
||||
|
||||
if self.children.is_empty() {
|
||||
return layout::Node::new(limits.min());
|
||||
}
|
||||
|
||||
let max_main = self.axis.main(limits.max()) / self.children().len() as f32;
|
||||
let max_cross = self.axis.cross(limits.max());
|
||||
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);
|
||||
let (x, y) = self.axis.pack(total_main, 0.0);
|
||||
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<WorkspaceBar<'a, Msg>> for cosmic::Element<'a, Msg> {
|
||||
fn from(widget: WorkspaceBar<'a, Msg>) -> Self {
|
||||
cosmic::Element::new(widget)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue