summaryrefslogtreecommitdiffstats
path: root/src/display.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/display.rs')
-rw-r--r--src/display.rs149
1 files changed, 140 insertions, 9 deletions
diff --git a/src/display.rs b/src/display.rs
index 826916ce..3537adb7 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -21,11 +21,11 @@ use parking_lot::{MutexGuard};
use Rgb;
use cli;
use config::Config;
-use font::{self, Rasterize};
+use font::{self, Rasterize, Metrics};
use meter::Meter;
-use renderer::{self, GlyphCache, QuadRenderer};
+use renderer::{self, GlyphCache, QuadRenderer, Rect};
use selection::Selection;
-use term::{Term, SizeInfo};
+use term::{cell, Term, SizeInfo, RenderableCell};
use window::{self, Size, Pixels, Window, SetInnerSize};
@@ -346,6 +346,8 @@ impl Display {
{
let glyph_cache = &mut self.glyph_cache;
+ let metrics = glyph_cache.font_metrics();
+ let mut cell_line_rects = Vec::new();
// Draw grid
{
@@ -363,17 +365,74 @@ impl Display {
api.clear(background_color);
}
- // Draw the grid
- api.render_cells(
- terminal.renderable_cells(config, selection, window_focused),
- glyph_cache,
- );
+ // Store underline/strikethrough information beyond current cell
+ let mut last_cell = None;
+ let mut start_underline: Option<RenderableCell> = None;
+ let mut start_strikethrough: Option<RenderableCell> = None;
+
+ // Iterate over all non-empty cells in the grid
+ for cell in terminal.renderable_cells(config, selection, window_focused) {
+ // Check if there is a new underline
+ if let Some(underline) = calculate_cell_line_state(
+ cell,
+ &mut start_underline,
+ &last_cell,
+ &metrics,
+ &size_info,
+ cell::Flags::UNDERLINE,
+ ) {
+ cell_line_rects.push(underline);
+ }
+
+ // Check if there is a new strikethrough
+ if let Some(strikethrough) = calculate_cell_line_state(
+ cell,
+ &mut start_strikethrough,
+ &last_cell,
+ &metrics,
+ &size_info,
+ cell::Flags::STRIKE_THROUGH,
+ ) {
+ cell_line_rects.push(strikethrough);
+ }
+
+ // Change the last checked cell for underline/strikethrough
+ last_cell = Some(cell);
+
+ // Draw the cell
+ api.render_cell(cell, glyph_cache);
+ }
+
+ // If underline hasn't been reset, draw until the last cell
+ if let Some(start) = start_underline {
+ cell_line_rects.push(
+ cell_line_rect(
+ &start,
+ &last_cell.unwrap(),
+ &metrics, &size_info,
+ cell::Flags::UNDERLINE
+ )
+ );
+ }
+
+ // If strikethrough hasn't been reset, draw until the last cell
+ if let Some(start) = start_strikethrough {
+ let flag = cell::Flags::STRIKE_THROUGH;
+ cell_line_rects.push(
+ cell_line_rect(
+ &start,
+ &last_cell.unwrap(),
+ &metrics, &size_info,
+ cell::Flags::STRIKE_THROUGH
+ )
+ );
+ }
});
}
// Draw rectangles
let visual_bell_intensity = terminal.visual_bell.intensity();
- self.renderer.draw_rects(config, &size_info, visual_bell_intensity);
+ self.renderer.draw_rects(config, &size_info, visual_bell_intensity, cell_line_rects);
// Draw render timer
if self.render_timer {
@@ -423,3 +482,75 @@ impl Display {
self.window().send_xim_spot(nspot_x, nspot_y);
}
}
+
+// Check if the underline/strikethrough state has changed
+// This returns a new rectangle whenever an underline/strikethrough ends
+fn calculate_cell_line_state(
+ cell: RenderableCell,
+ start_cell_line: &mut Option<RenderableCell>,
+ last_cell: &Option<RenderableCell>,
+ metrics: &Metrics,
+ size_info: &SizeInfo,
+ flag: cell::Flags,
+) -> Option<(Rect<u32>, Rgb)> {
+ match *start_cell_line {
+ // If line is already started, check for end
+ Some(start) => {
+ // No change in line
+ if cell.line == start.line
+ && cell.flags.contains(flag)
+ && cell.fg == start.fg
+ {
+ return None;
+ }
+
+ // Check if we need to start a new line
+ // because the cell color has changed
+ *start_cell_line = if cell.fg != start.fg && cell.flags.contains(flag) {
+ // Start a new line
+ Some(cell)
+ } else {
+ // Disable line
+ None
+ };
+
+ return Some(
+ cell_line_rect(&start, &last_cell.unwrap(), metrics, size_info, flag)
+ );
+ },
+ // Check for new start of line
+ None => if cell.flags.contains(flag) {
+ *start_cell_line = Some(cell);
+ },
+ }
+ None
+}
+
+// Create a colored rectangle for an underline/strikethrough based on two cells
+fn cell_line_rect(
+ start: &RenderableCell,
+ end: &RenderableCell,
+ metrics: &Metrics,
+ size: &SizeInfo,
+ flag: cell::Flags,
+) -> (Rect<u32>, Rgb) {
+ let x = (start.column.0 as f64 * metrics.average_advance) as u32;
+ let end_x = ((end.column.0 + 1) as f64 * metrics.average_advance) as u32;
+ let width = end_x - x;
+
+ let y = match flag {
+ cell::Flags::UNDERLINE => {
+ ((start.line.0 as f32 + 1.) * metrics.line_height as f32 + metrics.descent - metrics.underline_position) as u32
+ },
+ cell::Flags::STRIKE_THROUGH => {
+ ((start.line.0 as f32 + 0.5) * metrics.line_height as f32) as u32
+ },
+ _ => panic!("Invalid flag for cell line drawing specified"),
+ };
+ let height = metrics.underline_thickness as u32;
+
+ let rect = Rect::new(x + size.padding_x as u32, y + size.padding_y as u32, width, height);
+ let color = start.fg;
+
+ (rect, color)
+}