use crate::*;
use rustler::{Atom, Encoder, Env, Term};
use std::time::Instant;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub(crate) struct EventModifiers {
pub control: bool,
pub alt: bool,
pub shift: bool,
pub platform: bool,
pub function: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct KeyEventPayload<'a> {
pub key: &'a str,
pub key_char: Option<&'a str>,
pub is_held: bool,
pub modifiers: EventModifiers,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct ActionEventPayload<'a> {
pub action: &'a str,
pub shortcut: &'a str,
pub key: &'a str,
pub key_char: Option<&'a str>,
pub modifiers: EventModifiers,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) struct ContextMenuEventPayload {
pub x: f64,
pub y: f64,
pub modifiers: EventModifiers,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) struct WindowBoundsEventPayload {
pub x: f64,
pub y: f64,
pub width: f64,
pub height: f64,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) struct DragMoveEventPayload<'a> {
pub source_id: &'a str,
pub pressed_button_code: i32,
pub x: f64,
pub y: f64,
pub modifiers: EventModifiers,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) struct MouseDownEventPayload {
pub button_code: i32,
pub x: f64,
pub y: f64,
pub click_count: u64,
pub modifiers: EventModifiers,
pub first_mouse: bool,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) struct MouseUpEventPayload {
pub button_code: i32,
pub x: f64,
pub y: f64,
pub click_count: u64,
pub modifiers: EventModifiers,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) struct MouseMoveEventPayload {
pub pressed_button_code: i32,
pub x: f64,
pub y: f64,
pub modifiers: EventModifiers,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) struct ScrollWheelEventPayload {
pub x: f64,
pub y: f64,
pub delta_kind_code: i32,
pub delta_x: f64,
pub delta_y: f64,
pub modifiers: EventModifiers,
}
pub(crate) fn send_app_activated_event() -> i32 {
#[cfg(test)]
record_basic_event_snapshot_for_test("app_activated", 0, None, None, None, None);
send_event(0, app_activated, |env| {
rustler::types::atom::undefined().encode(env)
})
}
pub(crate) fn send_app_deactivated_event() -> i32 {
#[cfg(test)]
record_basic_event_snapshot_for_test("app_deactivated", 0, None, None, None, None);
send_event(0, app_deactivated, |env| {
rustler::types::atom::undefined().encode(env)
})
}
pub(crate) fn send_window_close_requested_event(view_id: u64) -> i32 {
#[cfg(test)]
record_basic_event_snapshot_for_test("window_close_requested", view_id, None, None, None, None);
send_event(view_id, window_close_requested, |env| {
rustler::types::atom::undefined().encode(env)
})
}
pub(crate) fn send_window_closed_event(view_id: u64) -> i32 {
#[cfg(test)]
record_basic_event_snapshot_for_test("window_closed", view_id, None, None, None, None);
send_event(view_id, window_closed, |env| {
rustler::types::atom::undefined().encode(env)
})
}
pub(crate) fn send_window_focused_event(view_id: u64) -> i32 {
#[cfg(test)]
record_basic_event_snapshot_for_test("window_focused", view_id, None, None, None, None);
send_event(view_id, window_focused, |env| {
rustler::types::atom::undefined().encode(env)
})
}
pub(crate) fn send_window_blurred_event(view_id: u64) -> i32 {
#[cfg(test)]
record_basic_event_snapshot_for_test("window_blurred", view_id, None, None, None, None);
send_event(view_id, window_blurred, |env| {
rustler::types::atom::undefined().encode(env)
})
}
pub(crate) fn send_window_moved_event(view_id: u64, payload: WindowBoundsEventPayload) -> i32 {
#[cfg(test)]
record_basic_event_snapshot_for_test("window_moved", view_id, None, None, None, None);
send_event(view_id, window_moved, move |env| {
window_bounds_payload_map(env, payload)
})
}
pub(crate) fn send_window_resized_event(view_id: u64, payload: WindowBoundsEventPayload) -> i32 {
#[cfg(test)]
record_basic_event_snapshot_for_test("window_resized", view_id, None, None, None, None);
send_event(view_id, window_resized, move |env| {
window_bounds_payload_map(env, payload)
})
}
pub(crate) fn send_menu_action_event(action_id: &str, callback_id: &str) -> i32 {
#[cfg(test)]
{
record_menu_event_snapshot_for_test(action_id.to_owned(), callback_id.to_owned());
record_event_send(Instant::now(), false);
0
}
#[cfg(not(test))]
send_event(0, menu_action, move |env| {
base_payload_map(env, action_id, callback_id)
})
}
pub(crate) fn send_dock_menu_action_event(action_id: &str, callback_id: &str) -> i32 {
#[cfg(test)]
{
record_menu_event_snapshot_for_test(action_id.to_owned(), callback_id.to_owned());
record_event_send(Instant::now(), false);
0
}
#[cfg(not(test))]
send_event(0, dock_menu_action, move |env| {
base_payload_map(env, action_id, callback_id)
})
}
pub(crate) fn send_click_event(view_id: u64, node_id: &str, callback_id: &str) -> i32 {
#[cfg(test)]
record_basic_event_snapshot_for_test(
"click",
view_id,
Some(node_id.to_owned()),
Some(callback_id.to_owned()),
None,
None,
);
send_id_callback_event(view_id, click, node_id, callback_id)
}
pub(crate) fn send_close_event(view_id: u64, node_id: &str, callback_id: &str) -> i32 {
#[cfg(test)]
record_basic_event_snapshot_for_test(
"close",
view_id,
Some(node_id.to_owned()),
Some(callback_id.to_owned()),
None,
None,
);
send_id_callback_event(view_id, close, node_id, callback_id)
}
pub(crate) fn send_focus_event(view_id: u64, node_id: &str, callback_id: &str) -> i32 {
#[cfg(test)]
record_basic_event_snapshot_for_test(
"focus",
view_id,
Some(node_id.to_owned()),
Some(callback_id.to_owned()),
None,
None,
);
send_id_callback_event(view_id, focus, node_id, callback_id)
}
pub(crate) fn send_blur_event(view_id: u64, node_id: &str, callback_id: &str) -> i32 {
#[cfg(test)]
record_basic_event_snapshot_for_test(
"blur",
view_id,
Some(node_id.to_owned()),
Some(callback_id.to_owned()),
None,
None,
);
send_id_callback_event(view_id, blur, node_id, callback_id)
}
pub(crate) fn send_hover_event(
view_id: u64,
node_id: &str,
callback_id: &str,
hovered_value: bool,
) -> i32 {
send_event(view_id, hover, move |env| {
base_payload_with_one_map(
env,
node_id,
callback_id,
(hovered().encode(env), hovered_value.encode(env)),
)
})
}
pub(crate) fn send_change_event(
view_id: u64,
node_id: &str,
callback_id: &str,
value_string: &str,
) -> i32 {
#[cfg(test)]
record_basic_event_snapshot_for_test(
"change",
view_id,
Some(node_id.to_owned()),
Some(callback_id.to_owned()),
Some(value_string.to_owned()),
None,
);
send_event(view_id, change, move |env| {
base_payload_with_one_map(
env,
node_id,
callback_id,
(value().encode(env), value_string.encode(env)),
)
})
}
pub(crate) fn send_checkbox_change_event(
view_id: u64,
node_id: &str,
callback_id: &str,
checked_value: bool,
) -> i32 {
#[cfg(test)]
record_basic_event_snapshot_for_test(
"change",
view_id,
Some(node_id.to_owned()),
Some(callback_id.to_owned()),
None,
Some(checked_value),
);
send_event(view_id, change, move |env| {
base_payload_with_one_map(
env,
node_id,
callback_id,
(checked().encode(env), checked_value.encode(env)),
)
})
}
pub(crate) fn send_row_control_click_event(
view_id: u64,
node_id: &str,
callback_id: &str,
list_id_value: &str,
row_id_value: &str,
control_id_value: &str,
) -> i32 {
#[cfg(test)]
{
record_row_control_event_snapshot_for_test(
"click",
view_id,
node_id.to_owned(),
callback_id.to_owned(),
list_id_value.to_owned(),
row_id_value.to_owned(),
control_id_value.to_owned(),
None,
None,
);
record_event_send(Instant::now(), false);
0
}
#[cfg(not(test))]
send_event(view_id, click, move |env| {
row_control_payload_map(
env,
node_id,
callback_id,
list_id_value,
row_id_value,
control_id_value,
)
})
}
pub(crate) fn send_row_control_change_event(
view_id: u64,
node_id: &str,
callback_id: &str,
list_id_value: &str,
row_id_value: &str,
control_id_value: &str,
value_string: &str,
) -> i32 {
#[cfg(test)]
{
record_row_control_event_snapshot_for_test(
"change",
view_id,
node_id.to_owned(),
callback_id.to_owned(),
list_id_value.to_owned(),
row_id_value.to_owned(),
control_id_value.to_owned(),
Some(value_string.to_owned()),
None,
);
record_event_send(Instant::now(), false);
0
}
#[cfg(not(test))]
send_event(view_id, change, move |env| {
row_control_payload_with_one_map(
env,
node_id,
callback_id,
list_id_value,
row_id_value,
control_id_value,
(value().encode(env), value_string.encode(env)),
)
})
}
pub(crate) fn send_row_control_checkbox_change_event(
view_id: u64,
node_id: &str,
callback_id: &str,
list_id_value: &str,
row_id_value: &str,
control_id_value: &str,
checked_value: bool,
) -> i32 {
#[cfg(test)]
{
record_row_control_event_snapshot_for_test(
"change",
view_id,
node_id.to_owned(),
callback_id.to_owned(),
list_id_value.to_owned(),
row_id_value.to_owned(),
control_id_value.to_owned(),
None,
Some(checked_value),
);
record_event_send(Instant::now(), false);
0
}
#[cfg(not(test))]
send_event(view_id, change, move |env| {
row_control_payload_with_one_map(
env,
node_id,
callback_id,
list_id_value,
row_id_value,
control_id_value,
(checked().encode(env), checked_value.encode(env)),
)
})
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn send_data_table_event(
view_id: u64,
event_code: i32,
node_id: &str,
callback_id: &str,
table_id_value: &str,
row_id_value: Option<&str>,
column_id_value: Option<&str>,
) -> i32 {
let Some(event_name) = data_table_event_name(event_code) else {
return 0;
};
#[cfg(test)]
{
record_semantic_event_snapshot_for_test(
event_name,
view_id,
node_id.to_owned(),
callback_id.to_owned(),
Some(table_id_value.to_owned()),
row_id_value.map(str::to_owned),
column_id_value.map(str::to_owned),
None,
None,
None,
None,
None,
);
record_event_send(Instant::now(), false);
0
}
#[cfg(not(test))]
{
let _ = event_name;
send_event(
view_id,
|| data_table_event_atom(event_code),
move |env| {
data_table_payload_map(
env,
node_id,
callback_id,
table_id_value,
row_id_value,
column_id_value,
)
},
)
}
}
pub(crate) fn send_data_table_column_reorder_event(
view_id: u64,
node_id: &str,
callback_id: &str,
table_id_value: &str,
column_id_value: &str,
target_column_id_value: &str,
direction_value: &str,
) -> i32 {
#[cfg(test)]
{
record_semantic_event_snapshot_for_test(
"data_table_column_reorder",
view_id,
node_id.to_owned(),
callback_id.to_owned(),
Some(table_id_value.to_owned()),
None,
Some(column_id_value.to_owned()),
Some(target_column_id_value.to_owned()),
Some(direction_value.to_owned()),
None,
None,
None,
);
record_event_send(Instant::now(), false);
0
}
#[cfg(not(test))]
send_event(view_id, data_table_column_reorder, move |env| {
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(table_id().encode(env), table_id_value.encode(env)),
(column_id().encode(env), column_id_value.encode(env)),
(
target_column_id().encode(env),
target_column_id_value.encode(env),
),
(direction().encode(env), direction_value.encode(env)),
],
)
})
}
pub(crate) fn send_data_table_column_resize_event(
view_id: u64,
node_id: &str,
callback_id: &str,
table_id_value: &str,
column_id_value: &str,
width_delta_value: i32,
) -> i32 {
#[cfg(test)]
{
record_semantic_event_snapshot_for_test(
"data_table_column_resize",
view_id,
node_id.to_owned(),
callback_id.to_owned(),
Some(table_id_value.to_owned()),
None,
Some(column_id_value.to_owned()),
None,
None,
Some(width_delta_value),
None,
None,
);
record_event_send(Instant::now(), false);
0
}
#[cfg(not(test))]
send_event(view_id, data_table_column_resize, move |env| {
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(table_id().encode(env), table_id_value.encode(env)),
(column_id().encode(env), column_id_value.encode(env)),
(width_delta().encode(env), width_delta_value.encode(env)),
],
)
})
}
pub(crate) fn send_data_table_context_menu_event(
view_id: u64,
node_id: &str,
callback_id: &str,
table_id_value: &str,
row_id_value: &str,
column_id_value: Option<&str>,
payload: ContextMenuEventPayload,
) -> i32 {
#[cfg(test)]
{
let _ = payload;
record_semantic_event_snapshot_for_test(
"context_menu",
view_id,
node_id.to_owned(),
callback_id.to_owned(),
Some(table_id_value.to_owned()),
Some(row_id_value.to_owned()),
column_id_value.map(str::to_owned),
None,
None,
None,
None,
None,
);
record_event_send(Instant::now(), false);
0
}
#[cfg(not(test))]
send_event(view_id, context_menu, move |env| {
let column_id_term = optional_str_term(env, column_id_value);
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(table_id().encode(env), table_id_value.encode(env)),
(row_id().encode(env), row_id_value.encode(env)),
(column_id().encode(env), column_id_term),
(x().encode(env), payload.x.encode(env)),
(y().encode(env), payload.y.encode(env)),
modifiers_pair(env, payload.modifiers),
],
)
})
}
pub(crate) fn send_tree_context_menu_event(
view_id: u64,
node_id: &str,
callback_id: &str,
tree_id_value: &str,
item_id_value: &str,
payload: ContextMenuEventPayload,
) -> i32 {
#[cfg(test)]
{
let _ = payload;
record_semantic_event_snapshot_for_test(
"context_menu",
view_id,
node_id.to_owned(),
callback_id.to_owned(),
None,
None,
None,
None,
None,
None,
Some(tree_id_value.to_owned()),
Some(item_id_value.to_owned()),
);
record_event_send(Instant::now(), false);
0
}
#[cfg(not(test))]
send_event(view_id, context_menu, move |env| {
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(tree_id().encode(env), tree_id_value.encode(env)),
(item_id().encode(env), item_id_value.encode(env)),
(x().encode(env), payload.x.encode(env)),
(y().encode(env), payload.y.encode(env)),
modifiers_pair(env, payload.modifiers),
],
)
})
}
pub(crate) fn send_tree_event(
view_id: u64,
event_code: i32,
node_id: &str,
callback_id: &str,
tree_id_value: &str,
item_id_value: &str,
) -> i32 {
let Some(event_name) = tree_event_name(event_code) else {
return 0;
};
#[cfg(test)]
{
record_semantic_event_snapshot_for_test(
event_name,
view_id,
node_id.to_owned(),
callback_id.to_owned(),
None,
None,
None,
None,
None,
None,
Some(tree_id_value.to_owned()),
Some(item_id_value.to_owned()),
);
record_event_send(Instant::now(), false);
0
}
#[cfg(not(test))]
{
let _ = event_name;
send_event(
view_id,
|| tree_event_atom(event_code),
move |env| tree_payload_map(env, node_id, callback_id, tree_id_value, item_id_value),
)
}
}
pub(crate) fn send_key_down_event(
view_id: u64,
node_id: &str,
callback_id: &str,
payload: KeyEventPayload<'_>,
) -> i32 {
send_event(view_id, key_down, move |env| {
let key_char_term = optional_str_term(env, payload.key_char);
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(key().encode(env), payload.key.encode(env)),
(key_char().encode(env), key_char_term),
(is_held().encode(env), payload.is_held.encode(env)),
modifiers_pair(env, payload.modifiers),
],
)
})
}
pub(crate) fn send_key_up_event(
view_id: u64,
node_id: &str,
callback_id: &str,
payload: KeyEventPayload<'_>,
) -> i32 {
send_event(view_id, key_up, move |env| {
let key_char_term = optional_str_term(env, payload.key_char);
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(key().encode(env), payload.key.encode(env)),
(key_char().encode(env), key_char_term),
modifiers_pair(env, payload.modifiers),
],
)
})
}
pub(crate) fn send_action_event(
view_id: u64,
node_id: &str,
callback_id: &str,
payload: ActionEventPayload<'_>,
) -> i32 {
#[cfg(test)]
record_basic_event_snapshot_for_test(
"action",
view_id,
Some(node_id.to_owned()),
Some(callback_id.to_owned()),
Some(payload.action.to_owned()),
None,
);
send_event(view_id, action, move |env| {
let key_char_term = optional_str_term(env, payload.key_char);
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(action().encode(env), payload.action.encode(env)),
(shortcut().encode(env), payload.shortcut.encode(env)),
(key().encode(env), payload.key.encode(env)),
(key_char().encode(env), key_char_term),
modifiers_pair(env, payload.modifiers),
],
)
})
}
pub(crate) fn send_context_menu_event(
view_id: u64,
node_id: &str,
callback_id: &str,
payload: ContextMenuEventPayload,
) -> i32 {
#[cfg(test)]
record_basic_event_snapshot_for_test(
"context_menu",
view_id,
Some(node_id.to_owned()),
Some(callback_id.to_owned()),
None,
None,
);
send_event(view_id, context_menu, move |env| {
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(x().encode(env), payload.x.encode(env)),
(y().encode(env), payload.y.encode(env)),
modifiers_pair(env, payload.modifiers),
],
)
})
}
pub(crate) fn send_drag_start_event(
view_id: u64,
node_id: &str,
callback_id: &str,
source: &str,
) -> i32 {
source_event(view_id, drag_start, node_id, callback_id, source)
}
pub(crate) fn send_drop_event(view_id: u64, node_id: &str, callback_id: &str, source: &str) -> i32 {
source_event(view_id, drop, node_id, callback_id, source)
}
pub(crate) fn send_drag_move_event(
view_id: u64,
node_id: &str,
callback_id: &str,
payload: DragMoveEventPayload<'_>,
) -> i32 {
send_event(view_id, drag_move, move |env| {
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(source_id().encode(env), payload.source_id.encode(env)),
(
pressed_button().encode(env),
mouse_button_atom(payload.pressed_button_code).encode(env),
),
(x().encode(env), payload.x.encode(env)),
(y().encode(env), payload.y.encode(env)),
modifiers_pair(env, payload.modifiers),
],
)
})
}
pub(crate) fn send_mouse_down_event(
view_id: u64,
node_id: &str,
callback_id: &str,
payload: MouseDownEventPayload,
) -> i32 {
send_event(view_id, mouse_down, move |env| {
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(
button().encode(env),
mouse_button_atom(payload.button_code).encode(env),
),
(x().encode(env), payload.x.encode(env)),
(y().encode(env), payload.y.encode(env)),
(click_count().encode(env), payload.click_count.encode(env)),
(first_mouse().encode(env), payload.first_mouse.encode(env)),
modifiers_pair(env, payload.modifiers),
],
)
})
}
pub(crate) fn send_mouse_up_event(
view_id: u64,
node_id: &str,
callback_id: &str,
payload: MouseUpEventPayload,
) -> i32 {
send_event(view_id, mouse_up, move |env| {
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(
button().encode(env),
mouse_button_atom(payload.button_code).encode(env),
),
(x().encode(env), payload.x.encode(env)),
(y().encode(env), payload.y.encode(env)),
(click_count().encode(env), payload.click_count.encode(env)),
modifiers_pair(env, payload.modifiers),
],
)
})
}
pub(crate) fn send_mouse_move_event(
view_id: u64,
node_id: &str,
callback_id: &str,
payload: MouseMoveEventPayload,
) -> i32 {
send_event(view_id, mouse_move, move |env| {
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(
pressed_button().encode(env),
mouse_button_atom(payload.pressed_button_code).encode(env),
),
(x().encode(env), payload.x.encode(env)),
(y().encode(env), payload.y.encode(env)),
modifiers_pair(env, payload.modifiers),
],
)
})
}
pub(crate) fn send_scroll_wheel_event(
view_id: u64,
node_id: &str,
callback_id: &str,
payload: ScrollWheelEventPayload,
) -> i32 {
send_event(view_id, scroll_wheel, move |env| {
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(x().encode(env), payload.x.encode(env)),
(y().encode(env), payload.y.encode(env)),
(
delta_kind().encode(env),
if payload.delta_kind_code == 1 {
pixels()
} else {
lines()
}
.encode(env),
),
(delta_x().encode(env), payload.delta_x.encode(env)),
(delta_y().encode(env), payload.delta_y.encode(env)),
modifiers_pair(env, payload.modifiers),
],
)
})
}
fn window_bounds_payload_map<'a>(env: Env<'a>, payload: WindowBoundsEventPayload) -> Term<'a> {
map_from_pairs(
env,
[
(x().encode(env), payload.x.encode(env)),
(y().encode(env), payload.y.encode(env)),
(width().encode(env), payload.width.encode(env)),
(height().encode(env), payload.height.encode(env)),
],
)
}
fn send_event(
view_id: u64,
event: impl FnOnce() -> Atom,
payload: impl for<'a> FnOnce(Env<'a>) -> Term<'a>,
) -> i32 {
let started_at = Instant::now();
#[cfg(test)]
{
let _ = (view_id, event, payload);
record_event_send(started_at, false);
0
}
#[cfg(not(test))]
{
let target = {
let Ok(target) = EVENT_TARGET.lock() else {
record_event_send(started_at, false);
return 0;
};
target.as_ref().map(|target| target.pid)
};
let Some(target) = target else {
record_event_send(started_at, false);
return 0;
};
let mut msg_env = rustler::OwnedEnv::new();
match msg_env.send_and_clear(&target, |env| {
(guppy_native_event(), view_id, event(), payload(env)).encode(env)
}) {
Ok(()) => {
record_event_send(started_at, true);
1
}
Err(_) => {
record_event_send(started_at, false);
0
}
}
}
}
fn optional_str_term<'a>(env: Env<'a>, value: Option<&str>) -> Term<'a> {
value.map_or_else(|| nil().encode(env), |value| value.encode(env))
}
#[cfg_attr(test, allow(dead_code))]
fn base_payload_map<'a>(env: Env<'a>, node_id: &str, callback_id: &str) -> Term<'a> {
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
],
)
}
#[cfg_attr(test, allow(dead_code))]
fn base_payload_with_one_map<'a>(
env: Env<'a>,
node_id: &str,
callback_id: &str,
extra: (Term<'a>, Term<'a>),
) -> Term<'a> {
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
extra,
],
)
}
#[cfg_attr(test, allow(dead_code))]
fn row_control_payload_map<'a>(
env: Env<'a>,
node_id: &str,
callback_id: &str,
list_id_value: &str,
row_id_value: &str,
control_id_value: &str,
) -> Term<'a> {
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(list_id().encode(env), list_id_value.encode(env)),
(row_id().encode(env), row_id_value.encode(env)),
(control_id().encode(env), control_id_value.encode(env)),
],
)
}
#[cfg_attr(test, allow(dead_code))]
fn row_control_payload_with_one_map<'a>(
env: Env<'a>,
node_id: &str,
callback_id: &str,
list_id_value: &str,
row_id_value: &str,
control_id_value: &str,
extra: (Term<'a>, Term<'a>),
) -> Term<'a> {
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(list_id().encode(env), list_id_value.encode(env)),
(row_id().encode(env), row_id_value.encode(env)),
(control_id().encode(env), control_id_value.encode(env)),
extra,
],
)
}
#[cfg_attr(test, allow(dead_code))]
fn data_table_payload_map<'a>(
env: Env<'a>,
node_id: &str,
callback_id: &str,
table_id_value: &str,
row_id_value: Option<&str>,
column_id_value: Option<&str>,
) -> Term<'a> {
match (row_id_value, column_id_value) {
(Some(row_id_value), Some(column_id_value)) => map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(table_id().encode(env), table_id_value.encode(env)),
(row_id().encode(env), row_id_value.encode(env)),
(column_id().encode(env), column_id_value.encode(env)),
],
),
(Some(row_id_value), None) => map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(table_id().encode(env), table_id_value.encode(env)),
(row_id().encode(env), row_id_value.encode(env)),
],
),
(None, Some(column_id_value)) => map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(table_id().encode(env), table_id_value.encode(env)),
(column_id().encode(env), column_id_value.encode(env)),
],
),
(None, None) => map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(table_id().encode(env), table_id_value.encode(env)),
],
),
}
}
#[cfg_attr(test, allow(dead_code))]
fn tree_payload_map<'a>(
env: Env<'a>,
node_id: &str,
callback_id: &str,
tree_id_value: &str,
item_id_value: &str,
) -> Term<'a> {
map_from_pairs(
env,
[
(id().encode(env), node_id.encode(env)),
(callback().encode(env), callback_id.encode(env)),
(tree_id().encode(env), tree_id_value.encode(env)),
(item_id().encode(env), item_id_value.encode(env)),
],
)
}
fn modifiers_payload<'a>(env: Env<'a>, modifiers_value: EventModifiers) -> Term<'a> {
map_from_pairs(
env,
[
(control().encode(env), modifiers_value.control.encode(env)),
(alt().encode(env), modifiers_value.alt.encode(env)),
(shift().encode(env), modifiers_value.shift.encode(env)),
(platform().encode(env), modifiers_value.platform.encode(env)),
(function().encode(env), modifiers_value.function.encode(env)),
],
)
}
fn modifiers_pair<'a>(env: Env<'a>, modifiers_value: EventModifiers) -> (Term<'a>, Term<'a>) {
(
modifiers().encode(env),
modifiers_payload(env, modifiers_value),
)
}
fn mouse_button_atom(code: i32) -> Atom {
match code {
1 => left(),
2 => right(),
3 => middle(),
4 => navigate_back(),
5 => navigate_forward(),
_ => nil(),
}
}
fn send_id_callback_event(
view_id: u64,
event: impl FnOnce() -> Atom,
node_id: &str,
callback_id: &str,
) -> i32 {
send_event(view_id, event, move |env| {
base_payload_map(env, node_id, callback_id)
})
}
fn source_event(
view_id: u64,
event: impl FnOnce() -> Atom,
node_id: &str,
callback_id: &str,
source: &str,
) -> i32 {
send_event(view_id, event, move |env| {
base_payload_with_one_map(
env,
node_id,
callback_id,
(source_id().encode(env), source.encode(env)),
)
})
}
fn data_table_event_name(code: i32) -> Option<&'static str> {
match code {
1 => Some("data_table_row_click"),
2 => Some("data_table_cell_click"),
3 => Some("data_table_sort"),
_ => None,
}
}
#[cfg(not(test))]
fn data_table_event_atom(code: i32) -> Atom {
match code {
1 => data_table_row_click(),
2 => data_table_cell_click(),
3 => data_table_sort(),
_ => nil(),
}
}
fn tree_event_name(code: i32) -> Option<&'static str> {
match code {
1 => Some("tree_select"),
2 => Some("tree_toggle"),
_ => None,
}
}
#[cfg(not(test))]
fn tree_event_atom(code: i32) -> Atom {
match code {
1 => tree_select(),
2 => tree_toggle(),
_ => nil(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn basic_event_snapshots_cover_click_change_and_window_lifecycle_payloads() {
let _ = send_click_event(7, "button", "clicked");
let click = crate::take_basic_event_snapshot_matching_for_test("click", 7).unwrap();
assert_eq!(click.event, "click");
assert_eq!(click.view_id, 7);
assert_eq!(click.node_id.as_deref(), Some("button"));
assert_eq!(click.callback_id.as_deref(), Some("clicked"));
assert_eq!(click.value, None);
assert_eq!(click.checked, None);
let _ = send_checkbox_change_event(8, "done", "toggle_done", true);
let checkbox = crate::take_basic_event_snapshot_matching_for_test("change", 8).unwrap();
assert_eq!(checkbox.event, "change");
assert_eq!(checkbox.view_id, 8);
assert_eq!(checkbox.node_id.as_deref(), Some("done"));
assert_eq!(checkbox.callback_id.as_deref(), Some("toggle_done"));
assert_eq!(checkbox.checked, Some(true));
let _ = send_change_event(9, "name", "name_changed", "Jason");
let change = crate::take_basic_event_snapshot_matching_for_test("change", 9).unwrap();
assert_eq!(change.event, "change");
assert_eq!(change.view_id, 9);
assert_eq!(change.node_id.as_deref(), Some("name"));
assert_eq!(change.callback_id.as_deref(), Some("name_changed"));
assert_eq!(change.value.as_deref(), Some("Jason"));
assert_eq!(change.checked, None);
let _ = send_app_activated_event();
let app_activated =
crate::take_basic_event_snapshot_matching_for_test("app_activated", 0).unwrap();
assert_eq!(app_activated.event, "app_activated");
assert_eq!(app_activated.view_id, 0);
let _ = send_window_close_requested_event(10);
let requested =
crate::take_basic_event_snapshot_matching_for_test("window_close_requested", 10)
.unwrap();
assert_eq!(requested.event, "window_close_requested");
assert_eq!(requested.view_id, 10);
assert_eq!(requested.node_id, None);
assert_eq!(requested.callback_id, None);
let _ = send_window_closed_event(11);
let closed =
crate::take_basic_event_snapshot_matching_for_test("window_closed", 11).unwrap();
assert_eq!(closed.event, "window_closed");
assert_eq!(closed.view_id, 11);
assert_eq!(closed.node_id, None);
assert_eq!(closed.callback_id, None);
let _ = send_window_resized_event(
12,
WindowBoundsEventPayload {
x: 1.0,
y: 2.0,
width: 640.0,
height: 480.0,
},
);
let resized =
crate::take_basic_event_snapshot_matching_for_test("window_resized", 12).unwrap();
assert_eq!(resized.event, "window_resized");
assert_eq!(resized.view_id, 12);
}
}