Selection, quick draw, primary action
This commit is contained in:
parent
8e38a59432
commit
c6ed343acd
4 changed files with 168 additions and 90 deletions
104
src/main.rs
104
src/main.rs
|
@ -13,6 +13,8 @@ mod ui;
|
|||
mod sources;
|
||||
mod matcher;
|
||||
|
||||
use roftl::{Roftl, Entry};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
env_logger::init();
|
||||
|
||||
|
@ -36,50 +38,88 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
debug!{"Window id: {:?}", window.id()}
|
||||
|
||||
debug!{"Draw empty state to window"}
|
||||
ui::draw_on_window(&window, "", vec![]);
|
||||
|
||||
let mut input_buffer = String::new();
|
||||
ui::draw(&window, "", vec![], 0);
|
||||
|
||||
debug!{"Start event loop"}
|
||||
let roftl_loop = RoftlLoop::new(roftl, window);
|
||||
roftl_loop.run(event_loop);
|
||||
}
|
||||
|
||||
struct RoftlLoop {
|
||||
input_buffer: String,
|
||||
input_changed: bool,
|
||||
selection: usize,
|
||||
roftl: Roftl,
|
||||
window: Window,
|
||||
}
|
||||
|
||||
impl RoftlLoop {
|
||||
fn new(roftl: Roftl, window: Window) -> Self
|
||||
{
|
||||
RoftlLoop{input_buffer: String::default(), input_changed: true, selection: 0, roftl, window}
|
||||
}
|
||||
|
||||
fn run<T>(mut self, event_loop: EventLoop<T>) -> !
|
||||
{
|
||||
event_loop.run(move |evt, _win, flow| {
|
||||
*flow = ControlFlow::Wait;
|
||||
|
||||
match evt {
|
||||
Event::WindowEvent{event: CloseRequested, window_id}
|
||||
if window_id == window.id() =>
|
||||
if window_id == self.window.id() =>
|
||||
{
|
||||
*flow = ControlFlow::Exit;
|
||||
}
|
||||
|
||||
Event::WindowEvent{event: ReceivedCharacter(character), window_id}
|
||||
if window_id == window.id() =>
|
||||
if window_id == self.window.id() =>
|
||||
{
|
||||
*flow = process_character(character, &mut input_buffer, &window);
|
||||
*flow = self.process_character(character);
|
||||
}
|
||||
|
||||
Event::WindowEvent{event: winit::event::WindowEvent::KeyboardInput{input, ..}, window_id}
|
||||
if window_id == window.id() =>
|
||||
if window_id == self.window.id() =>
|
||||
{
|
||||
process_input(input, &mut input_buffer, &window);
|
||||
self.process_input(input);
|
||||
}
|
||||
|
||||
Event::RedrawRequested(window_id)
|
||||
if window_id == window.id() =>
|
||||
if window_id == self.window.id() =>
|
||||
{
|
||||
trace!{"Redrawing with input {}", input_buffer}
|
||||
if self.input_changed {
|
||||
trace!{"Redrawing with input {}", self.input_buffer}
|
||||
|
||||
let result = roftl.narrow(&input_buffer);
|
||||
trace!{"Narrow result {:?}", result}
|
||||
let results = self.roftl.narrow(&self.input_buffer);
|
||||
trace!{"Narrow result {:?}", results}
|
||||
|
||||
ui::draw_on_window(&window, &input_buffer, result);
|
||||
// correct selection for results
|
||||
if results.len() > 0 { self.selection = self.selection % results.len() }
|
||||
else { self.selection = 0 }
|
||||
|
||||
ui::draw(&self.window, &self.input_buffer, results, self.selection);
|
||||
} else {
|
||||
trace!{"Quick redraw with input {}", self.input_buffer}
|
||||
|
||||
let results = self.roftl.narrow(&self.input_buffer);
|
||||
trace!{"Narrow result {:?}", results}
|
||||
|
||||
// correct selection for results
|
||||
if results.len() > 0 { self.selection = self.selection % results.len() }
|
||||
else { self.selection = 0 }
|
||||
|
||||
ui::redraw_quick(&self.window, results, self.selection);
|
||||
}
|
||||
|
||||
self.input_changed = false;
|
||||
}
|
||||
|
||||
_ => ()
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
fn process_input(input: KeyboardInput, input_buffer: &mut String, window: &Window) -> ControlFlow {
|
||||
fn process_input(&mut self, input: KeyboardInput) -> ControlFlow {
|
||||
if let KeyboardInput { virtual_keycode: Some(code), state, .. } = input {
|
||||
return match (code, state) {
|
||||
(VirtualKeyCode::Down, ElementState::Released) => {
|
||||
|
@ -98,8 +138,7 @@ fn process_input(input: KeyboardInput, input_buffer: &mut String, window: &Windo
|
|||
ControlFlow::Wait
|
||||
}
|
||||
|
||||
|
||||
fn process_character(character: char, input_buffer: &mut String, window: &Window) -> ControlFlow {
|
||||
fn process_character(&mut self, character: char) -> ControlFlow {
|
||||
match character {
|
||||
'q' | 'Q' => ControlFlow::Exit,
|
||||
|
||||
|
@ -109,20 +148,32 @@ fn process_character(character: char, input_buffer: &mut String, window: &Window
|
|||
// Backspace
|
||||
c if c == char::from(0x08) => {
|
||||
trace!{"Retrieved backspace. Pop char from input"}
|
||||
input_buffer.pop();
|
||||
window.request_redraw();
|
||||
self.input_buffer.pop();
|
||||
self.input_changed = true;
|
||||
self.window.request_redraw();
|
||||
ControlFlow::Wait
|
||||
}
|
||||
|
||||
// Ctrl+n
|
||||
c if c == char::from(0x0e) => {
|
||||
debug!{"Received Ctrl+next"}
|
||||
// Enter
|
||||
c if c == char::from(0x0d) => {
|
||||
trace!{"Retrieved enter. Trigger primary action"}
|
||||
self.roftl.action(self.selection, roftl::Action::Primary);
|
||||
ControlFlow::Exit
|
||||
}
|
||||
|
||||
// Ctrl+n or tab
|
||||
c if c == char::from(0x0e) || c == char::from(0x09) => {
|
||||
debug!{"Received next"}
|
||||
self.selection += 1;
|
||||
self.window.request_redraw();
|
||||
ControlFlow::Wait
|
||||
}
|
||||
|
||||
// Ctrl+p
|
||||
c if c == char::from(0x10) => {
|
||||
debug!{"Received Ctrl+previous"}
|
||||
debug!{"Received previous"}
|
||||
if self.selection != 0 { self.selection -= 1 }
|
||||
self.window.request_redraw();
|
||||
ControlFlow::Wait
|
||||
}
|
||||
|
||||
|
@ -133,9 +184,14 @@ fn process_character(character: char, input_buffer: &mut String, window: &Window
|
|||
|
||||
_ => {
|
||||
trace!{"Push {} to input buffer", character}
|
||||
input_buffer.push(character);
|
||||
window.request_redraw();
|
||||
self.input_buffer.push(character);
|
||||
self.input_changed = true;
|
||||
self.window.request_redraw();
|
||||
ControlFlow::Wait
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{any::type_name, collections::HashMap, sync::{Arc, Mutex, atomic::{AtomicUsize, Ordering}}};
|
||||
use std::{any::type_name, collections::HashMap, sync::{Arc, Mutex, atomic::{AtomicUsize, Ordering}}, usize};
|
||||
|
||||
use log::debug;
|
||||
use rayon::{iter::{IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator}, slice::ParallelSliceMut};
|
||||
|
@ -100,10 +100,10 @@ impl Roftl {
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub fn action(&self, entry_id: i32, action: Action) {
|
||||
pub fn action(&self, entry_id: usize, action: Action) {
|
||||
println!("NarrowMap {:?}", self.narrow_map.lock().unwrap());
|
||||
|
||||
let real_id = *self.narrow_map.lock().unwrap().get(&((entry_id-1) as usize)).unwrap();
|
||||
let real_id = *self.narrow_map.lock().unwrap().get(&entry_id).unwrap();
|
||||
let entry = self.entries.get(real_id).unwrap();
|
||||
|
||||
let source = self
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
mod ui;
|
||||
pub use ui::draw_on_window;
|
||||
pub use ui::draw;
|
||||
pub use ui::redraw_quick;
|
||||
|
||||
mod painter;
|
||||
|
|
25
src/ui/ui.rs
25
src/ui/ui.rs
|
@ -71,7 +71,7 @@ fn make_context(window: &Window) -> cairo::Context
|
|||
cairo::Context::new(&surface).expect("Could not create drawing context")
|
||||
}
|
||||
|
||||
pub fn draw_on_window(window: &Window, input: &str, result: Vec<&Entry>)
|
||||
pub fn draw(window: &Window, input: &str, result: Vec<&Entry>, selection: usize)
|
||||
{
|
||||
let context = make_context(&window);
|
||||
|
||||
|
@ -85,7 +85,28 @@ pub fn draw_on_window(window: &Window, input: &str, result: Vec<&Entry>)
|
|||
|
||||
result.iter().enumerate()
|
||||
.for_each(|(i, e)| {
|
||||
painter.result_box(0, 1+(i as u32), &e.name, false);
|
||||
painter.result_box(0, 1+(i as u32), &e.name, selection==i);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn redraw_quick(window: &Window, result: Vec<&Entry>, selection: usize) {
|
||||
let context = make_context(&window);
|
||||
|
||||
context.scale(30.0, 30.0);
|
||||
|
||||
let painter = painter::Painter::new(&context);
|
||||
|
||||
result.iter().enumerate()
|
||||
.for_each(|(i, e)| {
|
||||
// clear first and last as these may produce artifacts otherwise
|
||||
if i == 0 { painter.result_box(0, 1+(i as u32), &e.name, false) }
|
||||
if i == result.len()-1 { painter.result_box(0, 1+(i as u32), &e.name, false) }
|
||||
|
||||
// clear boxes around selection as these could be the old selection
|
||||
if selection > 0 && i == (selection-1) { painter.result_box(0, 1+(i as u32), &e.name, false) }
|
||||
if i == (selection+1) { painter.result_box(0, 1+(i as u32), &e.name, false) }
|
||||
|
||||
// mark selection, note that this negates any unmarking above in case they are the same
|
||||
if i == selection { painter.result_box(0, 1+(i as u32), &e.name, true) }
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue