use crate::core::{ObjectId, Orientation, PlatformFamily};
use crate::platform::state::{BackendState, WindowStateRecord};
use crate::platform::types::*;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) enum StubHandleKind {
Window,
}
pub struct StubPlatform {
backend: &'static str,
family: PlatformFamily,
state: BackendState<StubHandleKind>,
pub(crate) ime_bridge: crate::platform::ime::MockImeBridge,
}
impl StubPlatform {
pub fn new(backend: &'static str, family: PlatformFamily) -> Self {
Self {
backend,
family,
state: BackendState::new(),
ime_bridge: crate::platform::ime::MockImeBridge::new(),
}
}
pub fn register_widget(
&self,
widget_id: ObjectId,
text: &str,
x: i32,
y: i32,
width: u32,
height: u32,
) {
self.state.register_widget_with_id(
widget_id,
StubHandleKind::Window,
text,
x,
y,
width,
height,
);
}
pub fn widget_count(&self) -> usize {
self.state.widget_count()
}
}
pub(crate) fn stub_platform_singleton() -> &'static StubPlatform {
use crate::compat::OnceLock;
static HOST: OnceLock<StubPlatform> = OnceLock::new();
HOST.get_or_init(|| StubPlatform::new("portable", PlatformFamily::Embedded))
}
#[cfg(not(alloc_frugal))]
fn widget_is_checkable(widget_id: ObjectId) -> bool {
crate::widget::runtime::widget_is_checkable(widget_id)
}
#[cfg(alloc_frugal)]
fn widget_is_checkable(_widget_id: ObjectId) -> bool {
false
}
impl Platform for StubPlatform {
fn as_any(&self) -> &dyn core::any::Any {
self
}
fn backend_name(&self) -> &'static str {
self.backend
}
fn family(&self) -> PlatformFamily {
self.family
}
fn total_memory_mb(&self) -> Option<u64> {
None
}
fn is_on_battery(&self) -> bool {
false
}
fn process_memory_utilization(&self) -> Option<f32> {
None
}
fn process_cpu_utilization(&self) -> Option<f32> {
None
}
fn spawn_print_job(&self, _job_file: &std::path::Path) -> Result<(), String> {
Err("stub platform has no print spooler".to_string())
}
fn init(&self) {
log::info!("[stub] StubPlatform init (testing backend)");
}
fn run(&self) {
log::info!("[stub] StubPlatform run (testing backend)");
}
fn quit(&self) {
log::info!("[stub] StubPlatform quit");
}
fn destroy_widget(&self, widget_id: ObjectId) -> bool {
self.state.destroy_widget(widget_id)
}
fn create_window(&self, title: &str, x: i32, y: i32, width: u32, height: u32) -> ObjectId {
let id = self.state.create_widget(StubHandleKind::Window, title, x, y, width, height);
self.state.init_window_state(id, WindowStateRecord::new_window());
id
}
fn poll_menu_triggered(&self) -> Option<ObjectId> {
self.state.pop_menu_event()
}
fn inject_menu_trigger(&self, menu_item_id: ObjectId) -> bool {
if !self.state.contains_widget(menu_item_id) {
return false;
}
self.state.push_menu_event(menu_item_id);
true
}
fn poll_widget_triggered(&self) -> Option<ObjectId> {
self.poll_widget_trigger_event().map(|event| event.widget_id)
}
fn poll_widget_trigger_event(&self) -> Option<WidgetTriggerEvent> {
self.state.pop_widget_event()
}
fn inject_widget_trigger_event(&self, widget_id: ObjectId, kind: WidgetTriggerKind) -> bool {
if !self.state.contains_widget(widget_id) {
return false;
}
self.state.push_widget_event(WidgetTriggerEvent { widget_id, kind });
true
}
fn show_widget(&self, widget_id: ObjectId) {
self.state.set_visible(widget_id, true);
}
fn hide_widget(&self, widget_id: ObjectId) {
self.state.set_visible(widget_id, false);
}
fn set_widget_geometry(&self, widget_id: ObjectId, x: i32, y: i32, width: u32, height: u32) {
self.state.set_geometry(widget_id, x, y, width, height);
}
fn set_widget_text(&self, widget_id: ObjectId, text: &str) {
self.state.set_text(widget_id, text);
}
fn get_widget_text(&self, widget_id: ObjectId) -> String {
self.state.text(widget_id)
}
fn set_widget_enabled(&self, widget_id: ObjectId, enabled: bool) {
self.state.set_enabled(widget_id, enabled);
}
fn is_widget_enabled(&self, widget_id: ObjectId) -> bool {
self.state.enabled(widget_id)
}
fn set_widget_visible(&self, widget_id: ObjectId, visible: bool) {
self.state.set_visible(widget_id, visible);
}
fn is_widget_visible(&self, widget_id: ObjectId) -> bool {
self.state.visible(widget_id)
}
fn set_widget_value(&self, widget_id: ObjectId, value: f64) -> bool {
if !self.state.contains_widget(widget_id) {
return false;
}
self.state.set_value(widget_id, value)
}
fn widget_value(&self, widget_id: ObjectId) -> Option<f64> {
self.state.value(widget_id)
}
fn set_widget_range(&self, widget_id: ObjectId, min: f64, max: f64) -> bool {
if !self.state.contains_widget(widget_id) {
return false;
}
self.state.set_range(widget_id, min, max)
}
fn widget_range(&self, widget_id: ObjectId) -> Option<(f64, f64)> {
self.state.range(widget_id)
}
fn set_widget_selected_index(&self, widget_id: ObjectId, index: Option<usize>) -> bool {
if !self.state.contains_widget(widget_id) {
return false;
}
self.state.set_selected_index(widget_id, index)
}
fn widget_selected_index(&self, widget_id: ObjectId) -> Option<usize> {
self.state.selected_index(widget_id)
}
fn set_widget_checked(&self, widget_id: ObjectId, checked: bool) -> bool {
if !self.state.contains_widget(widget_id) {
return false;
}
self.state.set_checked(widget_id, checked)
}
fn is_widget_checked(&self, widget_id: ObjectId) -> Option<bool> {
self.state.checked(widget_id)
}
fn set_widget_step(&self, widget_id: ObjectId, step: f64) -> bool {
if !self.state.contains_widget(widget_id) {
return false;
}
self.state.set_step(widget_id, step)
}
fn widget_step(&self, widget_id: ObjectId) -> Option<f64> {
self.state.step(widget_id)
}
fn set_widget_indeterminate(&self, widget_id: ObjectId, indeterminate: bool) -> bool {
if !self.state.contains_widget(widget_id) {
return false;
}
self.state.set_indeterminate(widget_id, indeterminate)
}
fn is_widget_indeterminate(&self, widget_id: ObjectId) -> Option<bool> {
self.state.indeterminate(widget_id)
}
fn set_widget_read_only(&self, widget_id: ObjectId, read_only: bool) -> bool {
if !self.state.contains_widget(widget_id) {
return false;
}
self.state.set_read_only(widget_id, read_only)
}
fn is_widget_read_only(&self, widget_id: ObjectId) -> Option<bool> {
self.state.read_only(widget_id)
}
fn set_widget_max_length(&self, widget_id: ObjectId, max_length: u32) -> bool {
if !self.state.contains_widget(widget_id) {
return false;
}
self.state.set_max_length(widget_id, max_length)
}
fn widget_max_length(&self, widget_id: ObjectId) -> Option<u32> {
self.state.max_length(widget_id)
}
fn set_window_state(&self, widget_id: ObjectId, flag: WindowStateFlag, on: bool) -> bool {
self.state.set_window_state(widget_id, flag, on)
}
fn is_window_in_state(&self, widget_id: ObjectId, flag: WindowStateFlag) -> Option<bool> {
self.state.window_state(widget_id, flag)
}
fn set_window_min_size(&self, widget_id: ObjectId, width: u32, height: u32) -> bool {
self.state.set_window_min_size(widget_id, width, height)
}
fn window_min_size(&self, widget_id: ObjectId) -> Option<(u32, u32)> {
self.state.window_min_size(widget_id)
}
fn set_window_icon(&self, widget_id: ObjectId, path: &str) -> bool {
self.state.set_window_icon(widget_id, path)
}
fn window_icon(&self, widget_id: ObjectId) -> Option<String> {
self.state.window_icon(widget_id)
}
fn set_widget_selection(&self, widget_id: ObjectId, start: u32, end: u32) -> bool {
self.state.set_selection(widget_id, start, end)
}
fn widget_selection(&self, widget_id: ObjectId) -> Option<(u32, u32)> {
self.state.selection(widget_id)
}
fn set_widget_placeholder(&self, widget_id: ObjectId, text: &str) -> bool {
self.state.set_placeholder(widget_id, text)
}
fn widget_placeholder(&self, widget_id: ObjectId) -> Option<String> {
self.state.placeholder(widget_id)
}
fn set_widget_echo_mode(&self, widget_id: ObjectId, mode: EchoMode) -> bool {
self.state.set_echo_mode(widget_id, mode)
}
fn widget_echo_mode(&self, widget_id: ObjectId) -> Option<EchoMode> {
self.state.echo_mode(widget_id)
}
fn set_slider_orientation(&self, widget_id: ObjectId, orientation: Orientation) -> bool {
if !self.state.contains_widget(widget_id) {
return false;
}
self.state.set_orientation(widget_id, orientation)
}
fn slider_orientation(&self, widget_id: ObjectId) -> Option<Orientation> {
self.state.orientation(widget_id)
}
fn set_widget_tristate(&self, widget_id: ObjectId, enabled: bool) -> bool {
if !self.state.contains_widget(widget_id) {
return false;
}
if !widget_is_checkable(widget_id) {
return false;
}
self.state.set_tristate(widget_id, enabled)
}
fn is_widget_tristate(&self, widget_id: ObjectId) -> Option<bool> {
if !widget_is_checkable(widget_id) {
return None;
}
self.state.tristate(widget_id)
}
fn set_widget_group(&self, widget_id: ObjectId, group: &str) -> bool {
if !self.state.contains_widget(widget_id) {
return false;
}
self.state.set_group(widget_id, group)
}
fn widget_group(&self, widget_id: ObjectId) -> Option<String> {
self.state.group(widget_id)
}
fn set_widget_scroll_position(&self, widget_id: ObjectId, x: i32, y: i32) -> bool {
if !self.state.contains_widget(widget_id) {
return false;
}
self.state.set_scroll(widget_id, x, y)
}
fn widget_scroll_position(&self, widget_id: ObjectId) -> Option<(i32, i32)> {
self.state.scroll(widget_id)
}
fn set_widget_ime_enabled(&self, widget_id: ObjectId, enabled: bool) -> bool {
self.state.set_ime_enabled(widget_id, enabled)
}
fn is_widget_ime_enabled(&self, widget_id: ObjectId) -> bool {
self.state.ime_enabled(widget_id)
}
fn set_widget_accessibility_name(&self, widget_id: ObjectId, name: &str) -> bool {
self.state.set_accessibility_name(widget_id, name)
}
fn get_widget_accessibility_name(&self, widget_id: ObjectId) -> String {
self.state.accessibility_name(widget_id)
}
fn set_clipboard_text(&self, text: &str) -> bool {
self.state.set_clipboard_text(text)
}
fn get_clipboard_text(&self) -> String {
self.state.clipboard_text()
}
fn ime_bridge(&self) -> Option<&dyn crate::platform::ime::ImeBridge> {
Some(&self.ime_bridge)
}
fn begin_drag(&self, source_widget_id: ObjectId, mime: &str, payload: &[u8]) -> bool {
self.state.begin_drag(source_widget_id, mime, payload)
}
fn poll_drop_event(&self) -> Option<DropEvent> {
self.state.pop_drop_event()
}
fn inject_drop_event(&self, event: DropEvent) -> bool {
self.state.inject_drop_event(event)
}
}