feat(core): first half of context menu handling
This commit is contained in:
parent
716c50cee1
commit
cba94607fa
70
espanso/src/cli/worker/engine/executor/context_menu.rs
Normal file
70
espanso/src/cli/worker/engine/executor/context_menu.rs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* This file is part of espanso.
|
||||||
|
*
|
||||||
|
* Copyright (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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use espanso_ui::UIRemote;
|
||||||
|
|
||||||
|
use crate::engine::dispatch::ContextMenuHandler;
|
||||||
|
|
||||||
|
pub struct ContextMenuHandlerAdapter<'a> {
|
||||||
|
remote: &'a dyn UIRemote,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ContextMenuHandlerAdapter<'a> {
|
||||||
|
pub fn new(remote: &'a dyn UIRemote) -> Self {
|
||||||
|
Self { remote }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ContextMenuHandler for ContextMenuHandlerAdapter<'a> {
|
||||||
|
fn show_context_menu(&self, items: &[crate::engine::event::ui::MenuItem]) -> anyhow::Result<()> {
|
||||||
|
let ui_menu_items: Vec<espanso_ui::menu::MenuItem> =
|
||||||
|
items.iter().map(convert_to_ui_menu_item).collect();
|
||||||
|
let ui_menu = espanso_ui::menu::Menu {
|
||||||
|
items: ui_menu_items,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.remote.show_context_menu(&ui_menu);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_to_ui_menu_item(
|
||||||
|
item: &crate::engine::event::ui::MenuItem,
|
||||||
|
) -> espanso_ui::menu::MenuItem {
|
||||||
|
match item {
|
||||||
|
crate::engine::event::ui::MenuItem::Simple(simple) => {
|
||||||
|
espanso_ui::menu::MenuItem::Simple(espanso_ui::menu::SimpleMenuItem {
|
||||||
|
id: simple.id,
|
||||||
|
label: simple.label.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
crate::engine::event::ui::MenuItem::Sub(sub) => {
|
||||||
|
espanso_ui::menu::MenuItem::Sub(espanso_ui::menu::SubMenuItem {
|
||||||
|
label: sub.label.clone(),
|
||||||
|
items: sub
|
||||||
|
.items
|
||||||
|
.iter()
|
||||||
|
.map(|item| convert_to_ui_menu_item(item))
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
crate::engine::event::ui::MenuItem::Separator => espanso_ui::menu::MenuItem::Separator,
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,5 +18,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub mod clipboard_injector;
|
pub mod clipboard_injector;
|
||||||
|
pub mod context_menu;
|
||||||
pub mod event_injector;
|
pub mod event_injector;
|
||||||
pub mod key_injector;
|
pub mod key_injector;
|
|
@ -23,7 +23,7 @@ use anyhow::Result;
|
||||||
use crossbeam::channel::Receiver;
|
use crossbeam::channel::Receiver;
|
||||||
use espanso_config::{config::ConfigStore, matches::store::MatchStore};
|
use espanso_config::{config::ConfigStore, matches::store::MatchStore};
|
||||||
use espanso_path::Paths;
|
use espanso_path::Paths;
|
||||||
use espanso_ui::UIRemote;
|
use espanso_ui::{UIRemote, event::UIEvent};
|
||||||
use log::info;
|
use log::info;
|
||||||
use ui::selector::MatchSelectorAdapter;
|
use ui::selector::MatchSelectorAdapter;
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ pub fn initialize_and_spawn(
|
||||||
icon_paths: IconPaths,
|
icon_paths: IconPaths,
|
||||||
ui_remote: Box<dyn UIRemote>,
|
ui_remote: Box<dyn UIRemote>,
|
||||||
exit_signal: Receiver<()>,
|
exit_signal: Receiver<()>,
|
||||||
|
ui_event_receiver: Receiver<UIEvent>,
|
||||||
) -> Result<JoinHandle<()>> {
|
) -> Result<JoinHandle<()>> {
|
||||||
let handle = std::thread::Builder::new()
|
let handle = std::thread::Builder::new()
|
||||||
.name("engine thread".to_string())
|
.name("engine thread".to_string())
|
||||||
|
@ -68,7 +69,8 @@ pub fn initialize_and_spawn(
|
||||||
let (detect_source, modifier_state_store, sequencer) =
|
let (detect_source, modifier_state_store, sequencer) =
|
||||||
super::engine::source::init_and_spawn().expect("failed to initialize detector module");
|
super::engine::source::init_and_spawn().expect("failed to initialize detector module");
|
||||||
let exit_source = super::engine::source::exit::ExitSource::new(exit_signal, &sequencer);
|
let exit_source = super::engine::source::exit::ExitSource::new(exit_signal, &sequencer);
|
||||||
let sources: Vec<&dyn crate::engine::funnel::Source> = vec![&detect_source, &exit_source];
|
let ui_source = super::engine::source::ui::UISource::new(ui_event_receiver, &sequencer);
|
||||||
|
let sources: Vec<&dyn crate::engine::funnel::Source> = vec![&detect_source, &exit_source, &ui_source];
|
||||||
let funnel = crate::engine::funnel::default(&sources);
|
let funnel = crate::engine::funnel::default(&sources);
|
||||||
|
|
||||||
let rolling_matcher = super::engine::matcher::rolling::RollingMatcherAdapter::new(
|
let rolling_matcher = super::engine::matcher::rolling::RollingMatcherAdapter::new(
|
||||||
|
@ -140,6 +142,7 @@ pub fn initialize_and_spawn(
|
||||||
&config_manager,
|
&config_manager,
|
||||||
);
|
);
|
||||||
let key_injector = super::engine::executor::key_injector::KeyInjectorAdapter::new(&*injector);
|
let key_injector = super::engine::executor::key_injector::KeyInjectorAdapter::new(&*injector);
|
||||||
|
let context_menu_adapter = super::engine::executor::context_menu::ContextMenuHandlerAdapter::new(&*ui_remote);
|
||||||
let dispatcher = crate::engine::dispatch::default(
|
let dispatcher = crate::engine::dispatch::default(
|
||||||
&event_injector,
|
&event_injector,
|
||||||
&clipboard_injector,
|
&clipboard_injector,
|
||||||
|
@ -147,6 +150,7 @@ pub fn initialize_and_spawn(
|
||||||
&key_injector,
|
&key_injector,
|
||||||
&clipboard_injector,
|
&clipboard_injector,
|
||||||
&clipboard_injector,
|
&clipboard_injector,
|
||||||
|
&context_menu_adapter,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut engine = crate::engine::Engine::new(&funnel, &mut processor, &dispatcher);
|
let mut engine = crate::engine::Engine::new(&funnel, &mut processor, &dispatcher);
|
||||||
|
|
|
@ -30,6 +30,7 @@ pub mod detect;
|
||||||
pub mod exit;
|
pub mod exit;
|
||||||
pub mod modifier;
|
pub mod modifier;
|
||||||
pub mod sequencer;
|
pub mod sequencer;
|
||||||
|
pub mod ui;
|
||||||
|
|
||||||
// TODO: pass options
|
// TODO: pass options
|
||||||
pub fn init_and_spawn() -> Result<(DetectSource, ModifierStateStore, Sequencer)> {
|
pub fn init_and_spawn() -> Result<(DetectSource, ModifierStateStore, Sequencer)> {
|
||||||
|
|
64
espanso/src/cli/worker/engine/source/ui.rs
Normal file
64
espanso/src/cli/worker/engine/source/ui.rs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* This file is part of espanso.
|
||||||
|
*
|
||||||
|
* Copyright (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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crossbeam::channel::{Receiver, Select, SelectedOperation};
|
||||||
|
use espanso_ui::event::UIEvent;
|
||||||
|
|
||||||
|
use crate::engine::{
|
||||||
|
event::{input::ContextMenuClickedEvent, Event, EventType},
|
||||||
|
funnel,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::sequencer::Sequencer;
|
||||||
|
|
||||||
|
pub struct UISource<'a> {
|
||||||
|
pub ui_receiver: Receiver<UIEvent>,
|
||||||
|
pub sequencer: &'a Sequencer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> UISource<'a> {
|
||||||
|
pub fn new(ui_receiver: Receiver<UIEvent>, sequencer: &'a Sequencer) -> Self {
|
||||||
|
UISource {
|
||||||
|
ui_receiver,
|
||||||
|
sequencer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> funnel::Source<'a> for UISource<'a> {
|
||||||
|
fn register(&'a self, select: &mut Select<'a>) -> usize {
|
||||||
|
select.recv(&self.ui_receiver)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receive(&self, op: SelectedOperation) -> Event {
|
||||||
|
let ui_event = op
|
||||||
|
.recv(&self.ui_receiver)
|
||||||
|
.expect("unable to select data from UISource receiver");
|
||||||
|
|
||||||
|
Event {
|
||||||
|
source_id: self.sequencer.next_id(),
|
||||||
|
etype: match ui_event {
|
||||||
|
UIEvent::TrayIconClick => EventType::TrayIconClicked,
|
||||||
|
UIEvent::ContextMenuClick(context_item_id) => {
|
||||||
|
EventType::ContextMenuClicked(ContextMenuClickedEvent { context_item_id })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -80,6 +80,7 @@ fn worker_main(args: CliModuleArgs) -> i32 {
|
||||||
.expect("unable to initialize UI module");
|
.expect("unable to initialize UI module");
|
||||||
|
|
||||||
let (engine_exit_notify, engine_exit_receiver) = unbounded();
|
let (engine_exit_notify, engine_exit_receiver) = unbounded();
|
||||||
|
let (engine_ui_event_sender, engine_ui_event_receiver) = unbounded();
|
||||||
|
|
||||||
// Initialize the engine on another thread and start it
|
// Initialize the engine on another thread and start it
|
||||||
engine::initialize_and_spawn(
|
engine::initialize_and_spawn(
|
||||||
|
@ -89,6 +90,7 @@ fn worker_main(args: CliModuleArgs) -> i32 {
|
||||||
icon_paths,
|
icon_paths,
|
||||||
remote,
|
remote,
|
||||||
engine_exit_receiver,
|
engine_exit_receiver,
|
||||||
|
engine_ui_event_receiver,
|
||||||
)
|
)
|
||||||
.expect("unable to initialize engine");
|
.expect("unable to initialize engine");
|
||||||
|
|
||||||
|
@ -97,8 +99,10 @@ fn worker_main(args: CliModuleArgs) -> i32 {
|
||||||
.expect("unable to initialize IPC server");
|
.expect("unable to initialize IPC server");
|
||||||
|
|
||||||
eventloop.run(Box::new(move |event| {
|
eventloop.run(Box::new(move |event| {
|
||||||
// TODO: handle event
|
if let Err(error) = engine_ui_event_sender.send(event) {
|
||||||
}));
|
error!("unable to send UIEvent to engine: {}", error);
|
||||||
|
}
|
||||||
|
})).expect("unable to run main eventloop");
|
||||||
|
|
||||||
info!("exiting worker process...");
|
info!("exiting worker process...");
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use super::{Event, ImageInjector};
|
use super::{ContextMenuHandler, Event, ImageInjector};
|
||||||
use super::{ModeProvider, Dispatcher, Executor, KeyInjector, TextInjector, HtmlInjector};
|
use super::{ModeProvider, Dispatcher, Executor, KeyInjector, TextInjector, HtmlInjector};
|
||||||
|
|
||||||
pub struct DefaultDispatcher<'a> {
|
pub struct DefaultDispatcher<'a> {
|
||||||
|
@ -32,6 +32,7 @@ impl<'a> DefaultDispatcher<'a> {
|
||||||
key_injector: &'a dyn KeyInjector,
|
key_injector: &'a dyn KeyInjector,
|
||||||
html_injector: &'a dyn HtmlInjector,
|
html_injector: &'a dyn HtmlInjector,
|
||||||
image_injector: &'a dyn ImageInjector,
|
image_injector: &'a dyn ImageInjector,
|
||||||
|
context_menu_handler: &'a dyn ContextMenuHandler,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
executors: vec![
|
executors: vec![
|
||||||
|
@ -48,6 +49,9 @@ impl<'a> DefaultDispatcher<'a> {
|
||||||
)),
|
)),
|
||||||
Box::new(super::executor::image_inject::ImageInjectExecutor::new(
|
Box::new(super::executor::image_inject::ImageInjectExecutor::new(
|
||||||
image_injector,
|
image_injector,
|
||||||
|
)),
|
||||||
|
Box::new(super::executor::context_menu::ContextMenuExecutor::new(
|
||||||
|
context_menu_handler,
|
||||||
))
|
))
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
53
espanso/src/engine/dispatch/executor/context_menu.rs
Normal file
53
espanso/src/engine/dispatch/executor/context_menu.rs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* This file is part of espanso.
|
||||||
|
*
|
||||||
|
* Copyright (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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use super::super::{Event, Executor};
|
||||||
|
use crate::engine::event::{ui::MenuItem, EventType};
|
||||||
|
use anyhow::Result;
|
||||||
|
use log::error;
|
||||||
|
|
||||||
|
pub trait ContextMenuHandler {
|
||||||
|
fn show_context_menu(&self, items: &[MenuItem]) -> Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ContextMenuExecutor<'a> {
|
||||||
|
handler: &'a dyn ContextMenuHandler,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ContextMenuExecutor<'a> {
|
||||||
|
pub fn new(handler: &'a dyn ContextMenuHandler) -> Self {
|
||||||
|
Self { handler }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Executor for ContextMenuExecutor<'a> {
|
||||||
|
fn execute(&self, event: &Event) -> bool {
|
||||||
|
if let EventType::ShowContextMenu(context_menu_event) = &event.etype {
|
||||||
|
if let Err(error) = self.handler.show_context_menu(&context_menu_event.items) {
|
||||||
|
error!("context menu handler reported an error: {:?}", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: test
|
|
@ -17,7 +17,8 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub mod text_inject;
|
pub mod context_menu;
|
||||||
pub mod key_inject;
|
pub mod image_inject;
|
||||||
pub mod html_inject;
|
pub mod html_inject;
|
||||||
pub mod image_inject;
|
pub mod key_inject;
|
||||||
|
pub mod text_inject;
|
|
@ -36,6 +36,7 @@ pub trait Dispatcher {
|
||||||
pub use executor::html_inject::HtmlInjector;
|
pub use executor::html_inject::HtmlInjector;
|
||||||
pub use executor::text_inject::{Mode, ModeProvider, TextInjector};
|
pub use executor::text_inject::{Mode, ModeProvider, TextInjector};
|
||||||
pub use executor::image_inject::{ImageInjector};
|
pub use executor::image_inject::{ImageInjector};
|
||||||
|
pub use executor::context_menu::{ContextMenuHandler};
|
||||||
|
|
||||||
// TODO: move into module
|
// TODO: move into module
|
||||||
pub trait KeyInjector {
|
pub trait KeyInjector {
|
||||||
|
@ -49,6 +50,7 @@ pub fn default<'a>(
|
||||||
key_injector: &'a dyn KeyInjector,
|
key_injector: &'a dyn KeyInjector,
|
||||||
html_injector: &'a dyn HtmlInjector,
|
html_injector: &'a dyn HtmlInjector,
|
||||||
image_injector: &'a dyn ImageInjector,
|
image_injector: &'a dyn ImageInjector,
|
||||||
|
context_menu_handler: &'a dyn ContextMenuHandler,
|
||||||
) -> impl Dispatcher + 'a {
|
) -> impl Dispatcher + 'a {
|
||||||
default::DefaultDispatcher::new(
|
default::DefaultDispatcher::new(
|
||||||
event_injector,
|
event_injector,
|
||||||
|
@ -57,5 +59,6 @@ pub fn default<'a>(
|
||||||
key_injector,
|
key_injector,
|
||||||
html_injector,
|
html_injector,
|
||||||
image_injector,
|
image_injector,
|
||||||
|
context_menu_handler,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,4 +110,9 @@ pub enum Key {
|
||||||
|
|
||||||
// Other keys, includes the raw code provided by the operating system
|
// Other keys, includes the raw code provided by the operating system
|
||||||
Other(i32),
|
Other(i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct ContextMenuClickedEvent {
|
||||||
|
pub context_item_id: u32,
|
||||||
}
|
}
|
|
@ -20,6 +20,7 @@
|
||||||
pub mod input;
|
pub mod input;
|
||||||
pub mod effect;
|
pub mod effect;
|
||||||
pub mod internal;
|
pub mod internal;
|
||||||
|
pub mod ui;
|
||||||
|
|
||||||
pub type SourceId = u32;
|
pub type SourceId = u32;
|
||||||
|
|
||||||
|
@ -54,6 +55,8 @@ pub enum EventType {
|
||||||
Keyboard(input::KeyboardEvent),
|
Keyboard(input::KeyboardEvent),
|
||||||
Mouse(input::MouseEvent),
|
Mouse(input::MouseEvent),
|
||||||
// TODO: hotkeys
|
// TODO: hotkeys
|
||||||
|
TrayIconClicked,
|
||||||
|
ContextMenuClicked(input::ContextMenuClickedEvent),
|
||||||
|
|
||||||
// Internal
|
// Internal
|
||||||
MatchesDetected(internal::MatchesDetectedEvent),
|
MatchesDetected(internal::MatchesDetectedEvent),
|
||||||
|
@ -76,4 +79,7 @@ pub enum EventType {
|
||||||
MarkdownInject(effect::MarkdownInjectRequest),
|
MarkdownInject(effect::MarkdownInjectRequest),
|
||||||
HtmlInject(effect::HtmlInjectRequest),
|
HtmlInject(effect::HtmlInjectRequest),
|
||||||
ImageInject(effect::ImageInjectRequest),
|
ImageInject(effect::ImageInjectRequest),
|
||||||
|
|
||||||
|
// UI
|
||||||
|
ShowContextMenu(ui::ShowContextMenuEvent),
|
||||||
}
|
}
|
42
espanso/src/engine/event/ui.rs
Normal file
42
espanso/src/engine/event/ui.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* This file is part of espanso.
|
||||||
|
*
|
||||||
|
* Copyright (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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct ShowContextMenuEvent {
|
||||||
|
pub items: Vec<MenuItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum MenuItem {
|
||||||
|
Simple(SimpleMenuItem),
|
||||||
|
Sub(SubMenuItem),
|
||||||
|
Separator,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct SimpleMenuItem {
|
||||||
|
pub id: u32,
|
||||||
|
pub label: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct SubMenuItem {
|
||||||
|
pub label: String,
|
||||||
|
pub items: Vec<MenuItem>,
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ use super::{MatchFilter, MatchInfoProvider, MatchSelector, Matcher, Middleware,
|
||||||
delay_modifiers::{DelayForModifierReleaseMiddleware, ModifierStatusProvider}, markdown::MarkdownMiddleware,
|
delay_modifiers::{DelayForModifierReleaseMiddleware, ModifierStatusProvider}, markdown::MarkdownMiddleware,
|
||||||
past_discard::PastEventsDiscardMiddleware,
|
past_discard::PastEventsDiscardMiddleware,
|
||||||
}};
|
}};
|
||||||
use crate::engine::{event::{Event, EventType}, process::middleware::{exit::ExitMiddleware, image_resolve::ImageResolverMiddleware}};
|
use crate::engine::{event::{Event, EventType}, process::middleware::{context_menu::ContextMenuMiddleware, exit::ExitMiddleware, image_resolve::ImageResolverMiddleware}};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
pub struct DefaultProcessor<'a> {
|
pub struct DefaultProcessor<'a> {
|
||||||
|
@ -50,6 +50,7 @@ impl<'a> DefaultProcessor<'a> {
|
||||||
middleware: vec![
|
middleware: vec![
|
||||||
Box::new(PastEventsDiscardMiddleware::new()),
|
Box::new(PastEventsDiscardMiddleware::new()),
|
||||||
Box::new(MatcherMiddleware::new(matchers)),
|
Box::new(MatcherMiddleware::new(matchers)),
|
||||||
|
Box::new(ContextMenuMiddleware::new()),
|
||||||
Box::new(MatchSelectMiddleware::new(match_filter, match_selector)),
|
Box::new(MatchSelectMiddleware::new(match_filter, match_selector)),
|
||||||
Box::new(CauseCompensateMiddleware::new()),
|
Box::new(CauseCompensateMiddleware::new()),
|
||||||
Box::new(MultiplexMiddleware::new(multiplexer)),
|
Box::new(MultiplexMiddleware::new(multiplexer)),
|
||||||
|
|
65
espanso/src/engine/process/middleware/context_menu.rs
Normal file
65
espanso/src/engine/process/middleware/context_menu.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use super::super::Middleware;
|
||||||
|
use crate::engine::{event::{Event, EventType, ui::{MenuItem, ShowContextMenuEvent, SimpleMenuItem}}};
|
||||||
|
|
||||||
|
pub struct ContextMenuMiddleware {
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContextMenuMiddleware {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Middleware for ContextMenuMiddleware {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"context_menu"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
||||||
|
if let EventType::TrayIconClicked = event.etype {
|
||||||
|
// TODO: fetch top matches for the active config to be added
|
||||||
|
|
||||||
|
// 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: vec![
|
||||||
|
MenuItem::Simple(SimpleMenuItem {
|
||||||
|
id: 0,
|
||||||
|
label: "Exit espanso".to_string(),
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: handle context menu clicks
|
||||||
|
|
||||||
|
event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: test
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
pub mod action;
|
pub mod action;
|
||||||
pub mod cause;
|
pub mod cause;
|
||||||
|
pub mod context_menu;
|
||||||
pub mod cursor_hint;
|
pub mod cursor_hint;
|
||||||
pub mod delay_modifiers;
|
pub mod delay_modifiers;
|
||||||
pub mod exit;
|
pub mod exit;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user