Refactor new Rect construction (#575)
* Refactor new Rect construction Introduces methods that can be chained to construct new Rects out of pre-existing ones * Clamp x and y to edges in Rect chop methods * Rename Rect clipping functions
This commit is contained in:
parent
ac8bc54108
commit
f9375f449c
6 changed files with 119 additions and 53 deletions
|
@ -108,13 +108,11 @@ impl EditorView {
|
|||
|
||||
self.render_diagnostics(doc, view, inner, surface, theme);
|
||||
|
||||
let area = Rect::new(
|
||||
view.area.x,
|
||||
view.area.y + view.area.height.saturating_sub(1),
|
||||
view.area.width,
|
||||
1,
|
||||
);
|
||||
self.render_statusline(doc, view, area, surface, theme, is_focused);
|
||||
let statusline_area = view
|
||||
.area
|
||||
.clip_top(view.area.height.saturating_sub(1))
|
||||
.clip_bottom(1); // -1 from bottom to remove commandline
|
||||
self.render_statusline(doc, view, statusline_area, surface, theme, is_focused);
|
||||
}
|
||||
|
||||
/// Get syntax highlights for a document in a view represented by the first line
|
||||
|
@ -528,12 +526,7 @@ impl EditorView {
|
|||
let width = 80.min(viewport.width);
|
||||
let height = 15.min(viewport.height);
|
||||
paragraph.render(
|
||||
Rect::new(
|
||||
viewport.right() - width,
|
||||
viewport.y as u16 + 1,
|
||||
width,
|
||||
height,
|
||||
),
|
||||
Rect::new(viewport.right() - width, viewport.y + 1, width, height),
|
||||
surface,
|
||||
);
|
||||
}
|
||||
|
@ -572,7 +565,7 @@ impl EditorView {
|
|||
theme.get("ui.statusline.inactive")
|
||||
};
|
||||
// statusline
|
||||
surface.set_style(Rect::new(viewport.x, viewport.y, viewport.width, 1), style);
|
||||
surface.set_style(viewport.with_height(1), style);
|
||||
if is_focused {
|
||||
surface.set_string(viewport.x + 1, viewport.y, mode, style);
|
||||
}
|
||||
|
@ -1001,8 +994,7 @@ impl Component for EditorView {
|
|||
surface.set_style(area, cx.editor.theme.get("ui.background"));
|
||||
|
||||
// if the terminal size suddenly changed, we need to trigger a resize
|
||||
cx.editor
|
||||
.resize(Rect::new(area.x, area.y, area.width, area.height - 1)); // - 1 to account for commandline
|
||||
cx.editor.resize(area.clip_bottom(1)); // -1 from bottom for commandline
|
||||
|
||||
for (view, is_focused) in cx.editor.tree.views() {
|
||||
let doc = cx.editor.document(view.doc).unwrap();
|
||||
|
|
|
@ -13,7 +13,7 @@ use helix_core::{
|
|||
Rope,
|
||||
};
|
||||
use helix_view::{
|
||||
graphics::{Color, Rect, Style},
|
||||
graphics::{Color, Margin, Rect, Style},
|
||||
Theme,
|
||||
};
|
||||
|
||||
|
@ -207,8 +207,11 @@ impl Component for Markdown {
|
|||
.wrap(Wrap { trim: false })
|
||||
.scroll((cx.scroll.unwrap_or_default() as u16, 0));
|
||||
|
||||
let area = Rect::new(area.x + 1, area.y + 1, area.width - 2, area.height - 2);
|
||||
par.render(area, surface);
|
||||
let margin = Margin {
|
||||
vertical: 1,
|
||||
horizontal: 1,
|
||||
};
|
||||
par.render(area.inner(&margin), surface);
|
||||
}
|
||||
|
||||
fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
|
||||
|
|
|
@ -304,14 +304,6 @@ impl<T: Item + 'static> Component for Menu<T> {
|
|||
},
|
||||
);
|
||||
|
||||
// // TODO: set bg for the whole row if selected
|
||||
// if line == self.cursor {
|
||||
// surface.set_style(
|
||||
// Rect::new(area.x, area.y + i as u16, area.width - 1, 1),
|
||||
// selected,
|
||||
// )
|
||||
// }
|
||||
|
||||
for (i, _) in (scroll..(scroll + win_height).min(len)).enumerate() {
|
||||
let is_marked = i >= scroll_line && i < scroll_line + scroll_height;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ use helix_core::Position;
|
|||
use helix_view::{
|
||||
document::canonicalize_path,
|
||||
editor::Action,
|
||||
graphics::{Color, CursorKind, Rect, Style},
|
||||
graphics::{Color, CursorKind, Margin, Rect, Style},
|
||||
Document, Editor,
|
||||
};
|
||||
|
||||
|
@ -90,23 +90,26 @@ impl<T: 'static> Component for FilePicker<T> {
|
|||
area.width
|
||||
};
|
||||
|
||||
let picker_area = Rect::new(area.x, area.y, picker_width, area.height);
|
||||
let picker_area = area.with_width(picker_width);
|
||||
self.picker.render(picker_area, surface, cx);
|
||||
|
||||
if !render_preview {
|
||||
return;
|
||||
}
|
||||
|
||||
let preview_area = Rect::new(area.x + picker_width, area.y, area.width / 2, area.height);
|
||||
let preview_area = area.clip_left(picker_width);
|
||||
|
||||
// don't like this but the lifetime sucks
|
||||
let block = Block::default().borders(Borders::ALL);
|
||||
|
||||
// calculate the inner area inside the box
|
||||
let mut inner = block.inner(preview_area);
|
||||
let inner = block.inner(preview_area);
|
||||
// 1 column gap on either side
|
||||
inner.x += 1;
|
||||
inner.width = inner.width.saturating_sub(2);
|
||||
let margin = Margin {
|
||||
vertical: 1,
|
||||
horizontal: 0,
|
||||
};
|
||||
let inner = inner.inner(&margin);
|
||||
|
||||
block.render(preview_area, surface);
|
||||
|
||||
|
@ -282,15 +285,11 @@ impl<T> Picker<T> {
|
|||
// - score all the names in relation to input
|
||||
|
||||
fn inner_rect(area: Rect) -> Rect {
|
||||
let padding_vertical = area.height * 10 / 100;
|
||||
let padding_horizontal = area.width * 10 / 100;
|
||||
|
||||
Rect::new(
|
||||
area.x + padding_horizontal,
|
||||
area.y + padding_vertical,
|
||||
area.width - padding_horizontal * 2,
|
||||
area.height - padding_vertical * 2,
|
||||
)
|
||||
let margin = Margin {
|
||||
vertical: area.height * 10 / 100,
|
||||
horizontal: area.width * 10 / 100,
|
||||
};
|
||||
area.inner(&margin)
|
||||
}
|
||||
|
||||
impl<T: 'static> Component for Picker<T> {
|
||||
|
@ -410,7 +409,7 @@ impl<T: 'static> Component for Picker<T> {
|
|||
|
||||
// -- Render the input bar:
|
||||
|
||||
let area = Rect::new(inner.x + 1, inner.y, inner.width - 1, 1);
|
||||
let area = inner.clip_left(1).with_height(1);
|
||||
|
||||
let count = format!("{}/{}", self.matches.len(), self.options.len());
|
||||
surface.set_stringn(
|
||||
|
@ -434,8 +433,8 @@ impl<T: 'static> Component for Picker<T> {
|
|||
}
|
||||
|
||||
// -- Render the contents:
|
||||
// subtract the area of the prompt (-2) and current item marker " > " (-3)
|
||||
let inner = Rect::new(inner.x + 3, inner.y + 2, inner.width - 3, inner.height - 2);
|
||||
// subtract area of prompt from top and current item marker " > " from left
|
||||
let inner = inner.clip_top(2).clip_left(3);
|
||||
|
||||
let selected = cx.editor.theme.get("ui.text.focus");
|
||||
|
||||
|
@ -474,7 +473,7 @@ impl<T: 'static> Component for Picker<T> {
|
|||
let inner = block.inner(area);
|
||||
|
||||
// prompt area
|
||||
let area = Rect::new(inner.x + 1, inner.y, inner.width - 1, 1);
|
||||
let area = inner.clip_left(1).with_height(1);
|
||||
|
||||
self.prompt.cursor(area, editor)
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ pub struct Margin {
|
|||
}
|
||||
|
||||
/// A simple rectangle used in the computation of the layout and to give widgets an hint about the
|
||||
/// area they are supposed to render to.
|
||||
/// area they are supposed to render to. (x, y) = (0, 0) is at the top left corner of the screen.
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
pub struct Rect {
|
||||
pub x: u16,
|
||||
|
@ -92,6 +92,57 @@ impl Rect {
|
|||
self.y.saturating_add(self.height)
|
||||
}
|
||||
|
||||
// Returns a new Rect with width reduced from the left side.
|
||||
// This changes the `x` coordinate and clamps it to the right
|
||||
// edge of the original Rect.
|
||||
pub fn clip_left(self, width: u16) -> Rect {
|
||||
let width = std::cmp::min(width, self.width);
|
||||
Rect {
|
||||
x: self.x.saturating_add(width),
|
||||
width: self.width.saturating_sub(width),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a new Rect with width reduced from the right side.
|
||||
// This does _not_ change the `x` coordinate.
|
||||
pub fn clip_right(self, width: u16) -> Rect {
|
||||
Rect {
|
||||
width: self.width.saturating_sub(width),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a new Rect with height reduced from the top.
|
||||
// This changes the `y` coordinate and clamps it to the bottom
|
||||
// edge of the original Rect.
|
||||
pub fn clip_top(self, height: u16) -> Rect {
|
||||
let height = std::cmp::min(height, self.height);
|
||||
Rect {
|
||||
y: self.y.saturating_add(height),
|
||||
height: self.height.saturating_sub(height),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a new Rect with height reduced from the bottom.
|
||||
// This does _not_ change the `y` coordinate.
|
||||
pub fn clip_bottom(self, height: u16) -> Rect {
|
||||
Rect {
|
||||
height: self.height.saturating_sub(height),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_height(self, height: u16) -> Rect {
|
||||
// new height may make area > u16::max_value, so use new()
|
||||
Self::new(self.x, self.y, self.width, height)
|
||||
}
|
||||
|
||||
pub fn with_width(self, width: u16) -> Rect {
|
||||
Self::new(self.x, self.y, width, self.height)
|
||||
}
|
||||
|
||||
pub fn inner(self, margin: &Margin) -> Rect {
|
||||
if self.width < 2 * margin.horizontal || self.height < 2 * margin.vertical {
|
||||
Rect::default()
|
||||
|
@ -495,6 +546,40 @@ mod tests {
|
|||
assert_eq!(rect.height, 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rect_chop_from_left() {
|
||||
let rect = Rect::new(0, 0, 20, 30);
|
||||
assert_eq!(Rect::new(10, 0, 10, 30), rect.clip_left(10));
|
||||
assert_eq!(
|
||||
Rect::new(20, 0, 0, 30),
|
||||
rect.clip_left(40),
|
||||
"x should be clamped to original width if new width is bigger"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rect_chop_from_right() {
|
||||
let rect = Rect::new(0, 0, 20, 30);
|
||||
assert_eq!(Rect::new(0, 0, 10, 30), rect.clip_right(10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rect_chop_from_top() {
|
||||
let rect = Rect::new(0, 0, 20, 30);
|
||||
assert_eq!(Rect::new(0, 10, 20, 20), rect.clip_top(10));
|
||||
assert_eq!(
|
||||
Rect::new(0, 30, 20, 0),
|
||||
rect.clip_top(50),
|
||||
"y should be clamped to original height if new height is bigger"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rect_chop_from_bottom() {
|
||||
let rect = Rect::new(0, 0, 20, 30);
|
||||
assert_eq!(Rect::new(0, 0, 20, 20), rect.clip_bottom(10));
|
||||
}
|
||||
|
||||
fn styles() -> Vec<Style> {
|
||||
vec![
|
||||
Style::default(),
|
||||
|
|
|
@ -83,12 +83,7 @@ impl View {
|
|||
pub fn inner_area(&self) -> Rect {
|
||||
// TODO: not ideal
|
||||
const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
|
||||
Rect::new(
|
||||
self.area.x + OFFSET,
|
||||
self.area.y,
|
||||
self.area.width - OFFSET,
|
||||
self.area.height.saturating_sub(1), // -1 for statusline
|
||||
)
|
||||
self.area.clip_left(OFFSET).clip_bottom(1) // -1 for statusline
|
||||
}
|
||||
|
||||
pub fn ensure_cursor_in_view(&mut self, doc: &Document, scrolloff: usize) {
|
||||
|
|
Loading…
Add table
Reference in a new issue