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

LibGUI+VisualBuilder: Support custom editing widgets for property values.

Implemented this by letting GAbstractViews provide a GModelEditingDelegate
for a given index, which then knows how to create and setup a custom widget
appropriate for the data type being edited.
This commit is contained in:
Andreas Kling 2019-06-23 08:18:28 +02:00
parent 1d0ada32cc
commit 6a0011dcea
8 changed files with 170 additions and 7 deletions

View file

@ -1,6 +1,7 @@
#include <Kernel/KeyCode.h>
#include <LibGUI/GAbstractView.h>
#include <LibGUI/GModel.h>
#include <LibGUI/GModelEditingDelegate.h>
#include <LibGUI/GPainter.h>
#include <LibGUI/GScrollBar.h>
#include <LibGUI/GTextBox.h>
@ -71,15 +72,21 @@ void GAbstractView::begin_editing(const GModelIndex& index)
if (m_edit_widget)
delete m_edit_widget;
m_edit_index = index;
m_edit_widget = new GTextBox(this);
ASSERT(aid_create_editing_delegate);
m_editing_delegate = aid_create_editing_delegate(index);
m_editing_delegate->bind(*model(), index);
m_editing_delegate->set_value(model()->data(index, GModel::Role::Display));
m_edit_widget = m_editing_delegate->widget();
add_child(*m_edit_widget);
m_edit_widget->move_to_back();
m_edit_widget->set_text(model()->data(index, GModel::Role::Display).to_string());
m_edit_widget_content_rect = content_rect(index).translated(frame_thickness(), frame_thickness());
update_edit_widget_position();
m_edit_widget->set_focus(true);
m_edit_widget->on_return_pressed = [this] {
m_editing_delegate->will_begin_editing();
m_editing_delegate->on_commit = [this] {
ASSERT(model());
model()->set_data(m_edit_index, m_edit_widget->text());
model()->set_data(m_edit_index, m_editing_delegate->value());
stop_editing();
};
}

View file

@ -4,7 +4,7 @@
#include <LibGUI/GModel.h>
#include <LibGUI/GScrollableWidget.h>
class GTextBox;
class GModelEditingDelegate;
class GAbstractView : public GScrollableWidget {
friend class GModel;
@ -35,6 +35,8 @@ public:
Function<void(const GModelIndex&)> on_selection;
Function<void(const GModelNotification&)> on_model_notification;
Function<OwnPtr<GModelEditingDelegate>(const GModelIndex&)> aid_create_editing_delegate;
virtual const char* class_name() const override { return "GAbstractView"; }
protected:
@ -45,10 +47,11 @@ protected:
bool m_editable { false };
GModelIndex m_edit_index;
GTextBox* m_edit_widget { nullptr };
GWidget* m_edit_widget { nullptr };
Rect m_edit_widget_content_rect;
private:
RefPtr<GModel> m_model;
OwnPtr<GModelEditingDelegate> m_editing_delegate;
bool m_activates_on_selection { false };
};

View file

@ -41,7 +41,11 @@ GComboBox::GComboBox(GWidget* parent)
auto new_value = model()->data(index).to_string();
m_editor->set_text(new_value);
m_editor->select_all();
m_list_window->hide();
close();
deferred_invoke([this](auto&) {
if (on_change)
on_change(m_editor->text());
});
};
}
@ -63,6 +67,11 @@ void GComboBox::set_model(NonnullRefPtr<GModel> model)
m_list_view->set_model(move(model));
}
void GComboBox::select_all()
{
m_editor->select_all();
}
void GComboBox::open()
{
if (!model())
@ -100,3 +109,10 @@ void GComboBox::set_text(const String& text)
{
m_editor->set_text(text);
}
void GComboBox::set_only_allow_values_from_model(bool b)
{
if (m_only_allow_values_from_model == b)
return;
m_editor->set_readonly(m_only_allow_values_from_model);
}

View file

@ -16,11 +16,15 @@ public:
void open();
void close();
void select_all();
GModel* model() { return m_list_view->model(); }
const GModel* model() const { return m_list_view->model(); }
void set_model(NonnullRefPtr<GModel>);
bool only_allow_values_from_model() const { return m_only_allow_values_from_model; }
void set_only_allow_values_from_model(bool);
Function<void(const String&)> on_change;
Function<void()> on_return_pressed;
@ -34,4 +38,5 @@ private:
GButton* m_open_button { nullptr };
GWindow* m_list_window { nullptr };
GListView* m_list_view { nullptr };
bool m_only_allow_values_from_model { false };
};

View file

@ -0,0 +1,60 @@
#pragma once
#include <LibGUI/GModel.h>
#include <LibGUI/GTextBox.h>
#include <LibGUI/GWidget.h>
class GModelEditingDelegate {
public:
GModelEditingDelegate() {}
virtual ~GModelEditingDelegate() {}
void bind(GModel& model, const GModelIndex& index)
{
if (m_model.ptr() == &model && m_index == index)
return;
m_model = model;
m_index = index;
m_widget = create_widget()->make_weak_ptr();
}
GWidget* widget() { return m_widget; }
const GWidget* widget() const { return m_widget; }
Function<void()> on_commit;
virtual GVariant value() const = 0;
virtual void set_value(const GVariant&) = 0;
virtual void will_begin_editing() { }
protected:
virtual GWidget* create_widget() = 0;
void commit()
{
if (on_commit)
on_commit();
}
private:
RefPtr<GModel> m_model;
GModelIndex m_index;
WeakPtr<GWidget> m_widget;
};
class GStringModelEditingDelegate : public GModelEditingDelegate {
public:
GStringModelEditingDelegate() {}
virtual ~GStringModelEditingDelegate() override {}
virtual GWidget* create_widget() override
{
auto* textbox = new GTextBox(nullptr);
textbox->on_return_pressed = [this] {
commit();
};
return textbox;
}
virtual GVariant value() const override { return static_cast<const GTextBox*>(widget())->text(); }
virtual void set_value(const GVariant& value) override { static_cast<GTextBox*>(widget())->set_text(value.to_string()); }
};