refactored borders

This commit is contained in:
Evan Almloff 2022-02-22 19:41:45 -06:00
parent 5a00816fc9
commit a4fdb22197
5 changed files with 326 additions and 217 deletions

View file

@ -30,7 +30,6 @@
*/ */
use stretch2::{prelude::*, style::PositionType, style::Style}; use stretch2::{prelude::*, style::PositionType, style::Style};
use tui::style::{Color, Style as TuiStyle};
use crate::style::{RinkColor, RinkStyle}; use crate::style::{RinkColor, RinkStyle};
@ -40,16 +39,50 @@ pub struct StyleModifer {
pub tui_modifier: TuiModifier, pub tui_modifier: TuiModifier,
} }
#[derive(Default)]
pub struct TuiModifier { pub struct TuiModifier {
// border arrays start at the top and proceed clockwise pub borders: Borders,
pub border_colors: [Option<RinkColor>; 4], }
pub border_types: [BorderType; 4],
pub border_widths: [UnitSystem; 4], #[derive(Default)]
pub border_radi: [UnitSystem; 4], pub struct Borders {
pub top: BorderEdge,
pub right: BorderEdge,
pub bottom: BorderEdge,
pub left: BorderEdge,
}
impl Borders {
fn slice(&mut self) -> [&mut BorderEdge; 4] {
[
&mut self.top,
&mut self.right,
&mut self.bottom,
&mut self.left,
]
}
}
pub struct BorderEdge {
pub color: Option<RinkColor>,
pub style: BorderStyle,
pub width: UnitSystem,
pub radius: UnitSystem,
}
impl Default for BorderEdge {
fn default() -> Self {
Self {
color: None,
style: BorderStyle::NONE,
width: UnitSystem::Point(0.0),
radius: UnitSystem::Point(0.0),
}
}
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum BorderType { pub enum BorderStyle {
DOTTED, DOTTED,
DASHED, DASHED,
SOLID, SOLID,
@ -62,13 +95,30 @@ pub enum BorderType {
NONE, NONE,
} }
impl Default for TuiModifier { impl BorderStyle {
fn default() -> Self { pub fn symbol_set(&self) -> Option<tui::symbols::line::Set> {
Self { use tui::symbols::line::*;
border_colors: [None; 4], const DASHED: Set = Set {
border_types: [BorderType::NONE; 4], horizontal: "",
border_widths: [UnitSystem::Point(0.0); 4], vertical: "",
border_radi: [UnitSystem::Point(0.0); 4], ..NORMAL
};
const DOTTED: Set = Set {
horizontal: "",
vertical: "",
..NORMAL
};
match self {
BorderStyle::DOTTED => Some(DOTTED),
BorderStyle::DASHED => Some(DASHED),
BorderStyle::SOLID => Some(NORMAL),
BorderStyle::DOUBLE => Some(DOUBLE),
BorderStyle::GROOVE => Some(NORMAL),
BorderStyle::RIDGE => Some(NORMAL),
BorderStyle::INSET => Some(NORMAL),
BorderStyle::OUTSET => Some(NORMAL),
BorderStyle::HIDDEN => None,
BorderStyle::NONE => None,
} }
} }
} }
@ -345,8 +395,8 @@ fn parse_value(value: &str) -> Option<UnitSystem> {
} else { } else {
None None
} }
} else if value.ends_with("%") { } else if value.ends_with('%') {
if let Ok(pct) = value.trim_end_matches("%").parse::<f32>() { if let Ok(pct) = value.trim_end_matches('%').parse::<f32>() {
Some(UnitSystem::Percent(pct)) Some(UnitSystem::Percent(pct))
} else { } else {
None None
@ -421,18 +471,18 @@ fn apply_background(name: &str, value: &str, style: &mut StyleModifer) {
} }
fn apply_border(name: &str, value: &str, style: &mut StyleModifer) { fn apply_border(name: &str, value: &str, style: &mut StyleModifer) {
fn parse_border_type(v: &str) -> BorderType { fn parse_border_style(v: &str) -> BorderStyle {
match v { match v {
"dotted" => BorderType::DOTTED, "dotted" => BorderStyle::DOTTED,
"dashed" => BorderType::DASHED, "dashed" => BorderStyle::DASHED,
"solid" => BorderType::SOLID, "solid" => BorderStyle::SOLID,
"double" => BorderType::DOUBLE, "double" => BorderStyle::DOUBLE,
"groove" => BorderType::GROOVE, "groove" => BorderStyle::GROOVE,
"ridge" => BorderType::RIDGE, "ridge" => BorderStyle::RIDGE,
"inset" => BorderType::INSET, "inset" => BorderStyle::INSET,
"outset" => BorderType::OUTSET, "outset" => BorderStyle::OUTSET,
"none" => BorderType::NONE, "none" => BorderStyle::NONE,
"hidden" => BorderType::HIDDEN, "hidden" => BorderStyle::HIDDEN,
_ => todo!(), _ => todo!(),
} }
} }
@ -441,23 +491,25 @@ fn apply_border(name: &str, value: &str, style: &mut StyleModifer) {
"border-bottom" => {} "border-bottom" => {}
"border-bottom-color" => { "border-bottom-color" => {
if let Ok(c) = value.parse() { if let Ok(c) = value.parse() {
style.tui_modifier.border_colors[2] = Some(c); style.tui_modifier.borders.bottom.color = Some(c);
} }
} }
"border-bottom-left-radius" => { "border-bottom-left-radius" => {
if let Some(v) = parse_value(value) { if let Some(v) = parse_value(value) {
style.tui_modifier.border_radi[2] = v; style.tui_modifier.borders.left.radius = v;
} }
} }
"border-bottom-right-radius" => { "border-bottom-right-radius" => {
if let Some(v) = parse_value(value) { if let Some(v) = parse_value(value) {
style.tui_modifier.border_radi[1] = v; style.tui_modifier.borders.right.radius = v;
} }
} }
"border-bottom-style" => style.tui_modifier.border_types[2] = parse_border_type(value), "border-bottom-style" => {
style.tui_modifier.borders.bottom.style = parse_border_style(value)
}
"border-bottom-width" => { "border-bottom-width" => {
if let Some(v) = parse_value(value) { if let Some(v) = parse_value(value) {
style.tui_modifier.border_widths[2] = v; style.tui_modifier.borders.bottom.width = v;
} }
} }
"border-collapse" => {} "border-collapse" => {}
@ -465,14 +517,20 @@ fn apply_border(name: &str, value: &str, style: &mut StyleModifer) {
let values: Vec<_> = value.split(' ').collect(); let values: Vec<_> = value.split(' ').collect();
if values.len() == 1 { if values.len() == 1 {
if let Ok(c) = values[0].parse() { if let Ok(c) = values[0].parse() {
for i in 0..4 { style
style.tui_modifier.border_colors[i] = Some(c); .tui_modifier
} .borders
.slice()
.iter_mut()
.for_each(|b| b.color = Some(c));
} }
} else { } else {
for (i, v) in values.into_iter().enumerate() { for (v, b) in values
.into_iter()
.zip(style.tui_modifier.borders.slice().iter_mut())
{
if let Ok(c) = v.parse() { if let Ok(c) = v.parse() {
style.tui_modifier.border_colors[i] = Some(c); b.color = Some(c);
} }
} }
} }
@ -486,27 +544,33 @@ fn apply_border(name: &str, value: &str, style: &mut StyleModifer) {
"border-left" => {} "border-left" => {}
"border-left-color" => { "border-left-color" => {
if let Ok(c) = value.parse() { if let Ok(c) = value.parse() {
style.tui_modifier.border_colors[3] = Some(c); style.tui_modifier.borders.left.color = Some(c);
} }
} }
"border-left-style" => style.tui_modifier.border_types[3] = parse_border_type(value), "border-left-style" => style.tui_modifier.borders.left.style = parse_border_style(value),
"border-left-width" => { "border-left-width" => {
if let Some(v) = parse_value(value) { if let Some(v) = parse_value(value) {
style.tui_modifier.border_widths[3] = v; style.tui_modifier.borders.left.width = v;
} }
} }
"border-radius" => { "border-radius" => {
let values: Vec<_> = value.split(' ').collect(); let values: Vec<_> = value.split(' ').collect();
if values.len() == 1 { if values.len() == 1 {
if let Some(r) = parse_value(values[0]) { if let Some(r) = parse_value(values[0]) {
for i in 0..4 { style
style.tui_modifier.border_radi[i] = r; .tui_modifier
} .borders
.slice()
.iter_mut()
.for_each(|b| b.radius = r);
} }
} else { } else {
for (i, v) in values.into_iter().enumerate() { for (v, b) in values
.into_iter()
.zip(style.tui_modifier.borders.slice().iter_mut())
{
if let Some(r) = parse_value(v) { if let Some(r) = parse_value(v) {
style.tui_modifier.border_radi[i] = r; b.radius = r;
} }
} }
} }
@ -514,55 +578,76 @@ fn apply_border(name: &str, value: &str, style: &mut StyleModifer) {
"border-right" => {} "border-right" => {}
"border-right-color" => { "border-right-color" => {
if let Ok(c) = value.parse() { if let Ok(c) = value.parse() {
style.tui_modifier.border_colors[1] = Some(c); style.tui_modifier.borders.right.color = Some(c);
} }
} }
"border-right-style" => style.tui_modifier.border_types[1] = parse_border_type(value), "border-right-style" => style.tui_modifier.borders.right.style = parse_border_style(value),
"border-right-width" => { "border-right-width" => {
if let Some(v) = parse_value(value) { if let Some(v) = parse_value(value) {
style.tui_modifier.border_widths[1] = v; style.tui_modifier.borders.right.width = v;
} }
} }
"border-spacing" => {} "border-spacing" => {}
"border-style" => { "border-style" => {
let values: Vec<_> = value.split(' ').collect(); let values: Vec<_> = value.split(' ').collect();
if values.len() == 1 { if values.len() == 1 {
let border = parse_border_type(values[0]); let border_style = parse_border_style(values[0]);
for i in 0..4 { style
style.tui_modifier.border_types[i] = border; .tui_modifier
} .borders
.slice()
.iter_mut()
.for_each(|b| b.style = border_style);
} else { } else {
for (i, v) in values.into_iter().enumerate() { for (v, b) in values
style.tui_modifier.border_types[i] = parse_border_type(v); .into_iter()
.zip(style.tui_modifier.borders.slice().iter_mut())
{
b.style = parse_border_style(v);
} }
} }
} }
"border-top" => {} "border-top" => {}
"border-top-color" => { "border-top-color" => {
if let Ok(c) = value.parse() { if let Ok(c) = value.parse() {
style.tui_modifier.border_colors[0] = Some(c); style.tui_modifier.borders.top.color = Some(c);
} }
} }
"border-top-left-radius" => { "border-top-left-radius" => {
if let Some(v) = parse_value(value) { if let Some(v) = parse_value(value) {
style.tui_modifier.border_radi[3] = v; style.tui_modifier.borders.left.radius = v;
} }
} }
"border-top-right-radius" => { "border-top-right-radius" => {
if let Some(v) = parse_value(value) { if let Some(v) = parse_value(value) {
style.tui_modifier.border_radi[0] = v; style.tui_modifier.borders.right.radius = v;
} }
} }
"border-top-style" => style.tui_modifier.border_types[0] = parse_border_type(value), "border-top-style" => style.tui_modifier.borders.top.style = parse_border_style(value),
"border-top-width" => { "border-top-width" => {
if let Some(v) = parse_value(value) { if let Some(v) = parse_value(value) {
style.tui_modifier.border_widths[0] = v; style.tui_modifier.borders.top.width = v;
} }
} }
"border-width" => { "border-width" => {
if let Some(v) = parse_value(value) { let values: Vec<_> = value.split(' ').collect();
for i in 0..4 { if values.len() == 1 {
style.tui_modifier.border_widths[i] = v; if let Some(w) = parse_value(values[0]) {
style
.tui_modifier
.borders
.slice()
.iter_mut()
.for_each(|b| b.width = w);
}
} else {
for (v, b) in values
.into_iter()
.zip(style.tui_modifier.borders.slice().iter_mut())
{
if let Some(w) = parse_value(v) {
b.width = w;
}
} }
} }
} }
@ -654,11 +739,11 @@ fn apply_flex(name: &str, value: &str, style: &mut StyleModifer) {
fn apply_font(name: &str, value: &str, style: &mut StyleModifer) { fn apply_font(name: &str, value: &str, style: &mut StyleModifer) {
use tui::style::Modifier; use tui::style::Modifier;
match name { match name {
"font" => todo!(), "font" => (),
"font-family" => todo!(), "font-family" => (),
"font-size" => todo!(), "font-size" => (),
"font-size-adjust" => todo!(), "font-size-adjust" => (),
"font-stretch" => todo!(), "font-stretch" => (),
"font-style" => match value { "font-style" => match value {
"italic" => style.tui_style = style.tui_style.add_modifier(Modifier::ITALIC), "italic" => style.tui_style = style.tui_style.add_modifier(Modifier::ITALIC),
"oblique" => style.tui_style = style.tui_style.add_modifier(Modifier::ITALIC), "oblique" => style.tui_style = style.tui_style.add_modifier(Modifier::ITALIC),

View file

@ -1,6 +1,5 @@
use dioxus::core::*; use dioxus::core::*;
use std::collections::HashMap; use std::collections::HashMap;
use tui::style::Style as TuiStyle;
use crate::{ use crate::{
attributes::{apply_attributes, StyleModifer}, attributes::{apply_attributes, StyleModifer},
@ -88,7 +87,7 @@ pub fn collect_layout<'a>(
node.mounted_id(), node.mounted_id(),
TuiNode { TuiNode {
node, node,
block_style: modifier.tui_style.into(), block_style: modifier.tui_style,
tui_modifier: modifier.tui_modifier, tui_modifier: modifier.tui_modifier,
layout: layout.new_node(modifier.style, &child_layout).unwrap(), layout: layout.new_node(modifier.style, &child_layout).unwrap(),
}, },

View file

@ -10,7 +10,7 @@ use tui::{backend::CrosstermBackend, layout::Rect};
use crate::{ use crate::{
style::{RinkColor, RinkStyle}, style::{RinkColor, RinkStyle},
widget::{RinkBuffer, RinkCell, RinkWidget, WidgetWithContext}, widget::{RinkBuffer, RinkCell, RinkWidget, WidgetWithContext},
BorderType, Config, TuiNode, UnitSystem, BorderEdge, BorderStyle, Config, TuiNode, UnitSystem,
}; };
const RADIUS_MULTIPLIER: [f32; 2] = [1.0, 0.5]; const RADIUS_MULTIPLIER: [f32; 2] = [1.0, 0.5];
@ -72,10 +72,6 @@ pub fn render_vnode<'a>(
} }
} }
// let s = Span::raw(t.text);
// Block::default().
let label = Label { let label = Label {
text: t.text, text: t.text,
style: *style, style: *style,
@ -190,7 +186,7 @@ impl<'a> RinkWidget for TuiNode<'a> {
arc_angle: f32, arc_angle: f32,
radius: f32, radius: f32,
symbols: &Set, symbols: &Set,
mut buf: &mut RinkBuffer, buf: &mut RinkBuffer,
color: &Option<RinkColor>, color: &Option<RinkColor>,
) { ) {
if radius < 0.0 { if radius < 0.0 {
@ -202,6 +198,7 @@ impl<'a> RinkWidget for TuiNode<'a> {
(starting_angle.cos() * (radius * RADIUS_MULTIPLIER[0])) as i32, (starting_angle.cos() * (radius * RADIUS_MULTIPLIER[0])) as i32,
(starting_angle.sin() * (radius * RADIUS_MULTIPLIER[1])) as i32, (starting_angle.sin() * (radius * RADIUS_MULTIPLIER[1])) as i32,
]; ];
// keep track of the last 3 point to allow filling diagonals
let mut points_history = [ let mut points_history = [
[0, 0], [0, 0],
{ {
@ -238,16 +235,16 @@ impl<'a> RinkWidget for TuiNode<'a> {
_ => todo!(), _ => todo!(),
}; };
draw( draw(
&mut buf, buf,
[points_history[0], points_history[1], connecting_point], [points_history[0], points_history[1], connecting_point],
&symbols, symbols,
pos, pos,
color, color,
); );
points_history = [points_history[1], connecting_point, points_history[2]]; points_history = [points_history[1], connecting_point, points_history[2]];
} }
draw(&mut buf, points_history, &symbols, pos, color); draw(buf, points_history, symbols, pos, color);
} }
} }
@ -268,7 +265,21 @@ impl<'a> RinkWidget for TuiNode<'a> {
} }
}]; }];
draw(&mut buf, points_history, &symbols, pos, color); draw(buf, points_history, symbols, pos, color);
}
fn get_radius(border: &BorderEdge, area: Rect) -> f32 {
match border.style {
BorderStyle::HIDDEN => 0.0,
BorderStyle::NONE => 0.0,
_ => match border.radius {
UnitSystem::Percent(p) => p * area.width as f32 / 100.0,
UnitSystem::Point(p) => p,
}
.abs()
.min((area.width as f32 / RADIUS_MULTIPLIER[0]) / 2.0)
.min((area.height as f32 / RADIUS_MULTIPLIER[1]) / 2.0),
}
} }
if area.area() == 0 { if area.area() == 0 {
@ -286,91 +297,33 @@ impl<'a> RinkWidget for TuiNode<'a> {
} }
} }
for i in 0..4 { let borders = self.tui_modifier.borders;
let last_edge = &borders.left;
let current_edge = &borders.top;
if let Some(symbols) = current_edge.style.symbol_set() {
// the radius for the curve between this line and the next // the radius for the curve between this line and the next
let r = match self.tui_modifier.border_types[(i + 1) % 4] { let r = get_radius(current_edge, area);
BorderType::HIDDEN => 0.0,
BorderType::NONE => 0.0,
_ => match self.tui_modifier.border_radi[i] {
UnitSystem::Percent(p) => p * area.width as f32 / 100.0,
UnitSystem::Point(p) => p,
}
.abs()
.min((area.width as f32 / RADIUS_MULTIPLIER[0]) / 2.0)
.min((area.height as f32 / RADIUS_MULTIPLIER[1]) / 2.0),
};
let radius = [ let radius = [
(r * RADIUS_MULTIPLIER[0]) as u16, (r * RADIUS_MULTIPLIER[0]) as u16,
(r * RADIUS_MULTIPLIER[1]) as u16, (r * RADIUS_MULTIPLIER[1]) as u16,
]; ];
// the radius for the curve between this line and the last // the radius for the curve between this line and the last
let last_idx = if i == 0 { 3 } else { i - 1 }; let last_r = get_radius(last_edge, area);
let last_r = match self.tui_modifier.border_types[last_idx] {
BorderType::HIDDEN => 0.0,
BorderType::NONE => 0.0,
_ => match self.tui_modifier.border_radi[last_idx] {
UnitSystem::Percent(p) => p * area.width as f32 / 100.0,
UnitSystem::Point(p) => p,
}
.abs()
.min((area.width as f32 / RADIUS_MULTIPLIER[0]) / 2.0)
.min((area.height as f32 / RADIUS_MULTIPLIER[1]) / 2.0),
};
let last_radius = [ let last_radius = [
(last_r * RADIUS_MULTIPLIER[0]) as u16, (last_r * RADIUS_MULTIPLIER[0]) as u16,
(last_r * RADIUS_MULTIPLIER[1]) as u16, (last_r * RADIUS_MULTIPLIER[1]) as u16,
]; ];
let color = current_edge.color.or(self.block_style.fg);
let symbols = match self.tui_modifier.border_types[i] {
BorderType::DOTTED => NORMAL,
BorderType::DASHED => NORMAL,
BorderType::SOLID => NORMAL,
BorderType::DOUBLE => DOUBLE,
BorderType::GROOVE => NORMAL,
BorderType::RIDGE => NORMAL,
BorderType::INSET => NORMAL,
BorderType::OUTSET => NORMAL,
BorderType::HIDDEN => continue,
BorderType::NONE => continue,
};
let color = self.tui_modifier.border_colors[i].or(self.block_style.fg);
let mut new_cell = RinkCell::default(); let mut new_cell = RinkCell::default();
if let Some(c) = color { if let Some(c) = color {
new_cell.fg = c; new_cell.fg = c;
} }
match i {
0 => {
for x in (area.left() + last_radius[0] + 1)..(area.right() - radius[0]) { for x in (area.left() + last_radius[0] + 1)..(area.right() - radius[0]) {
new_cell.symbol = symbols.horizontal.to_string(); new_cell.symbol = symbols.horizontal.to_string();
buf.set(x, area.top(), &new_cell); buf.set(x, area.top(), &new_cell);
} }
} draw_arc(
1 => {
for y in (area.top() + last_radius[1] + 1)..(area.bottom() - radius[1]) {
new_cell.symbol = symbols.vertical.to_string();
buf.set(area.right() - 1, y, &new_cell);
}
}
2 => {
for x in (area.left() + radius[0])..(area.right() - last_radius[0] - 1) {
new_cell.symbol = symbols.horizontal.to_string();
buf.set(x, area.bottom() - 1, &new_cell);
}
}
3 => {
for y in (area.top() + radius[1])..(area.bottom() - last_radius[1] - 1) {
new_cell.symbol = symbols.vertical.to_string();
buf.set(area.left(), y, &new_cell);
}
}
_ => (),
}
match i {
0 => draw_arc(
[area.right() - radius[0] - 1, area.top() + radius[1]], [area.right() - radius[0] - 1, area.top() + radius[1]],
std::f32::consts::FRAC_PI_2 * 3.0, std::f32::consts::FRAC_PI_2 * 3.0,
std::f32::consts::FRAC_PI_2, std::f32::consts::FRAC_PI_2,
@ -378,8 +331,34 @@ impl<'a> RinkWidget for TuiNode<'a> {
&symbols, &symbols,
&mut buf, &mut buf,
&color, &color,
), );
1 => draw_arc( }
let last_edge = &borders.top;
let current_edge = &borders.right;
if let Some(symbols) = current_edge.style.symbol_set() {
// the radius for the curve between this line and the next
let r = get_radius(current_edge, area);
let radius = [
(r * RADIUS_MULTIPLIER[0]) as u16,
(r * RADIUS_MULTIPLIER[1]) as u16,
];
// the radius for the curve between this line and the last
let last_r = get_radius(last_edge, area);
let last_radius = [
(last_r * RADIUS_MULTIPLIER[0]) as u16,
(last_r * RADIUS_MULTIPLIER[1]) as u16,
];
let color = current_edge.color.or(self.block_style.fg);
let mut new_cell = RinkCell::default();
if let Some(c) = color {
new_cell.fg = c;
}
for y in (area.top() + last_radius[1] + 1)..(area.bottom() - radius[1]) {
new_cell.symbol = symbols.vertical.to_string();
buf.set(area.right() - 1, y, &new_cell);
}
draw_arc(
[area.right() - radius[0] - 1, area.bottom() - radius[1] - 1], [area.right() - radius[0] - 1, area.bottom() - radius[1] - 1],
0.0, 0.0,
std::f32::consts::FRAC_PI_2, std::f32::consts::FRAC_PI_2,
@ -387,8 +366,34 @@ impl<'a> RinkWidget for TuiNode<'a> {
&symbols, &symbols,
&mut buf, &mut buf,
&color, &color,
), );
2 => draw_arc( }
let last_edge = &borders.right;
let current_edge = &borders.bottom;
if let Some(symbols) = current_edge.style.symbol_set() {
// the radius for the curve between this line and the next
let r = get_radius(current_edge, area);
let radius = [
(r * RADIUS_MULTIPLIER[0]) as u16,
(r * RADIUS_MULTIPLIER[1]) as u16,
];
// the radius for the curve between this line and the last
let last_r = get_radius(last_edge, area);
let last_radius = [
(last_r * RADIUS_MULTIPLIER[0]) as u16,
(last_r * RADIUS_MULTIPLIER[1]) as u16,
];
let color = current_edge.color.or(self.block_style.fg);
let mut new_cell = RinkCell::default();
if let Some(c) = color {
new_cell.fg = c;
}
for x in (area.left() + radius[0])..(area.right() - last_radius[0] - 1) {
new_cell.symbol = symbols.horizontal.to_string();
buf.set(x, area.bottom() - 1, &new_cell);
}
draw_arc(
[area.left() + radius[0], area.bottom() - radius[1] - 1], [area.left() + radius[0], area.bottom() - radius[1] - 1],
std::f32::consts::FRAC_PI_2, std::f32::consts::FRAC_PI_2,
std::f32::consts::FRAC_PI_2, std::f32::consts::FRAC_PI_2,
@ -396,8 +401,34 @@ impl<'a> RinkWidget for TuiNode<'a> {
&symbols, &symbols,
&mut buf, &mut buf,
&color, &color,
), );
3 => draw_arc( }
let last_edge = &borders.bottom;
let current_edge = &borders.left;
if let Some(symbols) = current_edge.style.symbol_set() {
// the radius for the curve between this line and the next
let r = get_radius(current_edge, area);
let radius = [
(r * RADIUS_MULTIPLIER[0]) as u16,
(r * RADIUS_MULTIPLIER[1]) as u16,
];
// the radius for the curve between this line and the last
let last_r = get_radius(last_edge, area);
let last_radius = [
(last_r * RADIUS_MULTIPLIER[0]) as u16,
(last_r * RADIUS_MULTIPLIER[1]) as u16,
];
let color = current_edge.color.or(self.block_style.fg);
let mut new_cell = RinkCell::default();
if let Some(c) = color {
new_cell.fg = c;
}
for y in (area.top() + radius[1])..(area.bottom() - last_radius[1] - 1) {
new_cell.symbol = symbols.vertical.to_string();
buf.set(area.left(), y, &new_cell);
}
draw_arc(
[area.left() + radius[0], area.top() + radius[1]], [area.left() + radius[0], area.top() + radius[1]],
std::f32::consts::PI, std::f32::consts::PI,
std::f32::consts::FRAC_PI_2, std::f32::consts::FRAC_PI_2,
@ -405,9 +436,7 @@ impl<'a> RinkWidget for TuiNode<'a> {
&symbols, &symbols,
&mut buf, &mut buf,
&color, &color,
), );
_ => panic!("more than 4 sides?"),
}
} }
} }
} }

View file

@ -23,8 +23,7 @@ impl RinkColor {
pub fn blend(self, other: Color) -> Color { pub fn blend(self, other: Color) -> Color {
if self.color == Color::Reset { if self.color == Color::Reset {
Color::Reset Color::Reset
} else { } else if self.alpha == 0.0 {
if self.alpha == 0.0 {
other other
} else { } else {
let [sr, sg, sb] = to_rgb(self.color); let [sr, sg, sb] = to_rgb(self.color);
@ -36,13 +35,11 @@ impl RinkColor {
self.alpha, self.alpha,
); );
let (or, og, ob) = (or as f32 / 255.0, og as f32 / 255.0, ob as f32 / 255.0); let (or, og, ob) = (or as f32 / 255.0, og as f32 / 255.0, ob as f32 / 255.0);
let c = Color::Rgb( Color::Rgb(
(255.0 * (sr * sa + or * (1.0 - sa))) as u8, (255.0 * (sr * sa + or * (1.0 - sa))) as u8,
(255.0 * (sg * sa + og * (1.0 - sa))) as u8, (255.0 * (sg * sa + og * (1.0 - sa))) as u8,
(255.0 * (sb * sa + ob * (1.0 - sa))) as u8, (255.0 * (sb * sa + ob * (1.0 - sa))) as u8,
); )
c
}
} }
} }
} }
@ -52,8 +49,8 @@ fn parse_value(
current_max_output: f32, current_max_output: f32,
required_max_output: f32, required_max_output: f32,
) -> Result<f32, ParseFloatError> { ) -> Result<f32, ParseFloatError> {
if v.ends_with('%') { if let Some(stripped) = v.strip_suffix('%') {
Ok((v[..v.len() - 1].trim().parse::<f32>()? / 100.0) * required_max_output) Ok((stripped.trim().parse::<f32>()? / 100.0) * required_max_output)
} else { } else {
Ok((v.trim().parse::<f32>()? / current_max_output) * required_max_output) Ok((v.trim().parse::<f32>()? / current_max_output) * required_max_output)
} }
@ -224,8 +221,8 @@ impl FromStr for RinkColor {
color: c, color: c,
alpha: 1.0, alpha: 1.0,
}) })
} else if color.starts_with("rgb(") { } else if let Some(stripped) = color.strip_prefix("rgb(") {
let color_values = color[4..].trim_end_matches(')'); let color_values = stripped.trim_end_matches(')');
if color.matches(',').count() == 3 { if color.matches(',').count() == 3 {
let (alpha, rgb_values) = let (alpha, rgb_values) =
color_values.rsplit_once(',').ok_or(ParseColorError)?; color_values.rsplit_once(',').ok_or(ParseColorError)?;
@ -240,8 +237,8 @@ impl FromStr for RinkColor {
alpha: 1.0, alpha: 1.0,
}) })
} }
} else if color.starts_with("rgba(") { } else if let Some(stripped) = color.strip_prefix("rgba(") {
let color_values = color[5..].trim_end_matches(')'); let color_values = stripped.trim_end_matches(')');
if color.matches(',').count() == 3 { if color.matches(',').count() == 3 {
let (rgb_values, alpha) = let (rgb_values, alpha) =
color_values.rsplit_once(',').ok_or(ParseColorError)?; color_values.rsplit_once(',').ok_or(ParseColorError)?;
@ -256,8 +253,8 @@ impl FromStr for RinkColor {
alpha: 1.0, alpha: 1.0,
}) })
} }
} else if color.starts_with("hsl(") { } else if let Some(stripped) = color.strip_prefix("hsl(") {
let color_values = color[4..].trim_end_matches(')'); let color_values = stripped.trim_end_matches(')');
if color.matches(',').count() == 3 { if color.matches(',').count() == 3 {
let (rgb_values, alpha) = let (rgb_values, alpha) =
color_values.rsplit_once(',').ok_or(ParseColorError)?; color_values.rsplit_once(',').ok_or(ParseColorError)?;
@ -272,8 +269,8 @@ impl FromStr for RinkColor {
alpha: 1.0, alpha: 1.0,
}) })
} }
} else if color.starts_with("hsla(") { } else if let Some(stripped) = color.strip_prefix("hsla(") {
let color_values = color[5..].trim_end_matches(')'); let color_values = stripped.trim_end_matches(')');
if color.matches(',').count() == 3 { if color.matches(',').count() == 3 {
let (rgb_values, alpha) = let (rgb_values, alpha) =
color_values.rsplit_once(',').ok_or(ParseColorError)?; color_values.rsplit_once(',').ok_or(ParseColorError)?;
@ -332,7 +329,6 @@ fn to_rgb(c: Color) -> [u8; 3] {
_ => [0, 0, 0], _ => [0, 0, 0],
}, },
Color::Reset => [0, 0, 0], Color::Reset => [0, 0, 0],
_ => todo!("{c:?}"),
} }
} }
@ -384,7 +380,7 @@ fn rgb_to_ansi() {
if rgb[0] != rgb[1] || rgb[1] != rgb[2] { if rgb[0] != rgb[1] || rgb[1] != rgb[2] {
assert_eq!(idxed, converted); assert_eq!(idxed, converted);
} else { } else {
assert!(i >= 232 && i <= 255); assert!(i >= 232);
} }
} else { } else {
panic!("color is not indexed") panic!("color is not indexed")

View file

@ -23,8 +23,8 @@ impl<'a> RinkBuffer<'a> {
pub fn set(&mut self, x: u16, y: u16, new: &RinkCell) { pub fn set(&mut self, x: u16, y: u16, new: &RinkCell) {
let mut cell = self.buf.get_mut(x, y); let mut cell = self.buf.get_mut(x, y);
cell.bg = convert(self.cfg.rendering_mode, new.bg.blend(cell.bg)); cell.bg = convert(self.cfg.rendering_mode, new.bg.blend(cell.bg));
if &new.symbol == "" { if new.symbol.is_empty() {
if &cell.symbol != "" { if !cell.symbol.is_empty() {
// allows text to "shine through" transparent backgrounds // allows text to "shine through" transparent backgrounds
cell.fg = convert(self.cfg.rendering_mode, new.bg.blend(cell.fg)); cell.fg = convert(self.cfg.rendering_mode, new.bg.blend(cell.fg));
} }