use gtk::gdk::keys::constants::Return as RETURN; use gtk::glib; use gtk::prelude::*; use super::state::{View, ViewManager}; use std::rc::Rc; use std::thread; pub struct Search { vm : Rc } impl View for Search { fn name(&self) -> &str { "search" } fn set_vm(&mut self, vm : Rc) { self.vm = vm } fn make_current(&self) -> Option { let main = gtk::Box::new(gtk::Orientation::Vertical, 0); let scroll = gtk::ScrolledWindow::new(gtk::Adjustment::NONE, gtk::Adjustment::NONE); let search = gtk::SearchEntry::new(); let progress = gtk::ProgressBar::new(); search.set_widget_name("search_entry"); main.pack_start(&search, false, false, 0); main.pack_start(&progress, false, false, 0); let list = gtk::ListBox::new(); scroll.add(&list); let empty_container = gtk::Box::new(gtk::Orientation::Vertical, 0); let bt = include_bytes!("icon.svg"); let loader = gtk::gdk_pixbuf::PixbufLoader::new(); loader.write(bt).ok(); loader.set_size(200, 200); loader.close().ok(); let pixbuf = loader.pixbuf().unwrap(); let image = gtk::Image::from_pixbuf(Some(&pixbuf)); empty_container.pack_start(&image, true, true, 0); main.pack_start(&empty_container, true, true, 0); let vm = Rc::clone(&self.vm); search.connect_key_press_event(glib::clone!( @strong scroll, @strong list, @weak progress, @weak main, @strong empty_container => @default-return gtk::Inhibit(false), move |entry, event| { match event.keyval() { RETURN => { let query = entry.text().to_string(); if query.is_empty() { main.remove(&scroll); main.remove(&empty_container); main.pack_start(&empty_container, true, true, 0); return gtk::Inhibit(false); } let (tx, rx) = glib::MainContext::channel(glib::Priority::default()); let (status_tx, status_rx) = glib::MainContext::channel(glib::Priority::default()); let index = vm.get_index(); thread::spawn(move || { let searchvec = crate::splitter::split_to_words(query); let results = index.lock().unwrap().search(searchvec, |p| { status_tx.send(p).ok(); }); tx.send(results).ok(); }); status_rx.attach(None, glib::clone!( @weak progress => @default-return glib::Continue(true), move |p| { progress.set_fraction(f64::from(p) / 100.0); if p == 100 { glib::Continue(false) } else { glib::Continue(true) } })); rx.attach(None, glib::clone!( @weak empty_container, @weak progress, @weak list, @weak scroll => @default-return glib::Continue(false), move |results| { main.remove(&scroll); main.remove(&empty_container); progress.set_fraction(0.0); if results.is_empty() { main.pack_start(&empty_container, true, true, 0); return glib::Continue(false); } else { for child in list.children() { list.remove(&child); } for result in results.iter().rev().take(1000) { let entry = gtk::Box::new(gtk::Orientation::Horizontal, 0); entry.set_margin(10); let path_label = gtk::Label::new(Some(&result.path)); let prio_label = gtk::Label::new(Some(&result.priority.to_string())); entry.pack_start(&prio_label, false, false, 10); entry.pack_start(&path_label, true, true, 10); list.prepend(&entry) } main.pack_start(&scroll, true, true, 0); } main.show_all(); glib::Continue(false) })); } _ => {} } gtk::Inhibit(false) })); Some(main) } } impl Search { pub fn new() -> Self { Self { vm : Rc::new(ViewManager::empty()) } } }