1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 12:17:35 +00:00

ThemeEditor: Arrange the theme properties into groups

This makes it clearer which properties are related, instead of them all
being in one list per tab.
This commit is contained in:
Sam Atkins 2022-05-11 12:53:07 +01:00 committed by Andreas Kling
parent 423383e9aa
commit 4edc33b4a6
2 changed files with 198 additions and 164 deletions

View file

@ -22,6 +22,7 @@
#include <LibGUI/Button.h> #include <LibGUI/Button.h>
#include <LibGUI/FilePicker.h> #include <LibGUI/FilePicker.h>
#include <LibGUI/Frame.h> #include <LibGUI/Frame.h>
#include <LibGUI/GroupBox.h>
#include <LibGUI/Icon.h> #include <LibGUI/Icon.h>
#include <LibGUI/ItemListModel.h> #include <LibGUI/ItemListModel.h>
#include <LibGUI/Label.h> #include <LibGUI/Label.h>
@ -36,129 +37,149 @@ namespace ThemeEditor {
static const PropertyTab window_tab { static const PropertyTab window_tab {
"Windows", "Windows",
{ {
{ Gfx::FlagRole::IsDark }, { "General",
{ Gfx::AlignmentRole::TitleAlignment }, { { Gfx::FlagRole::IsDark },
{ Gfx::MetricRole::TitleHeight }, { Gfx::AlignmentRole::TitleAlignment },
{ Gfx::MetricRole::TitleButtonWidth }, { Gfx::MetricRole::TitleHeight },
{ Gfx::MetricRole::TitleButtonHeight }, { Gfx::MetricRole::TitleButtonWidth },
{ Gfx::PathRole::TitleButtonIcons }, { Gfx::MetricRole::TitleButtonHeight },
{ Gfx::FlagRole::TitleButtonsIconOnly }, { Gfx::PathRole::TitleButtonIcons },
{ Gfx::FlagRole::TitleButtonsIconOnly } } },
{ Gfx::MetricRole::BorderThickness }, { "Border",
{ Gfx::MetricRole::BorderRadius }, { { Gfx::MetricRole::BorderThickness },
{ Gfx::MetricRole::BorderRadius } } },
{ Gfx::ColorRole::ActiveWindowBorder1 }, { "Active Window",
{ Gfx::ColorRole::ActiveWindowBorder2 }, { { Gfx::ColorRole::ActiveWindowBorder1 },
{ Gfx::ColorRole::ActiveWindowTitle }, { Gfx::ColorRole::ActiveWindowBorder2 },
{ Gfx::ColorRole::ActiveWindowTitleShadow }, { Gfx::ColorRole::ActiveWindowTitle },
{ Gfx::ColorRole::ActiveWindowTitleStripes }, { Gfx::ColorRole::ActiveWindowTitleShadow },
{ Gfx::PathRole::ActiveWindowShadow }, { Gfx::ColorRole::ActiveWindowTitleStripes },
{ Gfx::PathRole::ActiveWindowShadow } } },
{ Gfx::ColorRole::InactiveWindowBorder1 }, { "Inactive Window",
{ Gfx::ColorRole::InactiveWindowBorder2 }, { { Gfx::ColorRole::InactiveWindowBorder1 },
{ Gfx::ColorRole::InactiveWindowTitle }, { Gfx::ColorRole::InactiveWindowBorder2 },
{ Gfx::ColorRole::InactiveWindowTitleShadow }, { Gfx::ColorRole::InactiveWindowTitle },
{ Gfx::ColorRole::InactiveWindowTitleStripes }, { Gfx::ColorRole::InactiveWindowTitleShadow },
{ Gfx::PathRole::InactiveWindowShadow }, { Gfx::ColorRole::InactiveWindowTitleStripes },
{ Gfx::PathRole::InactiveWindowShadow } } },
{ Gfx::ColorRole::HighlightWindowBorder1 }, { "Highlighted Window",
{ Gfx::ColorRole::HighlightWindowBorder2 }, { { Gfx::ColorRole::HighlightWindowBorder1 },
{ Gfx::ColorRole::HighlightWindowTitle }, { Gfx::ColorRole::HighlightWindowBorder2 },
{ Gfx::ColorRole::HighlightWindowTitleShadow }, { Gfx::ColorRole::HighlightWindowTitle },
{ Gfx::ColorRole::HighlightWindowTitleStripes }, { Gfx::ColorRole::HighlightWindowTitleShadow },
{ Gfx::ColorRole::HighlightWindowTitleStripes } } },
{ Gfx::ColorRole::MovingWindowBorder1 }, { "Moving Window",
{ Gfx::ColorRole::MovingWindowBorder2 }, { { Gfx::ColorRole::MovingWindowBorder1 },
{ Gfx::ColorRole::MovingWindowTitle }, { Gfx::ColorRole::MovingWindowBorder2 },
{ Gfx::ColorRole::MovingWindowTitleShadow }, { Gfx::ColorRole::MovingWindowTitle },
{ Gfx::ColorRole::MovingWindowTitleStripes }, { Gfx::ColorRole::MovingWindowTitleShadow },
{ Gfx::ColorRole::MovingWindowTitleStripes } } },
{ Gfx::ColorRole::Window }, { "Contents",
{ Gfx::ColorRole::WindowText }, { { Gfx::ColorRole::Window },
{ Gfx::ColorRole::WindowText } } },
{ Gfx::ColorRole::DesktopBackground }, { "Desktop",
{ Gfx::PathRole::TaskbarShadow }, { { Gfx::ColorRole::DesktopBackground },
{ Gfx::PathRole::TaskbarShadow } } },
} }
}; };
static const PropertyTab widgets_tab { static const PropertyTab widgets_tab {
"Widgets", "Widgets",
{ {
{ Gfx::ColorRole::Accent }, { "General",
{ Gfx::ColorRole::Base }, { { Gfx::ColorRole::Accent },
{ Gfx::ColorRole::ThreedHighlight }, { Gfx::ColorRole::Base },
{ Gfx::ColorRole::ThreedShadow1 }, { Gfx::ColorRole::ThreedHighlight },
{ Gfx::ColorRole::ThreedShadow2 }, { Gfx::ColorRole::ThreedShadow1 },
{ Gfx::ColorRole::HoverHighlight }, { Gfx::ColorRole::ThreedShadow2 },
{ Gfx::ColorRole::HoverHighlight } } },
{ Gfx::ColorRole::BaseText }, { "Text",
{ Gfx::ColorRole::DisabledTextFront }, { { Gfx::ColorRole::BaseText },
{ Gfx::ColorRole::DisabledTextBack }, { Gfx::ColorRole::DisabledTextFront },
{ Gfx::ColorRole::PlaceholderText }, { Gfx::ColorRole::DisabledTextBack },
{ Gfx::ColorRole::PlaceholderText } } },
{ Gfx::ColorRole::Link }, { "Links",
{ Gfx::ColorRole::ActiveLink }, { { Gfx::ColorRole::Link },
{ Gfx::ColorRole::VisitedLink }, { Gfx::ColorRole::ActiveLink },
{ Gfx::ColorRole::VisitedLink } } },
{ Gfx::ColorRole::Button }, { "Buttons",
{ Gfx::ColorRole::ButtonText }, { { Gfx::ColorRole::Button },
{ Gfx::ColorRole::ButtonText } } },
{ Gfx::ColorRole::Tooltip }, { "Tooltips",
{ Gfx::ColorRole::TooltipText }, { { Gfx::ColorRole::Tooltip },
{ Gfx::PathRole::TooltipShadow }, { Gfx::ColorRole::TooltipText },
{ Gfx::PathRole::TooltipShadow } } },
{ Gfx::ColorRole::Tray }, { "Trays",
{ Gfx::ColorRole::TrayText }, { { Gfx::ColorRole::Tray },
{ Gfx::ColorRole::TrayText } } },
{ Gfx::ColorRole::Ruler }, { "Ruler",
{ Gfx::ColorRole::RulerBorder }, { { Gfx::ColorRole::Ruler },
{ Gfx::ColorRole::RulerActiveText }, { Gfx::ColorRole::RulerBorder },
{ Gfx::ColorRole::RulerInactiveText }, { Gfx::ColorRole::RulerActiveText },
{ Gfx::ColorRole::RulerInactiveText } } },
{ Gfx::ColorRole::Gutter }, { "Gutter",
{ Gfx::ColorRole::GutterBorder }, { { Gfx::ColorRole::Gutter },
{ Gfx::ColorRole::GutterBorder } } },
{ Gfx::ColorRole::RubberBandBorder }, { "Rubber Band",
{ Gfx::ColorRole::RubberBandFill }, { { Gfx::ColorRole::RubberBandBorder },
{ Gfx::ColorRole::RubberBandFill } } },
{ Gfx::ColorRole::MenuBase }, { "Menus",
{ Gfx::ColorRole::MenuBaseText }, { { Gfx::ColorRole::MenuBase },
{ Gfx::ColorRole::MenuSelection }, { Gfx::ColorRole::MenuBaseText },
{ Gfx::ColorRole::MenuSelectionText }, { Gfx::ColorRole::MenuSelection },
{ Gfx::ColorRole::MenuStripe }, { Gfx::ColorRole::MenuSelectionText },
{ Gfx::PathRole::MenuShadow }, { Gfx::ColorRole::MenuStripe },
{ Gfx::PathRole::MenuShadow } } },
{ Gfx::ColorRole::FocusOutline }, { "Selection",
{ Gfx::ColorRole::TextCursor }, { { Gfx::ColorRole::FocusOutline },
{ Gfx::ColorRole::Selection }, { Gfx::ColorRole::TextCursor },
{ Gfx::ColorRole::SelectionText }, { Gfx::ColorRole::Selection },
{ Gfx::ColorRole::InactiveSelection }, { Gfx::ColorRole::SelectionText },
{ Gfx::ColorRole::InactiveSelectionText }, { Gfx::ColorRole::InactiveSelection },
{ Gfx::ColorRole::HighlightSearching }, { Gfx::ColorRole::InactiveSelectionText },
{ Gfx::ColorRole::HighlightSearchingText }, { Gfx::ColorRole::HighlightSearching },
{ Gfx::ColorRole::HighlightSearchingText } } },
} }
}; };
static const PropertyTab syntax_highlighting_tab { static const PropertyTab syntax_highlighting_tab {
"Syntax Highlighting", "Syntax Highlighting",
{ {
{ Gfx::ColorRole::SyntaxComment }, { "General",
{ Gfx::ColorRole::SyntaxControlKeyword }, { { Gfx::ColorRole::SyntaxComment },
{ Gfx::ColorRole::SyntaxIdentifier }, { Gfx::ColorRole::SyntaxControlKeyword },
{ Gfx::ColorRole::SyntaxKeyword }, { Gfx::ColorRole::SyntaxIdentifier },
{ Gfx::ColorRole::SyntaxNumber }, { Gfx::ColorRole::SyntaxKeyword },
{ Gfx::ColorRole::SyntaxOperator }, { Gfx::ColorRole::SyntaxNumber },
{ Gfx::ColorRole::SyntaxPreprocessorStatement }, { Gfx::ColorRole::SyntaxOperator },
{ Gfx::ColorRole::SyntaxPreprocessorValue }, { Gfx::ColorRole::SyntaxPreprocessorStatement },
{ Gfx::ColorRole::SyntaxPunctuation }, { Gfx::ColorRole::SyntaxPreprocessorValue },
{ Gfx::ColorRole::SyntaxString }, { Gfx::ColorRole::SyntaxPunctuation },
{ Gfx::ColorRole::SyntaxType }, { Gfx::ColorRole::SyntaxString },
{ Gfx::ColorRole::SyntaxFunction }, { Gfx::ColorRole::SyntaxType },
{ Gfx::ColorRole::SyntaxVariable }, { Gfx::ColorRole::SyntaxFunction },
{ Gfx::ColorRole::SyntaxCustomType }, { Gfx::ColorRole::SyntaxVariable },
{ Gfx::ColorRole::SyntaxNamespace }, { Gfx::ColorRole::SyntaxCustomType },
{ Gfx::ColorRole::SyntaxMember }, { Gfx::ColorRole::SyntaxNamespace },
{ Gfx::ColorRole::SyntaxParameter }, { Gfx::ColorRole::SyntaxMember },
{ Gfx::ColorRole::SyntaxParameter } } },
} }
}; };
@ -362,91 +383,99 @@ void MainWidget::add_property_tab(PropertyTab const& property_tab)
properties_list->layout()->set_spacing(12); properties_list->layout()->set_spacing(12);
properties_list->layout()->set_margins({ 8 }); properties_list->layout()->set_margins({ 8 });
for (auto const& property : property_tab.properties) { for (auto const& group : property_tab.property_groups) {
NonnullRefPtr<GUI::Widget> row_widget = properties_list->add<GUI::Widget>(); NonnullRefPtr<GUI::GroupBox> group_box = properties_list->add<GUI::GroupBox>(group.title);
row_widget->set_fixed_height(24); group_box->set_layout<GUI::VerticalBoxLayout>();
group_box->layout()->set_spacing(12);
// 1px less on the left makes the text line up with the group title.
group_box->layout()->set_margins({ 8, 8, 8, 7 });
group_box->set_shrink_to_fit(true);
property.role.visit( for (auto const& property : group.properties) {
[&](Gfx::AlignmentRole role) { NonnullRefPtr<GUI::Widget> row_widget = group_box->add<GUI::Widget>();
row_widget->load_from_gml(alignment_property_gml); row_widget->set_fixed_height(22);
property.role.visit(
[&](Gfx::AlignmentRole role) {
row_widget->load_from_gml(alignment_property_gml);
auto& name_label = *row_widget->find_descendant_of_type_named<GUI::Label>("name"); auto& name_label = *row_widget->find_descendant_of_type_named<GUI::Label>("name");
name_label.set_text(to_string(role)); name_label.set_text(to_string(role));
auto& alignment_picker = *row_widget->find_descendant_of_type_named<GUI::ComboBox>("combo_box"); auto& alignment_picker = *row_widget->find_descendant_of_type_named<GUI::ComboBox>("combo_box");
alignment_picker.set_model(*m_alignment_model); alignment_picker.set_model(*m_alignment_model);
alignment_picker.on_change = [&, role](auto&, auto& index) { alignment_picker.on_change = [&, role](auto&, auto& index) {
set_alignment(role, index.data(GUI::ModelRole::Custom).to_text_alignment(Gfx::TextAlignment::CenterLeft)); set_alignment(role, index.data(GUI::ModelRole::Custom).to_text_alignment(Gfx::TextAlignment::CenterLeft));
}; };
alignment_picker.set_selected_index(m_alignment_model->index_of(m_preview_widget->preview_palette().alignment(role)), GUI::AllowCallback::No); alignment_picker.set_selected_index(m_alignment_model->index_of(m_preview_widget->preview_palette().alignment(role)), GUI::AllowCallback::No);
VERIFY(m_alignment_inputs[to_underlying(role)].is_null()); VERIFY(m_alignment_inputs[to_underlying(role)].is_null());
m_alignment_inputs[to_underlying(role)] = alignment_picker; m_alignment_inputs[to_underlying(role)] = alignment_picker;
}, },
[&](Gfx::ColorRole role) { [&](Gfx::ColorRole role) {
row_widget->load_from_gml(color_property_gml); row_widget->load_from_gml(color_property_gml);
auto& name_label = *row_widget->find_descendant_of_type_named<GUI::Label>("name"); auto& name_label = *row_widget->find_descendant_of_type_named<GUI::Label>("name");
name_label.set_text(to_string(role)); name_label.set_text(to_string(role));
auto& color_input = *row_widget->find_descendant_of_type_named<GUI::ColorInput>("color_input"); auto& color_input = *row_widget->find_descendant_of_type_named<GUI::ColorInput>("color_input");
color_input.on_change = [&, role] { color_input.on_change = [&, role] {
set_color(role, color_input.color()); set_color(role, color_input.color());
}; };
color_input.set_color(m_preview_widget->preview_palette().color(role), GUI::AllowCallback::No); color_input.set_color(m_preview_widget->preview_palette().color(role), GUI::AllowCallback::No);
VERIFY(m_color_inputs[to_underlying(role)].is_null()); VERIFY(m_color_inputs[to_underlying(role)].is_null());
m_color_inputs[to_underlying(role)] = color_input; m_color_inputs[to_underlying(role)] = color_input;
}, },
[&](Gfx::FlagRole role) { [&](Gfx::FlagRole role) {
row_widget->load_from_gml(flag_property_gml); row_widget->load_from_gml(flag_property_gml);
auto& checkbox = *row_widget->find_descendant_of_type_named<GUI::CheckBox>("checkbox"); auto& checkbox = *row_widget->find_descendant_of_type_named<GUI::CheckBox>("checkbox");
checkbox.set_text(to_string(role)); checkbox.set_text(to_string(role));
checkbox.on_checked = [&, role](bool checked) { checkbox.on_checked = [&, role](bool checked) {
set_flag(role, checked); set_flag(role, checked);
}; };
checkbox.set_checked(m_preview_widget->preview_palette().flag(role), GUI::AllowCallback::No); checkbox.set_checked(m_preview_widget->preview_palette().flag(role), GUI::AllowCallback::No);
VERIFY(m_flag_inputs[to_underlying(role)].is_null()); VERIFY(m_flag_inputs[to_underlying(role)].is_null());
m_flag_inputs[to_underlying(role)] = checkbox; m_flag_inputs[to_underlying(role)] = checkbox;
}, },
[&](Gfx::MetricRole role) { [&](Gfx::MetricRole role) {
row_widget->load_from_gml(metric_property_gml); row_widget->load_from_gml(metric_property_gml);
auto& name_label = *row_widget->find_descendant_of_type_named<GUI::Label>("name"); auto& name_label = *row_widget->find_descendant_of_type_named<GUI::Label>("name");
name_label.set_text(to_string(role)); name_label.set_text(to_string(role));
auto& spin_box = *row_widget->find_descendant_of_type_named<GUI::SpinBox>("spin_box"); auto& spin_box = *row_widget->find_descendant_of_type_named<GUI::SpinBox>("spin_box");
spin_box.on_change = [&, role](int value) { spin_box.on_change = [&, role](int value) {
set_metric(role, value); set_metric(role, value);
}; };
spin_box.set_value(m_preview_widget->preview_palette().metric(role), GUI::AllowCallback::No); spin_box.set_value(m_preview_widget->preview_palette().metric(role), GUI::AllowCallback::No);
VERIFY(m_metric_inputs[to_underlying(role)].is_null()); VERIFY(m_metric_inputs[to_underlying(role)].is_null());
m_metric_inputs[to_underlying(role)] = spin_box; m_metric_inputs[to_underlying(role)] = spin_box;
}, },
[&](Gfx::PathRole role) { [&](Gfx::PathRole role) {
row_widget->load_from_gml(path_property_gml); row_widget->load_from_gml(path_property_gml);
auto& name_label = *row_widget->find_descendant_of_type_named<GUI::Label>("name"); auto& name_label = *row_widget->find_descendant_of_type_named<GUI::Label>("name");
name_label.set_text(to_string(role)); name_label.set_text(to_string(role));
auto& path_input = *row_widget->find_descendant_of_type_named<GUI::TextBox>("path_input"); auto& path_input = *row_widget->find_descendant_of_type_named<GUI::TextBox>("path_input");
path_input.on_change = [&, role] { path_input.on_change = [&, role] {
set_path(role, path_input.text()); set_path(role, path_input.text());
}; };
path_input.set_text(m_preview_widget->preview_palette().path(role), GUI::AllowCallback::No); path_input.set_text(m_preview_widget->preview_palette().path(role), GUI::AllowCallback::No);
auto& path_picker_button = *row_widget->find_descendant_of_type_named<GUI::Button>("path_picker_button"); auto& path_picker_button = *row_widget->find_descendant_of_type_named<GUI::Button>("path_picker_button");
auto picker_target = (role == Gfx::PathRole::TitleButtonIcons) ? PathPickerTarget::Folder : PathPickerTarget::File; auto picker_target = (role == Gfx::PathRole::TitleButtonIcons) ? PathPickerTarget::Folder : PathPickerTarget::File;
path_picker_button.on_click = [&, role, picker_target](auto) { path_picker_button.on_click = [&, role, picker_target](auto) {
show_path_picker_dialog(to_string(role), path_input, picker_target); show_path_picker_dialog(to_string(role), path_input, picker_target);
}; };
VERIFY(m_path_inputs[to_underlying(role)].is_null()); VERIFY(m_path_inputs[to_underlying(role)].is_null());
m_path_inputs[to_underlying(role)] = path_input; m_path_inputs[to_underlying(role)] = path_input;
}); });
}
} }
} }

View file

@ -66,11 +66,16 @@ struct Property {
Variant<Gfx::AlignmentRole, Gfx::ColorRole, Gfx::FlagRole, Gfx::MetricRole, Gfx::PathRole> role; Variant<Gfx::AlignmentRole, Gfx::ColorRole, Gfx::FlagRole, Gfx::MetricRole, Gfx::PathRole> role;
}; };
struct PropertyTab { struct PropertyGroup {
String title; String title;
Vector<Property> properties; Vector<Property> properties;
}; };
struct PropertyTab {
String title;
Vector<PropertyGroup> property_groups;
};
class MainWidget final : public GUI::Widget { class MainWidget final : public GUI::Widget {
C_OBJECT(MainWidget); C_OBJECT(MainWidget);