/*
* This file is part of espanso.
*
* Copyright id: (), label: () id: (), label: () id: (), label: ()(C) 2019-2021 Federico Terzi
*
* espanso is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* espanso is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with espanso. If not, see .
*/
use std::cell::RefCell;
use super::super::Middleware;
use crate::event::{
ui::{MenuItem, ShowContextMenuEvent, SimpleMenuItem},
Event, EventType, ExitMode,
};
const CONTEXT_ITEM_EXIT: u32 = 0;
const CONTEXT_ITEM_RELOAD: u32 = 1;
const CONTEXT_ITEM_ENABLE: u32 = 2;
const CONTEXT_ITEM_DISABLE: u32 = 3;
const CONTEXT_ITEM_SECURE_INPUT_EXPLAIN: u32 = 4;
const CONTEXT_ITEM_SECURE_INPUT_TRIGGER_WORKAROUND: u32 = 5;
const CONTEXT_ITEM_OPEN_SEARCH: u32 = 6;
pub struct ContextMenuMiddleware {
is_enabled: RefCell,
is_secure_input_enabled: RefCell,
}
impl ContextMenuMiddleware {
pub fn new() -> Self {
Self {
is_enabled: RefCell::new(true),
is_secure_input_enabled: RefCell::new(false),
}
}
}
#[allow(clippy::needless_return)]
impl Middleware for ContextMenuMiddleware {
fn name(&self) -> &'static str {
"context_menu"
}
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
let mut is_enabled = self.is_enabled.borrow_mut();
let mut is_secure_input_enabled = self.is_secure_input_enabled.borrow_mut();
match &event.etype {
EventType::TrayIconClicked => {
// TODO: fetch top matches for the active config to be added
let mut items = vec![
MenuItem::Simple(if *is_enabled {
SimpleMenuItem {
id: CONTEXT_ITEM_DISABLE,
label: "Disable".to_string(),
}
} else {
SimpleMenuItem {
id: CONTEXT_ITEM_ENABLE,
label: "Enable".to_string(),
}
}),
MenuItem::Simple(SimpleMenuItem {
id: CONTEXT_ITEM_OPEN_SEARCH,
label: "Open search bar".to_string(),
}),
MenuItem::Separator,
MenuItem::Simple(SimpleMenuItem {
id: CONTEXT_ITEM_RELOAD,
label: "Reload config".to_string(),
}),
MenuItem::Separator,
MenuItem::Simple(SimpleMenuItem {
id: CONTEXT_ITEM_EXIT,
label: "Exit espanso".to_string(),
}),
];
if *is_secure_input_enabled {
items.insert(
0,
MenuItem::Simple(SimpleMenuItem {
id: CONTEXT_ITEM_SECURE_INPUT_EXPLAIN,
label: "Why is espanso not working?".to_string(),
}),
);
items.insert(
1,
MenuItem::Simple(SimpleMenuItem {
id: CONTEXT_ITEM_SECURE_INPUT_TRIGGER_WORKAROUND,
label: "Launch SecureInput auto-fix".to_string(),
}),
);
items.insert(2, MenuItem::Separator);
}
// TODO: my idea is to use a set of reserved u32 ids for built-in
// actions such as Exit, Open Editor etc
// then we need some u32 for the matches, so we need to create
// a mapping structure match_id <-> context-menu-id
return Event::caused_by(
event.source_id,
EventType::ShowContextMenu(ShowContextMenuEvent {
// TODO: add actual entries
items,
}),
);
}
EventType::ContextMenuClicked(context_click_event) => {
match context_click_event.context_item_id {
CONTEXT_ITEM_EXIT => Event::caused_by(
event.source_id,
EventType::ExitRequested(ExitMode::ExitAllProcesses),
),
CONTEXT_ITEM_RELOAD => Event::caused_by(
event.source_id,
EventType::ExitRequested(ExitMode::RestartWorker),
),
CONTEXT_ITEM_ENABLE => {
dispatch(Event::caused_by(event.source_id, EventType::EnableRequest));
Event::caused_by(event.source_id, EventType::NOOP)
}
CONTEXT_ITEM_DISABLE => {
dispatch(Event::caused_by(event.source_id, EventType::DisableRequest));
Event::caused_by(event.source_id, EventType::NOOP)
}
CONTEXT_ITEM_SECURE_INPUT_EXPLAIN => {
dispatch(Event::caused_by(
event.source_id,
EventType::DisplaySecureInputTroubleshoot,
));
Event::caused_by(event.source_id, EventType::NOOP)
}
CONTEXT_ITEM_SECURE_INPUT_TRIGGER_WORKAROUND => {
dispatch(Event::caused_by(
event.source_id,
EventType::LaunchSecureInputAutoFix,
));
Event::caused_by(event.source_id, EventType::NOOP)
}
CONTEXT_ITEM_OPEN_SEARCH => {
dispatch(Event::caused_by(event.source_id, EventType::ShowSearchBar));
Event::caused_by(event.source_id, EventType::NOOP)
}
_ => {
// TODO: handle dynamic items
todo!()
}
}
}
EventType::Disabled => {
*is_enabled = false;
event
}
EventType::Enabled => {
*is_enabled = true;
event
}
EventType::SecureInputEnabled(_) => {
*is_secure_input_enabled = true;
event
}
EventType::SecureInputDisabled => {
*is_secure_input_enabled = false;
event
}
_ => event,
}
}
}
// TODO: test