Feat: better UI in the main view
This commit is contained in:
@@ -4,7 +4,7 @@ use ratatui::layout::{Constraint, Layout, Rect};
|
||||
use crate::commands::AppCommand;
|
||||
use crate::page::Page;
|
||||
use crate::state::{
|
||||
DeviceKind, DictFocus, EngineSection, HelpFocus, MainLayout, MinimapMode, Modal, OptionsFocus,
|
||||
DeviceKind, DictFocus, EngineSection, HelpFocus, MinimapMode, Modal, OptionsFocus,
|
||||
PatternsColumn, SettingKind,
|
||||
};
|
||||
use crate::views::{dict_view, engine_view, help_view, main_view, patterns_view};
|
||||
@@ -35,10 +35,11 @@ pub fn handle_mouse(ctx: &mut InputContext, mouse: MouseEvent, term: Rect) {
|
||||
}
|
||||
|
||||
fn padded(term: Rect) -> Rect {
|
||||
let h_pad = crate::views::horizontal_padding(term.width);
|
||||
Rect {
|
||||
x: term.x + 4,
|
||||
x: term.x + h_pad,
|
||||
y: term.y + 1,
|
||||
width: term.width.saturating_sub(8),
|
||||
width: term.width.saturating_sub(h_pad * 2),
|
||||
height: term.height.saturating_sub(2),
|
||||
}
|
||||
}
|
||||
@@ -303,111 +304,35 @@ fn handle_main_click(ctx: &mut InputContext, col: u16, row: u16, area: Rect) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Replay viz/sequencer split
|
||||
let show_scope = ctx.app.audio.config.show_scope;
|
||||
let show_spectrum = ctx.app.audio.config.show_spectrum;
|
||||
let show_preview = ctx.app.audio.config.show_preview;
|
||||
let has_viz = show_scope || show_spectrum || show_preview;
|
||||
let layout = ctx.app.audio.config.layout;
|
||||
|
||||
let sequencer_area = match layout {
|
||||
MainLayout::Top => {
|
||||
let viz_height = if has_viz { 16 } else { 0 };
|
||||
let [_viz, seq] =
|
||||
Layout::vertical([Constraint::Length(viz_height), Constraint::Fill(1)])
|
||||
.areas(main_area);
|
||||
seq
|
||||
}
|
||||
MainLayout::Bottom => {
|
||||
let viz_height = if has_viz { 16 } else { 0 };
|
||||
let [seq, _viz] =
|
||||
Layout::vertical([Constraint::Fill(1), Constraint::Length(viz_height)])
|
||||
.areas(main_area);
|
||||
seq
|
||||
}
|
||||
MainLayout::Left => {
|
||||
let viz_width = if has_viz { 33 } else { 0 };
|
||||
let [_viz, _spacer, seq] = Layout::horizontal([
|
||||
Constraint::Percentage(viz_width),
|
||||
Constraint::Length(2),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.areas(main_area);
|
||||
seq
|
||||
}
|
||||
MainLayout::Right => {
|
||||
let viz_width = if has_viz { 33 } else { 0 };
|
||||
let [seq, _spacer, _viz] = Layout::horizontal([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(2),
|
||||
Constraint::Percentage(viz_width),
|
||||
])
|
||||
.areas(main_area);
|
||||
seq
|
||||
}
|
||||
};
|
||||
let pattern = ctx.app.current_edit_pattern();
|
||||
let has_viz = ctx.app.audio.config.show_scope
|
||||
|| ctx.app.audio.config.show_spectrum
|
||||
|| ctx.app.audio.config.show_preview;
|
||||
let seq_h = main_view::sequencer_height(pattern.length, ctx.app.editor_ctx.step);
|
||||
let (_, sequencer_area) =
|
||||
main_view::viz_seq_split(main_area, ctx.app.audio.config.layout, has_viz, seq_h);
|
||||
|
||||
if !contains(sequencer_area, col, row) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Replay grid layout to find which step was clicked
|
||||
if let Some(step) = hit_test_grid(ctx, col, row, sequencer_area) {
|
||||
ctx.dispatch(AppCommand::GoToStep(step));
|
||||
}
|
||||
}
|
||||
|
||||
fn hit_test_grid(ctx: &InputContext, col: u16, row: u16, area: Rect) -> Option<usize> {
|
||||
if area.width < 50 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let pattern = ctx.app.current_edit_pattern();
|
||||
let length = pattern.length;
|
||||
let page = ctx.app.editor_ctx.step / STEPS_PER_PAGE;
|
||||
let page_start = page * STEPS_PER_PAGE;
|
||||
let steps_on_page = (page_start + STEPS_PER_PAGE).min(length) - page_start;
|
||||
|
||||
let num_rows = steps_on_page.div_ceil(8);
|
||||
let steps_per_row = steps_on_page.div_ceil(num_rows);
|
||||
|
||||
let row_height = area.height / num_rows as u16;
|
||||
|
||||
let row_constraints: Vec<Constraint> = (0..num_rows)
|
||||
.map(|_| Constraint::Length(row_height))
|
||||
.collect();
|
||||
let rows = Layout::vertical(row_constraints).split(area);
|
||||
|
||||
for row_idx in 0..num_rows {
|
||||
let row_area = rows[row_idx];
|
||||
if !contains(row_area, col, row) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let start_step = row_idx * steps_per_row;
|
||||
let end_step = (start_step + steps_per_row).min(steps_on_page);
|
||||
let cols_in_row = end_step - start_step;
|
||||
|
||||
let col_constraints: Vec<Constraint> = (0..cols_in_row * 2 - 1)
|
||||
.map(|i| {
|
||||
if i % 2 == 0 {
|
||||
Constraint::Fill(1)
|
||||
} else if i == cols_in_row - 1 {
|
||||
Constraint::Length(2)
|
||||
} else {
|
||||
Constraint::Length(1)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let cols = Layout::horizontal(col_constraints).split(row_area);
|
||||
|
||||
for col_idx in 0..cols_in_row {
|
||||
let tile_area = cols[col_idx * 2];
|
||||
if contains(tile_area, col, row) {
|
||||
let step_idx = page_start + start_step + col_idx;
|
||||
if step_idx < length {
|
||||
return Some(step_idx);
|
||||
}
|
||||
for (tile_rect, step_offset) in main_view::grid_layout(area, steps_on_page) {
|
||||
if contains(tile_rect, col, row) {
|
||||
let step_idx = page_start + step_offset;
|
||||
if step_idx < length {
|
||||
return Some(step_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user