Selection, quick draw, primary action
This commit is contained in:
parent
8e38a59432
commit
c6ed343acd
4 changed files with 168 additions and 90 deletions
108
src/main.rs
108
src/main.rs
|
@ -13,6 +13,8 @@ mod ui;
|
||||||
mod sources;
|
mod sources;
|
||||||
mod matcher;
|
mod matcher;
|
||||||
|
|
||||||
|
use roftl::{Roftl, Entry};
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
|
@ -36,50 +38,88 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
debug!{"Window id: {:?}", window.id()}
|
debug!{"Window id: {:?}", window.id()}
|
||||||
|
|
||||||
debug!{"Draw empty state to window"}
|
debug!{"Draw empty state to window"}
|
||||||
ui::draw_on_window(&window, "", vec![]);
|
ui::draw(&window, "", vec![], 0);
|
||||||
|
|
||||||
let mut input_buffer = String::new();
|
|
||||||
|
|
||||||
debug!{"Start event loop"}
|
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| {
|
event_loop.run(move |evt, _win, flow| {
|
||||||
*flow = ControlFlow::Wait;
|
*flow = ControlFlow::Wait;
|
||||||
|
|
||||||
match evt {
|
match evt {
|
||||||
Event::WindowEvent{event: CloseRequested, window_id}
|
Event::WindowEvent{event: CloseRequested, window_id}
|
||||||
if window_id == window.id() =>
|
if window_id == self.window.id() =>
|
||||||
{
|
{
|
||||||
*flow = ControlFlow::Exit;
|
*flow = ControlFlow::Exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::WindowEvent{event: ReceivedCharacter(character), window_id}
|
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}
|
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)
|
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);
|
let results = self.roftl.narrow(&self.input_buffer);
|
||||||
trace!{"Narrow result {:?}", result}
|
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 {
|
if let KeyboardInput { virtual_keycode: Some(code), state, .. } = input {
|
||||||
return match (code, state) {
|
return match (code, state) {
|
||||||
(VirtualKeyCode::Down, ElementState::Released) => {
|
(VirtualKeyCode::Down, ElementState::Released) => {
|
||||||
|
@ -96,10 +136,9 @@ fn process_input(input: KeyboardInput, input_buffer: &mut String, window: &Windo
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlFlow::Wait
|
ControlFlow::Wait
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process_character(&mut self, character: char) -> ControlFlow {
|
||||||
fn process_character(character: char, input_buffer: &mut String, window: &Window) -> ControlFlow {
|
|
||||||
match character {
|
match character {
|
||||||
'q' | 'Q' => ControlFlow::Exit,
|
'q' | 'Q' => ControlFlow::Exit,
|
||||||
|
|
||||||
|
@ -109,20 +148,32 @@ fn process_character(character: char, input_buffer: &mut String, window: &Window
|
||||||
// Backspace
|
// Backspace
|
||||||
c if c == char::from(0x08) => {
|
c if c == char::from(0x08) => {
|
||||||
trace!{"Retrieved backspace. Pop char from input"}
|
trace!{"Retrieved backspace. Pop char from input"}
|
||||||
input_buffer.pop();
|
self.input_buffer.pop();
|
||||||
window.request_redraw();
|
self.input_changed = true;
|
||||||
|
self.window.request_redraw();
|
||||||
ControlFlow::Wait
|
ControlFlow::Wait
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ctrl+n
|
// Enter
|
||||||
c if c == char::from(0x0e) => {
|
c if c == char::from(0x0d) => {
|
||||||
debug!{"Received Ctrl+next"}
|
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
|
ControlFlow::Wait
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ctrl+p
|
// Ctrl+p
|
||||||
c if c == char::from(0x10) => {
|
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
|
ControlFlow::Wait
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,9 +184,14 @@ fn process_character(character: char, input_buffer: &mut String, window: &Window
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
trace!{"Push {} to input buffer", character}
|
trace!{"Push {} to input buffer", character}
|
||||||
input_buffer.push(character);
|
self.input_buffer.push(character);
|
||||||
window.request_redraw();
|
self.input_changed = true;
|
||||||
|
self.window.request_redraw();
|
||||||
ControlFlow::Wait
|
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 log::debug;
|
||||||
use rayon::{iter::{IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator}, slice::ParallelSliceMut};
|
use rayon::{iter::{IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator}, slice::ParallelSliceMut};
|
||||||
|
@ -100,10 +100,10 @@ impl Roftl {
|
||||||
.collect()
|
.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());
|
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 entry = self.entries.get(real_id).unwrap();
|
||||||
|
|
||||||
let source = self
|
let source = self
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
mod ui;
|
mod ui;
|
||||||
pub use ui::draw_on_window;
|
pub use ui::draw;
|
||||||
|
pub use ui::redraw_quick;
|
||||||
|
|
||||||
mod painter;
|
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")
|
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);
|
let context = make_context(&window);
|
||||||
|
|
||||||
|
@ -85,7 +85,28 @@ pub fn draw_on_window(window: &Window, input: &str, result: Vec<&Entry>)
|
||||||
|
|
||||||
result.iter().enumerate()
|
result.iter().enumerate()
|
||||||
.for_each(|(i, e)| {
|
.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