Selection, quick draw, primary action

This commit is contained in:
Armin Friedl 2021-10-17 19:23:50 +02:00
parent 8e38a59432
commit c6ed343acd
4 changed files with 168 additions and 90 deletions

View file

@ -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
}
}
}
}

View file

@ -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

View file

@ -1,4 +1,5 @@
mod ui;
pub use ui::draw_on_window;
pub use ui::draw;
pub use ui::redraw_quick;
mod painter;

View file

@ -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) }
});
}