use crate::compat::String;
use crate::json::EventHandlerContext;
use crate::WidgetTriggerEvent;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum JsonEventBinding {
Published {
name: &'static str,
marker: Option<JsonTriggerMarker>,
},
Marker {
key: &'static str,
marker: JsonTriggerMarker,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum JsonTriggerMarker {
Clicked,
DoubleClicked,
FocusGained,
FocusLost,
ValueChanged,
SelectionChanged,
Closed,
}
impl JsonTriggerMarker {
pub fn trigger_kind(self) -> crate::platform::WidgetTriggerKind {
use crate::platform::WidgetTriggerKind;
match self {
Self::Clicked | Self::DoubleClicked => WidgetTriggerKind::Clicked,
Self::FocusGained | Self::FocusLost | Self::ValueChanged => {
WidgetTriggerKind::ValueChanged
}
Self::SelectionChanged => WidgetTriggerKind::SelectionChanged,
Self::Closed => WidgetTriggerKind::Closed,
}
}
}
pub const MARKER_KEYS: &[(&str, JsonTriggerMarker)] = &[
("on_click", JsonTriggerMarker::Clicked),
("on_change", JsonTriggerMarker::ValueChanged),
("on_close", JsonTriggerMarker::Closed),
("on_double_click", JsonTriggerMarker::DoubleClicked),
("on_focus", JsonTriggerMarker::FocusGained),
("on_blur", JsonTriggerMarker::FocusLost),
("on_selection_changed", JsonTriggerMarker::SelectionChanged),
("on_value_changed", JsonTriggerMarker::ValueChanged),
];
pub const EVENTS_KEY: &str = "events";
pub fn marker_key_names() -> impl Iterator<Item = &'static str> {
MARKER_KEYS.iter().map(|(key, _)| *key)
}
pub fn is_marker_key(key: &str) -> bool {
MARKER_KEYS.iter().any(|(candidate, _)| *candidate == key)
}
pub fn marker_for_key(key: &str) -> Option<JsonTriggerMarker> {
MARKER_KEYS.iter().find(|(candidate, _)| *candidate == key).map(|(_, marker)| *marker)
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DeclaredHandler {
pub handler: String,
pub marker: JsonTriggerMarker,
}
pub fn context_for(
widget_id: crate::core::ObjectId,
marker: JsonTriggerMarker,
) -> EventHandlerContext {
EventHandlerContext::new(WidgetTriggerEvent { widget_id, kind: marker.trigger_kind() })
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_marker_key_resolves_to_its_marker() {
for (key, marker) in MARKER_KEYS {
assert_eq!(marker_for_key(key), Some(*marker), "`{key}` must resolve to its marker");
assert!(is_marker_key(key));
}
assert_eq!(marker_for_key("on_click"), Some(JsonTriggerMarker::Clicked));
assert_eq!(marker_for_key("on_close"), Some(JsonTriggerMarker::Closed));
}
#[test]
fn a_non_event_key_is_not_a_marker_key() {
for key in ["text", "width", "on_", "clicked", "events"] {
assert!(!is_marker_key(key), "`{key}` is not an `on_*` event key");
assert_eq!(marker_for_key(key), None);
}
}
#[test]
fn the_marker_key_list_has_no_duplicates() {
let mut keys: Vec<&str> = marker_key_names().collect();
let count = keys.len();
keys.sort_unstable();
keys.dedup();
assert_eq!(keys.len(), count, "a duplicated key would be extracted twice");
}
#[test]
fn markers_report_distinct_trigger_kinds() {
assert_ne!(
JsonTriggerMarker::SelectionChanged.trigger_kind(),
JsonTriggerMarker::ValueChanged.trigger_kind()
);
}
#[test]
fn markers_that_share_a_callback_share_their_kind() {
assert_eq!(
JsonTriggerMarker::DoubleClicked.trigger_kind(),
JsonTriggerMarker::Clicked.trigger_kind()
);
assert_eq!(
JsonTriggerMarker::FocusGained.trigger_kind(),
JsonTriggerMarker::ValueChanged.trigger_kind()
);
assert_eq!(
JsonTriggerMarker::FocusLost.trigger_kind(),
JsonTriggerMarker::ValueChanged.trigger_kind()
);
}
}