use futures_channel::mpsc;
use futures_util::StreamExt;
use tracing::debug;
use windows_sys::Win32::{Foundation::HWND, UI::WindowsAndMessaging::WS_OVERLAPPEDWINDOW};
use crate::ui::{OptionsPageInternalMessage, OptionsPageLoadArgs, PageHandle};
pub use winio;
pub mod prelude {
pub use super::{super::OptionsPageMessage, OptionsPageInit};
pub use crate::PluginApp;
pub use winio::{Error, elm::*, handle::*, layout::*, primitive::*, ui::*, widgets::*};
}
use prelude::*;
pub trait OptionsPageComponent<'a>:
Component<
Init<'a> = OptionsPageInit<'a, Self::App>,
Message: From<OptionsPageMessage<Self::App>>,
> + 'static
{
type App: PluginApp;
}
impl<'a, T, A: PluginApp> OptionsPageComponent<'a> for T
where
T: Component<Init<'a> = OptionsPageInit<'a, A>, Message: From<OptionsPageMessage<A>>> + 'static,
{
type App = A;
}
pub fn spawn<'a, T: OptionsPageComponent<'a>>(args: OptionsPageLoadArgs) -> PageHandle<T::App> {
let parent: usize = args.parent as usize;
let (tx, rx) = mpsc::unbounded();
let thread_handle = std::thread::spawn(move || {
let parent: HWND = parent as HWND;
run::<T>(OptionsPageInit {
parent: unsafe { BorrowedContainer::win32(parent) },
rx: Some(rx),
})
.ok();
});
PageHandle { thread_handle, tx }
}
pub fn run<'a, T: OptionsPageComponent<'a>>(
init: OptionsPageInit<'a, T::App>,
) -> Result<T::Event, T::Error> {
App::new("").unwrap().run::<T>(init)
}
pub struct OptionsPageInit<'a, A: PluginApp> {
parent: BorrowedContainer<'a>,
rx: Option<mpsc::UnboundedReceiver<OptionsPageInternalMessage<A>>>,
}
impl<'a, A: PluginApp> From<()> for OptionsPageInit<'a, A> {
fn from(_: ()) -> Self {
Self {
parent: unsafe { BorrowedContainer::win32(Default::default()) },
rx: None,
}
}
}
impl<'a, A: PluginApp> OptionsPageInit<'a, A> {
pub async fn window<T: OptionsPageComponent<'a, App = A>>(
&mut self,
sender: &ComponentSender<T>,
) -> Result<Child<View>, Error> {
let mut window = Child::<View>::init(self.parent.clone()).await?;
self.init(&mut window, sender);
Ok(window)
}
pub fn init<T: OptionsPageComponent<'a, App = A>>(
&mut self,
window: &mut View,
sender: &ComponentSender<T>,
) {
if let Some(mut rx) = self.rx.take() {
let window = window.as_container().as_win32();
let sender = sender.clone();
winio::compio::runtime::spawn(async move {
while let Some(m) = rx.next().await {
if let Some(m) = m.try_into(window) {
debug!(?m, "Options page message");
sender.post(m.into());
}
}
debug!("Options page message channel closed");
})
.detach();
}
}
}
#[allow(unused_must_use)]
pub fn adjust_window(window: &mut Window) {
window.set_style(window.style().unwrap() & !WS_OVERLAPPEDWINDOW);
window.set_loc(Point::new(0.0, 0.0));
}