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::ui::{OptionsPageInternalMessage, OptionsPageLoadArgs, PageHandle};
14
15pub use winio;
16
17pub mod prelude {
18 pub use super::{super::OptionsPageMessage, OptionsPageInit};
19 pub use crate::PluginApp;
20 pub use winio::prelude::*;
21}
22use prelude::*;
23
24pub trait OptionsPageComponent<'a>:
25 Component<
26 Init<'a> = OptionsPageInit<'a, Self::App>,
27 Message: From<OptionsPageMessage<Self::App>>,
28 > + 'static
29{
30 type App: PluginApp;
31}
32
33impl<'a, T, A: PluginApp> OptionsPageComponent<'a> for T
34where
35 T: Component<Init<'a> = OptionsPageInit<'a, A>, Message: From<OptionsPageMessage<A>>> + 'static,
36{
37 type App = A;
38}
39
40pub fn spawn<'a, T: OptionsPageComponent<'a>>(args: OptionsPageLoadArgs) -> PageHandle<T::App> {
41 let parent: usize = unsafe { mem::transmute(args.parent) };
43
44 let (tx, rx) = mpsc::unbounded();
45 let thread_handle = std::thread::spawn(move || {
46 let parent: HWND = unsafe { mem::transmute(parent) };
47 run::<T>(OptionsPageInit {
48 parent: unsafe { BorrowedWindow::borrow_raw(RawWindow::Win32(parent)) }.into(),
49 rx: Some(rx),
50 });
51 });
53 PageHandle { thread_handle, tx }
54}
55
56pub fn run<'a, T: OptionsPageComponent<'a>>(init: OptionsPageInit<'a, T::App>) -> T::Event {
57 App::new("").run::<T>(init)
60}
61
62pub struct OptionsPageInit<'a, A: PluginApp> {
63 parent: Option<BorrowedWindow<'a>>,
65
66 rx: Option<mpsc::UnboundedReceiver<OptionsPageInternalMessage<A>>>,
70}
71
72impl<'a, A: PluginApp> From<()> for OptionsPageInit<'a, A> {
73 fn from(_: ()) -> Self {
74 Self {
75 parent: None,
76 rx: None,
77 }
78 }
79}
80
81impl<'a, A: PluginApp> OptionsPageInit<'a, A> {
82 pub fn window<T: OptionsPageComponent<'a, App = A>>(
84 &mut self,
85 sender: &ComponentSender<T>,
86 ) -> Child<Window> {
87 let mut window = Child::<Window>::init(self.parent.clone());
88 self.init(&mut window, sender);
89 window
90 }
91
92 pub fn init<T: OptionsPageComponent<'a, App = A>>(
94 &mut self,
95 window: &mut Window,
96 sender: &ComponentSender<T>,
97 ) {
98 adjust_window(window);
100
101 if let Some(mut rx) = self.rx.take() {
102 let window = window.as_raw_window();
103 let sender = sender.clone();
104 winio::compio::runtime::spawn(async move {
105 while let Some(m) = rx.next().await {
108 if let Some(m) = m.try_into(window.as_win32()) {
109 debug!(?m, "Options page message");
110 sender.post(m.into());
111 }
112 }
113 debug!("Options page message channel closed");
114 })
115 .detach();
116 }
117 }
118}
119
120pub fn adjust_window(window: &mut Window) {
124 window.set_style(window.style() & !WS_OVERLAPPEDWINDOW);
127
128 window.set_loc(Point::new(0.0, 0.0));
134}