|
|
@@ -34,7 +34,7 @@ use crate::{
|
|
|
prop::{PropertyAtomicGuard, PropertyFloat32, Role},
|
|
|
scene::{SceneNodePtr, Slot},
|
|
|
text,
|
|
|
- theme::wire_color,
|
|
|
+ theme::{wire_color, wire_shape},
|
|
|
ui::{Button, Layer, RedrawTrigger, Shortcut, Text, VectorArt, VectorShape},
|
|
|
util::i18n::I18nBabelFish,
|
|
|
};
|
|
|
@@ -189,19 +189,10 @@ pub async fn create_title(
|
|
|
prop.set_default_expr(2, expr::load_var("w")).unwrap();
|
|
|
prop.set_default_f32(3, (TITLE_PADDING * 2. + TITLE_FONTSIZE) / 2.).unwrap();
|
|
|
bg_node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
|
|
|
- let mut shape = VectorShape::new();
|
|
|
- shape.add_smooth_vertical_gradient(
|
|
|
- expr::const_f32(0.),
|
|
|
- expr::const_f32(0.),
|
|
|
- expr::load_var("w"),
|
|
|
- expr::load_var("h"),
|
|
|
- [0., 0.9059, 0.9216, 0.20],
|
|
|
- [0., 0.8784, 1., 0.],
|
|
|
- 8,
|
|
|
- 0.2,
|
|
|
- );
|
|
|
- let prop = bg_node.get_property("shape").unwrap();
|
|
|
- prop.set_default_shape(0, shape).unwrap();
|
|
|
+ // Class wiring: the bg follows the shared title token, so themes
|
|
|
+ // restyle every title by writing the token once.
|
|
|
+ let theme = app.sg_root.lookup_node("/theme").unwrap();
|
|
|
+ wire_shape(&bg_node, "shape", &theme, "wallet.title_shape").unwrap();
|
|
|
let bg_node = bg_node
|
|
|
.setup(|me| VectorArt::new(me, app.renderer.clone(), app.redraw_trigger.clone()))
|
|
|
.await;
|
|
|
@@ -323,10 +314,6 @@ pub async fn create_separator_expr(
|
|
|
y_expr: &str,
|
|
|
dimmed: bool,
|
|
|
) -> SceneNodePtr {
|
|
|
- let color = match dimmed {
|
|
|
- true => [0.1333, 0.1725, 0.1725, 1.],
|
|
|
- false => [0.2, 0.2745, 0.2784, 1.],
|
|
|
- };
|
|
|
let sep_node = create_vector_art(name);
|
|
|
let prop = sep_node.get_property("rect").unwrap();
|
|
|
prop.set_default_f32(0, 0.).unwrap();
|
|
|
@@ -335,16 +322,11 @@ pub async fn create_separator_expr(
|
|
|
prop.set_default_expr(2, expr::load_var("w")).unwrap();
|
|
|
prop.set_default_f32(3, 1.).unwrap();
|
|
|
sep_node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
|
|
|
- let mut shape = VectorShape::new();
|
|
|
- shape.add_filled_box(
|
|
|
- expr::const_f32(0.),
|
|
|
- expr::const_f32(0.),
|
|
|
- expr::load_var("w"),
|
|
|
- expr::const_f32(1.),
|
|
|
- color,
|
|
|
- );
|
|
|
- let prop = sep_node.get_property("shape").unwrap();
|
|
|
- prop.set_default_shape(0, shape).unwrap();
|
|
|
+ // Class wiring: the shape follows the shared separator token, so
|
|
|
+ // themes restyle every separator by writing the token once.
|
|
|
+ let theme = app.sg_root.lookup_node("/theme").unwrap();
|
|
|
+ let token = if dimmed { "separator_dim_shape" } else { "separator_shape" };
|
|
|
+ wire_shape(&sep_node, "shape", &theme, token).unwrap();
|
|
|
let sep_node = sep_node
|
|
|
.setup(|me| VectorArt::new(me, app.renderer.clone(), app.redraw_trigger.clone()))
|
|
|
.await;
|
|
|
@@ -362,10 +344,6 @@ pub async fn create_separator(
|
|
|
y: &mut f32,
|
|
|
dimmed: bool,
|
|
|
) -> SceneNodePtr {
|
|
|
- let color = match dimmed {
|
|
|
- true => [0.1333, 0.1725, 0.1725, 1.],
|
|
|
- false => [0.2, 0.2745, 0.2784, 1.],
|
|
|
- };
|
|
|
let sep_node = create_vector_art(name);
|
|
|
let prop = sep_node.get_property("rect").unwrap();
|
|
|
prop.set_default_f32(0, 0.).unwrap();
|
|
|
@@ -373,16 +351,10 @@ pub async fn create_separator(
|
|
|
prop.set_default_expr(2, expr::load_var("w")).unwrap();
|
|
|
prop.set_default_f32(3, 1.).unwrap();
|
|
|
sep_node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
|
|
|
- let mut shape = VectorShape::new();
|
|
|
- shape.add_filled_box(
|
|
|
- expr::const_f32(0.),
|
|
|
- expr::const_f32(0.),
|
|
|
- expr::load_var("w"),
|
|
|
- expr::const_f32(1.),
|
|
|
- color,
|
|
|
- );
|
|
|
- let prop = sep_node.get_property("shape").unwrap();
|
|
|
- prop.set_default_shape(0, shape).unwrap();
|
|
|
+ // Class wiring: see `create_separator_expr`.
|
|
|
+ let theme = app.sg_root.lookup_node("/theme").unwrap();
|
|
|
+ let token = if dimmed { "separator_dim_shape" } else { "separator_shape" };
|
|
|
+ wire_shape(&sep_node, "shape", &theme, token).unwrap();
|
|
|
let sep_node = sep_node
|
|
|
.setup(|me| VectorArt::new(me, app.renderer.clone(), app.redraw_trigger.clone()))
|
|
|
.await;
|
|
|
@@ -430,17 +402,9 @@ pub async fn create_bottom_button(
|
|
|
prop.set_default_expr(3, expr::load_var("h")).unwrap();
|
|
|
node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
|
|
|
node.set_property_bool(atom, Role::App, "is_visible", true).unwrap();
|
|
|
- let mut shape = VectorShape::new();
|
|
|
- shape.add_outline(
|
|
|
- expr::const_f32(0.),
|
|
|
- expr::const_f32(0.),
|
|
|
- expr::load_var("w"),
|
|
|
- expr::load_var("h"),
|
|
|
- 1.,
|
|
|
- COLOR_TEAL,
|
|
|
- );
|
|
|
- let prop = node.get_property("shape").unwrap();
|
|
|
- prop.set_default_shape(0, shape).unwrap();
|
|
|
+ // Class wiring: see `create_bottom_button_state`.
|
|
|
+ let theme = app.sg_root.lookup_node("/theme").unwrap();
|
|
|
+ wire_shape(&node, "shape", &theme, "wallet.btn_shape").unwrap();
|
|
|
let node =
|
|
|
node.setup(|me| VectorArt::new(me, app.renderer.clone(), app.redraw_trigger.clone())).await;
|
|
|
btn_layer.link(node);
|
|
|
@@ -492,9 +456,9 @@ pub async fn create_bottom_button(
|
|
|
}
|
|
|
|
|
|
/// Creates a bottom button with two states: valid (teal, active) and
|
|
|
-/// invalid (grey, inactive). Each state is a self-contained layer, so
|
|
|
+/// invalid (inactive). Each state is a self-contained layer, so
|
|
|
/// switching state is just an `is_visible` toggle on the two layers.
|
|
|
-/// Returns (button_node, valid_layer, grey_layer).
|
|
|
+/// Returns (button_node, valid_layer, inactive_layer).
|
|
|
pub async fn create_bottom_button_with_states(
|
|
|
app: &App,
|
|
|
atom: &mut PropertyAtomicGuard,
|
|
|
@@ -502,7 +466,7 @@ pub async fn create_bottom_button_with_states(
|
|
|
name: &str,
|
|
|
cc: &mut Compiler,
|
|
|
label_valid: &str,
|
|
|
- label_grey: &str,
|
|
|
+ label_inactive: &str,
|
|
|
window_scale: &PropertyFloat32,
|
|
|
i18n_fish: &I18nBabelFish,
|
|
|
initial_valid: bool,
|
|
|
@@ -516,34 +480,32 @@ pub async fn create_bottom_button_with_states(
|
|
|
label_valid,
|
|
|
window_scale,
|
|
|
i18n_fish,
|
|
|
- COLOR_TEAL,
|
|
|
COLOR_CYAN,
|
|
|
true,
|
|
|
initial_valid,
|
|
|
"",
|
|
|
)
|
|
|
.await;
|
|
|
- let grey_layer = create_bottom_button_state(
|
|
|
+ let inactive_layer = create_bottom_button_state(
|
|
|
app,
|
|
|
atom,
|
|
|
layer,
|
|
|
name,
|
|
|
cc,
|
|
|
- label_grey,
|
|
|
+ label_inactive,
|
|
|
window_scale,
|
|
|
i18n_fish,
|
|
|
[0.5, 0.5, 0.5, 1.],
|
|
|
- [0.5, 0.5, 0.5, 1.],
|
|
|
false,
|
|
|
!initial_valid,
|
|
|
- "_grey",
|
|
|
+ "_inactive",
|
|
|
)
|
|
|
.await;
|
|
|
|
|
|
let btn = btn_layer
|
|
|
.lookup_node(&format!("/{name}"))
|
|
|
.unwrap_or_else(|| panic!("bottom button node missing: {name}"));
|
|
|
- (btn, btn_layer, grey_layer)
|
|
|
+ (btn, btn_layer, inactive_layer)
|
|
|
}
|
|
|
|
|
|
/// One state of a bottom button, wrapped in its own layer so callers can
|
|
|
@@ -559,7 +521,6 @@ async fn create_bottom_button_state(
|
|
|
label_text: &str,
|
|
|
window_scale: &PropertyFloat32,
|
|
|
i18n_fish: &I18nBabelFish,
|
|
|
- outline_color: Color,
|
|
|
label_color: Color,
|
|
|
is_active: bool,
|
|
|
is_visible: bool,
|
|
|
@@ -589,17 +550,12 @@ async fn create_bottom_button_state(
|
|
|
prop.set_default_expr(2, expr::load_var("w")).unwrap();
|
|
|
prop.set_default_expr(3, expr::load_var("h")).unwrap();
|
|
|
node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
|
|
|
- let mut shape = VectorShape::new();
|
|
|
- shape.add_outline(
|
|
|
- expr::const_f32(0.),
|
|
|
- expr::const_f32(0.),
|
|
|
- expr::load_var("w"),
|
|
|
- expr::load_var("h"),
|
|
|
- 1.,
|
|
|
- outline_color,
|
|
|
- );
|
|
|
- let prop = node.get_property("shape").unwrap();
|
|
|
- prop.set_default_shape(0, shape).unwrap();
|
|
|
+ // Class wiring: the outline follows the shared button token, active
|
|
|
+ // and inactive states on separate tokens (state switch is a layer
|
|
|
+ // visibility toggle, so each state's bg stays on its own token).
|
|
|
+ let theme = app.sg_root.lookup_node("/theme").unwrap();
|
|
|
+ let token = if is_active { "wallet.btn_shape" } else { "wallet.btn_inactive_shape" };
|
|
|
+ wire_shape(&node, "shape", &theme, token).unwrap();
|
|
|
let node =
|
|
|
node.setup(|me| VectorArt::new(me, app.renderer.clone(), app.redraw_trigger.clone())).await;
|
|
|
btn_layer.link(node);
|
|
|
@@ -704,17 +660,9 @@ pub async fn create_tooltip(
|
|
|
let code = cc.compile("TOOLTIP_HEIGHT").unwrap();
|
|
|
prop.set_default_expr(3, code).unwrap();
|
|
|
|
|
|
- let mut shape = VectorShape::new();
|
|
|
- shape.add_outline(
|
|
|
- expr::const_f32(0.),
|
|
|
- expr::const_f32(0.),
|
|
|
- expr::const_f32(width),
|
|
|
- expr::const_f32(height),
|
|
|
- 1.,
|
|
|
- text_color,
|
|
|
- );
|
|
|
- let prop = node.get_property("shape").unwrap();
|
|
|
- prop.set_default_shape(0, shape).unwrap();
|
|
|
+ // Class wiring: same button-outline class as the other buttons.
|
|
|
+ let theme = app.sg_root.lookup_node("/theme").unwrap();
|
|
|
+ wire_shape(&node, "shape", &theme, "wallet.btn_shape").unwrap();
|
|
|
let node =
|
|
|
node.setup(|me| VectorArt::new(me, app.renderer.clone(), app.redraw_trigger.clone())).await;
|
|
|
tooltip_layer.link(node);
|