2021-02-08 18:37:25 +11:00
|
|
|
//! We use a few different windows in our app lifecycle, so it's easier to
|
|
|
|
//! just use a small abstraction here and keep the app delegate clean.
|
|
|
|
//!
|
|
|
|
//! This could be a lot cleaner, and is something I'd like to make cleaner on a framework level.
|
|
|
|
|
|
|
|
use std::sync::RwLock;
|
|
|
|
|
2022-07-16 00:14:02 +10:00
|
|
|
use cacao::appkit::window::{Window, WindowConfig, WindowDelegate, WindowStyle, WindowToolbarStyle};
|
2021-02-08 18:37:25 +11:00
|
|
|
use cacao::notification_center::Dispatcher;
|
|
|
|
|
|
|
|
use crate::storage::Message;
|
|
|
|
|
|
|
|
use crate::add::AddNewTodoWindow;
|
|
|
|
use crate::preferences::PreferencesWindow;
|
2022-07-16 00:14:02 +10:00
|
|
|
use crate::todos::TodosWindow;
|
2021-02-08 18:37:25 +11:00
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
pub struct WindowManager {
|
|
|
|
pub main: RwLock<Option<Window<TodosWindow>>>,
|
|
|
|
pub preferences: RwLock<Option<Window<PreferencesWindow>>>,
|
|
|
|
pub add: RwLock<Option<Window<AddNewTodoWindow>>>
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A helper method to handle checking for window existence, and creating
|
|
|
|
/// it if not - then showing it.
|
|
|
|
fn open_or_show<T, F>(window: &RwLock<Option<Window<T>>>, vendor: F)
|
|
|
|
where
|
|
|
|
T: WindowDelegate + 'static,
|
|
|
|
F: Fn() -> (WindowConfig, T)
|
|
|
|
{
|
|
|
|
let mut lock = window.write().unwrap();
|
2022-07-11 01:15:29 +10:00
|
|
|
|
2021-02-08 18:37:25 +11:00
|
|
|
if let Some(win) = &*lock {
|
|
|
|
win.show();
|
|
|
|
} else {
|
|
|
|
let (config, delegate) = vendor();
|
|
|
|
let win = Window::with(config, delegate);
|
|
|
|
win.show();
|
|
|
|
*lock = Some(win);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl WindowManager {
|
|
|
|
pub fn open_main(&self) {
|
2022-07-16 00:14:02 +10:00
|
|
|
open_or_show(&self.main, || (WindowConfig::default(), TodosWindow::new()));
|
2021-02-08 18:37:25 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
/// When we run a sheet, we want to run it on our main window, which is all
|
|
|
|
/// this helper is for.
|
|
|
|
pub fn begin_sheet<W, F>(&self, window: &Window<W>, completion: F)
|
|
|
|
where
|
|
|
|
W: WindowDelegate + 'static,
|
|
|
|
F: Fn() + Send + Sync + 'static
|
|
|
|
{
|
|
|
|
let main = self.main.write().unwrap();
|
2022-07-11 01:15:29 +10:00
|
|
|
|
2021-02-08 18:37:25 +11:00
|
|
|
if let Some(main_window) = &*main {
|
|
|
|
main_window.begin_sheet(window, completion);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Opens a "add file" window, which asks for a code and optional server to
|
|
|
|
/// check against. This should, probably, be a sheet - but for now it's fine as a
|
|
|
|
/// separate window until I can find time to port that API.
|
|
|
|
pub fn open_add(&self) {
|
|
|
|
let callback = || {};
|
|
|
|
|
|
|
|
let mut lock = self.add.write().unwrap();
|
|
|
|
|
|
|
|
if let Some(win) = &*lock {
|
|
|
|
self.begin_sheet(&win, callback);
|
|
|
|
} else {
|
|
|
|
let window = Window::with(WindowConfig::default(), AddNewTodoWindow::new());
|
|
|
|
self.begin_sheet(&window, callback);
|
|
|
|
*lock = Some(window);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn close_sheet(&self) {
|
|
|
|
let mut add = self.add.write().unwrap();
|
|
|
|
|
|
|
|
if let Some(add_window) = &*add {
|
|
|
|
let main = self.main.write().unwrap();
|
|
|
|
|
|
|
|
if let Some(main_window) = &*main {
|
|
|
|
main_window.end_sheet(&add_window);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*add = None;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Opens a "add file" window, which asks for a code and optional server to
|
|
|
|
/// check against.
|
|
|
|
pub fn open_preferences(&self) {
|
|
|
|
open_or_show(&self.preferences, || {
|
|
|
|
let mut config = WindowConfig::default();
|
|
|
|
config.set_initial_dimensions(100., 100., 400., 400.);
|
|
|
|
|
|
|
|
config.set_styles(&[
|
2022-07-16 00:14:02 +10:00
|
|
|
WindowStyle::Resizable,
|
|
|
|
WindowStyle::Miniaturizable,
|
|
|
|
WindowStyle::Closable,
|
|
|
|
WindowStyle::Titled
|
2021-02-08 18:37:25 +11:00
|
|
|
]);
|
|
|
|
|
|
|
|
config.toolbar_style = WindowToolbarStyle::Preferences;
|
|
|
|
|
|
|
|
(config, PreferencesWindow::new())
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Dispatcher for WindowManager {
|
|
|
|
type Message = Message;
|
|
|
|
|
|
|
|
/// Some jank message passing, it's fine for now.
|
|
|
|
fn on_ui_message(&self, message: Message) {
|
|
|
|
match message {
|
|
|
|
Message::OpenMainWindow => {
|
|
|
|
self.open_main();
|
|
|
|
},
|
|
|
|
|
|
|
|
Message::OpenPreferencesWindow => {
|
|
|
|
self.open_preferences();
|
|
|
|
},
|
|
|
|
|
|
|
|
Message::CloseSheet => {
|
|
|
|
self.close_sheet();
|
|
|
|
},
|
|
|
|
|
|
|
|
Message::OpenNewTodoSheet => {
|
|
|
|
self.open_add();
|
|
|
|
},
|
|
|
|
|
|
|
|
Message::StoreNewTodo(_) => {
|
|
|
|
self.close_sheet();
|
|
|
|
},
|
|
|
|
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(w) = &*(self.main.read().unwrap()) {
|
|
|
|
if let Some(delegate) = &w.delegate {
|
|
|
|
delegate.on_message(message.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(w) = &*(self.preferences.read().unwrap()) {
|
|
|
|
if let Some(delegate) = &w.delegate {
|
|
|
|
delegate.on_message(message.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(w) = &*(self.add.read().unwrap()) {
|
|
|
|
if let Some(delegate) = &w.delegate {
|
|
|
|
delegate.on_message(message.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|