use ratatui::Frame;
use ratatui::layout::Rect;
use ratatui::style::Style;
use ratatui::widgets::{Block, Borders, ListItem};
use crate::config::UblxPaths;
use crate::layout::{setup, style};
use crate::ui::{UI_STRINGS, chord_chrome_active};
use super::middle::{CONTENTS_LIST_VIRTUALIZE_MIN, contents_list_viewport};
pub fn draw_categories_pane(
f: &mut Frame,
state: &mut setup::UblxState,
view: &setup::ViewData,
chunks: &[Rect],
) {
let area = chunks[0];
let focused = matches!(state.panels.focus, setup::PanelFocus::Categories);
let title = super::panel_title_line(
UI_STRINGS.pane.categories,
focused,
chord_chrome_active(&state.chrome),
);
let mut items = vec![ListItem::new(UI_STRINGS.list.all_categories)];
items.extend(
view.filtered_categories
.iter()
.map(|s| ListItem::new(s.as_str())),
);
let block = super::panel_block(title, focused);
super::draw_list_panel(
f,
items,
block,
state.panels.highlight_style,
focused,
&mut state.panels.category_state,
area,
);
}
#[must_use]
pub fn contents_display_label(
path: &str,
category: &str,
dir_to_ublx: Option<&std::path::Path>,
) -> String {
if category != "UBLX Settings" {
return path.to_string();
}
let Some(dir) = dir_to_ublx else {
return path.to_string();
};
let paths = UblxPaths::new(dir);
let local = paths
.toml_path()
.and_then(|p| p.file_name().map(|n| n.to_string_lossy().into_owned()));
let global = paths
.global_config()
.map(|p| p.to_string_lossy().into_owned());
if local.as_deref() == Some(path) {
UI_STRINGS.config.local.to_string()
} else if global.as_deref() == Some(path) {
UI_STRINGS.config.global.to_string()
} else {
path.to_string()
}
}
fn contents_panel_block(
state: &setup::UblxState,
view: &setup::ViewData,
focused: bool,
transparent_page_chrome: bool,
) -> Block<'static> {
let left_title = super::panel_title_line(
UI_STRINGS.pane.contents,
focused,
chord_chrome_active(&state.chrome),
);
Block::default()
.borders(Borders::ALL)
.border_style(if focused {
style::panel_focused()
} else {
style::panel_unfocused()
})
.title_style(Style::default())
.title(left_title)
.title_bottom(super::line_for(super::MiddlePaneFooterLineCtx {
selected_index: state.panels.content_state.selected(),
content_len: view.content_len,
main_mode: state.main_mode,
sort: state.panels.content_sort,
chord_mode: chord_chrome_active(&state.chrome),
multiselect_active: state.multiselect.active,
multiselect_count: state.multiselect.selected.len(),
transparent_page_chrome,
}))
}
fn contents_panel_list_items(
state: &setup::UblxState,
view: &setup::ViewData,
all_rows: Option<&[setup::TuiRow]>,
dir_to_ublx: Option<&std::path::Path>,
area: Rect,
global_sel: usize,
) -> (Vec<ListItem<'static>>, Option<usize>) {
let total = view.content_len;
let max_cols = area.width.saturating_sub(2) as usize;
if total == 0 {
return (
vec![ListItem::new(if state.search.query.is_empty() {
UI_STRINGS.list.no_contents
} else {
UI_STRINGS.list.no_matches
})],
None,
);
}
if total >= CONTENTS_LIST_VIRTUALIZE_MIN
&& matches!(&view.contents, setup::ViewContents::SnapshotIndices(_))
&& let Some(all_rows_slice) = all_rows
{
let inner_h = area.height.saturating_sub(2).max(1) as usize;
let (w_start, w_end) = contents_list_viewport(total, global_sel, inner_h);
let items = (w_start..w_end)
.map(|i| {
super::middle::contents_list_item_for_row(
state,
view,
Some(all_rows_slice),
dir_to_ublx,
i,
global_sel,
max_cols,
)
})
.collect();
return (items, Some(w_start));
}
let items = (0..total)
.map(|i| {
super::middle::contents_list_item_for_row(
state,
view,
all_rows,
dir_to_ublx,
i,
global_sel,
max_cols,
)
})
.collect();
(items, None)
}
pub fn draw_contents_panel(
f: &mut Frame,
state: &mut setup::UblxState,
view: &setup::ViewData,
all_rows: Option<&[setup::TuiRow]>,
dir_to_ublx: Option<&std::path::Path>,
chunks: &[Rect],
transparent_page_chrome: bool,
) {
let area = chunks[1];
let focused = matches!(state.panels.focus, setup::PanelFocus::Contents);
let block = contents_panel_block(state, view, focused, transparent_page_chrome);
let total = view.content_len;
let global_sel = state
.panels
.content_state
.selected()
.unwrap_or(0)
.min(total.saturating_sub(1));
let (items, window_start) =
contents_panel_list_items(state, view, all_rows, dir_to_ublx, area, global_sel);
let saved_sel = state.panels.content_state.selected();
let saved_off = state.panels.content_state.offset();
if let Some(ws) = window_start {
let g = saved_sel.unwrap_or(0).min(total.saturating_sub(1));
state
.panels
.content_state
.select(Some(g.saturating_sub(ws)));
*state.panels.content_state.offset_mut() = 0;
}
let highlight_style = if state.multiselect.active && focused {
style::tab_active()
} else {
state.panels.highlight_style
};
super::draw_list_panel(
f,
items,
block,
highlight_style,
focused,
&mut state.panels.content_state,
area,
);
if window_start.is_some() {
state.panels.content_state.select(saved_sel);
*state.panels.content_state.offset_mut() = saved_off;
}
}