mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-11 01:06:01 +03:00
Spreadsheet: Add conditional formatting
Currently only supports setting the foregound and the background colours. This patch also unifies `foreground_color' and `background_color' used throughout to a `Format' struct, in hopes of getting more formatting options one day :P
This commit is contained in:
parent
6902a09e47
commit
395df7b27d
Notes:
sideshowbarker
2024-07-19 02:14:06 +09:00
Author: https://github.com/alimpfard Commit: https://github.com/SerenityOS/serenity/commit/395df7b27d7 Pull-request: https://github.com/SerenityOS/serenity/pull/3592 Reviewed-by: https://github.com/awesomekling
@ -1,3 +1,6 @@
|
|||||||
|
compile_json_gui(CondFormatting.json CondFormattingUI.h cond_fmt_ui_json)
|
||||||
|
compile_json_gui(CondView.json CondFormattingViewUI.h cond_fmt_view_ui_json)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
Cell.cpp
|
Cell.cpp
|
||||||
CellSyntaxHighlighter.cpp
|
CellSyntaxHighlighter.cpp
|
||||||
@ -7,6 +10,8 @@ set(SOURCES
|
|||||||
CellType/String.cpp
|
CellType/String.cpp
|
||||||
CellType/Type.cpp
|
CellType/Type.cpp
|
||||||
CellTypeDialog.cpp
|
CellTypeDialog.cpp
|
||||||
|
CondFormattingUI.h
|
||||||
|
CondFormattingViewUI.h
|
||||||
HelpWindow.cpp
|
HelpWindow.cpp
|
||||||
JSIntegration.cpp
|
JSIntegration.cpp
|
||||||
Spreadsheet.cpp
|
Spreadsheet.cpp
|
||||||
|
@ -109,16 +109,37 @@ void Cell::update_data()
|
|||||||
if (!dirty)
|
if (!dirty)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dirty = false;
|
if (dirty) {
|
||||||
if (kind == Formula) {
|
dirty = false;
|
||||||
if (!evaluated_externally)
|
if (kind == Formula) {
|
||||||
evaluated_data = sheet->evaluate(data, this);
|
if (!evaluated_externally)
|
||||||
|
evaluated_data = sheet->evaluate(data, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& ref : referencing_cells) {
|
||||||
|
if (ref) {
|
||||||
|
ref->dirty = true;
|
||||||
|
ref->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& ref : referencing_cells) {
|
m_evaluated_formats.background_color.clear();
|
||||||
if (ref) {
|
m_evaluated_formats.foreground_color.clear();
|
||||||
ref->dirty = true;
|
StringBuilder builder;
|
||||||
ref->update();
|
for (auto& fmt : m_conditional_formats) {
|
||||||
|
if (!fmt.condition.is_empty()) {
|
||||||
|
builder.clear();
|
||||||
|
builder.append("return (");
|
||||||
|
builder.append(fmt.condition);
|
||||||
|
builder.append(')');
|
||||||
|
auto value = sheet->evaluate(builder.string_view(), this);
|
||||||
|
if (value.to_boolean()) {
|
||||||
|
if (fmt.background_color.has_value())
|
||||||
|
m_evaluated_formats.background_color = fmt.background_color;
|
||||||
|
if (fmt.foreground_color.has_value())
|
||||||
|
m_evaluated_formats.foreground_color = fmt.foreground_color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CellType/Type.h"
|
#include "CellType/Type.h"
|
||||||
|
#include "ConditionalFormatting.h"
|
||||||
#include "Forward.h"
|
#include "Forward.h"
|
||||||
#include "JSIntegration.h"
|
#include "JSIntegration.h"
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
@ -62,6 +63,14 @@ struct Cell : public Weakable<Cell> {
|
|||||||
void set_type(const CellType*);
|
void set_type(const CellType*);
|
||||||
void set_type_metadata(CellTypeMetadata&&);
|
void set_type_metadata(CellTypeMetadata&&);
|
||||||
|
|
||||||
|
const Format& evaluated_formats() const { return m_evaluated_formats; }
|
||||||
|
const Vector<ConditionalFormat>& conditional_formats() const { return m_conditional_formats; }
|
||||||
|
void set_conditional_formats(Vector<ConditionalFormat>&& fmts)
|
||||||
|
{
|
||||||
|
dirty = true;
|
||||||
|
m_conditional_formats = move(fmts);
|
||||||
|
}
|
||||||
|
|
||||||
String typed_display() const;
|
String typed_display() const;
|
||||||
JS::Value typed_js_data() const;
|
JS::Value typed_js_data() const;
|
||||||
|
|
||||||
@ -91,6 +100,9 @@ struct Cell : public Weakable<Cell> {
|
|||||||
const CellType* m_type { nullptr };
|
const CellType* m_type { nullptr };
|
||||||
CellTypeMetadata m_type_metadata;
|
CellTypeMetadata m_type_metadata;
|
||||||
|
|
||||||
|
Vector<ConditionalFormat> m_conditional_formats;
|
||||||
|
Format m_evaluated_formats;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void update_data();
|
void update_data();
|
||||||
};
|
};
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../Forward.h"
|
#include "../Forward.h"
|
||||||
|
#include "../ConditionalFormatting.h"
|
||||||
#include <AK/Forward.h>
|
#include <AK/Forward.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <LibGfx/Color.h>
|
#include <LibGfx/Color.h>
|
||||||
@ -39,8 +40,7 @@ struct CellTypeMetadata {
|
|||||||
int length { -1 };
|
int length { -1 };
|
||||||
String format;
|
String format;
|
||||||
Gfx::TextAlignment alignment { Gfx::TextAlignment::CenterRight };
|
Gfx::TextAlignment alignment { Gfx::TextAlignment::CenterRight };
|
||||||
Optional<Gfx::Color> static_foreground_color;
|
Format static_format;
|
||||||
Optional<Gfx::Color> static_background_color;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CellType {
|
class CellType {
|
||||||
|
@ -28,12 +28,15 @@
|
|||||||
#include "Cell.h"
|
#include "Cell.h"
|
||||||
#include "Spreadsheet.h"
|
#include "Spreadsheet.h"
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
|
#include <Applications/Spreadsheet/CondFormattingUI.h>
|
||||||
|
#include <Applications/Spreadsheet/CondFormattingViewUI.h>
|
||||||
#include <LibGUI/BoxLayout.h>
|
#include <LibGUI/BoxLayout.h>
|
||||||
#include <LibGUI/Button.h>
|
#include <LibGUI/Button.h>
|
||||||
#include <LibGUI/CheckBox.h>
|
#include <LibGUI/CheckBox.h>
|
||||||
#include <LibGUI/ColorInput.h>
|
#include <LibGUI/ColorInput.h>
|
||||||
#include <LibGUI/ComboBox.h>
|
#include <LibGUI/ComboBox.h>
|
||||||
#include <LibGUI/ItemListModel.h>
|
#include <LibGUI/ItemListModel.h>
|
||||||
|
#include <LibGUI/JSSyntaxHighlighter.h>
|
||||||
#include <LibGUI/Label.h>
|
#include <LibGUI/Label.h>
|
||||||
#include <LibGUI/ListView.h>
|
#include <LibGUI/ListView.h>
|
||||||
#include <LibGUI/SpinBox.h>
|
#include <LibGUI/SpinBox.h>
|
||||||
@ -41,6 +44,8 @@
|
|||||||
#include <LibGUI/TextEditor.h>
|
#include <LibGUI/TextEditor.h>
|
||||||
#include <LibGUI/Widget.h>
|
#include <LibGUI/Widget.h>
|
||||||
|
|
||||||
|
REGISTER_WIDGET(Spreadsheet, ConditionsView);
|
||||||
|
|
||||||
namespace Spreadsheet {
|
namespace Spreadsheet {
|
||||||
|
|
||||||
CellTypeDialog::CellTypeDialog(const Vector<Position>& positions, Sheet& sheet, GUI::Window* parent)
|
CellTypeDialog::CellTypeDialog(const Vector<Position>& positions, Sheet& sheet, GUI::Window* parent)
|
||||||
@ -56,7 +61,7 @@ CellTypeDialog::CellTypeDialog(const Vector<Position>& positions, Sheet& sheet,
|
|||||||
builder.appendf("Format %zu Cells", positions.size());
|
builder.appendf("Format %zu Cells", positions.size());
|
||||||
|
|
||||||
set_title(builder.string_view());
|
set_title(builder.string_view());
|
||||||
resize(270, 360);
|
resize(285, 360);
|
||||||
|
|
||||||
auto& main_widget = set_main_widget<GUI::Widget>();
|
auto& main_widget = set_main_widget<GUI::Widget>();
|
||||||
main_widget.set_layout<GUI::VerticalBoxLayout>().set_margins({ 4, 4, 4, 4 });
|
main_widget.set_layout<GUI::VerticalBoxLayout>().set_margins({ 4, 4, 4, 4 });
|
||||||
@ -138,8 +143,8 @@ void CellTypeDialog::setup_tabs(GUI::TabWidget& tabs, const Vector<Position>& po
|
|||||||
m_type = &cell.type();
|
m_type = &cell.type();
|
||||||
m_vertical_alignment = vertical_alignment_from(cell.type_metadata().alignment);
|
m_vertical_alignment = vertical_alignment_from(cell.type_metadata().alignment);
|
||||||
m_horizontal_alignment = horizontal_alignment_from(cell.type_metadata().alignment);
|
m_horizontal_alignment = horizontal_alignment_from(cell.type_metadata().alignment);
|
||||||
m_static_background_color = cell.type_metadata().static_background_color;
|
m_static_format = cell.type_metadata().static_format;
|
||||||
m_static_foreground_color = cell.type_metadata().static_foreground_color;
|
m_conditional_formats = cell.conditional_formats();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& type_tab = tabs.add_tab<GUI::Widget>("Type");
|
auto& type_tab = tabs.add_tab<GUI::Widget>("Type");
|
||||||
@ -317,10 +322,10 @@ void CellTypeDialog::setup_tabs(GUI::TabWidget& tabs, const Vector<Position>& po
|
|||||||
auto& foreground_selector = foreground_container.add<GUI::ColorInput>();
|
auto& foreground_selector = foreground_container.add<GUI::ColorInput>();
|
||||||
foreground_selector.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
|
foreground_selector.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
|
||||||
foreground_selector.set_preferred_size(0, 22);
|
foreground_selector.set_preferred_size(0, 22);
|
||||||
if (m_static_foreground_color.has_value())
|
if (m_static_format.foreground_color.has_value())
|
||||||
foreground_selector.set_color(m_static_foreground_color.value());
|
foreground_selector.set_color(m_static_format.foreground_color.value());
|
||||||
foreground_selector.on_change = [&]() {
|
foreground_selector.on_change = [&]() {
|
||||||
m_static_foreground_color = foreground_selector.color();
|
m_static_format.foreground_color = foreground_selector.color();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,14 +345,32 @@ void CellTypeDialog::setup_tabs(GUI::TabWidget& tabs, const Vector<Position>& po
|
|||||||
auto& background_selector = background_container.add<GUI::ColorInput>();
|
auto& background_selector = background_container.add<GUI::ColorInput>();
|
||||||
background_selector.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
|
background_selector.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
|
||||||
background_selector.set_preferred_size(0, 22);
|
background_selector.set_preferred_size(0, 22);
|
||||||
if (m_static_background_color.has_value())
|
if (m_static_format.background_color.has_value())
|
||||||
background_selector.set_color(m_static_background_color.value());
|
background_selector.set_color(m_static_format.background_color.value());
|
||||||
background_selector.on_change = [&]() {
|
background_selector.on_change = [&]() {
|
||||||
m_static_background_color = background_selector.color();
|
m_static_format.background_color = background_selector.color();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto& conditional_fmt_tab = tabs.add_tab<GUI::Widget>("Conditional Format");
|
||||||
|
conditional_fmt_tab.load_from_json(cond_fmt_ui_json);
|
||||||
|
{
|
||||||
|
auto& view = static_cast<Spreadsheet::ConditionsView&>(*conditional_fmt_tab.find_descendant_by_name("conditions_view"));
|
||||||
|
view.set_formats(&m_conditional_formats);
|
||||||
|
|
||||||
|
auto& add_button = static_cast<GUI::Button&>(*conditional_fmt_tab.find_descendant_by_name("add_button"));
|
||||||
|
add_button.on_click = [&](auto) {
|
||||||
|
view.add_format();
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: Disable this when empty.
|
||||||
|
auto& remove_button = static_cast<GUI::Button&>(*conditional_fmt_tab.find_descendant_by_name("remove_button"));
|
||||||
|
remove_button.on_click = [&](auto) {
|
||||||
|
view.remove_top();
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CellTypeMetadata CellTypeDialog::metadata() const
|
CellTypeMetadata CellTypeDialog::metadata() const
|
||||||
@ -355,8 +378,7 @@ CellTypeMetadata CellTypeDialog::metadata() const
|
|||||||
CellTypeMetadata metadata;
|
CellTypeMetadata metadata;
|
||||||
metadata.format = m_format;
|
metadata.format = m_format;
|
||||||
metadata.length = m_length;
|
metadata.length = m_length;
|
||||||
metadata.static_foreground_color = m_static_foreground_color;
|
metadata.static_format = m_static_format;
|
||||||
metadata.static_background_color = m_static_background_color;
|
|
||||||
|
|
||||||
switch (m_vertical_alignment) {
|
switch (m_vertical_alignment) {
|
||||||
case VerticalAlignment::Top:
|
case VerticalAlignment::Top:
|
||||||
@ -403,4 +425,85 @@ CellTypeMetadata CellTypeDialog::metadata() const
|
|||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConditionView::ConditionView(ConditionalFormat& fmt)
|
||||||
|
: m_format(fmt)
|
||||||
|
{
|
||||||
|
load_from_json(cond_fmt_view_ui_json);
|
||||||
|
|
||||||
|
auto& fg_input = *static_cast<GUI::ColorInput*>(find_descendant_by_name("foreground_input"));
|
||||||
|
auto& bg_input = *static_cast<GUI::ColorInput*>(find_descendant_by_name("background_input"));
|
||||||
|
auto& formula_editor = *static_cast<GUI::TextEditor*>(find_descendant_by_name("formula_editor"));
|
||||||
|
|
||||||
|
if (m_format.foreground_color.has_value())
|
||||||
|
fg_input.set_color(m_format.foreground_color.value());
|
||||||
|
|
||||||
|
if (m_format.background_color.has_value())
|
||||||
|
bg_input.set_color(m_format.background_color.value());
|
||||||
|
|
||||||
|
formula_editor.set_text(m_format.condition);
|
||||||
|
|
||||||
|
// FIXME: Allow unsetting these.
|
||||||
|
fg_input.on_change = [&] {
|
||||||
|
m_format.foreground_color = fg_input.color();
|
||||||
|
};
|
||||||
|
|
||||||
|
bg_input.on_change = [&] {
|
||||||
|
m_format.background_color = bg_input.color();
|
||||||
|
};
|
||||||
|
|
||||||
|
formula_editor.set_syntax_highlighter(make<GUI::JSSyntaxHighlighter>());
|
||||||
|
formula_editor.set_should_hide_unnecessary_scrollbars(true);
|
||||||
|
formula_editor.set_font(&Gfx::Font::default_fixed_width_font());
|
||||||
|
formula_editor.on_change = [&] {
|
||||||
|
m_format.condition = formula_editor.text();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ConditionView::~ConditionView()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ConditionsView::ConditionsView()
|
||||||
|
{
|
||||||
|
set_layout<GUI::VerticalBoxLayout>().set_spacing(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConditionsView::set_formats(Vector<ConditionalFormat>* formats)
|
||||||
|
{
|
||||||
|
ASSERT(!m_formats);
|
||||||
|
|
||||||
|
m_formats = formats;
|
||||||
|
|
||||||
|
for (auto& entry : *m_formats)
|
||||||
|
m_widgets.append(add<ConditionView>(entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConditionsView::add_format()
|
||||||
|
{
|
||||||
|
ASSERT(m_formats);
|
||||||
|
|
||||||
|
m_formats->empend();
|
||||||
|
auto& last = m_formats->last();
|
||||||
|
|
||||||
|
m_widgets.append(add<ConditionView>(last));
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConditionsView::remove_top()
|
||||||
|
{
|
||||||
|
ASSERT(m_formats);
|
||||||
|
|
||||||
|
if (m_formats->is_empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_formats->take_last();
|
||||||
|
m_widgets.take_last()->remove_from_parent();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConditionsView::~ConditionsView()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CellType/Type.h"
|
#include "CellType/Type.h"
|
||||||
|
#include "ConditionalFormatting.h"
|
||||||
#include "Forward.h"
|
#include "Forward.h"
|
||||||
#include <LibGUI/Dialog.h>
|
#include <LibGUI/Dialog.h>
|
||||||
|
|
||||||
@ -38,6 +39,7 @@ class CellTypeDialog : public GUI::Dialog {
|
|||||||
public:
|
public:
|
||||||
CellTypeMetadata metadata() const;
|
CellTypeMetadata metadata() const;
|
||||||
const CellType* type() const { return m_type; }
|
const CellType* type() const { return m_type; }
|
||||||
|
Vector<ConditionalFormat> conditional_formats() { return m_conditional_formats; }
|
||||||
|
|
||||||
enum class HorizontalAlignment : int {
|
enum class HorizontalAlignment : int {
|
||||||
Left = 0,
|
Left = 0,
|
||||||
@ -60,8 +62,8 @@ private:
|
|||||||
String m_format;
|
String m_format;
|
||||||
HorizontalAlignment m_horizontal_alignment { HorizontalAlignment::Right };
|
HorizontalAlignment m_horizontal_alignment { HorizontalAlignment::Right };
|
||||||
VerticalAlignment m_vertical_alignment { VerticalAlignment::Center };
|
VerticalAlignment m_vertical_alignment { VerticalAlignment::Center };
|
||||||
Optional<Color> m_static_foreground_color;
|
Format m_static_format;
|
||||||
Optional<Color> m_static_background_color;
|
Vector<ConditionalFormat> m_conditional_formats;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
47
Applications/Spreadsheet/CondFormatting.json
Normal file
47
Applications/Spreadsheet/CondFormatting.json
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"name": "main",
|
||||||
|
"fill_with_background_color": true,
|
||||||
|
|
||||||
|
"layout": {
|
||||||
|
"class": "GUI::VerticalBoxLayout",
|
||||||
|
"spacing": 4
|
||||||
|
},
|
||||||
|
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"class": "Spreadsheet::ConditionsView",
|
||||||
|
"name": "conditions_view"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"class": "GUI::Widget",
|
||||||
|
"vertical_size_policy": "Fixed",
|
||||||
|
"horizontal_size_policy": "Fill",
|
||||||
|
"preferred_width": 0,
|
||||||
|
"preferred_height": 20,
|
||||||
|
"layout": {
|
||||||
|
"class": "GUI::HorizontalBoxLayout",
|
||||||
|
"spacing": 10
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"class": "GUI::Button",
|
||||||
|
"name": "add_button",
|
||||||
|
"text": "Add",
|
||||||
|
"horizontal_size_policy": "Fixed",
|
||||||
|
"vertical_size_policy": "Fixed",
|
||||||
|
"preferred_width": 100,
|
||||||
|
"preferred_height": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"class": "GUI::Button",
|
||||||
|
"name": "remove_button",
|
||||||
|
"text": "Remove",
|
||||||
|
"horizontal_size_policy": "Fixed",
|
||||||
|
"vertical_size_policy": "Fixed",
|
||||||
|
"preferred_width": 100,
|
||||||
|
"preferred_height": 20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
93
Applications/Spreadsheet/CondView.json
Normal file
93
Applications/Spreadsheet/CondView.json
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
{
|
||||||
|
"class": "GUI::Widget",
|
||||||
|
"layout": {
|
||||||
|
"class": "GUI::VerticalBoxLayout",
|
||||||
|
"spacing": 2
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"class": "GUI::Widget",
|
||||||
|
"layout": {
|
||||||
|
"class": "GUI::HorizontalBoxLayout",
|
||||||
|
"spacing": 10
|
||||||
|
},
|
||||||
|
"vertical_size_policy": "Fixed",
|
||||||
|
"preferred_height": 25,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"class": "GUI::Label",
|
||||||
|
"name": "if_label",
|
||||||
|
"horizontal_size_policy": "Fixed",
|
||||||
|
"vertical_size_policy": "Fixed",
|
||||||
|
"text": "if...",
|
||||||
|
"preferred_width": 40,
|
||||||
|
"preferred_height": 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"class": "GUI::TextEditor",
|
||||||
|
"name": "formula_editor",
|
||||||
|
"horizontal_size_policy": "Fill",
|
||||||
|
"vertical_size_policy": "Fixed",
|
||||||
|
"tooltip": "Use 'value' to refer to the current cell's value",
|
||||||
|
"preferred_height": 25
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"class": "GUI::Widget",
|
||||||
|
"layout": {
|
||||||
|
"class": "GUI::HorizontalBoxLayout",
|
||||||
|
"spacing": 10
|
||||||
|
},
|
||||||
|
"vertical_size_policy": "Fixed",
|
||||||
|
"preferred_height": 25,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"class": "GUI::Label",
|
||||||
|
"name": "fg_color_label",
|
||||||
|
"horizontal_size_policy": "Fixed",
|
||||||
|
"vertical_size_policy": "Fixed",
|
||||||
|
"text": "Foreground...",
|
||||||
|
"preferred_width": 150,
|
||||||
|
"preferred_height": 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"class": "GUI::ColorInput",
|
||||||
|
"name": "foreground_input",
|
||||||
|
"horizontal_size_policy": "Fill",
|
||||||
|
"vertical_size_policy": "Fixed",
|
||||||
|
"preferred_height": 25,
|
||||||
|
"preferred_width": 25
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"class": "GUI::Widget",
|
||||||
|
"layout": {
|
||||||
|
"class": "GUI::HorizontalBoxLayout",
|
||||||
|
"spacing": 10
|
||||||
|
},
|
||||||
|
"vertical_size_policy": "Fixed",
|
||||||
|
"preferred_height": 25,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"class": "GUI::Label",
|
||||||
|
"name": "bg_color_label",
|
||||||
|
"horizontal_size_policy": "Fixed",
|
||||||
|
"vertical_size_policy": "Fixed",
|
||||||
|
"text": "Background...",
|
||||||
|
"preferred_width": 150,
|
||||||
|
"preferred_height": 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"class": "GUI::ColorInput",
|
||||||
|
"name": "background_input",
|
||||||
|
"horizontal_size_policy": "Fill",
|
||||||
|
"vertical_size_policy": "Fixed",
|
||||||
|
"preferred_height": 25,
|
||||||
|
"preferred_width": 25
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
73
Applications/Spreadsheet/ConditionalFormatting.h
Normal file
73
Applications/Spreadsheet/ConditionalFormatting.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020, the SerenityOS developers.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Forward.h"
|
||||||
|
#include <AK/String.h>
|
||||||
|
#include <LibGUI/ScrollableWidget.h>
|
||||||
|
#include <LibGfx/Color.h>
|
||||||
|
|
||||||
|
namespace Spreadsheet {
|
||||||
|
|
||||||
|
struct Format {
|
||||||
|
Optional<Color> foreground_color;
|
||||||
|
Optional<Color> background_color;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConditionalFormat : public Format {
|
||||||
|
String condition;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConditionView : public GUI::Widget {
|
||||||
|
C_OBJECT(ConditionView)
|
||||||
|
public:
|
||||||
|
virtual ~ConditionView() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ConditionView(ConditionalFormat&);
|
||||||
|
|
||||||
|
ConditionalFormat& m_format;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConditionsView : public GUI::Widget {
|
||||||
|
C_OBJECT(ConditionsView)
|
||||||
|
public:
|
||||||
|
virtual ~ConditionsView() override;
|
||||||
|
|
||||||
|
void set_formats(Vector<ConditionalFormat>*);
|
||||||
|
|
||||||
|
void add_format();
|
||||||
|
void remove_top();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ConditionsView();
|
||||||
|
|
||||||
|
Vector<ConditionalFormat>* m_formats { nullptr };
|
||||||
|
NonnullRefPtrVector<GUI::Widget> m_widgets;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -28,11 +28,14 @@
|
|||||||
|
|
||||||
namespace Spreadsheet {
|
namespace Spreadsheet {
|
||||||
|
|
||||||
struct Cell;
|
class ConditionView;
|
||||||
class Sheet;
|
class Sheet;
|
||||||
struct Position;
|
class SheetGlobalObject;
|
||||||
class Workbook;
|
class Workbook;
|
||||||
class WorkbookObject;
|
class WorkbookObject;
|
||||||
class SheetGlobalObject;
|
struct Cell;
|
||||||
|
struct ConditionalFormat;
|
||||||
|
struct Format;
|
||||||
|
struct Position;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,12 @@ SheetGlobalObject::~SheetGlobalObject()
|
|||||||
JS::Value SheetGlobalObject::get(const JS::PropertyName& name, JS::Value receiver) const
|
JS::Value SheetGlobalObject::get(const JS::PropertyName& name, JS::Value receiver) const
|
||||||
{
|
{
|
||||||
if (name.is_string()) {
|
if (name.is_string()) {
|
||||||
|
if (name.as_string() == "value") {
|
||||||
|
if (auto cell = m_sheet.current_evaluated_cell())
|
||||||
|
return cell->js_data();
|
||||||
|
|
||||||
|
return JS::js_undefined();
|
||||||
|
}
|
||||||
if (auto pos = Sheet::parse_cell_name(name.as_string()); pos.has_value()) {
|
if (auto pos = Sheet::parse_cell_name(name.as_string()); pos.has_value()) {
|
||||||
auto& cell = m_sheet.ensure(pos.value());
|
auto& cell = m_sheet.ensure(pos.value());
|
||||||
cell.reference_from(m_sheet.current_evaluated_cell());
|
cell.reference_from(m_sheet.current_evaluated_cell());
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "SpreadsheetModel.h"
|
#include "SpreadsheetModel.h"
|
||||||
|
#include "ConditionalFormatting.h"
|
||||||
#include <LibJS/Runtime/Error.h>
|
#include <LibJS/Runtime/Error.h>
|
||||||
#include <LibJS/Runtime/Object.h>
|
#include <LibJS/Runtime/Object.h>
|
||||||
|
|
||||||
@ -85,7 +86,10 @@ GUI::Variant SheetModel::data(const GUI::ModelIndex& index, GUI::ModelRole role)
|
|||||||
return Color(Color::Red);
|
return Color(Color::Red);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto color = cell->type_metadata().static_foreground_color; color.has_value())
|
if (cell->evaluated_formats().foreground_color.has_value())
|
||||||
|
return cell->evaluated_formats().foreground_color.value();
|
||||||
|
|
||||||
|
if (auto color = cell->type_metadata().static_format.foreground_color; color.has_value())
|
||||||
return color.value();
|
return color.value();
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
@ -96,7 +100,10 @@ GUI::Variant SheetModel::data(const GUI::ModelIndex& index, GUI::ModelRole role)
|
|||||||
if (!cell)
|
if (!cell)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (auto color = cell->type_metadata().static_background_color; color.has_value())
|
if (cell->evaluated_formats().background_color.has_value())
|
||||||
|
return cell->evaluated_formats().background_color.value();
|
||||||
|
|
||||||
|
if (auto color = cell->type_metadata().static_format.background_color; color.has_value())
|
||||||
return color.value();
|
return color.value();
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
@ -140,6 +140,7 @@ SpreadsheetView::SpreadsheetView(Sheet& sheet)
|
|||||||
auto& cell = m_sheet->ensure(position);
|
auto& cell = m_sheet->ensure(position);
|
||||||
cell.set_type(dialog->type());
|
cell.set_type(dialog->type());
|
||||||
cell.set_type_metadata(dialog->metadata());
|
cell.set_type_metadata(dialog->metadata());
|
||||||
|
cell.set_conditional_formats(dialog->conditional_formats());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_table_view->update();
|
m_table_view->update();
|
||||||
|
Loading…
Reference in New Issue
Block a user