libcosmic/src/widget/segmented_button/vertical.rs
Michael Aaron Murphy 357de5e9be
improv(segmented-button): Express vertical/horizontal variants as a state machine
It's difficult to make iterative developments when there's two
nearly-identical types that need to be kept synchronized to any change.
Rust gives us traits so we should use them instead of duplicating code.

This made it easier to make styling and layout improvements to both
instances of the segmented button.
2023-01-04 05:55:27 +01:00

78 lines
2.5 KiB
Rust

use super::state::State;
use super::style::StyleSheet;
use super::widget::{SegmentedButton, SegmentedVariant};
use iced::{Length, Rectangle, Size};
use iced_native::layout;
/// A type marker defining the vertical variant of a [`SegmentedButton`].
pub struct Vertical;
/// Vertical [`SegmentedButton`].
pub type VerticalSegmentedButton<'a, Message, Renderer> =
SegmentedButton<'a, Vertical, Message, Renderer>;
/// Vertical implementation of the [`SegmentedButton`].
#[must_use]
pub fn vertical_segmented_button<Message, Renderer, Data>(
state: &State<Data>,
) -> SegmentedButton<Vertical, Message, Renderer>
where
Renderer: iced_native::Renderer + iced_native::text::Renderer,
Renderer::Theme: StyleSheet,
{
SegmentedButton::new(&state.inner)
}
impl<'a, Message, Renderer> SegmentedVariant for SegmentedButton<'a, Vertical, Message, Renderer>
where
Renderer: iced_native::Renderer + iced_native::text::Renderer,
Renderer::Theme: StyleSheet,
{
type Renderer = Renderer;
fn variant_appearance(
theme: &<Self::Renderer as iced_native::Renderer>::Theme,
style: &<<Self::Renderer as iced_native::Renderer>::Theme as StyleSheet>::Style,
) -> super::Appearance {
theme.vertical(style)
}
#[allow(clippy::cast_precision_loss)]
fn variant_button_bounds(&self, mut bounds: Rectangle, nth: usize) -> Rectangle {
let num = self.state.buttons.len();
if num != 0 {
let spacing = f32::from(self.spacing);
bounds.height = (bounds.height - (num as f32 * spacing) + spacing) / num as f32;
if nth != 0 {
bounds.y += (nth as f32 * bounds.height) + (nth as f32 * spacing);
}
}
bounds
}
#[allow(clippy::cast_precision_loss)]
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_sign_loss)]
fn variant_layout(&self, renderer: &Renderer, limits: &layout::Limits) -> layout::Node {
let limits = limits.width(self.width);
let text_size = renderer.default_size();
let (width, mut height) = self.max_button_dimensions(renderer, text_size, limits.max());
let num = self.state.buttons.len();
let spacing = f32::from(self.spacing);
if num != 0 {
height = (num as f32 * height) + (num as f32 * spacing) - spacing;
}
let size = limits
.height(Length::Units(height as u16))
.resolve(Size::new(width, height));
layout::Node::new(size)
}
}