FIX: Another round a borders
Only test are missing(!)
This commit is contained in:
committed by
Nicolás Hatcher Andrés
parent
0df132d5c2
commit
411c5de59b
@@ -47,7 +47,8 @@ fn is_max_color(a: &str, b: &str) -> bool {
|
||||
luminance_b < luminance_a
|
||||
}
|
||||
|
||||
pub(crate) fn is_max_border(a: &Option<BorderItem>, b: &Option<BorderItem>) -> bool {
|
||||
/// Is border b "heavier" than a?
|
||||
pub(crate) fn is_max_border(a: Option<&BorderItem>, b: Option<&BorderItem>) -> bool {
|
||||
match (a, b) {
|
||||
(_, None) => false,
|
||||
(None, Some(_)) => true,
|
||||
@@ -69,9 +70,23 @@ pub(crate) fn is_max_border(a: &Option<BorderItem>, b: &Option<BorderItem>) -> b
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::types::BorderStyle;
|
||||
|
||||
#[test]
|
||||
fn test_basic_colors() {
|
||||
fn compare_borders() {
|
||||
let b = BorderItem {
|
||||
style: BorderStyle::Thin,
|
||||
color: Some("#FFF".to_string()),
|
||||
};
|
||||
// Some border *always* beats no border
|
||||
assert!(is_max_border(None, Some(&b)));
|
||||
|
||||
// No border is beaten by some border
|
||||
assert!(!is_max_border(Some(&b), None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_colors() {
|
||||
// Black vs White
|
||||
assert!(is_max_color("#FFFFFF", "#000000"));
|
||||
assert!(!is_max_color("#000000", "#FFFFFF"));
|
||||
@@ -90,34 +105,13 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_same_color() {
|
||||
fn same_color() {
|
||||
// Comparing the same color should return false
|
||||
assert!(!is_max_color("#123456", "#123456"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shorthand_colors() {
|
||||
// Shorthand notation (#RGB)
|
||||
assert!(is_max_color("#FFF", "#000"));
|
||||
assert!(is_max_color("#F00", "#800"));
|
||||
assert!(is_max_color("#0F0", "#080"));
|
||||
assert!(is_max_color("#00F", "#008"));
|
||||
assert!(!is_max_color("#ABC", "#123"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_colors() {
|
||||
// Invalid color formats
|
||||
assert!(!is_max_color("#GGGGGG", "#000000"));
|
||||
assert!(!is_max_color("#12345", "#000000"));
|
||||
assert!(!is_max_color("#1234567", "#000000"));
|
||||
assert!(!is_max_color("123456", "#000000"));
|
||||
assert!(!is_max_color("#123456", "#XYZ"));
|
||||
assert!(!is_max_color("#", "#000000"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_edge_cases() {
|
||||
fn edge_cases() {
|
||||
// Colors with minimal luminance difference
|
||||
assert!(!is_max_color("#000000", "#010101"));
|
||||
assert!(!is_max_color("#FEFEFE", "#FFFFFF"));
|
||||
@@ -125,7 +119,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_luminance_ordering() {
|
||||
fn luminance_ordering() {
|
||||
// Colors with known luminance differences
|
||||
assert!(is_max_color("#CCCCCC", "#333333")); // Light gray vs Day
|
||||
assert!(is_max_color("#FFFF00", "#808000")); // Yellow ve
|
||||
@@ -133,7 +127,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_borderline_cases() {
|
||||
fn borderline_cases() {
|
||||
// Testing colors with equal luminance
|
||||
assert!(!is_max_color("#777777", "#777777"));
|
||||
|
||||
|
||||
@@ -802,86 +802,312 @@ impl UserModel {
|
||||
for row in range.row..=last_row {
|
||||
for column in range.column..=last_column {
|
||||
let old_value = self.model.get_style_for_cell(sheet, row, column)?;
|
||||
let mut style = old_value.clone();
|
||||
let mut new_value = old_value.clone();
|
||||
|
||||
match border_area.r#type {
|
||||
BorderType::All => {
|
||||
style.border.top = Some(border_area.item.clone());
|
||||
style.border.right = Some(border_area.item.clone());
|
||||
style.border.bottom = Some(border_area.item.clone());
|
||||
style.border.left = Some(border_area.item.clone());
|
||||
new_value.border.top = Some(border_area.item.clone());
|
||||
new_value.border.right = Some(border_area.item.clone());
|
||||
new_value.border.bottom = Some(border_area.item.clone());
|
||||
new_value.border.left = Some(border_area.item.clone());
|
||||
}
|
||||
BorderType::Inner => {
|
||||
if row != range.row {
|
||||
style.border.top = Some(border_area.item.clone());
|
||||
new_value.border.top = Some(border_area.item.clone());
|
||||
}
|
||||
if row != last_row {
|
||||
style.border.bottom = Some(border_area.item.clone());
|
||||
new_value.border.bottom = Some(border_area.item.clone());
|
||||
}
|
||||
if column != range.column {
|
||||
style.border.left = Some(border_area.item.clone());
|
||||
new_value.border.left = Some(border_area.item.clone());
|
||||
}
|
||||
if column != last_column {
|
||||
style.border.right = Some(border_area.item.clone());
|
||||
new_value.border.right = Some(border_area.item.clone());
|
||||
}
|
||||
}
|
||||
BorderType::Outer => {
|
||||
if row == range.row {
|
||||
style.border.top = Some(border_area.item.clone());
|
||||
new_value.border.top = Some(border_area.item.clone());
|
||||
}
|
||||
if row == last_row {
|
||||
style.border.bottom = Some(border_area.item.clone());
|
||||
new_value.border.bottom = Some(border_area.item.clone());
|
||||
}
|
||||
if column == range.column {
|
||||
style.border.left = Some(border_area.item.clone());
|
||||
new_value.border.left = Some(border_area.item.clone());
|
||||
}
|
||||
if column == last_column {
|
||||
style.border.right = Some(border_area.item.clone());
|
||||
new_value.border.right = Some(border_area.item.clone());
|
||||
}
|
||||
}
|
||||
BorderType::Top => {
|
||||
style.border.top = Some(border_area.item.clone());
|
||||
new_value.border.top = Some(border_area.item.clone());
|
||||
// Check if the cell above has a "heavier" bottom border
|
||||
if row > 1 {
|
||||
let old_value_cell_above =
|
||||
self.model.get_style_for_cell(sheet, row - 1, column)?;
|
||||
if is_max_border(
|
||||
Some(&border_area.item),
|
||||
old_value_cell_above.border.bottom.as_ref(),
|
||||
) {
|
||||
let mut new_value_cell_above = old_value_cell_above.clone();
|
||||
if border_area.r#type == BorderType::None {
|
||||
new_value_cell_above.border.bottom = None;
|
||||
} else {
|
||||
new_value_cell_above.border.bottom =
|
||||
Some(border_area.item.clone());
|
||||
}
|
||||
self.model.set_cell_style(
|
||||
sheet,
|
||||
row - 1,
|
||||
column,
|
||||
&new_value_cell_above,
|
||||
)?;
|
||||
diff_list.push(Diff::SetCellStyle {
|
||||
sheet,
|
||||
row: row - 1,
|
||||
column,
|
||||
old_value: Box::new(old_value_cell_above),
|
||||
new_value: Box::new(new_value_cell_above),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
BorderType::Right => {
|
||||
new_value.border.right = Some(border_area.item.clone());
|
||||
// Check if the cell to the right has a "heavier" left border
|
||||
if column < LAST_COLUMN {
|
||||
let old_value_cell_right =
|
||||
self.model.get_style_for_cell(sheet, row, column + 1)?;
|
||||
if is_max_border(
|
||||
Some(&border_area.item),
|
||||
old_value_cell_right.border.left.as_ref(),
|
||||
) {
|
||||
let mut new_value_cell_right = old_value_cell_right.clone();
|
||||
if border_area.r#type == BorderType::None {
|
||||
new_value_cell_right.border.left = None;
|
||||
} else {
|
||||
new_value_cell_right.border.left =
|
||||
Some(border_area.item.clone());
|
||||
}
|
||||
self.model.set_cell_style(
|
||||
sheet,
|
||||
row,
|
||||
column + 1,
|
||||
&new_value_cell_right,
|
||||
)?;
|
||||
diff_list.push(Diff::SetCellStyle {
|
||||
sheet,
|
||||
row,
|
||||
column: column + 1,
|
||||
old_value: Box::new(old_value_cell_right),
|
||||
new_value: Box::new(new_value_cell_right),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
BorderType::Right => style.border.right = Some(border_area.item.clone()),
|
||||
BorderType::Bottom => {
|
||||
style.border.bottom = Some(border_area.item.clone());
|
||||
new_value.border.bottom = Some(border_area.item.clone());
|
||||
// Check if the cell bellow has a "heavier" top border
|
||||
if row < LAST_ROW {
|
||||
let old_value_cell_below =
|
||||
self.model.get_style_for_cell(sheet, row + 1, column)?;
|
||||
if is_max_border(
|
||||
Some(&border_area.item),
|
||||
old_value_cell_below.border.top.as_ref(),
|
||||
) {
|
||||
let mut new_value_cell_below = old_value_cell_below.clone();
|
||||
if border_area.r#type == BorderType::None {
|
||||
new_value_cell_below.border.top = None;
|
||||
} else {
|
||||
new_value_cell_below.border.top =
|
||||
Some(border_area.item.clone());
|
||||
}
|
||||
self.model.set_cell_style(
|
||||
sheet,
|
||||
row + 1,
|
||||
column,
|
||||
&new_value_cell_below,
|
||||
)?;
|
||||
diff_list.push(Diff::SetCellStyle {
|
||||
sheet,
|
||||
row: row + 1,
|
||||
column,
|
||||
old_value: Box::new(old_value_cell_below),
|
||||
new_value: Box::new(new_value_cell_below),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
BorderType::Left => {
|
||||
new_value.border.left = Some(border_area.item.clone());
|
||||
// Check if the cell to the left has a "heavier" right border
|
||||
if column > 1 {
|
||||
let old_value_cell_left =
|
||||
self.model.get_style_for_cell(sheet, row, column - 1)?;
|
||||
if is_max_border(
|
||||
Some(&border_area.item),
|
||||
old_value_cell_left.border.right.as_ref(),
|
||||
) {
|
||||
let mut new_value_cell_left = old_value_cell_left.clone();
|
||||
if border_area.r#type == BorderType::None {
|
||||
new_value_cell_left.border.right = None;
|
||||
} else {
|
||||
new_value_cell_left.border.right =
|
||||
Some(border_area.item.clone());
|
||||
}
|
||||
self.model.set_cell_style(
|
||||
sheet,
|
||||
row,
|
||||
column - 1,
|
||||
&new_value_cell_left,
|
||||
)?;
|
||||
diff_list.push(Diff::SetCellStyle {
|
||||
sheet,
|
||||
row,
|
||||
column: column - 1,
|
||||
old_value: Box::new(old_value_cell_left),
|
||||
new_value: Box::new(new_value_cell_left),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
BorderType::Left => style.border.left = Some(border_area.item.clone()),
|
||||
BorderType::CenterH => {
|
||||
if row != range.row {
|
||||
style.border.top = Some(border_area.item.clone());
|
||||
new_value.border.top = Some(border_area.item.clone());
|
||||
}
|
||||
if row != last_row {
|
||||
style.border.bottom = Some(border_area.item.clone());
|
||||
new_value.border.bottom = Some(border_area.item.clone());
|
||||
}
|
||||
}
|
||||
BorderType::CenterV => {
|
||||
if column != range.column {
|
||||
style.border.left = Some(border_area.item.clone());
|
||||
new_value.border.left = Some(border_area.item.clone());
|
||||
}
|
||||
if column != last_column {
|
||||
style.border.right = Some(border_area.item.clone());
|
||||
new_value.border.right = Some(border_area.item.clone());
|
||||
}
|
||||
}
|
||||
BorderType::None => {
|
||||
style.border.top = None;
|
||||
style.border.right = None;
|
||||
style.border.bottom = None;
|
||||
style.border.left = None;
|
||||
new_value.border.top = None;
|
||||
new_value.border.right = None;
|
||||
new_value.border.bottom = None;
|
||||
new_value.border.left = None;
|
||||
}
|
||||
}
|
||||
|
||||
self.model.set_cell_style(sheet, row, column, &style)?;
|
||||
self.model.set_cell_style(sheet, row, column, &new_value)?;
|
||||
diff_list.push(Diff::SetCellStyle {
|
||||
sheet,
|
||||
row,
|
||||
column,
|
||||
old_value: Box::new(old_value),
|
||||
new_value: Box::new(style),
|
||||
new_value: Box::new(new_value),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// bottom of the cells above the first
|
||||
if range.row > 1
|
||||
&& [BorderType::All, BorderType::None, BorderType::Outer].contains(&border_area.r#type)
|
||||
{
|
||||
let row = range.row - 1;
|
||||
for column in range.column..=last_column {
|
||||
let old_value = self.model.get_style_for_cell(sheet, row, column)?;
|
||||
if is_max_border(Some(&border_area.item), old_value.border.bottom.as_ref()) {
|
||||
let mut style = old_value.clone();
|
||||
if border_area.r#type == BorderType::None {
|
||||
style.border.bottom = None;
|
||||
} else {
|
||||
style.border.bottom = Some(border_area.item.clone());
|
||||
}
|
||||
self.model.set_cell_style(sheet, row, column, &style)?;
|
||||
diff_list.push(Diff::SetCellStyle {
|
||||
sheet,
|
||||
row,
|
||||
column,
|
||||
old_value: Box::new(old_value),
|
||||
new_value: Box::new(style),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// Cells to the right
|
||||
if last_column < LAST_COLUMN
|
||||
&& [BorderType::All, BorderType::None, BorderType::Outer].contains(&border_area.r#type)
|
||||
{
|
||||
let column = last_column + 1;
|
||||
for row in range.row..=last_row {
|
||||
let old_value = self.model.get_style_for_cell(sheet, row, column)?;
|
||||
// If the border in the adjacent cell is "heavier" we change it
|
||||
if is_max_border(Some(&border_area.item), old_value.border.left.as_ref()) {
|
||||
let mut style = old_value.clone();
|
||||
if border_area.r#type == BorderType::None {
|
||||
style.border.left = None;
|
||||
} else {
|
||||
style.border.left = Some(border_area.item.clone());
|
||||
}
|
||||
self.model.set_cell_style(sheet, row, column, &style)?;
|
||||
diff_list.push(Diff::SetCellStyle {
|
||||
sheet,
|
||||
row,
|
||||
column,
|
||||
old_value: Box::new(old_value),
|
||||
new_value: Box::new(style),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// Cells bellow
|
||||
if last_row < LAST_ROW
|
||||
&& [BorderType::All, BorderType::None, BorderType::Outer].contains(&border_area.r#type)
|
||||
{
|
||||
let row = last_row + 1;
|
||||
for column in range.column..=last_column {
|
||||
let old_value = self.model.get_style_for_cell(sheet, row, column)?;
|
||||
if is_max_border(Some(&border_area.item), old_value.border.top.as_ref()) {
|
||||
let mut style = old_value.clone();
|
||||
if border_area.r#type == BorderType::None {
|
||||
style.border.top = None;
|
||||
} else {
|
||||
style.border.top = Some(border_area.item.clone());
|
||||
}
|
||||
self.model.set_cell_style(sheet, row, column, &style)?;
|
||||
diff_list.push(Diff::SetCellStyle {
|
||||
sheet,
|
||||
row,
|
||||
column,
|
||||
old_value: Box::new(old_value),
|
||||
new_value: Box::new(style),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// Cells to the left
|
||||
if range.column > 1
|
||||
&& [BorderType::All, BorderType::None, BorderType::Outer].contains(&border_area.r#type)
|
||||
{
|
||||
let column = range.column - 1;
|
||||
for row in range.row..=last_row {
|
||||
let old_value = self.model.get_style_for_cell(sheet, row, column)?;
|
||||
if is_max_border(Some(&border_area.item), old_value.border.right.as_ref()) {
|
||||
let mut style = old_value.clone();
|
||||
if border_area.r#type == BorderType::None {
|
||||
style.border.right = None;
|
||||
} else {
|
||||
style.border.right = Some(border_area.item.clone());
|
||||
}
|
||||
self.model.set_cell_style(sheet, row, column, &style)?;
|
||||
diff_list.push(Diff::SetCellStyle {
|
||||
sheet,
|
||||
row,
|
||||
column,
|
||||
old_value: Box::new(old_value),
|
||||
new_value: Box::new(style),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.push_diff_list(diff_list);
|
||||
Ok(())
|
||||
}
|
||||
@@ -984,13 +1210,16 @@ impl UserModel {
|
||||
|
||||
/// Returns the style for a cell
|
||||
///
|
||||
/// Cells share a border, so the left border of B1 is the right border of A1
|
||||
/// In the object structure the borders of the cells might be difference,
|
||||
/// We always pick the "heaviest" border.
|
||||
///
|
||||
/// See also:
|
||||
/// * [Model::get_style_for_cell]
|
||||
#[inline]
|
||||
pub fn get_cell_style(&self, sheet: u32, row: i32, column: i32) -> Result<Style, String> {
|
||||
let mut style = self.model.get_style_for_cell(sheet, row, column)?;
|
||||
|
||||
// We need to check if the adjacent cells have a "heavier" border
|
||||
// We need to check if the adjacent cells have a "heavier" border
|
||||
let border_top = if row > 1 {
|
||||
self.model
|
||||
.get_style_for_cell(sheet, row - 1, column)?
|
||||
@@ -1027,19 +1256,19 @@ impl UserModel {
|
||||
None
|
||||
};
|
||||
|
||||
if is_max_border(&style.border.top, &border_top) {
|
||||
if is_max_border(style.border.top.as_ref(), border_top.as_ref()) {
|
||||
style.border.top = border_top;
|
||||
}
|
||||
|
||||
if is_max_border(&style.border.right, &border_right) {
|
||||
if is_max_border(style.border.right.as_ref(), border_right.as_ref()) {
|
||||
style.border.right = border_right;
|
||||
}
|
||||
|
||||
if is_max_border(&style.border.bottom, &border_bottom) {
|
||||
if is_max_border(style.border.bottom.as_ref(), border_bottom.as_ref()) {
|
||||
style.border.bottom = border_bottom;
|
||||
}
|
||||
|
||||
if is_max_border(&style.border.left, &border_left) {
|
||||
if is_max_border(style.border.left.as_ref(), border_left.as_ref()) {
|
||||
style.border.left = border_left;
|
||||
}
|
||||
|
||||
@@ -1291,7 +1520,7 @@ impl UserModel {
|
||||
for column in column_start..=column_end {
|
||||
let text = self.get_formatted_cell_value(sheet, row, column)?;
|
||||
let content = self.get_cell_content(sheet, row, column)?;
|
||||
let style = self.get_cell_style(sheet, row, column)?;
|
||||
let style = self.model.get_style_for_cell(sheet, row, column)?;
|
||||
data_row.insert(
|
||||
column,
|
||||
ClipboardCell {
|
||||
@@ -1505,7 +1734,7 @@ impl UserModel {
|
||||
|
||||
fn apply_undo_diff_list(&mut self, diff_list: &DiffList) -> Result<(), String> {
|
||||
let mut needs_evaluation = false;
|
||||
for diff in diff_list {
|
||||
for diff in diff_list.iter().rev() {
|
||||
match diff {
|
||||
Diff::SetCellValue {
|
||||
sheet,
|
||||
|
||||
Reference in New Issue
Block a user