use crate::{
model::update,
view::{
article::TogglePlainText,
root::{
CloseProject, Cydonia, NewArticle, NewBoard, NewSession, NewTable, NextEntry,
OpenProject, OpenSettings, Pane, PrevEntry, ToggleSidebar,
},
},
};
use bezel::{
gpui::{
self, App, Context, Div, KeyBinding, Menu, MenuItem, OsAction, Window, actions, prelude::*,
},
ui::input,
};
actions!(
cydonia,
[
CheckForUpdates,
CloseWindow,
Hide,
HideOthers,
Minimize,
Quit,
ShowAll,
ToggleFullScreen,
Zoom
]
);
pub fn bindings() -> Vec<KeyBinding> {
vec![
KeyBinding::new("cmd-q", Quit, None),
KeyBinding::new("cmd-h", Hide, None),
KeyBinding::new("alt-cmd-h", HideOthers, None),
KeyBinding::new("cmd-w", CloseWindow, None),
KeyBinding::new("cmd-m", Minimize, None),
KeyBinding::new("ctrl-cmd-f", ToggleFullScreen, None),
]
}
pub fn init(cx: &mut App) {
cx.on_action(|_: &Quit, cx: &mut App| cx.quit());
cx.on_action(|_: &Hide, cx: &mut App| cx.hide());
cx.on_action(|_: &HideOthers, cx: &mut App| cx.hide_other_apps());
cx.on_action(|_: &ShowAll, cx: &mut App| cx.unhide_other_apps());
cx.on_action(|_: &Minimize, cx: &mut App| front(cx, |window| window.minimize_window()));
cx.on_action(|_: &Zoom, cx: &mut App| front(cx, |window| window.zoom_window()));
cx.on_action(|_: &ToggleFullScreen, cx: &mut App| {
front(cx, |window| window.toggle_fullscreen())
});
cx.on_action(|_: &CloseWindow, cx: &mut App| front(cx, |window| window.remove_window()));
cx.on_action(|_: &OpenProject, cx: &mut App| {
workspace(cx, |this, window, cx| {
this.open_project_action(&OpenProject, window, cx)
})
});
cx.on_action(|_: &OpenSettings, cx: &mut App| {
workspace(cx, |this, window, cx| {
this.open_settings_action(&OpenSettings, window, cx)
})
});
if update::supported(cx)
&& let Some(updater) = update::of(cx)
{
cx.on_action(move |_: &CheckForUpdates, cx: &mut App| {
updater.update(cx, |updater, cx| updater.check(true, cx));
});
}
refresh(cx);
}
pub fn refresh(cx: &mut App) {
let menus = menus(cx);
cx.set_menus(menus);
}
fn menus(cx: &App) -> Vec<Menu> {
let mut app = Vec::new();
if update::supported(cx) {
app.push(MenuItem::action("Check for Updates…", CheckForUpdates));
app.push(MenuItem::separator());
}
app.extend([
MenuItem::action("Settings…", OpenSettings),
MenuItem::separator(),
MenuItem::action("Hide cydonia", Hide),
MenuItem::action("Hide Others", HideOthers),
MenuItem::action("Show All", ShowAll),
MenuItem::separator(),
MenuItem::action("Quit cydonia", Quit),
]);
vec![
Menu::new("cydonia").items(app),
Menu::new("File").items([
MenuItem::action("New Session", NewSession),
MenuItem::action("New Board", NewBoard),
MenuItem::action("New Article", NewArticle),
MenuItem::action("New Table", NewTable),
MenuItem::separator(),
MenuItem::action("Open Project…", OpenProject),
MenuItem::action("Close Project", CloseProject),
MenuItem::separator(),
MenuItem::action("Close Window", CloseWindow),
]),
Menu::new("Edit").items([
MenuItem::os_action("Undo", input::Undo, OsAction::Undo),
MenuItem::os_action("Redo", input::Redo, OsAction::Redo),
MenuItem::separator(),
MenuItem::os_action("Cut", input::Cut, OsAction::Cut),
MenuItem::os_action("Copy", input::Copy, OsAction::Copy),
MenuItem::os_action("Paste", input::Paste, OsAction::Paste),
MenuItem::separator(),
MenuItem::os_action("Select All", input::SelectAll, OsAction::SelectAll),
]),
Menu::new("View").items([
MenuItem::action("Toggle Sidebar", ToggleSidebar),
MenuItem::separator(),
MenuItem::action("Next Entry", NextEntry),
MenuItem::action("Previous Entry", PrevEntry),
MenuItem::separator(),
MenuItem::action("Plain Text", TogglePlainText),
MenuItem::separator(),
MenuItem::action("Enter Full Screen", ToggleFullScreen),
]),
Menu::new("Window").items([
MenuItem::action("Minimize", Minimize),
MenuItem::action("Zoom", Zoom),
]),
]
}
fn front(cx: &mut App, f: impl FnOnce(&mut Window) + 'static) {
let Some(window) = cx.active_window() else {
return;
};
cx.defer(move |cx| {
let _ = window.update(cx, |_, window, _| f(window));
});
}
fn workspace(cx: &mut App, f: impl FnOnce(&mut Cydonia, &mut Window, &mut Context<Cydonia>)) {
let Some(handle) = cx
.windows()
.into_iter()
.find_map(|window| window.downcast::<Cydonia>())
else {
return;
};
let _ = handle.update(cx, |this, window, cx| {
window.activate_window();
f(this, window, cx);
});
}
impl Cydonia {
pub(crate) fn commands(&self, root: Div, cx: &mut Context<Self>) -> Div {
let workspace = self.workspace.read(cx);
let features = &workspace.settings.features;
let (sessions, boards, tables) = (features.sessions, features.boards, features.tables);
let project = workspace.active.is_some();
let showing = self.showing(cx);
let entries = showing.is_some();
root.on_action(cx.listener(Self::toggle_sidebar_action))
.on_action(cx.listener(Self::open_project_action))
.on_action(cx.listener(Self::open_settings_action))
.when(project, |root| {
root.on_action(cx.listener(Self::close_project_action))
.on_action(cx.listener(Self::new_article_action))
.when(sessions, |root| {
root.on_action(cx.listener(Self::new_session_action))
})
.when(boards, |root| {
root.on_action(cx.listener(Self::new_board_action))
})
.when(tables, |root| {
root.on_action(cx.listener(Self::new_table_action))
})
})
.when(showing == Some(Pane::Article), |root| {
root.on_action(cx.listener(Self::toggle_plain_text))
})
.when(entries, |root| {
root.on_action(cx.listener(Self::next_entry))
.on_action(cx.listener(Self::prev_entry))
})
}
}