Segmented button
- Implemented the segmented button widget
This commit is contained in:
parent
34b3d8a54b
commit
f630d66c67
3 changed files with 145 additions and 6 deletions
|
|
@ -9,7 +9,7 @@ use cosmic::{
|
||||||
iced_lazy::responsive,
|
iced_lazy::responsive,
|
||||||
iced_winit::window::{drag, toggle_maximize, minimize},
|
iced_winit::window::{drag, toggle_maximize, minimize},
|
||||||
theme::{self, Theme},
|
theme::{self, Theme},
|
||||||
widget::{button, nav_button, nav_bar, header_bar, settings, scrollable, toggler, nav_bar_item},
|
widget::{button, nav_button, nav_bar, header_bar, settings, scrollable, toggler, nav_bar_item, segmented_button},
|
||||||
Element,
|
Element,
|
||||||
ElementExt,
|
ElementExt,
|
||||||
};
|
};
|
||||||
|
|
@ -62,6 +62,7 @@ pub enum Message {
|
||||||
TogglerToggled(bool),
|
TogglerToggled(bool),
|
||||||
PickListSelected(&'static str),
|
PickListSelected(&'static str),
|
||||||
RowSelected(usize),
|
RowSelected(usize),
|
||||||
|
SegmentatedButtonPressed(usize),
|
||||||
Close,
|
Close,
|
||||||
ToggleSidebar,
|
ToggleSidebar,
|
||||||
Drag,
|
Drag,
|
||||||
|
|
@ -110,6 +111,9 @@ impl Application for Window {
|
||||||
Message::Minimize => return minimize(true),
|
Message::Minimize => return minimize(true),
|
||||||
Message::Maximize => return toggle_maximize(),
|
Message::Maximize => return toggle_maximize(),
|
||||||
Message::RowSelected(row) => println!("Selected row {row}"),
|
Message::RowSelected(row) => println!("Selected row {row}"),
|
||||||
|
Message::SegmentatedButtonPressed(index) => {
|
||||||
|
println!("Segmented button at index: {index}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::none()
|
Command::none()
|
||||||
|
|
@ -143,6 +147,7 @@ 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<_> = nav_bar()
|
let sidebar: Element<_> = nav_bar()
|
||||||
|
// TODO: Make this take an iterator
|
||||||
.source(BTreeMap::from([
|
.source(BTreeMap::from([
|
||||||
(
|
(
|
||||||
nav_bar_item()
|
nav_bar_item()
|
||||||
|
|
@ -272,9 +277,49 @@ impl Application for Window {
|
||||||
.width(Length::Units(250))
|
.width(Length::Units(250))
|
||||||
.height(Length::Units(4))
|
.height(Length::Units(4))
|
||||||
))
|
))
|
||||||
.into()
|
.add(settings::item(
|
||||||
|
"Segmented Button",
|
||||||
|
segmented_button()
|
||||||
|
.options(vec!["Vertical", "Horizontal"])
|
||||||
|
.on_button_pressed(Box::new(Message::SegmentatedButtonPressed))
|
||||||
|
))
|
||||||
|
.add(settings::item(
|
||||||
|
"Checkbox",
|
||||||
|
checkbox("Checkbox", self.checkbox_value, Message::CheckboxToggled)
|
||||||
|
))
|
||||||
|
.into(),
|
||||||
|
settings::view_section("Expander")
|
||||||
|
.add(settings::item(
|
||||||
|
"Expander",
|
||||||
|
expander()
|
||||||
|
.title("Label")
|
||||||
|
.subtitle("Caption")
|
||||||
|
.icon(String::from("edit-paste"))
|
||||||
|
.on_row_selected(Box::new(Message::RowSelected))
|
||||||
|
.rows(vec![
|
||||||
|
list_row()
|
||||||
|
.title("Label")
|
||||||
|
.subtitle("Caption")
|
||||||
|
.icon(String::from("help-about")),
|
||||||
|
list_row().subtitle("Caption").title("Label"),
|
||||||
|
list_row().title("Label")
|
||||||
])
|
])
|
||||||
.into();
|
)).into(),
|
||||||
|
settings::view_section("List Box")
|
||||||
|
.add(settings::item(
|
||||||
|
"List Box",
|
||||||
|
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()
|
||||||
|
])
|
||||||
|
.render()
|
||||||
|
)).into(),
|
||||||
|
]);
|
||||||
|
|
||||||
let mut widgets = Vec::with_capacity(2);
|
let mut widgets = Vec::with_capacity(2);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,4 +28,7 @@ mod scrollable;
|
||||||
pub use scrollable::*;
|
pub use scrollable::*;
|
||||||
|
|
||||||
pub mod separator;
|
pub mod separator;
|
||||||
pub use separator::{horizontal_rule, vertical_rule};
|
pub use separator::*;
|
||||||
|
|
||||||
|
pub mod segmented_button;
|
||||||
|
pub use segmented_button::*;
|
||||||
|
|
|
||||||
91
src/widget/segmented_button.rs
Normal file
91
src/widget/segmented_button.rs
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
use derive_setters::Setters;
|
||||||
|
use iced::{
|
||||||
|
alignment::{Horizontal, Vertical},
|
||||||
|
theme,
|
||||||
|
widget::{button, container, text, Row},
|
||||||
|
Background, Element, Length, Renderer, Theme,
|
||||||
|
};
|
||||||
|
use iced_lazy::Component;
|
||||||
|
|
||||||
|
#[derive(Setters)]
|
||||||
|
pub struct SegmentedButton<'a, Message> {
|
||||||
|
options: Vec<&'a str>,
|
||||||
|
#[setters(strip_option)]
|
||||||
|
on_button_pressed: Option<Box<dyn Fn(usize) -> Message>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn segmented_button<'a, Message>() -> SegmentedButton<'a, Message> {
|
||||||
|
SegmentedButton {
|
||||||
|
options: vec![],
|
||||||
|
on_button_pressed: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum SegmentedButtonEvent {
|
||||||
|
Pressed(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Message> Component<Message, Renderer> for SegmentedButton<'a, Message> {
|
||||||
|
type State = usize;
|
||||||
|
|
||||||
|
type Event = SegmentedButtonEvent;
|
||||||
|
|
||||||
|
fn update(&mut self, state: &mut Self::State, event: Self::Event) -> Option<Message> {
|
||||||
|
match event {
|
||||||
|
SegmentedButtonEvent::Pressed(index) => {
|
||||||
|
*state = index;
|
||||||
|
self.on_button_pressed
|
||||||
|
.as_ref()
|
||||||
|
.map(|on_button_pressed| (on_button_pressed)(index))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(&self, state: &Self::State) -> Element<Self::Event> {
|
||||||
|
let buttons: Vec<Element<'a, Self::Event>> = self
|
||||||
|
.options
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, option)| {
|
||||||
|
button(
|
||||||
|
container(text(*option))
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill)
|
||||||
|
.align_x(Horizontal::Center)
|
||||||
|
.align_y(Vertical::Center),
|
||||||
|
)
|
||||||
|
.width(Length::Units(136))
|
||||||
|
.height(Length::Units(32))
|
||||||
|
.style(if *state == index {
|
||||||
|
theme::Button::Secondary.into()
|
||||||
|
} else {
|
||||||
|
theme::Button::Primary.into()
|
||||||
|
})
|
||||||
|
.on_press(SegmentedButtonEvent::Pressed(index))
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
container(Row::with_children(buttons).spacing(5).width(Length::Shrink))
|
||||||
|
.padding(2)
|
||||||
|
.style(theme::Container::Custom(view_switcher_container_style))
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn view_switcher_container_style(theme: &Theme) -> iced_style::container::Appearance {
|
||||||
|
let accent = &theme.cosmic().accent;
|
||||||
|
iced_style::container::Appearance {
|
||||||
|
text_color: Default::default(),
|
||||||
|
background: Some(Background::Color(accent.base.into())),
|
||||||
|
border_radius: 24.0,
|
||||||
|
border_width: 2.0,
|
||||||
|
border_color: accent.base.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Message: 'a> From<SegmentedButton<'a, Message>> for Element<'a, Message> {
|
||||||
|
fn from(segmented_button: SegmentedButton<'a, Message>) -> Self {
|
||||||
|
iced_lazy::component(segmented_button)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue