use dyn_clone::DynClone;
use iced::{
window::{self, Id},
Element, Task,
};
use std::{any::type_name, collections::HashMap};
#[allow(private_bounds)]
pub trait Window<App, Theme, Message, Renderer = iced::Renderer>:
Send + std::fmt::Debug + DynClone
{
fn view<'a>(&'a self, app: &'a App) -> iced::Element<'a, Message, Theme, Renderer>;
fn title(&self, app: &App) -> String;
fn theme(&self, app: &App) -> Theme;
fn settings(&self) -> window::Settings;
fn id(&self) -> String {
let data = format!("{:?}", self);
let data = if let Some(i) = data.find(" {") {
data[i..].to_string()
} else {
format!("::{}", data)
};
format!("{}{}", type_name::<Self>(), data)
}
fn class(&self) -> &'static str {
type_name::<Self>()
}
}
dyn_clone::clone_trait_object!(<App, Theme, Message, Renderer> Window<App, Theme, Message, Renderer>);
impl<App, Theme, Message, Renderer, T: Window<App, Theme, Message, Renderer>> PartialEq<T>
for Box<dyn Window<App, Theme, Message, Renderer>>
{
fn eq(&self, other: &T) -> bool {
self.id() == other.id()
}
}
impl<App, Theme, Message, Renderer> Window<App, Theme, Message, Renderer>
for Box<dyn Window<App, Theme, Message, Renderer>>
{
fn view<'a>(&'a self, app: &'a App) -> iced::Element<'a, Message, Theme, Renderer> {
self.as_ref().view(app)
}
fn title(&self, app: &App) -> String {
self.as_ref().title(app)
}
fn theme(&self, app: &App) -> Theme {
self.as_ref().theme(app)
}
fn settings(&self) -> window::Settings {
self.as_ref().settings()
}
fn id(&self) -> String {
self.as_ref().id()
}
fn class(&self) -> &'static str {
self.as_ref().class()
}
}
pub struct WindowManager<App, Theme, Message, Renderer = iced::Renderer> {
windows: HashMap<Id, Box<dyn Window<App, Theme, Message, Renderer>>>,
}
impl<App, Theme, Message, Renderer> WindowManager<App, Theme, Message, Renderer> {
fn get(&self, id: Id) -> &dyn Window<App, Theme, Message, Renderer> {
self.windows
.get(&id)
.expect("No window found with given Id")
.as_ref()
}
pub fn view<'a>(&'a self, app: &'a App, id: Id) -> Element<'a, Message, Theme, Renderer> {
self.get(id).view(app)
}
pub fn title(&self, app: &App, id: Id) -> String {
self.get(id).title(app)
}
pub fn theme(&self, app: &App, id: Id) -> Theme {
self.get(id).theme(app)
}
pub fn open(
&mut self,
window: Box<dyn Window<App, Theme, Message, Renderer>>,
) -> (Id, Task<Id>) {
let (id, task) = window::open(window.settings());
self.windows.insert(id, window);
(id, task)
}
pub fn close_all(&mut self) -> Task<Id> {
let mut tasks = Vec::new();
for id in self.windows.keys() {
tasks.push(window::close(*id));
}
Task::batch(tasks)
}
pub fn close_all_of(
&mut self,
window: Box<dyn Window<App, Theme, Message, Renderer>>,
) -> Task<Id> {
let mut tasks = Vec::new();
for (id, w) in self.windows.iter() {
if *w == window {
tasks.push(window::close(*id));
}
}
Task::batch(tasks)
}
pub fn any_of(&self, window: &impl Window<App, Theme, Message, Renderer>) -> bool {
self.windows.values().any(|w| w == window)
}
pub fn was_closed(&mut self, id: Id) {
self.windows.remove(&id);
}
#[allow(clippy::type_complexity)]
pub fn instances_of(
&self,
window: &impl Window<App, Theme, Message, Renderer>,
) -> Vec<(&Id, &Box<dyn Window<App, Theme, Message, Renderer>>)> {
self.windows.iter().filter(|(_, w)| *w == window).collect()
}
pub fn empty(&self) -> bool {
self.windows.is_empty()
}
}
impl<App, Theme, Message, Renderer> Default for WindowManager<App, Theme, Message, Renderer> {
fn default() -> Self {
Self {
windows: HashMap::new(),
}
}
}