mirror of
https://github.com/project-gauntlet/gauntlet.git
synced 2025-12-23 10:35:53 +00:00
Use conditional widget to switch between plugin and search view
This commit is contained in:
parent
9bd13fa5c8
commit
1401ef489f
1 changed files with 88 additions and 66 deletions
|
|
@ -2,7 +2,7 @@ use std::path::Path;
|
|||
use gtk::gdk::Key;
|
||||
use gtk::glib;
|
||||
use gtk::prelude::*;
|
||||
use relm4::{ComponentParts, ComponentSender, SimpleComponent};
|
||||
use relm4::{ComponentParts, ComponentSender, RelmRemoveAllExt, SimpleComponent};
|
||||
use relm4::typed_list_view::TypedListView;
|
||||
|
||||
use search_entry::SearchListEntry;
|
||||
|
|
@ -20,6 +20,15 @@ pub struct AppModel {
|
|||
search: SearchHandle,
|
||||
list: TypedListView<SearchListEntry, gtk::SingleSelection>,
|
||||
plugin_manager: PluginManager,
|
||||
state: AppState,
|
||||
}
|
||||
|
||||
enum AppState {
|
||||
SearchView,
|
||||
PluginView {
|
||||
plugin_id: String,
|
||||
entrypoint_id: String,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AppInput {
|
||||
|
|
@ -31,9 +40,11 @@ pub struct AppInput {
|
|||
#[derive(Debug)]
|
||||
pub enum AppMsg {
|
||||
OpenView {
|
||||
plugin_container: gtk::Box,
|
||||
plugin_id: String,
|
||||
entrypoint_id: String,
|
||||
},
|
||||
CloseCurrentView,
|
||||
PromptChanged {
|
||||
value: String
|
||||
}
|
||||
|
|
@ -55,43 +66,60 @@ impl SimpleComponent for AppModel {
|
|||
set_default_height: 400,
|
||||
set_default_width: 650,
|
||||
|
||||
gtk::Box::new(gtk::Orientation::Vertical, 0) {
|
||||
#[name = "search"]
|
||||
gtk::Entry {
|
||||
set_margin_top: SPACING,
|
||||
set_margin_bottom: SPACING,
|
||||
set_margin_start: SPACING,
|
||||
set_margin_end: SPACING,
|
||||
connect_changed[sender] => move |entry| {
|
||||
sender.input(AppMsg::PromptChanged {
|
||||
value: entry.buffer().text().to_string(),
|
||||
});
|
||||
match model.state {
|
||||
AppState::SearchView => {
|
||||
gtk::Box::new(gtk::Orientation::Vertical, 0) {
|
||||
#[name = "search"]
|
||||
gtk::Entry {
|
||||
set_margin_top: SPACING,
|
||||
set_margin_bottom: SPACING,
|
||||
set_margin_start: SPACING,
|
||||
set_margin_end: SPACING,
|
||||
connect_changed[sender] => move |entry| {
|
||||
sender.input(AppMsg::PromptChanged {
|
||||
value: entry.buffer().text().to_string(),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
gtk::Separator::new(gtk::Orientation::Horizontal),
|
||||
|
||||
gtk::ScrolledWindow {
|
||||
set_hscrollbar_policy: gtk::PolicyType::Never,
|
||||
set_vexpand: true,
|
||||
set_margin_top: SPACING,
|
||||
set_margin_bottom: SPACING,
|
||||
set_margin_start: SPACING,
|
||||
set_margin_end: SPACING,
|
||||
|
||||
#[local_ref]
|
||||
list_view -> gtk::ListView {
|
||||
connect_activate[sender, plugin_container] => move |list_view, pos| {
|
||||
let item = get_item_from_list_view(list_view, pos);
|
||||
let item = item.borrow::<SearchListEntry>();
|
||||
|
||||
sender.input(AppMsg::OpenView {
|
||||
plugin_container: plugin_container.clone(),
|
||||
plugin_id: item.plugin_id().to_owned(),
|
||||
entrypoint_id: item.entrypoint_id().to_owned()
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
gtk::Separator::new(gtk::Orientation::Horizontal),
|
||||
|
||||
gtk::ScrolledWindow {
|
||||
set_hscrollbar_policy: gtk::PolicyType::Never,
|
||||
set_vexpand: true,
|
||||
set_margin_top: SPACING,
|
||||
set_margin_bottom: SPACING,
|
||||
set_margin_start: SPACING,
|
||||
set_margin_end: SPACING,
|
||||
|
||||
#[local_ref]
|
||||
list_view -> gtk::ListView {
|
||||
connect_activate[sender] => move |list_view, pos| {
|
||||
let item = get_item_from_list_view(list_view, pos);
|
||||
let item = item.borrow::<SearchListEntry>();
|
||||
|
||||
sender.input(AppMsg::OpenView {
|
||||
plugin_id: item.plugin_id().to_owned(),
|
||||
entrypoint_id: item.entrypoint_id().to_owned()
|
||||
});
|
||||
AppState::PluginView { .. } => {
|
||||
#[name = "plugin_container"]
|
||||
gtk::Box::new(gtk::Orientation::Vertical, 0) {
|
||||
add_controller = gtk::EventControllerKey {
|
||||
connect_key_released[sender] => move |_controller, key, _keycode, _state| {
|
||||
if key == Key::q {
|
||||
sender.input(AppMsg::CloseCurrentView);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -124,6 +152,7 @@ impl SimpleComponent for AppModel {
|
|||
search,
|
||||
list,
|
||||
plugin_manager,
|
||||
state: AppState::SearchView
|
||||
};
|
||||
|
||||
let list_view = &model.list.view;
|
||||
|
|
@ -135,13 +164,30 @@ impl SimpleComponent for AppModel {
|
|||
|
||||
fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>) {
|
||||
match message {
|
||||
AppMsg::OpenView { plugin_id, entrypoint_id} => {
|
||||
create_list_view(
|
||||
self.plugin_manager.clone(),
|
||||
self.window.clone(),
|
||||
&plugin_id,
|
||||
&entrypoint_id,
|
||||
)
|
||||
AppMsg::OpenView { plugin_container, plugin_id, entrypoint_id} => {
|
||||
plugin_container.remove_all();
|
||||
|
||||
let mut ui_context = self.plugin_manager.ui_context(&plugin_id).unwrap();
|
||||
ui_context.set_current_container(plugin_container.clone().upcast::<gtk::Widget>());
|
||||
ui_context.send_event(UiEvent::ViewCreated { view_name: entrypoint_id.to_owned() });
|
||||
|
||||
self.state = AppState::PluginView {
|
||||
plugin_id: plugin_id.clone(),
|
||||
entrypoint_id: entrypoint_id.clone()
|
||||
};
|
||||
}
|
||||
AppMsg::CloseCurrentView => {
|
||||
match &self.state {
|
||||
AppState::SearchView => {
|
||||
panic!("invalid state");
|
||||
}
|
||||
AppState::PluginView { plugin_id, .. } => {
|
||||
let mut ui_context = self.plugin_manager.ui_context(&plugin_id).unwrap();
|
||||
ui_context.send_event(UiEvent::ViewDestroyed);
|
||||
|
||||
self.state = AppState::SearchView;
|
||||
}
|
||||
}
|
||||
}
|
||||
AppMsg::PromptChanged { value } => {
|
||||
let result: Vec<_> = self.search.search(&value).unwrap()
|
||||
|
|
@ -174,27 +220,3 @@ fn get_item_from_list_view(list_view: >k::ListView, position: u32) -> glib::Bo
|
|||
|
||||
return object;
|
||||
}
|
||||
|
||||
fn create_list_view(mut plugin_manager: PluginManager, window: gtk::ApplicationWindow, plugin_id: &str, entrypoint_id: &str) {
|
||||
// FIXME this is ugly, but relm's conditional widgets seem broken when used on enums
|
||||
let mut ui_context = plugin_manager.ui_context(&plugin_id).unwrap();
|
||||
|
||||
let prev_child = window.child().unwrap().clone();
|
||||
|
||||
let container = gtk::Box::new(gtk::Orientation::Vertical, 0);
|
||||
window.set_child(Some(&container.clone()));
|
||||
ui_context.set_current_container(container.clone().upcast::<gtk::Widget>());
|
||||
ui_context.send_event(UiEvent::ViewCreated { view_name: entrypoint_id.to_owned() });
|
||||
|
||||
let window = window.clone();
|
||||
let controller = gtk::EventControllerKey::new();
|
||||
controller.connect_key_pressed(move |_controller, key, _keycode, _state| {
|
||||
if key == Key::q {
|
||||
ui_context.send_event(UiEvent::ViewDestroyed);
|
||||
window.set_child(Some(&prev_child));
|
||||
}
|
||||
|
||||
gtk::Inhibit(false)
|
||||
});
|
||||
container.add_controller(controller);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue