wip: Various refactorings and improvements
This commit is contained in:
parent
702ea033af
commit
37f978d1b3
33 changed files with 744 additions and 1229 deletions
|
|
@ -1,16 +1,28 @@
|
|||
// Copyright 2022 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use apply::Apply;
|
||||
use derive_setters::*;
|
||||
use iced::{self, alignment::Vertical, widget, Length};
|
||||
use iced_lazy::Component;
|
||||
use crate::{theme, Element, Renderer};
|
||||
use derive_setters::Setters;
|
||||
use iced::{self, widget, Length};
|
||||
use crate::{theme, Element};
|
||||
|
||||
#[must_use]
|
||||
pub fn header_bar<'a, Message>() -> HeaderBar<'a, Message> {
|
||||
HeaderBar {
|
||||
title: "",
|
||||
on_close: None,
|
||||
on_drag: None,
|
||||
on_maximize: None,
|
||||
on_minimize: None,
|
||||
start: None,
|
||||
center: None,
|
||||
end: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Setters)]
|
||||
pub struct HeaderBar<Message> {
|
||||
title: String,
|
||||
nav_title: String,
|
||||
sidebar_active: bool,
|
||||
show_minimize: bool,
|
||||
show_maximize: bool,
|
||||
pub struct HeaderBar<'a, Message> {
|
||||
title: &'a str,
|
||||
#[setters(strip_option)]
|
||||
on_close: Option<Message>,
|
||||
#[setters(strip_option)]
|
||||
|
|
@ -20,133 +32,98 @@ pub struct HeaderBar<Message> {
|
|||
#[setters(strip_option)]
|
||||
on_minimize: Option<Message>,
|
||||
#[setters(strip_option)]
|
||||
on_sidebar_toggle: Option<Message>,
|
||||
start: Option<Element<'a, Message>>,
|
||||
#[setters(strip_option)]
|
||||
center: Option<Element<'a, Message>>,
|
||||
#[setters(strip_option)]
|
||||
end: Option<Element<'a, Message>>
|
||||
}
|
||||
|
||||
pub fn header_bar<Message>() -> HeaderBar<Message> {
|
||||
HeaderBar {
|
||||
title: String::default(),
|
||||
nav_title: String::default(),
|
||||
sidebar_active: false,
|
||||
show_minimize: false,
|
||||
show_maximize: false,
|
||||
on_sidebar_toggle: None,
|
||||
on_close: None,
|
||||
on_drag: None,
|
||||
on_maximize: None,
|
||||
on_minimize: None,
|
||||
}
|
||||
}
|
||||
impl<'a, Message: Clone + 'static> HeaderBar<'a, Message> {
|
||||
/// Converts the headerbar builder into an Iced element.
|
||||
pub fn into_element(mut self) -> Element<'a, Message> {
|
||||
let mut packed: Vec<Element<Message>> = Vec::with_capacity(4);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum HeaderEvent {
|
||||
Close,
|
||||
ToggleSidebar,
|
||||
Drag,
|
||||
Minimize,
|
||||
Maximize,
|
||||
}
|
||||
|
||||
impl<Message: Clone> Component<Message, Renderer> for HeaderBar<Message> {
|
||||
type State = ();
|
||||
|
||||
type Event = HeaderEvent;
|
||||
|
||||
fn update(&mut self, _state: &mut Self::State, event: Self::Event) -> Option<Message> {
|
||||
match event {
|
||||
HeaderEvent::Close => self.on_close.clone(),
|
||||
|
||||
HeaderEvent::ToggleSidebar => self.on_sidebar_toggle.clone(),
|
||||
|
||||
HeaderEvent::Drag => self.on_drag.clone(),
|
||||
|
||||
HeaderEvent::Maximize => self.on_maximize.clone(),
|
||||
|
||||
HeaderEvent::Minimize => self.on_minimize.clone(),
|
||||
if let Some(start) = self.start.take() {
|
||||
packed.push(widget::container(start).align_x(iced::alignment::Horizontal::Left).into());
|
||||
}
|
||||
|
||||
packed.push(if let Some(center) = self.center.take() {
|
||||
widget::container(center).align_x(iced::alignment::Horizontal::Center).into()
|
||||
} else {
|
||||
self.title_widget()
|
||||
});
|
||||
|
||||
packed.push(if let Some(end) = self.end.take() {
|
||||
widget::row(vec![end, self.window_controls()])
|
||||
.apply(widget::container)
|
||||
.align_x(iced::alignment::Horizontal::Right)
|
||||
.into()
|
||||
} else {
|
||||
self.window_controls()
|
||||
});
|
||||
|
||||
let mut widget = widget::row(packed)
|
||||
.height(Length::Units(50))
|
||||
.padding(10)
|
||||
.apply(widget::event_container)
|
||||
.center_y();
|
||||
|
||||
if let Some(message) = self.on_drag.clone() {
|
||||
widget = widget.on_press(message);
|
||||
}
|
||||
|
||||
if let Some(message) = self.on_maximize.clone() {
|
||||
widget = widget.on_release(message);
|
||||
}
|
||||
|
||||
widget.into()
|
||||
}
|
||||
|
||||
fn view(&self, _state: &Self::State) -> Element<Self::Event> {
|
||||
let nav_button = {
|
||||
let text = widget::text(&self.nav_title)
|
||||
.style(theme::Text::Accent)
|
||||
.vertical_alignment(Vertical::Center)
|
||||
.width(Length::Shrink)
|
||||
.height(Length::Fill);
|
||||
|
||||
let icon = super::icon(
|
||||
if self.sidebar_active {
|
||||
"go-previous-symbolic"
|
||||
} else {
|
||||
"go-next-symbolic"
|
||||
},
|
||||
24,
|
||||
)
|
||||
.style(theme::Svg::Accent)
|
||||
.width(Length::Units(24))
|
||||
.height(Length::Fill);
|
||||
|
||||
widget::row!(text, icon)
|
||||
.padding(4)
|
||||
.spacing(4)
|
||||
.apply(widget::button)
|
||||
.style(theme::Button::Secondary)
|
||||
.on_press(HeaderEvent::ToggleSidebar)
|
||||
.apply(widget::container)
|
||||
.center_y()
|
||||
.height(Length::Fill)
|
||||
.into()
|
||||
};
|
||||
|
||||
let content = widget::container(widget::text(&self.title))
|
||||
fn title_widget(&self) -> Element<'a, Message> {
|
||||
widget::container(widget::text(self.title))
|
||||
.center_x()
|
||||
.center_y()
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.into();
|
||||
.into()
|
||||
}
|
||||
|
||||
let window_controls = {
|
||||
let mut widgets: Vec<Element<HeaderEvent>> = Vec::with_capacity(3);
|
||||
/// Creates the widget for window controls.
|
||||
fn window_controls(&mut self) -> Element<'a, Message> {
|
||||
let mut widgets: Vec<Element<_>> = Vec::with_capacity(3);
|
||||
|
||||
let icon = |name, size, on_press| {
|
||||
super::icon(name, size)
|
||||
.style(crate::theme::Svg::Accent)
|
||||
.apply(widget::button)
|
||||
.style(theme::Button::Text)
|
||||
.on_press(on_press)
|
||||
};
|
||||
|
||||
if self.show_minimize {
|
||||
widgets.push(icon("window-minimize-symbolic", 16, HeaderEvent::Minimize).into());
|
||||
}
|
||||
|
||||
if self.show_maximize {
|
||||
widgets.push(icon("window-maximize-symbolic", 16, HeaderEvent::Maximize).into());
|
||||
}
|
||||
|
||||
widgets.push(icon("window-close-symbolic", 16, HeaderEvent::Close).into());
|
||||
|
||||
widget::row(widgets)
|
||||
.spacing(8)
|
||||
.apply(widget::container)
|
||||
.height(Length::Fill)
|
||||
.center_y()
|
||||
.into()
|
||||
let icon = |name, size, on_press| {
|
||||
super::icon(name, size)
|
||||
.style(crate::theme::Svg::SymbolicActive)
|
||||
.apply(iced::widget::button)
|
||||
.style(theme::Button::Text)
|
||||
.on_press(on_press)
|
||||
};
|
||||
|
||||
widget::row(vec![nav_button, content, window_controls])
|
||||
.height(Length::Units(50))
|
||||
.padding(10)
|
||||
.apply(widget::event_container)
|
||||
if let Some(message) = self.on_minimize.take() {
|
||||
widgets.push(icon("window-minimize-symbolic", 16, message).into());
|
||||
}
|
||||
|
||||
if let Some(message) = self.on_maximize.take() {
|
||||
widgets.push(icon("window-maximize-symbolic", 16, message).into());
|
||||
}
|
||||
|
||||
if let Some(message) = self.on_close.take() {
|
||||
widgets.push(icon("window-close-symbolic", 16, message).into());
|
||||
}
|
||||
|
||||
widget::row(widgets)
|
||||
.spacing(8)
|
||||
.apply(widget::container)
|
||||
.height(Length::Fill)
|
||||
.center_y()
|
||||
.on_press(HeaderEvent::Drag)
|
||||
.on_release(HeaderEvent::Maximize)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Message: Clone + 'a> From<HeaderBar<Message>> for Element<'a, Message> {
|
||||
fn from(header_bar: HeaderBar<Message>) -> Self {
|
||||
iced_lazy::component(header_bar)
|
||||
impl<'a, Message: Clone + 'static> From<HeaderBar<'a, Message>> for Element<'a, Message> {
|
||||
fn from(headerbar: HeaderBar<'a, Message>) -> Self {
|
||||
headerbar.into_element()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue