Reimplemented NavigationBar

- Navigation Bar was reimplemented to support sections and pages.
- Created new widget called separator, a horizontal rule with the COSMIC
  theme.
This commit is contained in:
Eduardo Flores 2022-10-13 02:23:37 -07:00 committed by Michael Murphy
parent 420d3c3dfc
commit 07e53ddadd
8 changed files with 390 additions and 383 deletions

View file

@ -1,4 +1,4 @@
use cosmic::widget::{expander, ListBox};
use cosmic::widget::{expander, nav_bar, nav_bar_page, nav_bar_section};
use cosmic::{
iced::widget::{
checkbox, column, container, horizontal_space, pick_list, progress_bar, radio, row, slider,
@ -7,9 +7,10 @@ use cosmic::{
iced::{self, theme, Alignment, Application, Color, Command, Element, Length, Theme},
iced_lazy::responsive,
iced_winit::window::{drag, maximize, minimize},
list_item, list_row, list_section, list_view, nav_button, scrollable,
widget::{button, header_bar, list_row, list_view::*, nav_bar::nav_bar_style, toggler},
list_view, list_view_item, list_view_row, list_view_section, scrollable,
widget::{button, header_bar, list_box, list_row, list_view::*, toggler},
};
use std::collections::BTreeMap;
#[derive(Default)]
pub struct Window {
@ -101,7 +102,7 @@ impl Application for Window {
Message::RowSelected(row) => println!("Selected row {row}"),
}
iced::Command::none()
Command::none()
}
fn view(&self) -> Element<Message> {
@ -128,38 +129,84 @@ impl Application for Window {
let content = responsive(|size| {
let condensed = size.width < 900.0;
let sidebar: Element<_> = cosmic::navbar![
nav_button!("network-wireless", "Wi-Fi", condensed)
.on_press(Message::Page(0))
.style(if self.page == 0 {
theme::Button::Primary
} else {
theme::Button::Text
}),
nav_button!("preferences-desktop", "Desktop", condensed)
.on_press(Message::Page(1))
.style(if self.page == 1 {
theme::Button::Primary
} else {
theme::Button::Text
}),
nav_button!("system-software-update", "OS Upgrade & Recovery", condensed)
.on_press(Message::Page(2))
.style(if self.page == 2 {
theme::Button::Primary
} else {
theme::Button::Text
}),
]
.active(self.sidebar_toggled)
.condensed(condensed)
.style(theme::Container::Custom(nav_bar_style))
.into();
// cosmic::navbar![
// nav_button!("network-wireless", "Network & Wireless", condensed)
// .on_press(Message::Page(0))
// .style(if self.page == 0 {
// theme::Button::Primary
// } else {
// theme::Button::Text
// }),
// nav_button!("preferences-desktop", "Bluetooth", condensed)
// .on_press(Message::Page(1))
// .style(if self.page == 1 {
// theme::Button::Primary
// } else {
// theme::Button::Text
// }),
// nav_button!("system-software-update", "Personalization", condensed)
// .on_press(Message::Page(2))
// .style(if self.page == 2 {
// theme::Button::Primary
// } else {
// theme::Button::Text
// }),
// ]
let sidebar: Element<_> = nav_bar()
.source(BTreeMap::from([
(
nav_bar_section()
.title("Network & Wireless")
.icon("network-wireless"),
vec![nav_bar_page("Wi-Fi")],
),
(
nav_bar_section()
.title("Bluetooth")
.icon("cs-bluetooth"),
vec![nav_bar_page("Devices")],
),
(
nav_bar_section()
.title("Personalization")
.icon("applications-system"),
vec![
nav_bar_page("Desktop Session"),
nav_bar_page("Wallpaper"),
nav_bar_page("Appearance"),
nav_bar_page("Dock & Top Panel"),
nav_bar_page("Workspaces"),
nav_bar_page("Notifications"),
],
),
(
nav_bar_section()
.title("Input Devices")
.icon("input-keyboard"),
vec![nav_bar_page("Keyboard")],
),
(
nav_bar_section().title("Displays").icon("cs-display"),
vec![nav_bar_page("Keyboard")],
),
(
nav_bar_section()
.title("Power & Battery")
.icon("battery"),
vec![nav_bar_page("Status")],
),
(
nav_bar_section().title("Sound").icon("sound"),
vec![nav_bar_page("Volume")],
),
]))
.active(self.sidebar_toggled)
.condensed(condensed)
.into();
let choose_theme = [Theme::Light, Theme::Dark].iter().fold(
row![text("Debug theme:")]
.spacing(10)
.align_items(Alignment::Center),
row![].spacing(10).align_items(Alignment::Center),
|row, theme| {
row.push(radio(
format!("{:?}", theme),
@ -171,14 +218,17 @@ impl Application for Window {
);
let content: Element<_> = list_view!(
list_section!(
list_view_section!(
"Debug",
choose_theme,
toggler(String::from("Debug layout"), self.debug, Message::Debug,)
list_view_item!("Debug theme", choose_theme),
list_view_item!(
"Debug layout",
toggler(String::from("Debug layout"), self.debug, Message::Debug,)
)
),
list_section!(
list_view_section!(
"Buttons",
list_row!(
list_view_row!(
button!("Primary")
.style(theme::Button::Primary)
.on_press(Message::ButtonPressed),
@ -195,7 +245,7 @@ impl Application for Window {
.style(theme::Button::Text)
.on_press(Message::ButtonPressed),
),
list_row!(
list_view_row!(
button!("Primary").style(theme::Button::Primary),
button!("Secondary").style(theme::Button::Secondary),
button!("Positive").style(theme::Button::Positive),
@ -203,13 +253,13 @@ impl Application for Window {
button!("Text").style(theme::Button::Text),
),
),
list_section!(
list_view_section!(
"Controls",
list_item!(
list_view_item!(
"Toggler",
toggler(None, self.toggler_value, Message::TogglerToggled)
),
list_item!(
list_view_item!(
"Pick List (TODO)",
pick_list(
vec!["Option 1", "Option 2", "Option 3", "Option 4",],
@ -218,12 +268,12 @@ impl Application for Window {
)
.padding([8, 0, 8, 16])
),
list_item!(
list_view_item!(
"Slider",
slider(0.0..=100.0, self.slider_value, Message::SliderChanged)
.width(Length::Units(250))
),
list_item!(
list_view_item!(
"Progress",
progress_bar(0.0..=100.0, self.slider_value)
.width(Length::Units(250))
@ -231,7 +281,7 @@ impl Application for Window {
),
checkbox("Checkbox", self.checkbox_value, Message::CheckboxToggled),
),
list_section!(
list_view_section!(
"Expander",
expander()
.title("Label")
@ -247,19 +297,18 @@ impl Application for Window {
list_row().title("Label")
])
),
list_section!(
list_view_section!(
"List Box",
ListBox::with_children(
vec![
list_box()
.style(theme::Container::Custom(list_section_style))
.children(vec![
cosmic::list_box_row!("Title").into(),
cosmic::list_box_row!("Title", "Subtitle").into(),
cosmic::list_box_row!("Title", "", "edit-paste").into(),
cosmic::list_box_row!("", "Subtitle", "edit-paste").into(),
cosmic::list_box_row!("Title", "Subtitle", "edit-paste").into()
],
true,
)
.style(theme::Container::Custom(list_section_style))
])
.render()
),
)
.into();

View file

@ -1,6 +1,6 @@
use std::vec;
use crate::{list_box_row, widget::ListRow};
use crate::{list_box_row, separator, widget::ListRow};
use apply::Apply;
use derive_setters::Setters;
use iced::{
@ -9,7 +9,7 @@ use iced::{
Alignment, Background, Element, Length, Renderer, Theme,
};
use iced_lazy::Component;
use iced_native::widget::{column, event_container, horizontal_rule};
use iced_native::widget::{column, event_container};
#[derive(Setters)]
pub struct Expander<'a, Message> {
@ -145,12 +145,7 @@ impl<'a, Message: Clone + 'a> Component<Message, Renderer> for Expander<'a, Mess
.enumerate()
.flat_map(|(index, child)| {
if index != rows.len() - 1 {
vec![
child,
horizontal_rule(1)
.style(theme::Rule::Custom(separator_style))
.into(),
]
vec![child, separator!(1).into()]
} else {
vec![child]
}

View file

@ -1,3 +1,4 @@
use crate::separator;
use derive_setters::Setters;
use iced::mouse::Interaction;
use iced::{overlay, Alignment, Length, Padding, Point, Rectangle};
@ -6,7 +7,7 @@ use iced_native::layout::flex::{resolve, Axis};
use iced_native::layout::{Limits, Node};
use iced_native::overlay::from_children;
use iced_native::renderer::Style;
use iced_native::widget::{column, horizontal_rule, Operation, Tree};
use iced_native::widget::{column, Operation, Tree};
use iced_native::{
renderer, row, Background, Clipboard, Color, Element, Event, Layout, Shell, Widget,
};
@ -15,6 +16,7 @@ use iced_style::theme;
use iced_style::theme::Container;
#[derive(Setters)]
#[allow(dead_code)]
pub struct ListBox<'a, Message, Renderer>
where
Renderer: iced_native::Renderer,
@ -22,6 +24,7 @@ where
<Renderer as iced_native::Renderer>::Theme: iced_style::rule::StyleSheet,
{
spacing: u16,
#[setters(into)]
padding: Padding,
width: Length,
height: Length,
@ -31,6 +34,7 @@ where
children: Vec<Element<'a, Message, Renderer>>,
#[setters(strip_option)]
placeholder: Option<Element<'a, Message, Renderer>>,
show_separators: bool,
on_item_selected: Option<Box<dyn Fn(usize) -> Message + 'a>>,
}
@ -57,51 +61,54 @@ where
/// Creates an empty [`ListBox`].
pub fn new() -> Self {
Self::with_children(Vec::<Element<Message, Renderer>>::new(), true)
Self::with_children(Vec::<Element<Message, Renderer>>::new()).render()
}
/// Creates a new [`ListBox`].
///
/// [`ListBox`]: struct.ListBox.html
pub fn with_children(
children: Vec<Element<'a, Message, Renderer>>,
show_separators: bool,
) -> Self {
let children_size = children.len();
let children: Vec<Element<Message, Renderer>> = children
.into_iter()
.enumerate()
.map(|(index, child)| {
let row_items = if show_separators && index != children_size - 1 {
vec![
row![child].align_items(Alignment::Center).into(),
horizontal_rule(1)
.style(theme::Rule::Custom(separator_style))
.into(),
]
} else {
vec![row![child].align_items(Alignment::Center).into()]
};
column(row_items).into()
})
.collect();
Self {
pub fn with_children(children: Vec<Element<'a, Message, Renderer>>) -> Self {
let list_box = Self {
spacing: 0,
padding: Padding::from(Self::DEFAULT_PADDING),
width: Length::Shrink,
height: Length::Shrink,
max_width: u32::MAX,
align_items: Alignment::Start,
align_items: Alignment::Center,
style: Default::default(),
children,
placeholder: None,
show_separators: true,
on_item_selected: None,
}
};
list_box.render()
}
pub fn render(mut self) -> Self {
let children_size = self.children.len();
self.children = self
.children
.into_iter()
.enumerate()
.map(|(index, child)| {
let row_items = if self.show_separators && index != children_size - 1 {
vec![
row![child].align_items(self.align_items).into(),
separator!(1).into(),
]
} else {
vec![row![child].align_items(self.align_items).into()]
};
column(row_items).spacing(self.spacing).into()
})
.collect();
self
}
/// Adds an element to the [`ListBox`].
pub fn push(mut self, child: impl Into<Element<'a, Message, Renderer>>) -> Self {
self.children.push(child.into());
self = self.render();
self
}
}
@ -444,5 +451,3 @@ macro_rules! list_box_heading {
};
}
pub use list_box_heading;
use crate::widget::separator_style;

View file

@ -14,7 +14,7 @@ pub mod list_view {
}
#[macro_export]
macro_rules! list_row {
macro_rules! list_view_row {
($($x:expr),+ $(,)?) => (
$crate::iced::widget::Row::with_children(vec![
$($crate::iced::Element::from($x)),+
@ -26,7 +26,7 @@ pub mod list_view {
}
#[macro_export]
macro_rules! list_section {
macro_rules! list_view_section {
($title:expr, $($x:expr),+ $(,)?) => (
$crate::iced::widget::Column::with_children(vec![
$crate::iced::widget::Text::new($title)
@ -39,7 +39,7 @@ pub mod list_view {
//TODO: more efficient method for adding separators
let mut i = 1;
while i < children.len() {
children.insert(i, $crate::iced::widget::horizontal_rule(12).into());
children.insert(i, $crate::separator!(12).into());
i += 2;
}
@ -57,9 +57,9 @@ pub mod list_view {
}
#[macro_export]
macro_rules! list_item {
macro_rules! list_view_item {
($title:expr, $($x:expr),+ $(,)?) => (
$crate::list_row!(
$crate::list_view_row!(
$crate::iced::widget::Text::new($title),
$crate::iced::widget::horizontal_space(
$crate::iced::Length::Fill
@ -84,10 +84,10 @@ pub mod list_view {
use iced::widget;
use iced_style::Theme;
pub use list_item;
pub use list_row;
pub use list_section;
pub use list_view;
pub use list_view_item;
pub use list_view_row;
pub use list_view_section;
}
pub mod list_box {

View file

@ -21,3 +21,6 @@ pub use expander::*;
pub mod list;
pub use list::*;
pub mod separator;
pub use separator::*;

View file

@ -16,7 +16,7 @@ pub mod nav_bar {
}};
}
pub fn nav_bar_style(theme: &Theme) -> widget::container::Appearance {
pub fn nav_bar_sections_style(theme: &Theme) -> widget::container::Appearance {
let cosmic = &theme.cosmic().primary;
widget::container::Appearance {
text_color: Some(cosmic.on.into()),
@ -27,5 +27,17 @@ pub mod nav_bar {
}
}
pub fn nav_bar_pages_style(theme: &Theme) -> widget::container::Appearance {
let primary = &theme.cosmic().primary;
let secondary = &theme.cosmic().secondary;
widget::container::Appearance {
text_color: Some(primary.on.into()),
background: Some(Background::Color(secondary.component.base.into())),
border_radius: 8.0,
border_width: 0.0,
border_color: Color::TRANSPARENT,
}
}
pub use nav_button;
}

View file

@ -1,313 +1,249 @@
use iced::{
alignment,
widget::{scrollable, Column, Container},
Alignment, Element, Length, Padding,
};
use iced_native::{
renderer, row,
widget::{
container::{draw_background, layout},
Tree,
},
Widget,
};
use iced_style::container::StyleSheet;
use crate::scrollable;
use crate::widget::nav_bar::{nav_bar_pages_style, nav_bar_sections_style};
use crate::widget::{icon, Background};
use derive_setters::Setters;
use iced::Length;
use iced_lazy::Component;
use iced_native::widget::{button, column, container, text};
use iced_native::{row, Alignment, Element};
use iced_style::button::Appearance;
use iced_style::{scrollable, theme, Theme};
use std::collections::BTreeMap;
pub struct NavBar<'a, Message, Renderer>
where
Renderer: iced_native::Renderer,
Renderer::Theme: StyleSheet,
{
spacing: u16,
padding: Padding,
width: Length,
height: Length,
max_width: u32,
max_height: u32,
align_items: Alignment,
horizontal_alignment: alignment::Horizontal,
vertical_alignment: alignment::Vertical,
style: <Renderer::Theme as StyleSheet>::Style,
condensed: bool,
#[derive(Setters, Default)]
pub struct NavBar<'a, Message> {
source: BTreeMap<NavBarSection, Vec<NavBarPage>>,
active: bool,
content: Element<'a, Message, Renderer>,
condensed: bool,
on_page_selected: Option<Box<dyn Fn(NavBarSection, NavBarPage) -> Message + 'a>>,
}
impl<'a, Message: 'a, Renderer> NavBar<'a, Message, Renderer>
where
Renderer: iced_native::Renderer + 'a,
Renderer::Theme: StyleSheet,
{
/// Creates a [`NavBar`] with the given elements.
pub fn with_children(children: Vec<Element<'a, Message, Renderer>>) -> Self
where
<Renderer as iced_native::Renderer>::Theme: iced_style::scrollable::StyleSheet,
{
let nav = Self::default();
NavBar {
content: Container::new(
scrollable(row![Column::with_children(children)
.spacing(nav.spacing)
.padding(nav.padding)])
.scrollbar_width(6)
.scroller_width(6),
)
.into(),
..Default::default()
}
}
pub fn condensed(mut self, condensed: bool) -> Self {
self.condensed = condensed;
self
}
pub fn active(mut self, active: bool) -> Self {
self.active = active;
self
}
/// Sets the horizontal spacing _between_ elements.
///
/// Custom margins per element do not exist in iced. You should use this
/// method instead! While less flexible, it helps you keep spacing between
/// elements consistent.
pub fn spacing(mut self, units: u16) -> Self {
self.spacing = units;
self
}
/// Sets the [`Padding`] of the [`NavBar`].
pub fn padding<P: Into<iced::Padding>>(mut self, padding: P) -> Self {
self.padding = padding.into();
self
}
/// Sets the width of the [`NavBar`].
pub fn width(mut self, width: iced::Length) -> Self {
self.width = width;
self
}
/// Sets the height of the [`NavBar`].
pub fn height(mut self, height: iced::Length) -> Self {
self.height = height;
self
}
/// Sets the vertical alignment of the contents of the [`NavBar`] .
pub fn align_items(mut self, align: iced::Alignment) -> Self {
self.align_items = align;
self
}
/// Sets the maximum width of the [`NavBar`].
pub fn max_width(mut self, max_width: u32) -> Self {
self.max_width = max_width;
self
}
/// Sets the maximum height of the [`NavBar`].
pub fn max_height(mut self, max_height: u32) -> Self {
self.max_height = max_height;
self
}
/// Sets the style of the [`NavBar`].
pub fn style(mut self, style: impl Into<<Renderer::Theme as StyleSheet>::Style>) -> Self {
self.style = style.into();
self
}
}
impl<'a, Message: 'a, Renderer> Default for NavBar<'a, Message, Renderer>
where
Renderer: iced_native::Renderer + 'a,
Renderer::Theme: StyleSheet,
{
fn default() -> Self {
impl<'a, Message> NavBar<'a, Message> {
pub fn new() -> Self {
Self {
spacing: 12,
padding: Padding::new(12),
width: Length::Shrink,
height: Length::Fill,
max_width: 300,
max_height: u32::MAX,
align_items: Alignment::Start,
horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Top,
style: Default::default(),
source: Default::default(),
active: false,
condensed: false,
active: true,
content: Container::new(row![Column::new()]).into(),
on_page_selected: None,
}
}
}
impl<'a, Message, Renderer> Widget<Message, Renderer> for NavBar<'a, Message, Renderer>
pub fn nav_bar<'a, Message>() -> NavBar<'a, Message> {
NavBar::new()
}
#[derive(Setters, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct NavBarSection {
#[setters(into)]
title: String,
#[setters(into)]
icon: String,
}
impl NavBarSection {
pub fn new() -> Self {
Self {
title: String::new(),
icon: String::new(),
}
}
}
pub fn nav_bar_section() -> NavBarSection {
NavBarSection::new()
}
#[derive(Default, Clone, Setters, PartialOrd, Ord, PartialEq, Eq)]
pub struct NavBarPage {
#[setters(into)]
title: String,
}
impl NavBarPage {
pub fn new() -> Self {
Self {
title: String::new(),
}
}
}
pub fn nav_bar_page(title: &str) -> NavBarPage {
let mut page = NavBarPage::new();
page.title = title.to_string();
page
}
#[derive(Clone)]
pub enum NavBarEvent {
SectionSelected(NavBarSection),
PageSelected(NavBarSection, NavBarPage),
}
#[derive(Default)]
pub struct NavBarState {
selected_section: NavBarSection,
section_active: bool,
selected_page: Option<NavBarPage>,
page_active: bool,
}
impl<'a, Message, Renderer> Component<Message, Renderer> for NavBar<'a, Message>
where
Renderer: iced_native::Renderer,
Renderer::Theme: StyleSheet,
Renderer: iced_native::Renderer + iced_native::text::Renderer + iced_native::svg::Renderer + 'a,
<Renderer as iced_native::Renderer>::Theme:
container::StyleSheet + button::StyleSheet + text::StyleSheet + scrollable::StyleSheet,
<<Renderer as iced_native::Renderer>::Theme as button::StyleSheet>::Style: From<theme::Button>,
<<Renderer as iced_native::Renderer>::Theme as container::StyleSheet>::Style:
From<theme::Container>,
<<Renderer as iced_native::Renderer>::Theme as text::StyleSheet>::Style: From<theme::Text>,
{
fn width(&self) -> Length {
self.width
}
type State = NavBarState;
type Event = NavBarEvent;
fn height(&self) -> Length {
self.height
}
fn layout(
&self,
renderer: &Renderer,
limits: &iced_native::layout::Limits,
) -> iced_native::layout::Node {
layout(
renderer,
limits,
self.width,
self.height,
if self.condensed { 100 } else { self.max_width },
self.max_height,
if self.active {
self.padding
} else {
Padding::ZERO
},
self.horizontal_alignment,
self.vertical_alignment,
|renderer, limits| {
if self.active {
self.content.as_widget().layout(renderer, limits)
fn update(&mut self, state: &mut Self::State, event: Self::Event) -> Option<Message> {
match event {
NavBarEvent::SectionSelected(section) => {
if state.selected_section == section {
state.section_active = !state.section_active;
} else {
let content: Element<Message, Renderer> =
Container::new(row![Column::new()]).into();
content.as_widget().layout(renderer, limits)
state.selected_section = section;
state.section_active = true;
}
},
)
}
fn draw(
&self,
tree: &Tree,
renderer: &mut Renderer,
theme: &Renderer::Theme,
renderer_style: &iced_native::renderer::Style,
layout: iced_native::Layout<'_>,
cursor_position: iced::Point,
viewport: &iced::Rectangle,
) {
if self.active {
let style = theme.appearance(self.style);
draw_background(renderer, &style, layout.bounds());
self.content.as_widget().draw(
&tree.children[0],
renderer,
theme,
&renderer::Style {
text_color: style.text_color.unwrap_or(renderer_style.text_color),
},
layout.children().next().unwrap(),
cursor_position,
viewport,
);
state.selected_page = None;
state.page_active = false;
None
}
NavBarEvent::PageSelected(section, page) => {
if state.selected_page.is_some() && &page == state.selected_page.as_ref().unwrap() {
state.page_active = !state.page_active;
} else {
state.selected_page = Some(page.clone());
state.page_active = true;
}
self.on_page_selected
.as_ref()
.map(|on_page_selected| (on_page_selected)(section, page))
}
}
}
fn children(&self) -> Vec<iced_native::widget::Tree> {
vec![Tree::new(&self.content)]
}
fn view(&self, state: &Self::State) -> Element<'a, Self::Event, Renderer> {
if self.active {
let mut sections: Vec<Element<Self::Event, Renderer>> = vec![];
let mut pages: Vec<Element<Self::Event, Renderer>> = vec![];
fn diff(&self, tree: &mut Tree) {
tree.diff_children(std::slice::from_ref(&self.content))
}
for (section, section_pages) in &self.source {
sections.push(
button(
column(vec![
icon(&section.icon, 20).into(),
text(&section.title).size(14).into(),
])
.width(Length::Units(100))
.height(Length::Units(50))
.align_items(Alignment::Center),
)
.style(if *section == state.selected_section && state.section_active {
theme::Button::Primary.into()
} else {
theme::Button::Text.into()
})
.on_press(NavBarEvent::SectionSelected(section.clone()))
.into(),
);
if *section == state.selected_section {
for page in section_pages {
pages.push(
button(row![text(&page.title).size(16).width(Length::Fill)])
.padding(10)
.style(
if let Some(selected_page) = &state.selected_page {
if state.page_active && page == selected_page {
theme::Button::Primary.into()
} else {
theme::Button::Text.into()
}
} else {
theme::Button::Text.into()
}
)
.on_press(NavBarEvent::PageSelected(section.clone(), page.clone()))
.into(),
);
}
}
}
fn operate(
&self,
tree: &mut Tree,
layout: iced_native::Layout<'_>,
operation: &mut dyn iced_native::widget::Operation<Message>,
) {
operation.container(None, &mut |operation| {
self.content.as_widget().operate(
&mut tree.children[0],
layout.children().next().unwrap(),
operation,
);
});
}
fn on_event(
&mut self,
tree: &mut iced_native::widget::Tree,
event: iced::Event,
layout: iced_native::Layout<'_>,
cursor_position: iced::Point,
renderer: &Renderer,
clipboard: &mut dyn iced_native::Clipboard,
shell: &mut iced_native::Shell<'_, Message>,
) -> iced::event::Status {
self.content.as_widget_mut().on_event(
&mut tree.children[0],
event,
layout.children().next().unwrap(),
cursor_position,
renderer,
clipboard,
shell,
)
}
fn mouse_interaction(
&self,
tree: &iced_native::widget::Tree,
layout: iced_native::Layout<'_>,
cursor_position: iced::Point,
viewport: &iced::Rectangle,
renderer: &Renderer,
) -> iced_native::mouse::Interaction {
self.content.as_widget().mouse_interaction(
&tree.children[0],
layout.children().next().unwrap(),
cursor_position,
viewport,
renderer,
)
}
fn overlay<'b>(
&'b self,
tree: &'b mut iced_native::widget::Tree,
layout: iced_native::Layout<'_>,
renderer: &Renderer,
) -> Option<iced_native::overlay::Element<'b, Message, Renderer>> {
self.content.as_widget().overlay(
&mut tree.children[0],
layout.children().next().unwrap(),
renderer,
)
let nav_bar: Element<Self::Event, Renderer> =
container(if self.condensed && state.selected_page.is_some() {
row![container(scrollable!(column(pages)
.spacing(10)
.padding(10)
.max_width(200)
.width(Length::Units(200))
.height(Length::Shrink)))
.height(Length::Fill)
.style(theme::Container::Custom(nav_bar_pages_style))]
} else if !state.section_active || self.condensed && state.selected_page.is_none() {
row![scrollable!(column(sections)
.spacing(10)
.padding(10)
.max_width(100)
.align_items(Alignment::Center)
.height(Length::Shrink))]
} else {
row![
scrollable!(column(sections)
.spacing(10)
.padding(10)
.max_width(100)
.align_items(Alignment::Center)
.height(Length::Shrink)),
container(scrollable!(column(pages)
.spacing(10)
.padding(10)
.max_width(200)
.width(Length::Units(200))
.height(Length::Shrink)))
.height(Length::Fill)
.style(theme::Container::Custom(nav_bar_pages_style)),
]
})
.height(Length::Fill)
.style(theme::Container::Custom(nav_bar_sections_style))
.into();
nav_bar
} else {
row![].into()
}
}
}
impl<'a, Message, Renderer> From<NavBar<'a, Message, Renderer>> for Element<'a, Message, Renderer>
impl<'a, Message: 'a, Renderer> From<NavBar<'a, Message>>
for Element<'a, Message, Renderer>
where
Message: 'a,
Renderer: iced_native::Renderer + 'a,
Renderer::Theme: StyleSheet,
Renderer: iced_native::text::Renderer + iced_native::svg::Renderer + 'a,
<Renderer as iced_native::Renderer>::Theme:
container::StyleSheet + button::StyleSheet + text::StyleSheet + scrollable::StyleSheet,
<<Renderer as iced_native::Renderer>::Theme as button::StyleSheet>::Style: From<theme::Button>,
<<Renderer as iced_native::Renderer>::Theme as container::StyleSheet>::Style:
From<theme::Container>,
<<Renderer as iced_native::Renderer>::Theme as text::StyleSheet>::Style: From<theme::Text>,
{
fn from(navbar: NavBar<'a, Message, Renderer>) -> Self {
Self::new(navbar)
fn from(nav_bar: NavBar<'a, Message>) -> Self {
iced_lazy::component(nav_bar)
}
}
/// Creates a [NavBar`] with the given children.
///
/// [`NavBar`]: widget::NavBar
#[macro_export]
macro_rules! navbar {
($($x:expr),+ $(,)?) => (
$crate::widget::NavBar::with_children(vec![$($crate::iced::Element::from($x)),+])
);
pub fn section_button_style(theme: &Theme) -> Appearance {
let primary = &theme.cosmic().primary;
Appearance {
shadow_offset: Default::default(),
background: Some(Background::Color(primary.base.into())),
border_radius: 5.0,
border_width: 0.0,
border_color: Default::default(),
text_color: Default::default(),
}
}

7
src/widget/separator.rs Normal file
View file

@ -0,0 +1,7 @@
#[macro_export]
macro_rules! separator {
($size:expr) => {
$crate::iced::widget::horizontal_rule($size)
.style(theme::Rule::Custom($crate::widget::separator_style))
};
}