@effindomv2/fui-rs 0.1.18 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +1 -1
- package/package.json +1 -1
- package/src/color.rs +112 -0
- package/src/controls/shared.rs +2 -5
- package/src/controls/tests.rs +17 -0
- package/src/lib.rs +3 -0
- package/src/node/core.rs +20 -0
- package/src/theme.rs +6 -46
package/Cargo.toml
CHANGED
package/package.json
CHANGED
package/src/color.rs
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
pub const fn rgba(red: u32, green: u32, blue: u32, alpha: u32) -> u32 {
|
|
2
|
+
((red & 0xff) << 24) | ((green & 0xff) << 16) | ((blue & 0xff) << 8) | (alpha & 0xff)
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
pub const fn rgb(red: u32, green: u32, blue: u32) -> u32 {
|
|
6
|
+
rgba(red, green, blue, 0xff)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
pub const fn with_alpha(color: u32, alpha: u32) -> u32 {
|
|
10
|
+
(color & 0xffff_ff00) | (alpha & 0xff)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
pub(crate) fn color_red(color: u32) -> u32 {
|
|
14
|
+
(color >> 24) & 0xff
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
pub(crate) fn color_green(color: u32) -> u32 {
|
|
18
|
+
(color >> 16) & 0xff
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
pub(crate) fn color_blue(color: u32) -> u32 {
|
|
22
|
+
(color >> 8) & 0xff
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
pub(crate) fn color_alpha(color: u32) -> u32 {
|
|
26
|
+
color & 0xff
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
fn clamp_unit(value: f32) -> f32 {
|
|
30
|
+
value.clamp(0.0, 1.0)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
fn hue_to_rgb(p: f32, q: f32, mut t: f32) -> f32 {
|
|
34
|
+
if t < 0.0 {
|
|
35
|
+
t += 1.0;
|
|
36
|
+
}
|
|
37
|
+
if t > 1.0 {
|
|
38
|
+
t -= 1.0;
|
|
39
|
+
}
|
|
40
|
+
if t < 1.0 / 6.0 {
|
|
41
|
+
return p + (q - p) * 6.0 * t;
|
|
42
|
+
}
|
|
43
|
+
if t < 0.5 {
|
|
44
|
+
return q;
|
|
45
|
+
}
|
|
46
|
+
if t < 2.0 / 3.0 {
|
|
47
|
+
return p + (q - p) * ((2.0 / 3.0) - t) * 6.0;
|
|
48
|
+
}
|
|
49
|
+
p
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
pub fn hsl_to_color(hue: f32, saturation: f32, lightness: f32) -> u32 {
|
|
53
|
+
let normalized_hue = hue % 360.0;
|
|
54
|
+
let hue = if normalized_hue < 0.0 {
|
|
55
|
+
normalized_hue + 360.0
|
|
56
|
+
} else {
|
|
57
|
+
normalized_hue
|
|
58
|
+
};
|
|
59
|
+
let saturation = clamp_unit(saturation);
|
|
60
|
+
let lightness = clamp_unit(lightness);
|
|
61
|
+
if saturation <= 0.0 {
|
|
62
|
+
let channel = (lightness * 255.0) as u32;
|
|
63
|
+
return rgb(channel, channel, channel);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let hue_fraction = hue / 360.0;
|
|
67
|
+
let q = if lightness < 0.5 {
|
|
68
|
+
lightness * (1.0 + saturation)
|
|
69
|
+
} else {
|
|
70
|
+
lightness + saturation - (lightness * saturation)
|
|
71
|
+
};
|
|
72
|
+
let p = 2.0 * lightness - q;
|
|
73
|
+
rgba(
|
|
74
|
+
(clamp_unit(hue_to_rgb(p, q, hue_fraction + 1.0 / 3.0)) * 255.0) as u32,
|
|
75
|
+
(clamp_unit(hue_to_rgb(p, q, hue_fraction)) * 255.0) as u32,
|
|
76
|
+
(clamp_unit(hue_to_rgb(p, q, hue_fraction - 1.0 / 3.0)) * 255.0) as u32,
|
|
77
|
+
0xff,
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
fn mix_channel(from: u32, to: u32, amount: f32) -> u32 {
|
|
82
|
+
let weight = clamp_unit(amount);
|
|
83
|
+
(from as f32 + ((to as f32 - from as f32) * weight)).round() as u32
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
pub fn mix_color(from: u32, to: u32, amount: f32) -> u32 {
|
|
87
|
+
rgba(
|
|
88
|
+
mix_channel(color_red(from), color_red(to), amount),
|
|
89
|
+
mix_channel(color_green(from), color_green(to), amount),
|
|
90
|
+
mix_channel(color_blue(from), color_blue(to), amount),
|
|
91
|
+
mix_channel(color_alpha(from), color_alpha(to), amount),
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
#[cfg(test)]
|
|
96
|
+
mod tests {
|
|
97
|
+
use super::*;
|
|
98
|
+
|
|
99
|
+
#[test]
|
|
100
|
+
fn color_helpers_match_effindom_rgba_packing() {
|
|
101
|
+
assert_eq!(rgb(0x12, 0x34, 0x56), 0x123456ff);
|
|
102
|
+
assert_eq!(rgba(0x12, 0x34, 0x56, 0x78), 0x12345678);
|
|
103
|
+
assert_eq!(with_alpha(0x123456ff, 0x78), 0x12345678);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
#[test]
|
|
107
|
+
fn color_helpers_mask_channels_and_interpolate() {
|
|
108
|
+
assert_eq!(rgba(0x112, 0x134, 0x156, 0x178), 0x12345678);
|
|
109
|
+
assert_eq!(mix_color(rgb(0, 0, 0), rgb(255, 255, 255), 0.5), rgba(128, 128, 128, 255));
|
|
110
|
+
assert_eq!(hsl_to_color(0.0, 1.0, 0.5), rgb(255, 0, 0));
|
|
111
|
+
}
|
|
112
|
+
}
|
package/src/controls/shared.rs
CHANGED
|
@@ -59,10 +59,7 @@ pub(crate) fn update_semantic_checked(
|
|
|
59
59
|
state: SemanticCheckedState,
|
|
60
60
|
announce: bool,
|
|
61
61
|
) {
|
|
62
|
-
if let Some(
|
|
63
|
-
|
|
64
|
-
if announce {
|
|
65
|
-
ui::request_semantic_announcement(handle.raw());
|
|
66
|
-
}
|
|
62
|
+
if let Some(root) = weak_root.upgrade() {
|
|
63
|
+
root.set_semantic_checked(state, announce);
|
|
67
64
|
}
|
|
68
65
|
}
|
package/src/controls/tests.rs
CHANGED
|
@@ -2927,6 +2927,23 @@ fn checkbox_user_activation_emits_changed_and_semantic_announcement() {
|
|
|
2927
2927
|
Application::unmount();
|
|
2928
2928
|
}
|
|
2929
2929
|
|
|
2930
|
+
#[test]
|
|
2931
|
+
fn checkbox_prebuild_state_is_retained_into_semantic_build_state() {
|
|
2932
|
+
ffi::test::reset();
|
|
2933
|
+
let checkbox = checkbox("Agree");
|
|
2934
|
+
checkbox.check(true);
|
|
2935
|
+
|
|
2936
|
+
Application::mount(checkbox.clone());
|
|
2937
|
+
let handle = checkbox.retained_node_ref().handle().raw();
|
|
2938
|
+
let calls = ffi::test::take_calls();
|
|
2939
|
+
assert!(calls.iter().any(|call| matches!(
|
|
2940
|
+
call,
|
|
2941
|
+
Call::SetSemanticChecked { handle: checked_handle, checked_state_enum }
|
|
2942
|
+
if *checked_handle == handle && *checked_state_enum == SemanticCheckedState::True as u32
|
|
2943
|
+
)));
|
|
2944
|
+
Application::unmount();
|
|
2945
|
+
}
|
|
2946
|
+
|
|
2930
2947
|
#[test]
|
|
2931
2948
|
fn radio_and_switch_programmatic_changes_emit_without_semantic_announcement() {
|
|
2932
2949
|
ffi::test::reset();
|
package/src/lib.rs
CHANGED
|
@@ -4,6 +4,7 @@ pub mod assets;
|
|
|
4
4
|
#[doc(hidden)]
|
|
5
5
|
pub mod bindings;
|
|
6
6
|
pub mod bitmap;
|
|
7
|
+
pub mod color;
|
|
7
8
|
#[doc(hidden)]
|
|
8
9
|
pub mod bridge_callbacks;
|
|
9
10
|
pub(crate) mod context_menu_manager;
|
|
@@ -408,6 +409,7 @@ pub mod prelude {
|
|
|
408
409
|
pub use crate::app::{Application, ApplicationRegistration, ManagedApplication};
|
|
409
410
|
pub use crate::bitmap::{Bitmap, BitmapTextReadyEventArgs};
|
|
410
411
|
pub use crate::bridge_callbacks::current_route;
|
|
412
|
+
pub use crate::color::{hsl_to_color, mix_color, rgb, rgba, with_alpha};
|
|
411
413
|
pub use crate::controls::{
|
|
412
414
|
anti_selection_area, button, checkbox, clear_control_templates, combo_box, context_menu,
|
|
413
415
|
create_default_button_presenter, create_default_checkbox_indicator_presenter,
|
|
@@ -534,6 +536,7 @@ pub use app::{Application, ApplicationRegistration, ManagedApplication};
|
|
|
534
536
|
pub use assets::*;
|
|
535
537
|
pub use bitmap::{Bitmap, BitmapTextReadyEventArgs};
|
|
536
538
|
pub use bridge_callbacks::current_route;
|
|
539
|
+
pub use color::{hsl_to_color, mix_color, rgb, rgba, with_alpha};
|
|
537
540
|
pub use controls::{
|
|
538
541
|
anti_selection_area, button, checkbox, clear_control_templates, combo_box, context_menu,
|
|
539
542
|
create_default_button_presenter, create_default_checkbox_indicator_presenter,
|
package/src/node/core.rs
CHANGED
|
@@ -513,6 +513,26 @@ impl NodeRef {
|
|
|
513
513
|
self.inner.borrow().handle
|
|
514
514
|
}
|
|
515
515
|
|
|
516
|
+
pub(crate) fn set_semantic_checked(
|
|
517
|
+
&self,
|
|
518
|
+
state: SemanticCheckedState,
|
|
519
|
+
announce: bool,
|
|
520
|
+
) {
|
|
521
|
+
let handle = {
|
|
522
|
+
let mut core = self.inner.borrow_mut();
|
|
523
|
+
core.behavior.semantic_checked = Some(state);
|
|
524
|
+
core.handle
|
|
525
|
+
};
|
|
526
|
+
if handle == NodeHandle::INVALID {
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
ui::set_semantic_checked(handle.raw(), state as u32);
|
|
530
|
+
if announce {
|
|
531
|
+
ui::request_semantic_announcement(handle.raw());
|
|
532
|
+
}
|
|
533
|
+
crate::frame_scheduler::mark_needs_commit();
|
|
534
|
+
}
|
|
535
|
+
|
|
516
536
|
pub(crate) fn ptr_eq(&self, other: &Self) -> bool {
|
|
517
537
|
Rc::ptr_eq(&self.inner, &other.inner)
|
|
518
538
|
}
|
package/src/theme.rs
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
use crate::generated::framework_host_services;
|
|
2
|
+
use crate::color::{
|
|
3
|
+
color_alpha, color_blue, color_green, color_red, mix_color, rgb, rgba, with_alpha,
|
|
4
|
+
};
|
|
2
5
|
use crate::signal::{Callback, Signal, SubscriptionGuard};
|
|
3
6
|
use crate::typography::{FontFamily, FontStack};
|
|
4
7
|
use std::cell::RefCell;
|
|
5
8
|
use std::rc::Rc;
|
|
6
9
|
|
|
7
|
-
const DEFAULT_ACCENT_COLOR: u32 =
|
|
8
|
-
const WHITE: u32 =
|
|
9
|
-
const BLACK: u32 =
|
|
10
|
+
const DEFAULT_ACCENT_COLOR: u32 = rgb(0x25, 0x63, 0xeb);
|
|
11
|
+
const WHITE: u32 = rgb(0xff, 0xff, 0xff);
|
|
12
|
+
const BLACK: u32 = rgb(0x00, 0x00, 0x00);
|
|
10
13
|
|
|
11
14
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
12
15
|
pub struct Colors {
|
|
@@ -166,49 +169,6 @@ fn default_fonts() -> Fonts {
|
|
|
166
169
|
}
|
|
167
170
|
}
|
|
168
171
|
|
|
169
|
-
const fn rgba(r: u32, g: u32, b: u32, a: u32) -> u32 {
|
|
170
|
-
(r << 24) | (g << 16) | (b << 8) | a
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
fn color_red(color: u32) -> u32 {
|
|
174
|
-
(color >> 24) & 0xff
|
|
175
|
-
}
|
|
176
|
-
fn color_green(color: u32) -> u32 {
|
|
177
|
-
(color >> 16) & 0xff
|
|
178
|
-
}
|
|
179
|
-
fn color_blue(color: u32) -> u32 {
|
|
180
|
-
(color >> 8) & 0xff
|
|
181
|
-
}
|
|
182
|
-
fn color_alpha(color: u32) -> u32 {
|
|
183
|
-
color & 0xff
|
|
184
|
-
}
|
|
185
|
-
fn clamp_unit(value: f32) -> f32 {
|
|
186
|
-
value.clamp(0.0, 1.0)
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
fn mix_channel(from: u32, to: u32, amount: f32) -> u32 {
|
|
190
|
-
let weight = clamp_unit(amount);
|
|
191
|
-
(from as f32 + ((to as f32 - from as f32) * weight)).round() as u32
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
fn mix_color(from: u32, to: u32, amount: f32) -> u32 {
|
|
195
|
-
rgba(
|
|
196
|
-
mix_channel(color_red(from), color_red(to), amount),
|
|
197
|
-
mix_channel(color_green(from), color_green(to), amount),
|
|
198
|
-
mix_channel(color_blue(from), color_blue(to), amount),
|
|
199
|
-
mix_channel(color_alpha(from), color_alpha(to), amount),
|
|
200
|
-
)
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
fn with_alpha(color: u32, alpha: u32) -> u32 {
|
|
204
|
-
rgba(
|
|
205
|
-
color_red(color),
|
|
206
|
-
color_green(color),
|
|
207
|
-
color_blue(color),
|
|
208
|
-
alpha,
|
|
209
|
-
)
|
|
210
|
-
}
|
|
211
|
-
|
|
212
172
|
fn normalize_accent_color(color: u32) -> u32 {
|
|
213
173
|
if color == 0 {
|
|
214
174
|
return DEFAULT_ACCENT_COLOR;
|