Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion src/input/state/actions/key_press/panels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,11 @@ impl InputState {
_ => true,
}
} else if self.board_picker_focus() == BoardPickerFocus::PagePanel {
self.handle_board_picker_page_panel_key(key)
if let Some(consumed) = self.handle_board_picker_page_nav_key(key) {
consumed
} else {
self.handle_board_picker_page_panel_key(key)
}
} else {
self.handle_board_picker_board_list_key(key)
}
Expand Down Expand Up @@ -348,6 +352,18 @@ impl InputState {
self.board_picker_add_page();
true
}
Key::Char('g') | Key::Char('G') if self.modifiers.ctrl => {
self.board_picker_begin_page_jump();
true
}
Key::Char('f') | Key::Char('F') if self.modifiers.ctrl => {
self.board_picker_begin_page_search();
true
}
Key::Char('/') if !self.modifiers.ctrl && !self.modifiers.alt => {
self.board_picker_begin_page_search();
true
}
Key::Backspace => {
self.board_picker_backspace_search();
true
Expand Down
13 changes: 13 additions & 0 deletions src/input/state/core/board_picker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ const BOARD_PICKER_RECENT_LINE_HEIGHT_COMPACT: f64 = 14.0;
const BOARD_PICKER_RECENT_MAX_NAMES: usize = 3;
const BOARD_PICKER_RECENT_LABEL_MAX_CHARS: usize = BOARD_PICKER_SEARCH_MAX_LEN + 6;
const MAX_PAGE_NAME_LEN: usize = 40;
const BOARD_PICKER_PAGE_SEARCH_MAX_LEN: usize = 40;
const BOARD_PICKER_PAGE_JUMP_MAX_LEN: usize = 6;
const PAGE_PANEL_GAP: f64 = 16.0;
const PAGE_PANEL_PADDING_X: f64 = 12.0;
const PAGE_THUMB_HEIGHT: f64 = 88.0;
Expand Down Expand Up @@ -77,6 +79,10 @@ pub enum BoardPickerState {
page_focus_page_index: Option<usize>,
page_scroll_row: usize,
page_scroll_target_page_index: Option<usize>,
page_nav_mode: BoardPickerPageNavMode,
page_search_query: String,
page_search_cursor: Option<usize>,
page_jump_buffer: String,
},
}

