everything_plugin/ui/
winio.rs1use std::mem;
7
8use futures_channel::mpsc;
9use futures_util::StreamExt;
10use tracing::debug;
11use windows_sys::Win32::{Foundation::HWND, UI::WindowsAndMessaging::WS_OVERLAPPEDWINDOW};
12
13use crate::{
14 PluginApp,
15 ui::{OptionsPageInternalMessage, OptionsPageLoadArgs, PageHandle},
16};
17
18pub use ::winio;
19
20pub mod prelude {
21 pub use super::{super::OptionsPageMessage, OptionsPageInit};
22 pub use crate::PluginApp;
23 pub use ::winio::prelude::*;
24}
25use prelude::*;
26
27pub trait OptionsPageComponent<'a>:
28 Component<
29 Init<'a> = OptionsPageInit<'a, Self::App>,
30 Message: From<OptionsPageMessage<Self::App>>,
31 > + 'static
32{
33 type App: PluginApp;
34}
35
36impl<'a, T, A: PluginApp> OptionsPageComponent<'a> for T
37where
38 T: Component<Init<'a> = OptionsPageInit<'a, A>, Message: From<OptionsPageMessage<A>>> + 'static,
39{
40 type App = A;
41}
42
43pub fn spawn<'a, T: OptionsPageComponent<'a>>(args: OptionsPageLoadArgs) -> PageHandle<T::App> {
44 let parent: usize = unsafe { mem::transmute(args.parent) };
46
47 let (tx, rx) = mpsc::unbounded();
48 let thread_handle = std::thread::spawn(move || {
49 let parent: HWND = unsafe { mem::transmute(parent) };
50 run::<T>(OptionsPageInit {
51 parent: unsafe { BorrowedWindow::borrow_raw(RawWindow::Win32(parent)) }.into(),
52 rx: Some(rx),
53 });
54 });
56 PageHandle { thread_handle, tx }
57}
58
59pub fn run<'a, T: OptionsPageComponent<'a>>(init: OptionsPageInit<'a, T::App>) -> T::Event {
60 App::new("").run::<T>(init)
63}
64
65pub struct OptionsPageInit<'a, A: PluginApp> {
66 parent: Option<BorrowedWindow<'a>>,
68
69 rx: Option<mpsc::UnboundedReceiver<OptionsPageInternalMessage<A>>>,
73}
74
75impl<'a, A: PluginApp> From<()> for OptionsPageInit<'a, A> {
76 fn from(_: ()) -> Self {
77 Self {
78 parent: None,
79 rx: None,
80 }
81 }
82}
83
84impl<'a, A: PluginApp> OptionsPageInit<'a, A> {
85 pub fn window<T: OptionsPageComponent<'a, App = A>>(
87 &mut self,
88 sender: &ComponentSender<T>,
89 ) -> Child<Window> {
90 let mut window = Child::<Window>::init(self.parent.clone());
91 self.init(&mut window, sender);
92 window
93 }
94
95 pub fn init<T: OptionsPageComponent<'a, App = A>>(
97 &mut self,
98 window: &mut Window,
99 sender: &ComponentSender<T>,
100 ) {
101 adjust_window(window);
103
104 if let Some(mut rx) = self.rx.take() {
105 let window = window.as_raw_window();
106 let sender = sender.clone();
107 winio::compio::runtime::spawn(async move {
108 while let Some(m) = rx.next().await {
111 if let Some(m) = m.try_into(window.as_win32()) {
112 debug!(?m, "Options page message");
113 sender.post(m.into());
114 }
115 }
116 debug!("Options page message channel closed");
117 })
118 .detach();
119 }
120 }
121}
122
123pub fn adjust_window(window: &mut Window) {
127 window.set_style(window.style() & !WS_OVERLAPPEDWINDOW);
130
131 window.set_loc(Point::new(0.0, 0.0));
137}