From 4c72dbb3e9d1ff52f6b119154daf9cb82cf5038d Mon Sep 17 00:00:00 2001 From: dsjkvf Date: Sun, 5 Feb 2023 15:06:12 +0200 Subject: [PATCH] perf: colors, layout cleaned up, improved --- src/draw.rs | 21 +- src/widget/add_stock.rs | 3 +- src/widget/block.rs | 3 +- src/widget/chart/prices_candlestick.rs | 21 +- src/widget/chart/prices_kagi.rs | 21 +- src/widget/chart/prices_line.rs | 23 +- src/widget/chart/volume_bar.rs | 3 +- src/widget/stock.rs | 468 ++++++++++++++----------- 8 files changed, 314 insertions(+), 249 deletions(-) diff --git a/src/draw.rs b/src/draw.rs index f5b1df2..14391dc 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -101,12 +101,14 @@ fn draw_main(frame: &mut Frame, app: &mut App, area: Rect) { // layout[0] - Header // layout[1] - Main widget let mut layout = Layout::default() - .constraints([Constraint::Length(3), Constraint::Min(0)].as_ref()) + // changed from 3 to 1 not to waste space + .constraints([Constraint::Length(0), Constraint::Min(0)].as_ref()) .split(area); if !app.stocks.is_empty() { - frame.render_widget(crate::widget::block::new(" Tabs "), layout[0]); - layout[0] = add_padding(layout[0], 1, PaddingDirection::All); + // drawing the block disabled, a separating line is more than enough + // frame.render_widget(crate::widget::block::new(""), layout[0]); + // layout[0] = add_padding(layout[0], 1, PaddingDirection::All); // header[0] - Stock symbol tabs // header[1] - (Optional) help icon @@ -126,8 +128,9 @@ fn draw_main(frame: &mut Frame, app: &mut App, area: Rect) { frame.render_widget( Tabs::new(tabs) .select(app.current_tab) - .style(style().fg(THEME.text_secondary())) - .highlight_style(style().fg(THEME.text_primary())), + .style(style().fg(THEME.gray())) + // color updated from primary to normal + .highlight_style(style().fg(THEME.text_normal())), header[0], ); } @@ -135,9 +138,11 @@ fn draw_main(frame: &mut Frame, app: &mut App, area: Rect) { // Draw help icon if !app.hide_help { frame.render_widget( - Paragraph::new(Text::styled("Help '?'", style())) - .style(style().fg(THEME.text_normal())) - .alignment(Alignment::Center), + Paragraph::new(Text::styled("?", style())) + // color updated from normal to gray + .style(style().fg(THEME.gray())) + // alignment updated from center to right + .alignment(Alignment::Right), header[1], ); } diff --git a/src/widget/add_stock.rs b/src/widget/add_stock.rs index 65d3ae0..922b7f3 100644 --- a/src/widget/add_stock.rs +++ b/src/widget/add_stock.rs @@ -65,7 +65,8 @@ impl StatefulWidget for AddStockWidget { &state.search_string, style() .add_modifier(Modifier::BOLD) - .fg(THEME.text_secondary()), + // color updated from secondary to normal + .fg(THEME.text_normal()), ), ]) }; diff --git a/src/widget/block.rs b/src/widget/block.rs index a2311b1..129883f 100644 --- a/src/widget/block.rs +++ b/src/widget/block.rs @@ -7,6 +7,7 @@ use crate::THEME; pub fn new(title: &str) -> Block { Block::default() .borders(Borders::ALL) - .border_style(style().fg(THEME.border_primary())) + // border color updated from secondary to gray + .border_style(style().fg(THEME.gray())) .title(Span::styled(title, style().fg(THEME.text_normal()))) } diff --git a/src/widget/chart/prices_candlestick.rs b/src/widget/chart/prices_candlestick.rs index 15a7293..08dc7a3 100644 --- a/src/widget/chart/prices_candlestick.rs +++ b/src/widget/chart/prices_candlestick.rs @@ -34,13 +34,14 @@ impl<'a> StatefulWidget for PricesCandlestickChart<'a> { return; } - if !self.is_summary { - Block::default() - .borders(Borders::TOP) - .border_style(style().fg(THEME.border_secondary())) - .render(area, buf); - area = add_padding(area, 1, PaddingDirection::Top); - } +// if !self.is_summary { +// Block::default() +// .borders(Borders::TOP) +// // border color updated from secondary to gray +// .border_style(style().fg(THEME.gray())) +// .render(area, buf); +// area = add_padding(area, 1, PaddingDirection::Top); +// } let mut data = self.data.to_vec(); data.push(Price { @@ -181,7 +182,8 @@ impl<'a> StatefulWidget for PricesCandlestickChart<'a> { } else { Borders::LEFT }) - .border_style(style().fg(THEME.border_axis())), + // border color updated from axis to gray + .border_style(style().fg(THEME.gray())), ) .x_bounds([0.0, num_candles as f64 * 4.0]) .y_bounds(state.y_bounds(min, max)) @@ -245,7 +247,8 @@ impl<'a> StatefulWidget for PricesCandlestickChart<'a> { } else { Borders::LEFT }) - .border_style(style().fg(THEME.border_axis())) + // border color updated from axis to gray + .border_style(style().fg(THEME.gray())) .render(layout[1], buf); } } diff --git a/src/widget/chart/prices_kagi.rs b/src/widget/chart/prices_kagi.rs index 6192c3b..15f093e 100644 --- a/src/widget/chart/prices_kagi.rs +++ b/src/widget/chart/prices_kagi.rs @@ -332,13 +332,14 @@ impl<'a> StatefulWidget for PricesKagiChart<'a> { let kagi_trends = calculate_trends(self.data, reversal_option, price_option); - if !self.is_summary { - Block::default() - .borders(Borders::TOP) - .border_style(style().fg(THEME.border_secondary())) - .render(area, buf); - area = add_padding(area, 1, PaddingDirection::Top); - } +// if !self.is_summary { +// Block::default() +// // border color updated from secondary to gray +// .borders(Borders::TOP) +// .border_style(style().fg(THEME.gray())) +// .render(area, buf); +// area = add_padding(area, 1, PaddingDirection::Top); +// } // x_layout[0] - chart + y labels // x_layout[1] - (x labels) @@ -464,7 +465,8 @@ impl<'a> StatefulWidget for PricesKagiChart<'a> { } else { Borders::LEFT }) - .border_style(style().fg(THEME.border_axis())), + // border color updated from axis to gray + .border_style(style().fg(THEME.gray())), ) .x_bounds([0.0, chart_width]) .y_bounds(state.y_bounds(min, max)) @@ -582,7 +584,8 @@ impl<'a> StatefulWidget for PricesKagiChart<'a> { } else { Borders::LEFT }) - .border_style(style().fg(THEME.border_axis())) + // border color updated from axis to gray + .border_style(style().fg(THEME.gray())) .render(layout[1], buf); } } diff --git a/src/widget/chart/prices_line.rs b/src/widget/chart/prices_line.rs index 9aac28b..101c52b 100644 --- a/src/widget/chart/prices_line.rs +++ b/src/widget/chart/prices_line.rs @@ -197,7 +197,8 @@ impl<'a> StatefulWidget for PricesLineChart<'a> { let axis = Axis::default().bounds(state.x_bounds(start, end, self.data)); if self.show_x_labels && self.loaded && !self.is_summary { - axis.labels(x_labels).style(style().fg(THEME.border_axis())) + // border color updated from axis to gray + axis.labels(x_labels).style(style().fg(THEME.gray())) } else { axis } @@ -206,17 +207,19 @@ impl<'a> StatefulWidget for PricesLineChart<'a> { Axis::default() .bounds(state.y_bounds(min, max)) .labels(state.y_labels(min, max)) - .style(style().fg(THEME.border_axis())), + // border color updated from axis to gray + .style(style().fg(THEME.gray())), ); - if !self.is_summary { - chart = chart.block( - Block::default() - .style(style().fg(THEME.border_secondary())) - .borders(Borders::TOP) - .border_style(style()), - ); - } +// if !self.is_summary { +// chart = chart.block( +// Block::default() +// // border color updated from secondary to gray +// .style(style().fg(THEME.gray())) +// .borders(Borders::TOP) +// .border_style(style()), +// ); +// } chart.render(area, buf); } diff --git a/src/widget/chart/volume_bar.rs b/src/widget/chart/volume_bar.rs index 5d53667..8abf007 100644 --- a/src/widget/chart/volume_bar.rs +++ b/src/widget/chart/volume_bar.rs @@ -56,7 +56,8 @@ impl<'a> StatefulWidget for VolumeBarChart<'a> { Block::default() .borders(Borders::LEFT) - .border_style(style().fg(THEME.border_axis())) + // border color updated from axis to gray + .border_style(style().fg(THEME.gray())) .render(volume_chunks, buf); volume_chunks.x += 1; diff --git a/src/widget/stock.rs b/src/widget/stock.rs index 961ec55..674c3e8 100644 --- a/src/widget/stock.rs +++ b/src/widget/stock.rs @@ -474,7 +474,8 @@ impl StockState { let label = Span::styled( self.time_frame.format_time(*timestamp), - style().fg(THEME.text_normal()), + // color updated from normal to gray + style().fg(THEME.gray()), ); labels.push(label); @@ -491,16 +492,19 @@ impl StockState { if self.loaded() { vec![ Span::styled( - format!("{:>8}", format_decimals(min)), - style().fg(THEME.text_normal()), + format!("{:>9}", format_decimals(min)), + // color updated from normal to gray + style().fg(THEME.gray()), ), Span::styled( - format!("{:>8}", format_decimals((min + max) / 2.0)), - style().fg(THEME.text_normal()), + format!("{:>9}", format_decimals((min + max) / 2.0)), + // color updated from normal to gray + style().fg(THEME.gray()), ), Span::styled( - format!("{:>8}", format_decimals(max)), - style().fg(THEME.text_normal()), + format!("{:>9}", format_decimals(max)), + // color updated from normal to gray + style().fg(THEME.gray()), ), ] } else { @@ -602,34 +606,35 @@ impl CachableWidget for StockWidget { let loaded = state.loaded(); - let (company_name, currency) = match state.profile.as_ref() { - Some(profile) => ( - profile.price.short_name.as_str(), - profile.price.currency.as_deref().unwrap_or("USD"), - ), - None => ("", ""), - }; - - let loading_indicator = ".".repeat(state.loading_tick); - - // Draw widget block - { - block::new(&format!( - " {}{:<4} ", - state.symbol, - if loaded { - format!(" - {}", company_name) - } else if state.profile.is_some() { - format!(" - {}{:<4}", company_name, loading_indicator) - } else { - loading_indicator - } - )) - .render(area, buf); - area = add_padding(area, 1, PaddingDirection::All); - area = add_padding(area, 1, PaddingDirection::Left); - area = add_padding(area, 1, PaddingDirection::Right); - } +// company_info widget disabled (part 1, disabling the widget) +// let (company_name, currency) = match state.profile.as_ref() { +// Some(profile) => ( +// profile.price.short_name.as_str(), +// profile.price.currency.as_deref().unwrap_or("USD"), +// ), +// None => ("", ""), +// }; +// +// let loading_indicator = ".".repeat(state.loading_tick); +// +// // Draw widget block +// { +// block::new(&format!( +// " {}{:<4} ", +// state.symbol, +// if loaded { +// format!(" - {}", company_name) +// } else if state.profile.is_some() { +// format!(" - {}{:<4}", company_name, loading_indicator) +// } else { +// loading_indicator +// } +// )) +// .render(area, buf); +// area = add_padding(area, 1, PaddingDirection::All); +// area = add_padding(area, 1, PaddingDirection::Left); +// area = add_padding(area, 1, PaddingDirection::Right); +// } // chunks[0] - Company Info // chunks[1] - Graph - fill remaining space @@ -637,7 +642,8 @@ impl CachableWidget for StockWidget { let mut chunks = Layout::default() .constraints( [ - Constraint::Length(6), + // company_info widget disabled, thus Length from 5 changed to 0 + Constraint::Length(0), Constraint::Min(0), Constraint::Length(2), ] @@ -645,177 +651,180 @@ impl CachableWidget for StockWidget { ) .split(area); - // Draw company info - { - // info_chunks[0] - Prices / volumes - // info_chunks[1] - Toggle block - let mut info_chunks = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Min(23), Constraint::Length(29)].as_ref()) - .split(chunks[0]); - info_chunks[0] = add_padding(info_chunks[0], 1, PaddingDirection::Top); - - let (high, low) = state.high_low(&data); +// company_info widget disabled (part 2, disabling the info, keeping the current price) +// // Draw company info +// { +// // info_chunks[0] - Prices / volumes +// // info_chunks[1] - Toggle block +// let mut info_chunks = Layout::default() +// .direction(Direction::Horizontal) +// .constraints([Constraint::Min(23), Constraint::Length(29)].as_ref()) +// .split(chunks[0]); +// info_chunks[0] = add_padding(info_chunks[0], 1, PaddingDirection::Top); +// +// let (high, low) = state.high_low(&data); let current_fmt = format_decimals(state.current_price()); - let high_fmt = format_decimals(high); - let low_fmt = format_decimals(low); - - let vol = state.reg_mkt_volume.clone().unwrap_or_default(); - - let company_info = vec![ - Spans::from(vec![ - Span::styled("C: ", style()), - Span::styled( - if loaded { - format!("{} {}", current_fmt, currency) - } else { - "".to_string() - }, - style() - .add_modifier(Modifier::BOLD) - .fg(THEME.text_primary()), - ), - Span::styled( - if loaded { - format!(" {:.2}%", pct_change * 100.0) - } else { - "".to_string() - }, - style() - .add_modifier(Modifier::BOLD) - .fg(if pct_change >= 0.0 { - THEME.profit() - } else { - THEME.loss() - }), - ), - ]), - Spans::from(vec![ - Span::styled("H: ", style()), - Span::styled( - if loaded { high_fmt } else { "".to_string() }, - style().fg(THEME.text_secondary()), - ), - ]), - Spans::from(vec![ - Span::styled("L: ", style()), - Span::styled( - if loaded { low_fmt } else { "".to_string() }, - style().fg(THEME.text_secondary()), - ), - ]), - Spans::default(), - Spans::from(vec![ - Span::styled("Volume: ", style()), - Span::styled( - if loaded { vol } else { "".to_string() }, - style().fg(THEME.text_secondary()), - ), - ]), - ]; - - Paragraph::new(company_info) - .style(style().fg(THEME.text_normal())) - .alignment(Alignment::Left) - .wrap(Wrap { trim: true }) - .render(info_chunks[0], buf); - - if !*HIDE_TOGGLE { - let toggle_block = block::new(" Toggle "); - toggle_block.render(info_chunks[1], buf); - - info_chunks[1] = add_padding(info_chunks[1], 1, PaddingDirection::All); - info_chunks[1] = add_padding(info_chunks[1], 1, PaddingDirection::Left); - - let toggle_chunks = Layout::default() - .direction(Direction::Horizontal) - .constraints([ - Constraint::Length(12), - Constraint::Length(2), - Constraint::Length(12), - ]) - .split(info_chunks[1]); - - let mut left_info = vec![Spans::from(Span::styled("Summary 's'", style()))]; - let mut right_info = vec![]; - - if loaded { - left_info.push(Spans::from(Span::styled( - format!("{: <8} 'c'", chart_type.as_str()), - style(), - ))); - - left_info.push(Spans::from(Span::styled( - "Volumes 'v'", - style() - .bg(if show_volumes { - THEME.highlight_unfocused() - } else { - THEME.background() - }) - .fg(if chart_type == ChartType::Kagi { - THEME.gray() - } else { - THEME.text_normal() - }), - ))); - - left_info.push(Spans::from(Span::styled( - "X Labels 'x'", - style().bg(if show_x_labels { - THEME.highlight_unfocused() - } else { - THEME.background() - }), - ))); - - right_info.push(Spans::from(Span::styled( - "Pre Post 'p'", - style().bg(if enable_pre_post { - THEME.highlight_unfocused() - } else { - THEME.background() - }), - ))); - - right_info.push(Spans::from(Span::styled( - "Edit 'e'", - style() - .bg(if state.show_configure { - THEME.highlight_unfocused() - } else { - THEME.background() - }) - .fg(if state.configure_enabled() { - THEME.text_normal() - } else { - THEME.gray() - }), - ))); - } - - if state.options_enabled() && loaded { - right_info.push(Spans::from(Span::styled( - "Options 'o'", - style().bg(if state.show_options { - THEME.highlight_unfocused() - } else { - THEME.background() - }), - ))); - } - - Paragraph::new(left_info) - .style(style().fg(THEME.text_normal())) - .alignment(Alignment::Left) - .render(toggle_chunks[0], buf); - - Paragraph::new(right_info) - .style(style().fg(THEME.text_normal())) - .alignment(Alignment::Left) - .render(toggle_chunks[2], buf); - } - } +// let high_fmt = format_decimals(high); +// let low_fmt = format_decimals(low); +// +// let vol = state.reg_mkt_volume.clone().unwrap_or_default(); +// +// let company_info = vec![ +// Spans::from(vec![ +// Span::styled("C: ", style()), +// Span::styled( +// if loaded { +// format!("{} {}", current_fmt, currency) +// } else { +// "".to_string() +// }, +// style() +// .add_modifier(Modifier::BOLD) +// .fg(THEME.text_primary()), +// ), +// Span::styled( +// if loaded { +// format!(" {:.2}%", pct_change * 100.0) +// } else { +// "".to_string() +// }, +// style() +// .add_modifier(Modifier::BOLD) +// .fg(if pct_change >= 0.0 { +// THEME.profit() +// } else { +// THEME.loss() +// }), +// ), +// ]), +// Spans::from(vec![ +// Span::styled("H: ", style()), +// Span::styled( +// if loaded { high_fmt } else { "".to_string() }, +// style().fg(THEME.text_secondary()), +// ), +// ]), +// Spans::from(vec![ +// Span::styled("L: ", style()), +// Span::styled( +// if loaded { low_fmt } else { "".to_string() }, +// style().fg(THEME.text_secondary()), +// ), +// ]), +// Spans::default(), +// Spans::from(vec![ +// Span::styled("Volume: ", style()), +// Span::styled( +// if loaded { vol } else { "".to_string() }, +// style().fg(THEME.text_secondary()), +// ), +// ]), +// ]; +// +// Paragraph::new(company_info) +// .style(style().fg(THEME.text_normal())) +// .alignment(Alignment::Left) +// .wrap(Wrap { trim: true }) +// .render(info_chunks[0], buf); +// + +// help widget disabled +// if !*HIDE_TOGGLE { +// let toggle_block = block::new(" Toggle "); +// toggle_block.render(info_chunks[1], buf); +// +// info_chunks[1] = add_padding(info_chunks[1], 1, PaddingDirection::All); +// info_chunks[1] = add_padding(info_chunks[1], 1, PaddingDirection::Left); +// +// let toggle_chunks = Layout::default() +// .direction(Direction::Horizontal) +// .constraints([ +// Constraint::Length(12), +// Constraint::Length(2), +// Constraint::Length(12), +// ]) +// .split(info_chunks[1]); +// +// let mut left_info = vec![Spans::from(Span::styled("Summary 's'", style()))]; +// let mut right_info = vec![]; +// +// if loaded { +// left_info.push(Spans::from(Span::styled( +// format!("{: <8} 'c'", chart_type.as_str()), +// style(), +// ))); +// +// left_info.push(Spans::from(Span::styled( +// "Volumes 'v'", +// style() +// .bg(if show_volumes { +// THEME.highlight_unfocused() +// } else { +// THEME.background() +// }) +// .fg(if chart_type == ChartType::Kagi { +// THEME.gray() +// } else { +// THEME.text_normal() +// }), +// ))); +// +// left_info.push(Spans::from(Span::styled( +// "X Labels 'x'", +// style().bg(if show_x_labels { +// THEME.highlight_unfocused() +// } else { +// THEME.background() +// }), +// ))); +// +// right_info.push(Spans::from(Span::styled( +// "Pre Post 'p'", +// style().bg(if enable_pre_post { +// THEME.highlight_unfocused() +// } else { +// THEME.background() +// }), +// ))); +// +// right_info.push(Spans::from(Span::styled( +// "Edit 'e'", +// style() +// .bg(if state.show_configure { +// THEME.highlight_unfocused() +// } else { +// THEME.background() +// }) +// .fg(if state.configure_enabled() { +// THEME.text_normal() +// } else { +// THEME.gray() +// }), +// ))); +// } +// +// if state.options_enabled() && loaded { +// right_info.push(Spans::from(Span::styled( +// "Options 'o'", +// style().bg(if state.show_options { +// THEME.highlight_unfocused() +// } else { +// THEME.background() +// }), +// ))); +// } +// +// Paragraph::new(left_info) +// .style(style().fg(THEME.text_normal())) +// .alignment(Alignment::Left) +// .render(toggle_chunks[0], buf); +// +// Paragraph::new(right_info) +// .style(style().fg(THEME.text_normal())) +// .alignment(Alignment::Left) +// .render(toggle_chunks[2], buf); +// } +// } // graph_chunks[0] = prices // graph_chunks[1] = volume @@ -899,8 +908,45 @@ impl CachableWidget for StockWidget { Tabs::new(tab_names) .select(state.time_frame.idx()) - .style(style().fg(THEME.text_secondary())) - .highlight_style(style().fg(THEME.text_primary())) + // color updated from secondary to gray + .style(style().fg(THEME.gray())) + // color updated from primary to normal + .highlight_style(style().fg(THEME.text_normal())) + .render(layout[0], buf); + + // gains_info widget introduced (gets the current price from the company_info widget) + let gains_info = vec![ + Spans::from(vec![ + Span::styled( + if loaded { + format!("{}: {}", state.symbol, current_fmt) + } else { + "".to_string() + }, + style() + .add_modifier(Modifier::BOLD) + .fg(THEME.text_normal()), + ), + Span::styled( + if loaded { + format!(" ({:.2}%)", pct_change * 100.0) + } else { + "".to_string() + }, + style() + .add_modifier(Modifier::BOLD) + .fg(if pct_change >= 0.0 { + THEME.profit() + } else { + THEME.loss() + }), + ), + ]), + ]; + + Paragraph::new(gains_info) + .alignment(Alignment::Right) + .wrap(Wrap { trim: true }) .render(layout[0], buf); if let Some(chart_state) = state.chart_state.as_ref() { @@ -911,15 +957,17 @@ impl CachableWidget for StockWidget { let left_arrow = Span::styled( "ᐸ", style().fg(if more_left { - THEME.text_normal() + // color updated from normal to gray + THEME.gray() } else { + // color updated from normal to gray THEME.gray() }), ); let right_arrow = Span::styled( "ᐳ", style().fg(if more_right { - THEME.text_normal() + THEME.gray() } else { THEME.gray() }),