feat: search (#64)

* core func implemented

* its buggy but its something

* hide sidebar when searching

* optimize filter_options by using values iterator

* don't show categories

---------

Co-authored-by: Adam Perkowski <adas1per@protonmail.com>
This commit is contained in:
nyx
2024-11-02 18:11:37 -04:00
committed by GitHub
parent 4e601217d2
commit ff2a150431
2 changed files with 95 additions and 8 deletions

View File

@@ -1,7 +1,7 @@
use gtk::{
gdk, glib, prelude::*, Application, ApplicationWindow, Box, Button, ColorButton, DropDown,
Entry, Frame, HeaderBar, Image, Label, MessageDialog, Orientation, Popover, ScrolledWindow,
SpinButton, Stack, StackSidebar, StringList, Switch, Widget,
SearchEntry, SpinButton, Stack, StackSidebar, StringList, Switch, Widget,
};
use hyprparser::HyprlandConfig;
@@ -68,12 +68,13 @@ fn add_dropdown_option(
pub struct ConfigGUI {
pub window: ApplicationWindow,
config_widgets: HashMap<String, ConfigWidget>,
pub config_widgets: HashMap<String, ConfigWidget>,
pub save_button: Button,
pub search_entry: SearchEntry,
content_box: Box,
changed_options: Rc<RefCell<HashMap<(String, String), String>>>,
stack: Stack,
sidebar: StackSidebar,
pub sidebar: StackSidebar,
load_config_button: Button,
save_config_button: Button,
pub gear_menu: Rc<RefCell<Popover>>,
@@ -104,6 +105,15 @@ impl ConfigGUI {
gear_menu_box.set_margin_start(5);
gear_menu_box.set_margin_end(5);
let search_button = Button::from_icon_name("system-search-symbolic");
let search_entry = SearchEntry::new();
search_entry.set_width_chars(25);
let popover = gtk::Popover::new();
popover.set_child(Some(&search_entry));
popover.set_position(gtk::PositionType::Bottom);
popover.set_parent(&search_button);
let save_config_button = Button::with_label("Save HyprGUI Config");
let load_config_button = Button::with_label("Load HyprGUI Config");
@@ -112,11 +122,34 @@ impl ConfigGUI {
gear_menu.borrow().set_child(Some(&gear_menu_box));
let gear_menu_clone = gear_menu.clone();
gear_button.connect_clicked(move |_| {
gear_menu_clone.borrow().popup();
let popover_clone = popover.clone();
let search_entry_clone = search_entry.clone();
search_button.connect_clicked(move |_| {
if !popover_clone.is_visible() {
popover_clone.popup();
search_entry_clone.grab_focus();
}
});
let popover_clone = popover.clone();
search_entry.connect_activate(move |_| {
popover_clone.popdown();
});
let popover_clone = popover.clone();
let key_controller = gtk::EventControllerKey::new();
key_controller.connect_key_pressed(move |_, key, _, _| {
if key == gdk::Key::Escape {
popover_clone.popdown();
glib::Propagation::Stop
} else {
glib::Propagation::Proceed
}
});
search_entry.add_controller(key_controller);
header_bar.pack_start(&search_button);
let save_button = Button::with_label("Save");
header_bar.pack_end(&save_button);
@@ -141,6 +174,7 @@ impl ConfigGUI {
window,
config_widgets,
save_button,
search_entry,
content_box,
changed_options: Rc::new(RefCell::new(HashMap::new())),
stack,
@@ -562,8 +596,8 @@ fn get_option_limits(name: &str, description: &str) -> (f64, f64, f64) {
}
pub struct ConfigWidget {
options: HashMap<String, Widget>,
scrolled_window: ScrolledWindow,
pub options: HashMap<String, Widget>,
pub scrolled_window: ScrolledWindow,
}
impl ConfigWidget {

View File

@@ -53,6 +53,11 @@ fn build_ui(app: &Application) {
save_config_file(gui_clone.clone());
});
let gui_clone = gui.clone();
gui.borrow().search_entry.connect_changed(move |entry| {
filter_options(gui_clone.clone(), entry.text());
});
let undo_button = Button::with_label("Undo Changes");
let copy_button = Button::with_label("Copyright");
@@ -103,6 +108,54 @@ along with this program; if not, see
gui.borrow().window.present();
}
fn filter_options(gui: Rc<RefCell<gui::ConfigGUI>>, search_text: impl AsRef<str>) {
let gui_ref = gui.borrow();
let search_text = search_text.as_ref().to_lowercase();
gui_ref.sidebar.set_visible(search_text.is_empty());
for config_widget in gui_ref.config_widgets.values() {
if search_text.is_empty() {
config_widget.scrolled_window.set_visible(true);
if let Some(scrolled) = config_widget.scrolled_window.child() {
if let Some(container) = scrolled.first_child() {
let mut child = container.first_child();
while let Some(widget) = child {
widget.set_visible(true);
child = widget.next_sibling();
}
}
}
} else {
let mut has_matches = false;
if let Some(scrolled) = config_widget.scrolled_window.child() {
if let Some(container) = scrolled.first_child() {
let mut child = container.first_child();
while let Some(widget) = child {
widget.set_visible(false);
if let Some(box_widget) = widget.downcast_ref::<gtk::Box>() {
if let Some(label_box) = box_widget.first_child() {
if let Some(label) = label_box.first_child() {
if let Some(label) = label.downcast_ref::<gtk::Label>() {
if label.text().to_lowercase().contains(&search_text) {
has_matches = true;
widget.set_visible(true);
}
}
}
}
}
child = widget.next_sibling();
}
}
}
config_widget.scrolled_window.set_visible(has_matches);
}
}
}
fn save_config_file(gui: Rc<RefCell<gui::ConfigGUI>>) {
let mut gui_ref = gui.borrow_mut();
let path = get_config_path();