diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 36f9a03..ceb83c3 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -1,7 +1,7 @@ use core::slice::GetDisjointMutIndex; use std::{collections::HashSet, fs::File, io::Read, path::PathBuf}; use crossterm::event::KeyEvent; -use ratatui::{layout::{Constraint, Rect}, style::{Color, Stylize}, text::Span, widgets::{Block, Clear, Widget}}; +use ratatui::{layout::{Constraint, Rect}, style::{Color, Style, Stylize}, text::Span, widgets::{Block, Borders, Clear, Widget}}; use serde::{Deserialize, Serialize}; use crate::{BYTES_PER_LINE, action::{Action, AppAction, bytes_to_nat}, app::WindowSize, config::Config, cursor::Cursor, edit_action::EditAction}; @@ -55,6 +55,7 @@ pub enum PartialAction { pub struct Popup { at: usize, width: u16, + primary: bool, lines: Vec> } @@ -118,6 +119,7 @@ impl Popup { .map(|line| line.width() as u16) .max() .unwrap_or(0), + primary: false, lines } } @@ -130,17 +132,31 @@ impl Popup { height: self.lines.len() as u16 } } + + #[allow(clippy::wrong_self_convention)] + const fn as_primary(mut self) -> Self { + self.primary = true; + self + } } impl Widget for Popup { fn render(self, area: Rect, buf: &mut ratatui::prelude::Buffer) { + Clear.render(area, buf); + + let border_color = if self.primary { + Style::new().white() + } else { + Style::new().gray() + }; + + Block::new() + .on_dark_gray() + .borders(Borders::LEFT | Borders::RIGHT) + .border_style(border_color) + .render(area, buf); + for (line, area) in self.lines.iter().zip(area.rows()) { - Clear.render(area, buf); - - Block::new() - .on_dark_gray() - .render(area, buf); - line.render( area.centered_horizontally(Constraint::Length(line.width() as u16)), buf diff --git a/src/buffer/widget.rs b/src/buffer/widget.rs index cee27c0..404fa65 100644 --- a/src/buffer/widget.rs +++ b/src/buffer/widget.rs @@ -43,6 +43,9 @@ impl Widget for &Buffer { .right_aligned() .render(status_line_area, buf); + let mut primary_popup = None; + let mut primary_popup_area = None; + for popup in &self.popups { if self.scroll_position <= popup.at && popup.at < self.scroll_position + (hex_area.height.saturating_sub(1) as usize * BYTES_PER_LINE) @@ -57,10 +60,21 @@ impl Widget for &Buffer { ) .clamp(hex_area); + if popup.at == self.primary_cursor.lower_bound() { + primary_popup = Some(popup); + primary_popup_area = Some(popup_area); + } + popup.clone().render(popup_area, buf); } } + if let Some(primary_popup) = primary_popup && + let Some(primary_popup_area) = primary_popup_area + { + primary_popup.clone().as_primary().render(primary_popup_area, buf); + } + // if self.partial_action == Some(PartialAction::Space) { // let input_field_area = Rect::new(area.x, area.bottom() - 2, area.width, 1); // Span::from("/0F673 ") diff --git a/src/main.rs b/src/main.rs index c778b55..43b932a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,6 +28,8 @@ const LINES_OF_PADDING: usize = 5; const BYTES_OF_PADDING: usize = LINES_OF_PADDING * BYTES_PER_LINE; // TODO: +// - keep popups for some actions +// - inspector translations for varint // - search // - ascii and bytes (`/` and `A-/`?) // - diffing