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:
parent
420d3c3dfc
commit
07e53ddadd
8 changed files with 390 additions and 383 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
use cosmic::widget::{expander, ListBox};
|
use cosmic::widget::{expander, nav_bar, nav_bar_page, nav_bar_section};
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
iced::widget::{
|
iced::widget::{
|
||||||
checkbox, column, container, horizontal_space, pick_list, progress_bar, radio, row, slider,
|
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::{self, theme, Alignment, Application, Color, Command, Element, Length, Theme},
|
||||||
iced_lazy::responsive,
|
iced_lazy::responsive,
|
||||||
iced_winit::window::{drag, maximize, minimize},
|
iced_winit::window::{drag, maximize, minimize},
|
||||||
list_item, list_row, list_section, list_view, nav_button, scrollable,
|
list_view, list_view_item, list_view_row, list_view_section, scrollable,
|
||||||
widget::{button, header_bar, list_row, list_view::*, nav_bar::nav_bar_style, toggler},
|
widget::{button, header_bar, list_box, list_row, list_view::*, toggler},
|
||||||
};
|
};
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
|
|
@ -101,7 +102,7 @@ impl Application for Window {
|
||||||
Message::RowSelected(row) => println!("Selected row {row}"),
|
Message::RowSelected(row) => println!("Selected row {row}"),
|
||||||
}
|
}
|
||||||
|
|
||||||
iced::Command::none()
|
Command::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<Message> {
|
||||||
|
|
@ -128,38 +129,84 @@ impl Application for Window {
|
||||||
let content = responsive(|size| {
|
let content = responsive(|size| {
|
||||||
let condensed = size.width < 900.0;
|
let condensed = size.width < 900.0;
|
||||||
|
|
||||||
let sidebar: Element<_> = cosmic::navbar![
|
// cosmic::navbar![
|
||||||
nav_button!("network-wireless", "Wi-Fi", condensed)
|
// nav_button!("network-wireless", "Network & Wireless", condensed)
|
||||||
.on_press(Message::Page(0))
|
// .on_press(Message::Page(0))
|
||||||
.style(if self.page == 0 {
|
// .style(if self.page == 0 {
|
||||||
theme::Button::Primary
|
// theme::Button::Primary
|
||||||
} else {
|
// } else {
|
||||||
theme::Button::Text
|
// theme::Button::Text
|
||||||
}),
|
// }),
|
||||||
nav_button!("preferences-desktop", "Desktop", condensed)
|
// nav_button!("preferences-desktop", "Bluetooth", condensed)
|
||||||
.on_press(Message::Page(1))
|
// .on_press(Message::Page(1))
|
||||||
.style(if self.page == 1 {
|
// .style(if self.page == 1 {
|
||||||
theme::Button::Primary
|
// theme::Button::Primary
|
||||||
} else {
|
// } else {
|
||||||
theme::Button::Text
|
// theme::Button::Text
|
||||||
}),
|
// }),
|
||||||
nav_button!("system-software-update", "OS Upgrade & Recovery", condensed)
|
// nav_button!("system-software-update", "Personalization", condensed)
|
||||||
.on_press(Message::Page(2))
|
// .on_press(Message::Page(2))
|
||||||
.style(if self.page == 2 {
|
// .style(if self.page == 2 {
|
||||||
theme::Button::Primary
|
// theme::Button::Primary
|
||||||
} else {
|
// } else {
|
||||||
theme::Button::Text
|
// theme::Button::Text
|
||||||
}),
|
// }),
|
||||||
]
|
// ]
|
||||||
.active(self.sidebar_toggled)
|
|
||||||
.condensed(condensed)
|
let sidebar: Element<_> = nav_bar()
|
||||||
.style(theme::Container::Custom(nav_bar_style))
|
.source(BTreeMap::from([
|
||||||
.into();
|
(
|
||||||
|
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(
|
let choose_theme = [Theme::Light, Theme::Dark].iter().fold(
|
||||||
row![text("Debug theme:")]
|
row![].spacing(10).align_items(Alignment::Center),
|
||||||
.spacing(10)
|
|
||||||
.align_items(Alignment::Center),
|
|
||||||
|row, theme| {
|
|row, theme| {
|
||||||
row.push(radio(
|
row.push(radio(
|
||||||
format!("{:?}", theme),
|
format!("{:?}", theme),
|
||||||
|
|
@ -171,14 +218,17 @@ impl Application for Window {
|
||||||
);
|
);
|
||||||
|
|
||||||
let content: Element<_> = list_view!(
|
let content: Element<_> = list_view!(
|
||||||
list_section!(
|
list_view_section!(
|
||||||
"Debug",
|
"Debug",
|
||||||
choose_theme,
|
list_view_item!("Debug theme", choose_theme),
|
||||||
toggler(String::from("Debug layout"), self.debug, Message::Debug,)
|
list_view_item!(
|
||||||
|
"Debug layout",
|
||||||
|
toggler(String::from("Debug layout"), self.debug, Message::Debug,)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
list_section!(
|
list_view_section!(
|
||||||
"Buttons",
|
"Buttons",
|
||||||
list_row!(
|
list_view_row!(
|
||||||
button!("Primary")
|
button!("Primary")
|
||||||
.style(theme::Button::Primary)
|
.style(theme::Button::Primary)
|
||||||
.on_press(Message::ButtonPressed),
|
.on_press(Message::ButtonPressed),
|
||||||
|
|
@ -195,7 +245,7 @@ impl Application for Window {
|
||||||
.style(theme::Button::Text)
|
.style(theme::Button::Text)
|
||||||
.on_press(Message::ButtonPressed),
|
.on_press(Message::ButtonPressed),
|
||||||
),
|
),
|
||||||
list_row!(
|
list_view_row!(
|
||||||
button!("Primary").style(theme::Button::Primary),
|
button!("Primary").style(theme::Button::Primary),
|
||||||
button!("Secondary").style(theme::Button::Secondary),
|
button!("Secondary").style(theme::Button::Secondary),
|
||||||
button!("Positive").style(theme::Button::Positive),
|
button!("Positive").style(theme::Button::Positive),
|
||||||
|
|
@ -203,13 +253,13 @@ impl Application for Window {
|
||||||
button!("Text").style(theme::Button::Text),
|
button!("Text").style(theme::Button::Text),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
list_section!(
|
list_view_section!(
|
||||||
"Controls",
|
"Controls",
|
||||||
list_item!(
|
list_view_item!(
|
||||||
"Toggler",
|
"Toggler",
|
||||||
toggler(None, self.toggler_value, Message::TogglerToggled)
|
toggler(None, self.toggler_value, Message::TogglerToggled)
|
||||||
),
|
),
|
||||||
list_item!(
|
list_view_item!(
|
||||||
"Pick List (TODO)",
|
"Pick List (TODO)",
|
||||||
pick_list(
|
pick_list(
|
||||||
vec!["Option 1", "Option 2", "Option 3", "Option 4",],
|
vec!["Option 1", "Option 2", "Option 3", "Option 4",],
|
||||||
|
|
@ -218,12 +268,12 @@ impl Application for Window {
|
||||||
)
|
)
|
||||||
.padding([8, 0, 8, 16])
|
.padding([8, 0, 8, 16])
|
||||||
),
|
),
|
||||||
list_item!(
|
list_view_item!(
|
||||||
"Slider",
|
"Slider",
|
||||||
slider(0.0..=100.0, self.slider_value, Message::SliderChanged)
|
slider(0.0..=100.0, self.slider_value, Message::SliderChanged)
|
||||||
.width(Length::Units(250))
|
.width(Length::Units(250))
|
||||||
),
|
),
|
||||||
list_item!(
|
list_view_item!(
|
||||||
"Progress",
|
"Progress",
|
||||||
progress_bar(0.0..=100.0, self.slider_value)
|
progress_bar(0.0..=100.0, self.slider_value)
|
||||||
.width(Length::Units(250))
|
.width(Length::Units(250))
|
||||||
|
|
@ -231,7 +281,7 @@ impl Application for Window {
|
||||||
),
|
),
|
||||||
checkbox("Checkbox", self.checkbox_value, Message::CheckboxToggled),
|
checkbox("Checkbox", self.checkbox_value, Message::CheckboxToggled),
|
||||||
),
|
),
|
||||||
list_section!(
|
list_view_section!(
|
||||||
"Expander",
|
"Expander",
|
||||||
expander()
|
expander()
|
||||||
.title("Label")
|
.title("Label")
|
||||||
|
|
@ -247,19 +297,18 @@ impl Application for Window {
|
||||||
list_row().title("Label")
|
list_row().title("Label")
|
||||||
])
|
])
|
||||||
),
|
),
|
||||||
list_section!(
|
list_view_section!(
|
||||||
"List Box",
|
"List Box",
|
||||||
ListBox::with_children(
|
list_box()
|
||||||
vec![
|
.style(theme::Container::Custom(list_section_style))
|
||||||
|
.children(vec![
|
||||||
cosmic::list_box_row!("Title").into(),
|
cosmic::list_box_row!("Title").into(),
|
||||||
cosmic::list_box_row!("Title", "Subtitle").into(),
|
cosmic::list_box_row!("Title", "Subtitle").into(),
|
||||||
cosmic::list_box_row!("Title", "", "edit-paste").into(),
|
cosmic::list_box_row!("Title", "", "edit-paste").into(),
|
||||||
cosmic::list_box_row!("", "Subtitle", "edit-paste").into(),
|
cosmic::list_box_row!("", "Subtitle", "edit-paste").into(),
|
||||||
cosmic::list_box_row!("Title", "Subtitle", "edit-paste").into()
|
cosmic::list_box_row!("Title", "Subtitle", "edit-paste").into()
|
||||||
],
|
])
|
||||||
true,
|
.render()
|
||||||
)
|
|
||||||
.style(theme::Container::Custom(list_section_style))
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.into();
|
.into();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::vec;
|
use std::vec;
|
||||||
|
|
||||||
use crate::{list_box_row, widget::ListRow};
|
use crate::{list_box_row, separator, widget::ListRow};
|
||||||
use apply::Apply;
|
use apply::Apply;
|
||||||
use derive_setters::Setters;
|
use derive_setters::Setters;
|
||||||
use iced::{
|
use iced::{
|
||||||
|
|
@ -9,7 +9,7 @@ use iced::{
|
||||||
Alignment, Background, Element, Length, Renderer, Theme,
|
Alignment, Background, Element, Length, Renderer, Theme,
|
||||||
};
|
};
|
||||||
use iced_lazy::Component;
|
use iced_lazy::Component;
|
||||||
use iced_native::widget::{column, event_container, horizontal_rule};
|
use iced_native::widget::{column, event_container};
|
||||||
|
|
||||||
#[derive(Setters)]
|
#[derive(Setters)]
|
||||||
pub struct Expander<'a, Message> {
|
pub struct Expander<'a, Message> {
|
||||||
|
|
@ -145,12 +145,7 @@ impl<'a, Message: Clone + 'a> Component<Message, Renderer> for Expander<'a, Mess
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.flat_map(|(index, child)| {
|
.flat_map(|(index, child)| {
|
||||||
if index != rows.len() - 1 {
|
if index != rows.len() - 1 {
|
||||||
vec![
|
vec![child, separator!(1).into()]
|
||||||
child,
|
|
||||||
horizontal_rule(1)
|
|
||||||
.style(theme::Rule::Custom(separator_style))
|
|
||||||
.into(),
|
|
||||||
]
|
|
||||||
} else {
|
} else {
|
||||||
vec![child]
|
vec![child]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::separator;
|
||||||
use derive_setters::Setters;
|
use derive_setters::Setters;
|
||||||
use iced::mouse::Interaction;
|
use iced::mouse::Interaction;
|
||||||
use iced::{overlay, Alignment, Length, Padding, Point, Rectangle};
|
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::layout::{Limits, Node};
|
||||||
use iced_native::overlay::from_children;
|
use iced_native::overlay::from_children;
|
||||||
use iced_native::renderer::Style;
|
use iced_native::renderer::Style;
|
||||||
use iced_native::widget::{column, horizontal_rule, Operation, Tree};
|
use iced_native::widget::{column, Operation, Tree};
|
||||||
use iced_native::{
|
use iced_native::{
|
||||||
renderer, row, Background, Clipboard, Color, Element, Event, Layout, Shell, Widget,
|
renderer, row, Background, Clipboard, Color, Element, Event, Layout, Shell, Widget,
|
||||||
};
|
};
|
||||||
|
|
@ -15,6 +16,7 @@ use iced_style::theme;
|
||||||
use iced_style::theme::Container;
|
use iced_style::theme::Container;
|
||||||
|
|
||||||
#[derive(Setters)]
|
#[derive(Setters)]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct ListBox<'a, Message, Renderer>
|
pub struct ListBox<'a, Message, Renderer>
|
||||||
where
|
where
|
||||||
Renderer: iced_native::Renderer,
|
Renderer: iced_native::Renderer,
|
||||||
|
|
@ -22,6 +24,7 @@ where
|
||||||
<Renderer as iced_native::Renderer>::Theme: iced_style::rule::StyleSheet,
|
<Renderer as iced_native::Renderer>::Theme: iced_style::rule::StyleSheet,
|
||||||
{
|
{
|
||||||
spacing: u16,
|
spacing: u16,
|
||||||
|
#[setters(into)]
|
||||||
padding: Padding,
|
padding: Padding,
|
||||||
width: Length,
|
width: Length,
|
||||||
height: Length,
|
height: Length,
|
||||||
|
|
@ -31,6 +34,7 @@ where
|
||||||
children: Vec<Element<'a, Message, Renderer>>,
|
children: Vec<Element<'a, Message, Renderer>>,
|
||||||
#[setters(strip_option)]
|
#[setters(strip_option)]
|
||||||
placeholder: Option<Element<'a, Message, Renderer>>,
|
placeholder: Option<Element<'a, Message, Renderer>>,
|
||||||
|
show_separators: bool,
|
||||||
on_item_selected: Option<Box<dyn Fn(usize) -> Message + 'a>>,
|
on_item_selected: Option<Box<dyn Fn(usize) -> Message + 'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,51 +61,54 @@ where
|
||||||
|
|
||||||
/// Creates an empty [`ListBox`].
|
/// Creates an empty [`ListBox`].
|
||||||
pub fn new() -> Self {
|
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`].
|
/// Creates a new [`ListBox`].
|
||||||
///
|
///
|
||||||
/// [`ListBox`]: struct.ListBox.html
|
/// [`ListBox`]: struct.ListBox.html
|
||||||
pub fn with_children(
|
pub fn with_children(children: Vec<Element<'a, Message, Renderer>>) -> Self {
|
||||||
children: Vec<Element<'a, Message, Renderer>>,
|
let list_box = Self {
|
||||||
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 {
|
|
||||||
spacing: 0,
|
spacing: 0,
|
||||||
padding: Padding::from(Self::DEFAULT_PADDING),
|
padding: Padding::from(Self::DEFAULT_PADDING),
|
||||||
width: Length::Shrink,
|
width: Length::Shrink,
|
||||||
height: Length::Shrink,
|
height: Length::Shrink,
|
||||||
max_width: u32::MAX,
|
max_width: u32::MAX,
|
||||||
align_items: Alignment::Start,
|
align_items: Alignment::Center,
|
||||||
style: Default::default(),
|
style: Default::default(),
|
||||||
children,
|
children,
|
||||||
placeholder: None,
|
placeholder: None,
|
||||||
|
show_separators: true,
|
||||||
on_item_selected: None,
|
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`].
|
/// Adds an element to the [`ListBox`].
|
||||||
pub fn push(mut self, child: impl Into<Element<'a, Message, Renderer>>) -> Self {
|
pub fn push(mut self, child: impl Into<Element<'a, Message, Renderer>>) -> Self {
|
||||||
self.children.push(child.into());
|
self.children.push(child.into());
|
||||||
|
self = self.render();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -444,5 +451,3 @@ macro_rules! list_box_heading {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub use list_box_heading;
|
pub use list_box_heading;
|
||||||
|
|
||||||
use crate::widget::separator_style;
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ pub mod list_view {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! list_row {
|
macro_rules! list_view_row {
|
||||||
($($x:expr),+ $(,)?) => (
|
($($x:expr),+ $(,)?) => (
|
||||||
$crate::iced::widget::Row::with_children(vec![
|
$crate::iced::widget::Row::with_children(vec![
|
||||||
$($crate::iced::Element::from($x)),+
|
$($crate::iced::Element::from($x)),+
|
||||||
|
|
@ -26,7 +26,7 @@ pub mod list_view {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! list_section {
|
macro_rules! list_view_section {
|
||||||
($title:expr, $($x:expr),+ $(,)?) => (
|
($title:expr, $($x:expr),+ $(,)?) => (
|
||||||
$crate::iced::widget::Column::with_children(vec![
|
$crate::iced::widget::Column::with_children(vec![
|
||||||
$crate::iced::widget::Text::new($title)
|
$crate::iced::widget::Text::new($title)
|
||||||
|
|
@ -39,7 +39,7 @@ pub mod list_view {
|
||||||
//TODO: more efficient method for adding separators
|
//TODO: more efficient method for adding separators
|
||||||
let mut i = 1;
|
let mut i = 1;
|
||||||
while i < children.len() {
|
while i < children.len() {
|
||||||
children.insert(i, $crate::iced::widget::horizontal_rule(12).into());
|
children.insert(i, $crate::separator!(12).into());
|
||||||
i += 2;
|
i += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,9 +57,9 @@ pub mod list_view {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! list_item {
|
macro_rules! list_view_item {
|
||||||
($title:expr, $($x:expr),+ $(,)?) => (
|
($title:expr, $($x:expr),+ $(,)?) => (
|
||||||
$crate::list_row!(
|
$crate::list_view_row!(
|
||||||
$crate::iced::widget::Text::new($title),
|
$crate::iced::widget::Text::new($title),
|
||||||
$crate::iced::widget::horizontal_space(
|
$crate::iced::widget::horizontal_space(
|
||||||
$crate::iced::Length::Fill
|
$crate::iced::Length::Fill
|
||||||
|
|
@ -84,10 +84,10 @@ pub mod list_view {
|
||||||
use iced::widget;
|
use iced::widget;
|
||||||
use iced_style::Theme;
|
use iced_style::Theme;
|
||||||
|
|
||||||
pub use list_item;
|
|
||||||
pub use list_row;
|
|
||||||
pub use list_section;
|
|
||||||
pub use list_view;
|
pub use list_view;
|
||||||
|
pub use list_view_item;
|
||||||
|
pub use list_view_row;
|
||||||
|
pub use list_view_section;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod list_box {
|
pub mod list_box {
|
||||||
|
|
|
||||||
|
|
@ -21,3 +21,6 @@ pub use expander::*;
|
||||||
|
|
||||||
pub mod list;
|
pub mod list;
|
||||||
pub use list::*;
|
pub use list::*;
|
||||||
|
|
||||||
|
pub mod separator;
|
||||||
|
pub use separator::*;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
let cosmic = &theme.cosmic().primary;
|
||||||
widget::container::Appearance {
|
widget::container::Appearance {
|
||||||
text_color: Some(cosmic.on.into()),
|
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;
|
pub use nav_button;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,313 +1,249 @@
|
||||||
use iced::{
|
use crate::scrollable;
|
||||||
alignment,
|
use crate::widget::nav_bar::{nav_bar_pages_style, nav_bar_sections_style};
|
||||||
widget::{scrollable, Column, Container},
|
use crate::widget::{icon, Background};
|
||||||
Alignment, Element, Length, Padding,
|
use derive_setters::Setters;
|
||||||
};
|
use iced::Length;
|
||||||
use iced_native::{
|
use iced_lazy::Component;
|
||||||
renderer, row,
|
use iced_native::widget::{button, column, container, text};
|
||||||
widget::{
|
use iced_native::{row, Alignment, Element};
|
||||||
container::{draw_background, layout},
|
use iced_style::button::Appearance;
|
||||||
Tree,
|
use iced_style::{scrollable, theme, Theme};
|
||||||
},
|
use std::collections::BTreeMap;
|
||||||
Widget,
|
|
||||||
};
|
|
||||||
use iced_style::container::StyleSheet;
|
|
||||||
|
|
||||||
pub struct NavBar<'a, Message, Renderer>
|
#[derive(Setters, Default)]
|
||||||
where
|
pub struct NavBar<'a, Message> {
|
||||||
Renderer: iced_native::Renderer,
|
source: BTreeMap<NavBarSection, Vec<NavBarPage>>,
|
||||||
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,
|
|
||||||
active: bool,
|
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>
|
impl<'a, Message> NavBar<'a, Message> {
|
||||||
where
|
pub fn new() -> Self {
|
||||||
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 {
|
|
||||||
Self {
|
Self {
|
||||||
spacing: 12,
|
source: Default::default(),
|
||||||
padding: Padding::new(12),
|
active: false,
|
||||||
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(),
|
|
||||||
condensed: false,
|
condensed: false,
|
||||||
active: true,
|
on_page_selected: None,
|
||||||
content: Container::new(row![Column::new()]).into(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
where
|
||||||
Renderer: iced_native::Renderer,
|
Renderer: iced_native::Renderer + iced_native::text::Renderer + iced_native::svg::Renderer + 'a,
|
||||||
Renderer::Theme: StyleSheet,
|
<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 {
|
type State = NavBarState;
|
||||||
self.width
|
type Event = NavBarEvent;
|
||||||
}
|
|
||||||
|
|
||||||
fn height(&self) -> Length {
|
fn update(&mut self, state: &mut Self::State, event: Self::Event) -> Option<Message> {
|
||||||
self.height
|
match event {
|
||||||
}
|
NavBarEvent::SectionSelected(section) => {
|
||||||
|
if state.selected_section == section {
|
||||||
fn layout(
|
state.section_active = !state.section_active;
|
||||||
&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)
|
|
||||||
} else {
|
} else {
|
||||||
let content: Element<Message, Renderer> =
|
state.selected_section = section;
|
||||||
Container::new(row![Column::new()]).into();
|
state.section_active = true;
|
||||||
content.as_widget().layout(renderer, limits)
|
|
||||||
}
|
}
|
||||||
},
|
state.selected_page = None;
|
||||||
)
|
state.page_active = false;
|
||||||
}
|
None
|
||||||
|
}
|
||||||
fn draw(
|
NavBarEvent::PageSelected(section, page) => {
|
||||||
&self,
|
if state.selected_page.is_some() && &page == state.selected_page.as_ref().unwrap() {
|
||||||
tree: &Tree,
|
state.page_active = !state.page_active;
|
||||||
renderer: &mut Renderer,
|
} else {
|
||||||
theme: &Renderer::Theme,
|
state.selected_page = Some(page.clone());
|
||||||
renderer_style: &iced_native::renderer::Style,
|
state.page_active = true;
|
||||||
layout: iced_native::Layout<'_>,
|
}
|
||||||
cursor_position: iced::Point,
|
self.on_page_selected
|
||||||
viewport: &iced::Rectangle,
|
.as_ref()
|
||||||
) {
|
.map(|on_page_selected| (on_page_selected)(section, page))
|
||||||
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,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children(&self) -> Vec<iced_native::widget::Tree> {
|
fn view(&self, state: &Self::State) -> Element<'a, Self::Event, Renderer> {
|
||||||
vec![Tree::new(&self.content)]
|
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) {
|
for (section, section_pages) in &self.source {
|
||||||
tree.diff_children(std::slice::from_ref(&self.content))
|
sections.push(
|
||||||
}
|
button(
|
||||||
|
column(vec![
|
||||||
|
icon(§ion.icon, 20).into(),
|
||||||
|
text(§ion.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(
|
let nav_bar: Element<Self::Event, Renderer> =
|
||||||
&self,
|
container(if self.condensed && state.selected_page.is_some() {
|
||||||
tree: &mut Tree,
|
row![container(scrollable!(column(pages)
|
||||||
layout: iced_native::Layout<'_>,
|
.spacing(10)
|
||||||
operation: &mut dyn iced_native::widget::Operation<Message>,
|
.padding(10)
|
||||||
) {
|
.max_width(200)
|
||||||
operation.container(None, &mut |operation| {
|
.width(Length::Units(200))
|
||||||
self.content.as_widget().operate(
|
.height(Length::Shrink)))
|
||||||
&mut tree.children[0],
|
.height(Length::Fill)
|
||||||
layout.children().next().unwrap(),
|
.style(theme::Container::Custom(nav_bar_pages_style))]
|
||||||
operation,
|
} else if !state.section_active || self.condensed && state.selected_page.is_none() {
|
||||||
);
|
row![scrollable!(column(sections)
|
||||||
});
|
.spacing(10)
|
||||||
}
|
.padding(10)
|
||||||
|
.max_width(100)
|
||||||
fn on_event(
|
.align_items(Alignment::Center)
|
||||||
&mut self,
|
.height(Length::Shrink))]
|
||||||
tree: &mut iced_native::widget::Tree,
|
} else {
|
||||||
event: iced::Event,
|
row![
|
||||||
layout: iced_native::Layout<'_>,
|
scrollable!(column(sections)
|
||||||
cursor_position: iced::Point,
|
.spacing(10)
|
||||||
renderer: &Renderer,
|
.padding(10)
|
||||||
clipboard: &mut dyn iced_native::Clipboard,
|
.max_width(100)
|
||||||
shell: &mut iced_native::Shell<'_, Message>,
|
.align_items(Alignment::Center)
|
||||||
) -> iced::event::Status {
|
.height(Length::Shrink)),
|
||||||
self.content.as_widget_mut().on_event(
|
container(scrollable!(column(pages)
|
||||||
&mut tree.children[0],
|
.spacing(10)
|
||||||
event,
|
.padding(10)
|
||||||
layout.children().next().unwrap(),
|
.max_width(200)
|
||||||
cursor_position,
|
.width(Length::Units(200))
|
||||||
renderer,
|
.height(Length::Shrink)))
|
||||||
clipboard,
|
.height(Length::Fill)
|
||||||
shell,
|
.style(theme::Container::Custom(nav_bar_pages_style)),
|
||||||
)
|
]
|
||||||
}
|
})
|
||||||
|
.height(Length::Fill)
|
||||||
fn mouse_interaction(
|
.style(theme::Container::Custom(nav_bar_sections_style))
|
||||||
&self,
|
.into();
|
||||||
tree: &iced_native::widget::Tree,
|
nav_bar
|
||||||
layout: iced_native::Layout<'_>,
|
} else {
|
||||||
cursor_position: iced::Point,
|
row![].into()
|
||||||
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,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
where
|
||||||
Message: 'a,
|
Renderer: iced_native::text::Renderer + iced_native::svg::Renderer + 'a,
|
||||||
Renderer: iced_native::Renderer + 'a,
|
<Renderer as iced_native::Renderer>::Theme:
|
||||||
Renderer::Theme: StyleSheet,
|
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 {
|
fn from(nav_bar: NavBar<'a, Message>) -> Self {
|
||||||
Self::new(navbar)
|
iced_lazy::component(nav_bar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a [NavBar`] with the given children.
|
pub fn section_button_style(theme: &Theme) -> Appearance {
|
||||||
///
|
let primary = &theme.cosmic().primary;
|
||||||
/// [`NavBar`]: widget::NavBar
|
Appearance {
|
||||||
#[macro_export]
|
shadow_offset: Default::default(),
|
||||||
macro_rules! navbar {
|
background: Some(Background::Color(primary.base.into())),
|
||||||
($($x:expr),+ $(,)?) => (
|
border_radius: 5.0,
|
||||||
$crate::widget::NavBar::with_children(vec![$($crate::iced::Element::from($x)),+])
|
border_width: 0.0,
|
||||||
);
|
border_color: Default::default(),
|
||||||
|
text_color: Default::default(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
7
src/widget/separator.rs
Normal file
7
src/widget/separator.rs
Normal 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))
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue