Skip to content

Commit 68dcbbc

Browse files
committed
Bind color editor fields through Rml data
1 parent ae92459 commit 68dcbbc

1 file changed

Lines changed: 64 additions & 17 deletions

File tree

‎native/src/sbc/panels/fields/color.rs‎

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use spring_native::prelude::{Error, NativeInterfaceRef};
1+
use spring_native::{
2+
prelude::{Error, NativeInterfaceRef},
3+
RmlDataModel, RmlDataVariable,
4+
};
25

36
use crate::sbc::panels::field::{
47
element_by_id, escape_rml, on_change, on_pointer, ChangeQueue, Field, FieldValue,
@@ -20,6 +23,8 @@ pub(crate) struct ColorField {
2023
channels: [ChannelElems; 3],
2124
expanded: bool,
2225
drag_channel: Option<usize>, // 0=R, 1=G, 2=B
26+
swatch_color: Option<RmlDataVariable<'static, String>>,
27+
channel_values: [Option<RmlDataVariable<'static, String>>; 3],
2328
}
2429

2530
struct ChannelElems {
@@ -52,6 +57,8 @@ impl ColorField {
5257
],
5358
expanded: false,
5459
drag_channel: None,
60+
swatch_color: None,
61+
channel_values: [None, None, None],
5562
tooltip: None,
5663
}
5764
}
@@ -111,26 +118,39 @@ impl ColorField {
111118

112119
// ── DOM sync helpers ──
113120

114-
fn button_rml(&self) -> String {
115-
format!(
116-
r#"<span class="field-button-title">{title}:</span><span class="field-swatch" style="background-color: {bg};"></span>"#,
117-
title = escape_rml(self.title.trim_end_matches(':')),
118-
bg = Self::to_css(self.value),
119-
)
121+
fn binding_name(&self, suffix: &str) -> String {
122+
let name = self
123+
.name
124+
.chars()
125+
.map(|character| {
126+
if character.is_ascii_alphanumeric() {
127+
character
128+
} else {
129+
'_'
130+
}
131+
})
132+
.collect::<String>();
133+
format!("field_{name}_{suffix}")
120134
}
121135

122136
fn sync_swatch(&self, interface: &NativeInterfaceRef) {
123-
if let Some(e) = self.swatch {
124-
let _ = interface
125-
.rml_ui()
126-
.element_set_inner_rml(e, &self.button_rml());
137+
if let Some(color) = &self.swatch_color {
138+
let _ = color.set(Self::to_css(self.value));
139+
} else if let Some(e) = self.swatch {
140+
let _ = interface.rml_ui().element_set_attribute(
141+
e,
142+
"style",
143+
&format!("background-color: {};", Self::to_css(self.value)),
144+
);
127145
}
128146
}
129147

130148
fn sync_channels(&self, interface: &NativeInterfaceRef) {
131149
for (i, ch) in self.channels.iter().enumerate() {
132150
let val = format!("{:.2}", self.value[i]);
133-
if let Some(e) = ch.display {
151+
if let Some(value) = &self.channel_values[i] {
152+
let _ = value.set(val.clone());
153+
} else if let Some(e) = ch.display {
134154
let _ = interface.rml_ui().element_set_inner_rml(e, &val);
135155
}
136156
if let Some(e) = ch.edit {
@@ -189,20 +209,36 @@ impl Field for ColorField {
189209
self.tooltip.as_deref()
190210
}
191211

212+
fn prepare_data_model(&mut self, model: &RmlDataModel<'static>) -> Result<(), Error> {
213+
self.swatch_color =
214+
Some(model.bind(&self.binding_name("swatch"), Self::to_css(self.value))?);
215+
for index in 0..3 {
216+
self.channel_values[index] = Some(model.bind(
217+
&self.binding_name(&format!("channel_{index}")),
218+
format!("{:.2}", self.value[index]),
219+
)?);
220+
}
221+
Ok(())
222+
}
223+
192224
fn generate_rml(&self) -> String {
193225
let hex = Self::to_hex(self.value);
194226
let n = &self.name;
195227
let channels: String = ['r', 'g', 'b']
196228
.iter()
197229
.enumerate()
198230
.map(|(i, &ch)| {
199-
let val = format!("{:.2}", self.value[i]);
231+
let display = self.channel_values[i]
232+
.as_ref()
233+
.map(|_| format!("{{{{ {} }}}}", self.binding_name(&format!("channel_{i}"))))
234+
.unwrap_or_else(|| format!("{:.2}", self.value[i]));
235+
let input_value = format!("{:.2}", self.value[i]);
200236
format!(
201237
r#"<div class="field-inline"><span class="field-label channel-label {ch}">{ch}</span>"#
202238
) + &format!(
203-
r#"<button id="field-{n}-{ch}-display" class="field-composite-button field-numeric-button color-channel">{val}</button>"#,
239+
r#"<button id="field-{n}-{ch}-display" class="field-composite-button field-numeric-button color-channel">{display}</button>"#,
204240
) + &format!(
205-
r#"<input type="text" id="field-{n}-{ch}-edit" class="field-input field-numeric-input color-channel hidden" value="{val}"/></div>"#,
241+
r#"<input type="text" id="field-{n}-{ch}-edit" class="field-input field-numeric-input color-channel hidden" value="{input_value}"/></div>"#,
206242
)
207243
})
208244
.collect();
@@ -212,8 +248,19 @@ impl Field for ColorField {
212248
// editor below it is native-only (Lua opens a picker dialog instead).
213249
r#"<div class="field-row"><div class="color-field">"#.to_string()
214250
+ &format!(
215-
r#"<button id="field-{n}-swatch" class="field-composite-button field-color-button">{button}</button>"#,
216-
button = self.button_rml(),
251+
r#"<button id="field-{n}-swatch" class="field-composite-button field-color-button"><span class="field-button-title">{title}:</span><span class="field-swatch" {style}></span></button>"#,
252+
title = escape_rml(self.title.trim_end_matches(':')),
253+
style = self
254+
.swatch_color
255+
.as_ref()
256+
.map(|_| format!(
257+
r#"data-style-background-color="{}""#,
258+
self.binding_name("swatch")
259+
))
260+
.unwrap_or_else(|| format!(
261+
r#"style="background-color: {};""#,
262+
Self::to_css(self.value)
263+
)),
217264
)
218265
+ &format!(r#"<div id="field-{n}-editor" class="color-editor hidden">"#,)
219266
+ &format!(

0 commit comments

Comments
 (0)