Skip to main content

siglus_scene_vm/runtime/
native_ui.rs

1//! Platform UI bridge for runtime modal operations.
2//!
3//! The VM must not synchronously block on platform UI. Mobile ports should show
4//! the native dialog on the platform UI thread, then deliver the selected button
5//! back through `CommandContext::submit_native_messagebox_result` from the main
6//! engine loop or an event-loop callback.
7
8use std::collections::VecDeque;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum NativeMessageBoxKind {
12    Ok,
13    OkCancel,
14    YesNo,
15    YesNoCancel,
16}
17
18impl NativeMessageBoxKind {
19    pub fn from_system_op(op: i32) -> Self {
20        match op {
21            18 | 8 => Self::OkCancel,
22            19 | 9 => Self::YesNo,
23            20 | 10 => Self::YesNoCancel,
24            _ => Self::Ok,
25        }
26    }
27}
28
29#[derive(Debug, Clone)]
30pub struct NativeMessageBoxButton {
31    pub label: String,
32    pub value: i64,
33}
34
35#[derive(Debug, Clone)]
36pub struct NativeChihayaBenchDialogRequest {
37    pub request_id: u64,
38    pub title: String,
39    pub text: String,
40}
41
42#[derive(Debug, Clone)]
43pub struct NativeMessageBoxRequest {
44    pub request_id: u64,
45    pub kind: NativeMessageBoxKind,
46    pub title: String,
47    pub message: String,
48    pub buttons: Vec<NativeMessageBoxButton>,
49    pub debug_only: bool,
50}
51
52pub trait NativeUiBackend: Send + Sync {
53    fn show_system_messagebox(&self, request: NativeMessageBoxRequest);
54
55    /// Original `tnm_open_chihaya_bench_dialog()` is a blocking information
56    /// dialog with a read-only multi-line body, Copy-to-Clipboard, and Close.
57    /// Platforms without a dedicated implementation still preserve the modal
58    /// call boundary by falling back to an OK-style native message box.
59    fn show_chihaya_bench_dialog(&self, request: NativeChihayaBenchDialogRequest) {
60        self.show_system_messagebox(NativeMessageBoxRequest {
61            request_id: request.request_id,
62            kind: NativeMessageBoxKind::Ok,
63            title: request.title,
64            message: request.text,
65            buttons: vec![NativeMessageBoxButton {
66                label: "CLOSE".to_string(),
67                value: 0,
68            }],
69            debug_only: false,
70        });
71    }
72}
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75pub struct NativeMessageBoxResult {
76    pub request_id: u64,
77    pub value: i64,
78}
79
80#[derive(Debug, Clone)]
81pub struct NativeUiRuntime {
82    next_messagebox_request_id: u64,
83    messagebox_results: VecDeque<NativeMessageBoxResult>,
84}
85
86impl Default for NativeUiRuntime {
87    fn default() -> Self {
88        Self {
89            next_messagebox_request_id: 1,
90            messagebox_results: VecDeque::new(),
91        }
92    }
93}
94
95impl NativeUiRuntime {
96    pub fn next_messagebox_request_id(&mut self) -> u64 {
97        let id = self.next_messagebox_request_id;
98        self.next_messagebox_request_id = self.next_messagebox_request_id.wrapping_add(1).max(1);
99        id
100    }
101
102    pub fn enqueue_messagebox_result(&mut self, request_id: u64, value: i64) {
103        self.messagebox_results
104            .push_back(NativeMessageBoxResult { request_id, value });
105    }
106
107    pub fn pop_messagebox_result(&mut self) -> Option<NativeMessageBoxResult> {
108        self.messagebox_results.pop_front()
109    }
110}