Minor UI fixes.
This commit is contained in:
Generated
+2
-1
@@ -1180,7 +1180,7 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
||||
|
||||
[[package]]
|
||||
name = "furumi_tui"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arboard",
|
||||
@@ -1204,6 +1204,7 @@ dependencies = [
|
||||
"toml",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"unicode-width",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ tokio = { version = "1.52.3", features = ["rt-multi-thread", "macros", "sync", "
|
||||
toml = "1.1.2"
|
||||
tracing = "0.1.44"
|
||||
tracing-subscriber = { version = "0.3.23", features = ["env-filter"] }
|
||||
unicode-width = "0.2.2"
|
||||
|
||||
[target.'cfg(target_os="macos")'.dependencies]
|
||||
core-foundation = "0.10.1"
|
||||
|
||||
+76
-1
@@ -3,6 +3,7 @@ use ratatui::layout::{Alignment, Constraint, Layout, Rect};
|
||||
use ratatui::style::{Color, Style};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Block, Paragraph, Row, Table};
|
||||
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
|
||||
|
||||
use super::{art, theme};
|
||||
use crate::api::models::{ArtistCard, ReleaseCard};
|
||||
@@ -12,6 +13,10 @@ use crate::app::state::{
|
||||
};
|
||||
use crate::art::cache_key;
|
||||
|
||||
const TILE_MARQUEE_STEP_MS: u128 = 250;
|
||||
const TILE_MARQUEE_PAUSE_STEPS: u128 = 4;
|
||||
const TILE_MARQUEE_GAP: &str = " ";
|
||||
|
||||
pub fn draw(frame: &mut Frame, area: Rect, state: &AppState) {
|
||||
match state.global.stack.last() {
|
||||
None => draw_grid(frame, area, state),
|
||||
@@ -102,7 +107,10 @@ fn draw_tile(
|
||||
height: 1,
|
||||
..inner
|
||||
};
|
||||
frame.render_widget(Paragraph::new(Line::raw(title.to_string())), name_area);
|
||||
frame.render_widget(
|
||||
Paragraph::new(Line::raw(tile_title(title, name_area.width, selected))),
|
||||
name_area,
|
||||
);
|
||||
if selected {
|
||||
frame.buffer_mut().set_style(name_area, theme::tab_active());
|
||||
}
|
||||
@@ -123,6 +131,73 @@ fn draw_tile(
|
||||
}
|
||||
}
|
||||
|
||||
fn tile_title(title: &str, width: u16, selected: bool) -> String {
|
||||
let width = usize::from(width);
|
||||
if width == 0 {
|
||||
return String::new();
|
||||
}
|
||||
if !selected || UnicodeWidthStr::width(title) <= width {
|
||||
return title.to_string();
|
||||
}
|
||||
marquee_window(title, width)
|
||||
}
|
||||
|
||||
fn marquee_window(title: &str, width: usize) -> String {
|
||||
let stream = format!("{title}{TILE_MARQUEE_GAP}");
|
||||
let cells: Vec<(char, usize)> = stream
|
||||
.chars()
|
||||
.map(|ch| (ch, UnicodeWidthChar::width(ch).unwrap_or(0)))
|
||||
.collect();
|
||||
let total_width: usize = cells.iter().map(|(_, width)| *width).sum();
|
||||
if total_width == 0 {
|
||||
return title.to_string();
|
||||
}
|
||||
|
||||
let phase = marquee_phase(total_width);
|
||||
let mut skipped = 0usize;
|
||||
let mut index = 0usize;
|
||||
while index < cells.len() {
|
||||
let next = skipped + cells[index].1;
|
||||
if next > phase {
|
||||
break;
|
||||
}
|
||||
skipped = next;
|
||||
index += 1;
|
||||
}
|
||||
|
||||
let mut out = String::new();
|
||||
let mut used = 0usize;
|
||||
let mut steps = 0usize;
|
||||
while used < width && steps < cells.len() + width {
|
||||
let (ch, ch_width) = cells[(index + steps) % cells.len()];
|
||||
steps += 1;
|
||||
if ch_width == 0 {
|
||||
out.push(ch);
|
||||
continue;
|
||||
}
|
||||
if used + ch_width > width {
|
||||
continue;
|
||||
}
|
||||
out.push(ch);
|
||||
used += ch_width;
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn marquee_phase(total_width: usize) -> usize {
|
||||
let tick = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.map(|duration| duration.as_millis() / TILE_MARQUEE_STEP_MS)
|
||||
.unwrap_or(0);
|
||||
let cycle = total_width as u128 + TILE_MARQUEE_PAUSE_STEPS;
|
||||
let phase = tick % cycle;
|
||||
if phase < TILE_MARQUEE_PAUSE_STEPS {
|
||||
0
|
||||
} else {
|
||||
(phase - TILE_MARQUEE_PAUSE_STEPS) as usize
|
||||
}
|
||||
}
|
||||
|
||||
/// One selectable row: left content, optional right-aligned suffix, full-row
|
||||
/// highlight when selected.
|
||||
fn draw_row(frame: &mut Frame, area: Rect, line: Line, right: Option<String>, selected: bool) {
|
||||
|
||||
Reference in New Issue
Block a user