mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 14:48:14 +00:00

This is quite a radical change. The previous UI was very easy to add new properties to (just add to the FooRole enum and it automatically works), but not so nice to use: A ComboBox for selecting a property, and then a box to edit that property's value. This makes it difficult to compare different properties or edit multiple together without a lot of back-and-forth. This new design gives each property its own editing widgets, with those categorized into several tabs. To try and avoid increasing the maintenance burden for this, the UI is generated from the `windows_tab`, `widgets_tab` and `syntax_highlighting_tab` variables, which are basically just lists of which properties go in that tab. One of the `FooProperty.gml` files is loaded to create each property's widgets.
122 lines
3.6 KiB
C++
122 lines
3.6 KiB
C++
/*
|
|
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "PreviewWidget.h"
|
|
#include <AK/FixedArray.h>
|
|
#include <AK/Time.h>
|
|
#include <LibGUI/CheckBox.h>
|
|
#include <LibGUI/ColorInput.h>
|
|
#include <LibGUI/ComboBox.h>
|
|
#include <LibGUI/SpinBox.h>
|
|
#include <LibGUI/TabWidget.h>
|
|
#include <LibGUI/TextBox.h>
|
|
#include <LibGUI/Window.h>
|
|
#include <LibGfx/SystemTheme.h>
|
|
|
|
namespace ThemeEditor {
|
|
|
|
class AlignmentModel final : public GUI::Model {
|
|
public:
|
|
static ErrorOr<NonnullRefPtr<AlignmentModel>> try_create()
|
|
{
|
|
return adopt_nonnull_ref_or_enomem(new (nothrow) AlignmentModel());
|
|
}
|
|
|
|
virtual ~AlignmentModel() = default;
|
|
|
|
virtual int row_count(GUI::ModelIndex const& = GUI::ModelIndex()) const override { return 3; }
|
|
virtual int column_count(GUI::ModelIndex const& = GUI::ModelIndex()) const override { return 2; }
|
|
|
|
virtual GUI::Variant data(GUI::ModelIndex const& index, GUI::ModelRole role) const override
|
|
{
|
|
if (role == GUI::ModelRole::Display)
|
|
return m_alignments[index.row()].title;
|
|
if (role == GUI::ModelRole::Custom)
|
|
return m_alignments[index.row()].setting_value;
|
|
|
|
return {};
|
|
}
|
|
|
|
size_t index_of(Gfx::TextAlignment alignment) const
|
|
{
|
|
auto match = m_alignments.find_if([&](auto& it) { return it.setting_value == alignment; });
|
|
return match.index();
|
|
}
|
|
|
|
private:
|
|
AlignmentModel() = default;
|
|
|
|
struct AlignmentValue {
|
|
String title;
|
|
Gfx::TextAlignment setting_value;
|
|
};
|
|
Vector<AlignmentValue> m_alignments {
|
|
{ "Center", Gfx::TextAlignment::Center },
|
|
{ "Left", Gfx::TextAlignment::CenterLeft },
|
|
{ "Right", Gfx::TextAlignment::CenterRight },
|
|
};
|
|
};
|
|
|
|
struct Property {
|
|
Variant<Gfx::AlignmentRole, Gfx::ColorRole, Gfx::FlagRole, Gfx::MetricRole, Gfx::PathRole> role;
|
|
};
|
|
|
|
struct PropertyTab {
|
|
String title;
|
|
Vector<Property> properties;
|
|
};
|
|
|
|
class MainWidget final : public GUI::Widget {
|
|
C_OBJECT(MainWidget);
|
|
|
|
public:
|
|
virtual ~MainWidget() override = default;
|
|
|
|
ErrorOr<void> initialize_menubar(GUI::Window&);
|
|
GUI::Window::CloseRequestDecision request_close();
|
|
void update_title();
|
|
|
|
private:
|
|
explicit MainWidget(Optional<String> path, Gfx::Palette startup_preview_palette);
|
|
|
|
void load_from_file(String const& path);
|
|
void save_to_file(Core::File&);
|
|
void set_path(String);
|
|
|
|
void add_property_tab(PropertyTab const&);
|
|
void set_alignment(Gfx::AlignmentRole, Gfx::TextAlignment);
|
|
void set_color(Gfx::ColorRole, Gfx::Color);
|
|
void set_flag(Gfx::FlagRole, bool);
|
|
void set_metric(Gfx::MetricRole, int);
|
|
void set_path(Gfx::PathRole, String);
|
|
|
|
enum class PathPickerTarget {
|
|
File,
|
|
Folder,
|
|
};
|
|
void show_path_picker_dialog(StringView property_display_name, GUI::TextBox&, PathPickerTarget);
|
|
|
|
RefPtr<PreviewWidget> m_preview_widget;
|
|
RefPtr<GUI::TabWidget> m_property_tabs;
|
|
RefPtr<GUI::Action> m_save_action;
|
|
|
|
Optional<String> m_path;
|
|
Time m_last_modified_time { Time::now_monotonic() };
|
|
|
|
RefPtr<AlignmentModel> m_alignment_model;
|
|
|
|
Array<RefPtr<GUI::ComboBox>, to_underlying(Gfx::AlignmentRole::__Count)> m_alignment_inputs;
|
|
Array<RefPtr<GUI::ColorInput>, to_underlying(Gfx::ColorRole::__Count)> m_color_inputs;
|
|
Array<RefPtr<GUI::CheckBox>, to_underlying(Gfx::FlagRole::__Count)> m_flag_inputs;
|
|
Array<RefPtr<GUI::SpinBox>, to_underlying(Gfx::MetricRole::__Count)> m_metric_inputs;
|
|
Array<RefPtr<GUI::TextBox>, to_underlying(Gfx::PathRole::__Count)> m_path_inputs;
|
|
|
|
OwnPtr<GUI::ActionGroup> m_preview_type_action_group;
|
|
};
|
|
|
|
}
|