Skip to content
This repository was archived by the owner on Jun 5, 2024. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ keywords = ["gui", "graphics", "interface", "widgets", "floem-themes"]

[dependencies]
embed-doc-image = "0.1.4"
floem = "0.1.1"
floem = { git = "https://github.com/lapce/floem", rev = "1c417d0ef87122f5baaf493db7db4351dba5d403" }
im = "15.1.0"
num = "0.4.1"
strum = { version = "0.25.0", features = ["derive"] }
Expand Down
2 changes: 1 addition & 1 deletion examples/counter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ edition = "2021"

[dependencies]
floem-ui-kit = { path = "../.." }
floem = "0.1.1"
floem = { git = "https://github.com/lapce/floem", rev = "1c417d0ef87122f5baaf493db7db4351dba5d403" }
2 changes: 1 addition & 1 deletion examples/showcase/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ edition = "2021"

[dependencies]
floem-ui-kit = { path = "../.." }
floem = "0.1.1"
floem = { git = "https://github.com/lapce/floem", rev = "1c417d0ef87122f5baaf493db7db4351dba5d403" }
strum = { version = "0.25.0", features = ["derive"] }
4 changes: 2 additions & 2 deletions examples/showcase/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn app_view() -> impl View {
theme.padded_container(
v_stack((
theme
.labeled_checkbox(inputs_enabled, || "Enable all inputs")
.labeled_checkbox(move || inputs_enabled.get(), || "Enable all inputs")
.on_click_stop(move |_| {
set_inputs_enabled.set(!inputs_enabled.get());
}),
Expand Down Expand Up @@ -79,7 +79,7 @@ fn app_view() -> impl View {
.integer_input(rw_counter, 1, Some(-2), Some(9000))
.disabled(move || !inputs_enabled.get()),
theme
.labeled_checkbox(boolean_signal, || "Ordinary checkbox")
.labeled_checkbox(move || boolean_signal.get(), || "Ordinary checkbox")
.on_click_stop(move |_| {
set_boolean_signal.set(!boolean_signal.get());
})
Expand Down
177 changes: 72 additions & 105 deletions src/checkbox.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
use std::fmt::Display;

use floem::{
event::EventListener,
peniko::Color,
reactive::{create_signal, ReadSignal},
style::AlignItems,
view::View,
views::{container, h_stack, label, svg, Decorators},
views::{create_value_container_signals, Decorators, ValueContainer},
widgets::{labeled_checkbox as floem_labeled_checkbox, CheckboxClass, LabeledCheckboxClass},
};

use crate::{
Expand All @@ -15,113 +12,83 @@ use crate::{
};

impl Theme {
fn checkbox_symbol(self, read_signal: ReadSignal<bool>) -> impl View {
const CHECKED_SVG: &str = r#"
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<g transform="matrix(0.925671,0,0,0.925671,2.36266,1.94611)">
<path d="M5.19,11.83L0.18,7.44L1.82,5.56L4.81,8.17L10,1.25L12,2.75L5.19,11.83Z" style="fill:white;fill-rule:nonzero;"/>
</g>
</svg>
"#;
let svg_str = move || if read_signal.get() { CHECKED_SVG } else { "" }.to_string();
svg(svg_str)
}

/// Instantiates a checkbox widget controlling a boolean with a text label next to it.
pub fn labeled_checkbox<S: Display + 'static>(
self,
read_signal: ReadSignal<bool>,
label_render_func: impl Fn() -> S + 'static,
) -> impl View {
let (is_hovering, set_is_hovering) = create_signal(false);
let (is_focused, set_is_focused) = create_signal(false);
checked: impl Fn() -> bool + Clone + 'static,
label: impl Fn() -> S + 'static,
) -> ValueContainer<bool> {
let (inbound_signal, _) = create_value_container_signals(checked.clone());

container(
h_stack((
self.checkbox_symbol(read_signal).style(move |s| {
let accent_color = self.accent_color.get();
floem_labeled_checkbox(checked, label).style(move |s| {
s.class(CheckboxClass, |s| {
let accent_color = self.accent_color.get();
let is_selected = inbound_signal.get();

let is_selected = read_signal.get();
let unhovered_bg_color = match is_selected {
true => {
accent_color.primary_fill_color(PrimaryFillColorVariant::DefaultColored)
}
false => accent_color
.primary_fill_color(PrimaryFillColorVariant::DefaultGrayscale),
};
let unhovered_border_color = match is_selected {
true => accent_color.border_color(BorderColorVariant::DefaultColored),
false => accent_color.border_color(BorderColorVariant::DefaultGrayscale),
};
let hovered_bg_color = match is_selected {
true => accent_color.primary_fill_color(PrimaryFillColorVariant::Hovered),
false => Color::BLACK.with_alpha_factor(0.1),
};
let hovered_border_color = match is_selected {
true => accent_color.border_color(BorderColorVariant::HoveredColored),
false => accent_color.border_color(BorderColorVariant::HoveredGrayscale),
};
let unhovered_bg_color = match is_selected {
true => {
accent_color.primary_fill_color(PrimaryFillColorVariant::DefaultColored)
}
false => {
accent_color.primary_fill_color(PrimaryFillColorVariant::DefaultGrayscale)
}
};
let unhovered_border_color = match is_selected {
true => accent_color.border_color(BorderColorVariant::DefaultColored),
false => accent_color.border_color(BorderColorVariant::DefaultGrayscale),
};
let hovered_bg_color = match is_selected {
true => accent_color.primary_fill_color(PrimaryFillColorVariant::Hovered),
false => Color::BLACK.with_alpha_factor(0.1),
};
let hovered_border_color = match is_selected {
true => accent_color.border_color(BorderColorVariant::HoveredColored),
false => accent_color.border_color(BorderColorVariant::HoveredGrayscale),
};

s.background(unhovered_bg_color)
.padding(12.0)
.border(1.0)
.border_color(unhovered_border_color)
.border_radius(5.0)
.disabled(|s| {
s.background(
self.accent_color
.get()
.primary_fill_color(PrimaryFillColorVariant::Disabled),
)
.border_color(
self.accent_color
.get()
.border_color(BorderColorVariant::Disabled),
)
})
.apply_if(is_hovering.get(), |s| {
s.background(hovered_bg_color)
.border_color(hovered_border_color)
})
.apply_if(is_focused.get(), |s| match is_selected {
true => s.border_color(
self.accent_color
.get()
.border_color(BorderColorVariant::FocusedColored),
),
false => s.border_color(
self.accent_color
.get()
.border_color(BorderColorVariant::FocusedGrayscale),
),
})
}),
label(label_render_func).style(move |s| {
s.disabled(|s| s.color(self.accent_color.get().disabled_text_color()))
}),
))
.keyboard_navigatable()
.style(|s| {
s.align_items(AlignItems::Center)
.border_radius(5.0)
.focus_visible(|s| {
s.outline(2.0)
.outline_color(Color::WHITE.with_alpha_factor(0.5))
})
.gap(10.0, 0.0)
})
.on_event_stop(EventListener::PointerEnter, move |_| {
set_is_hovering.set(true);
})
.on_event_stop(EventListener::PointerLeave, move |_| {
set_is_hovering.set(false);
s.active(|s| {
s.background(accent_color.primary_fill_color(PrimaryFillColorVariant::Pressed))
})
.background(unhovered_bg_color)
.color(Color::WHITE)
.padding(12.0)
.border(1.0)
.border_color(unhovered_border_color)
.border_radius(5.0)
.disabled(|s| {
s.background(
self.accent_color
.get()
.primary_fill_color(PrimaryFillColorVariant::Disabled),
)
.border_color(
self.accent_color
.get()
.border_color(BorderColorVariant::Disabled),
)
})
.focus(|s| match is_selected {
true => s.border_color(
self.accent_color
.get()
.border_color(BorderColorVariant::FocusedColored),
),
false => s.border_color(
self.accent_color
.get()
.border_color(BorderColorVariant::FocusedGrayscale),
),
})
.hover(|s| {
s.background(hovered_bg_color)
.border_color(hovered_border_color)
})
})
.on_event_stop(EventListener::FocusGained, move |_| {
set_is_focused.set(true);
.class(LabeledCheckboxClass, |s| {
s.focus(|s| s.hover(|s| s.background(Color::TRANSPARENT)))
.hover(|s| s.background(Color::TRANSPARENT))
.padding(0)
})
.on_event_stop(EventListener::FocusLost, move |_| {
set_is_focused.set(false);
}),
)
})
}
}