Expand All @@ -92,6 +98,13 @@ pub enum BoardPickerMode {
Quick,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BoardPickerPageNavMode {
Normal,
Jump,
Search,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BoardPickerEditMode {
Name,
Expand Down
1 change: 1 addition & 0 deletions src/input/state/core/board_picker/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ mod actions;
mod drag;
mod edit;
mod lifecycle;
mod nav;
mod ordering;
8 changes: 7 additions & 1 deletion src/input/state/core/board_picker/state/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,19 @@ impl InputState {
{
self.board_picker_queue_page_scroll_to(page_index);
self.board_picker_set_page_focus_page_index(page_index);
self.board_picker_reconcile_page_nav_after_page_change();
}
}

pub(crate) fn board_picker_delete_page(&mut self, page_index: usize) -> PageDeleteOutcome {
let Some(board_index) = self.board_picker_page_panel_board_index() else {
return PageDeleteOutcome::Pending;
};
self.delete_page_in_board(board_index, page_index)
let outcome = self.delete_page_in_board(board_index, page_index);
if !matches!(outcome, PageDeleteOutcome::Pending) {
self.board_picker_reconcile_page_nav_after_page_change();
}
outcome
}

pub(crate) fn board_picker_duplicate_page(&mut self, page_index: usize) {
Expand All @@ -83,6 +88,7 @@ impl InputState {
{
self.board_picker_queue_page_scroll_to(new_page_index);
self.board_picker_set_page_focus_page_index(new_page_index);
self.board_picker_reconcile_page_nav_after_page_change();
}
}

Expand Down
29 changes: 26 additions & 3 deletions src/input/state/core/board_picker/state/edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use super::super::super::base::{InputState, UiToastKind};
use super::super::{
BOARD_PICKER_RECENT_LABEL_MAX_CHARS, BOARD_PICKER_RECENT_MAX_NAMES,
BOARD_PICKER_SEARCH_MAX_LEN, BoardPickerEdit, BoardPickerEditMode, BoardPickerFocus,
BoardPickerMode, BoardPickerPageEdit, BoardPickerState, MAX_BOARD_NAME_LEN, MAX_PAGE_NAME_LEN,
color_to_hex, parse_hex_color, truncate_search_label,
BoardPickerMode, BoardPickerPageEdit, BoardPickerPageNavMode, BoardPickerState,
MAX_BOARD_NAME_LEN, MAX_PAGE_NAME_LEN, color_to_hex, parse_hex_color, truncate_search_label,
};

impl InputState {
Expand Down Expand Up @@ -73,6 +73,7 @@ impl InputState {
let name = edit.buffer.trim().to_string();
let name = if name.is_empty() { None } else { Some(name) };
let _ = self.rename_page_in_board(edit.board_index, edit.page_index, name);
self.board_picker_reconcile_page_nav_after_page_change();
self.needs_redraw = true;
true
}
Expand Down Expand Up @@ -105,6 +106,20 @@ impl InputState {
}

pub(crate) fn board_picker_footer_text(&self) -> String {
match self.board_picker_page_nav_mode() {
BoardPickerPageNavMode::Jump => {
let buffer = self.board_picker_page_jump_buffer().unwrap_or_default();
return format!("Go to page: {buffer} Enter: go Esc: cancel");
}
BoardPickerPageNavMode::Search => {
let query = self.board_picker_page_search_query().unwrap_or_default();
if !query.trim().is_empty() && self.board_picker_page_search_match_count() == 0 {
return format!("Search pages: {query} No matches Esc: clear");
}
return format!("Search pages: {query} Enter: open F3: next Esc: clear");
}
BoardPickerPageNavMode::Normal => {}
}
let search = self.board_picker_search.trim();
if !search.is_empty() {
return format!(
Expand All @@ -115,7 +130,7 @@ impl InputState {
if self.board_picker_is_quick() {
"Enter: switch Type: jump Esc: close".to_string()
} else if self.board_picker_focus() == BoardPickerFocus::PagePanel {
"Enter: open Ctrl+N: add F2: rename Del: delete Tab: back".to_string()
"Enter: open Ctrl+N: add Ctrl+G: page /: search F2: rename".to_string()
} else {
let page_panel_enabled = self
.board_picker_layout
Expand Down Expand Up @@ -206,6 +221,10 @@ impl InputState {
page_focus_page_index,
page_scroll_row,
page_scroll_target_page_index,
page_nav_mode,
page_search_query,
page_search_cursor,
page_jump_buffer,
} = &mut self.board_picker_state
else {
return;
Expand All @@ -220,6 +239,10 @@ impl InputState {
*page_focus_page_index = None;
*page_scroll_row = 0;
*page_scroll_target_page_index = selected_active_page;
*page_nav_mode = BoardPickerPageNavMode::Normal;
page_search_query.clear();
*page_search_cursor = None;
page_jump_buffer.clear();
if let Some(row) = selected_row_full {
*selected = row;
}
Expand Down
94 changes: 71 additions & 23 deletions src/input/state/core/board_picker/state/lifecycle.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::super::super::base::InputState;
use super::super::{BoardPickerFocus, BoardPickerMode, BoardPickerState};
use super::super::{BoardPickerFocus, BoardPickerMode, BoardPickerPageNavMode, BoardPickerState};

impl InputState {
pub(crate) fn is_board_picker_open(&self) -> bool {
Expand Down Expand Up @@ -39,6 +39,10 @@ impl InputState {
page_focus_page_index: None,
page_scroll_row: 0,
page_scroll_target_page_index: Some(active_page),
page_nav_mode: BoardPickerPageNavMode::Normal,
page_search_query: String::new(),
page_search_cursor: None,
page_jump_buffer: String::new(),
};
let selected_row = self.board_picker_row_for_board(active_index);
if let (Some(selected), BoardPickerState::Open { selected: row, .. }) =
Expand Down Expand Up @@ -72,6 +76,10 @@ impl InputState {
page_focus_page_index: None,
page_scroll_row: 0,
page_scroll_target_page_index: Some(active_page),
page_nav_mode: BoardPickerPageNavMode::Normal,
page_search_query: String::new(),
page_search_cursor: None,
page_jump_buffer: String::new(),
};
let selected_row = self.board_picker_row_for_board(active_index);
if let (Some(selected), BoardPickerState::Open { selected: row, .. }) =
Expand Down Expand Up @@ -163,6 +171,10 @@ impl InputState {
focus,
page_focus_page_index,
page_scroll_target_page_index,
page_nav_mode,
page_search_query,
page_search_cursor,
page_jump_buffer,
..
} = &mut self.board_picker_state
else {
Expand All @@ -178,6 +190,10 @@ impl InputState {
}
BoardPickerFocus::BoardList => {
*page_focus_page_index = None;
*page_nav_mode = BoardPickerPageNavMode::Normal;
page_search_query.clear();
*page_search_cursor = None;
page_jump_buffer.clear();
}
}
self.needs_redraw = true;
Expand Down Expand Up @@ -237,12 +253,20 @@ impl InputState {
page_focus_page_index,
page_scroll_row,
page_scroll_target_page_index,
page_nav_mode,
page_search_query,
page_search_cursor,
page_jump_buffer,
..
} = &mut self.board_picker_state
{
*selected = next;
*focus = BoardPickerFocus::BoardList;
*page_focus_page_index = None;
*page_nav_mode = BoardPickerPageNavMode::Normal;
page_search_query.clear();
*page_search_cursor = None;
page_jump_buffer.clear();
if previous_board != Some(next_board) {
*page_scroll_row = 0;
*page_scroll_target_page_index = Some(next_active_page);
Expand Down Expand Up @@ -321,38 +345,62 @@ impl InputState {
let cols = layout.page_cols.max(1);
let visible_slots = layout.page_visible_slots.max(1);
let page_count = layout.page_count;
let Some((scroll_row, _, _)) = self.board_picker_page_panel_state_parts() else {
return false;
};
let current = scroll_row.min(max);
let next = if delta_rows.is_negative() {
current.saturating_sub(delta_rows.unsigned_abs())
} else {
current.saturating_add(delta_rows as usize).min(max)
};
if scroll_row == next {
return false;
}
let first_visible = next.saturating_mul(cols).min(page_count);
let last_visible = first_visible
.saturating_add(visible_slots)
.min(page_count)
.saturating_sub(1);
let visible_search_match = (self.board_picker_page_nav_mode()
== BoardPickerPageNavMode::Search)
.then(|| {
self.board_picker_page_search_visible_match(
first_visible,
last_visible,
delta_rows.is_negative(),
)
})
.flatten();
if let BoardPickerState::Open {
page_scroll_row,
page_focus_page_index,
page_scroll_target_page_index,
page_nav_mode,
page_search_cursor,
..
} = &mut self.board_picker_state
{
let current = (*page_scroll_row).min(max);
let next = if delta_rows.is_negative() {
current.saturating_sub(delta_rows.unsigned_abs())
} else {
current.saturating_add(delta_rows as usize).min(max)
};
*page_scroll_target_page_index = None;
if *page_scroll_row != next {
*page_scroll_row = next;
if let Some(focus_page) = page_focus_page_index {
let first_visible = next.saturating_mul(cols).min(page_count);
let last_visible = first_visible
.saturating_add(visible_slots)
.min(page_count)
.saturating_sub(1);
if *focus_page < first_visible {
*page_focus_page_index = Some(first_visible.min(last_visible));
} else if *focus_page > last_visible {
*page_focus_page_index = Some(last_visible);
}
*page_scroll_row = next;
if *page_nav_mode == BoardPickerPageNavMode::Search {
if let Some((cursor, page_index)) = visible_search_match {
*page_search_cursor = Some(cursor);
*page_focus_page_index = Some(page_index);
} else {
*page_search_cursor = None;
*page_focus_page_index = None;
}
} else if let Some(focus_page) = page_focus_page_index {
if *focus_page < first_visible {
*page_focus_page_index = Some(first_visible.min(last_visible));
} else if *focus_page > last_visible {
*page_focus_page_index = Some(last_visible);
}
self.needs_redraw = true;
self.dirty_tracker.mark_full();
return true;
}
self.needs_redraw = true;
self.dirty_tracker.mark_full();
return true;
}
false
}
Expand Down
Loading
Loading