mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 15:38:10 +00:00
LibGUI: Start working on GTableView inline editing.
This is pretty shaky still, but the basic idea is that you subclass GModel and return true for editable indices. The table view also needs to have its editable flag set.
This commit is contained in:
parent
9ef06e2117
commit
0e6b273620
9 changed files with 95 additions and 6 deletions
|
@ -19,6 +19,7 @@ VBPropertiesWindow::VBPropertiesWindow()
|
||||||
m_text_box->set_preferred_size({ 0, 21 });
|
m_text_box->set_preferred_size({ 0, 21 });
|
||||||
|
|
||||||
m_table_view = new GTableView(widget);
|
m_table_view = new GTableView(widget);
|
||||||
|
m_table_view->set_editable(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
VBPropertiesWindow::~VBPropertiesWindow()
|
VBPropertiesWindow::~VBPropertiesWindow()
|
||||||
|
|
|
@ -52,3 +52,19 @@ GVariant VBWidgetPropertyModel::data(const GModelIndex& index, Role role) const
|
||||||
}
|
}
|
||||||
return { };
|
return { };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VBWidgetPropertyModel::set_data(const GModelIndex& index, const GVariant& value)
|
||||||
|
{
|
||||||
|
ASSERT(index.column() == Column::Value);
|
||||||
|
auto& property = *m_widget.m_properties[index.row()];
|
||||||
|
ASSERT(!property.is_readonly());
|
||||||
|
property.set_value(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VBWidgetPropertyModel::is_editable(const GModelIndex& index) const
|
||||||
|
{
|
||||||
|
if (index.column() != Column::Value)
|
||||||
|
return false;
|
||||||
|
auto& property = *m_widget.m_properties[index.row()];
|
||||||
|
return !property.is_readonly();
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ public:
|
||||||
virtual ColumnMetadata column_metadata(int column) const override;
|
virtual ColumnMetadata column_metadata(int column) const override;
|
||||||
virtual GVariant data(const GModelIndex&, Role = Role::Display) const override;
|
virtual GVariant data(const GModelIndex&, Role = Role::Display) const override;
|
||||||
virtual void update() override { did_update(); }
|
virtual void update() override { did_update(); }
|
||||||
|
virtual bool is_editable(const GModelIndex&) const override;
|
||||||
|
virtual void set_data(const GModelIndex&, const GVariant&) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit VBWidgetPropertyModel(VBWidget&);
|
explicit VBWidgetPropertyModel(VBWidget&);
|
||||||
|
|
|
@ -26,14 +26,14 @@
|
||||||
#include <Kernel/Net/NetworkTask.h>
|
#include <Kernel/Net/NetworkTask.h>
|
||||||
#include <Kernel/Devices/DebugLogDevice.h>
|
#include <Kernel/Devices/DebugLogDevice.h>
|
||||||
|
|
||||||
#define SPAWN_TERMINAL
|
//#define SPAWN_TERMINAL
|
||||||
//#define SPAWN_LAUNCHER
|
//#define SPAWN_LAUNCHER
|
||||||
//#define SPAWN_GUITEST2
|
//#define SPAWN_GUITEST2
|
||||||
//#define SPAWN_FILE_MANAGER
|
//#define SPAWN_FILE_MANAGER
|
||||||
//#define SPAWN_PROCESS_MANAGER
|
//#define SPAWN_PROCESS_MANAGER
|
||||||
//#define SPAWN_TEXT_EDITOR
|
//#define SPAWN_TEXT_EDITOR
|
||||||
//#define SPAWN_FONTEDITOR
|
//#define SPAWN_FONTEDITOR
|
||||||
//#define SPAWN_VISUAL_BUILDER
|
#define SPAWN_VISUAL_BUILDER
|
||||||
//#define SPAWN_MULTIPLE_SHELLS
|
//#define SPAWN_MULTIPLE_SHELLS
|
||||||
//#define STRESS_TEST_SPAWNING
|
//#define STRESS_TEST_SPAWNING
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <LibGUI/GModel.h>
|
#include <LibGUI/GModel.h>
|
||||||
#include <LibGUI/GScrollBar.h>
|
#include <LibGUI/GScrollBar.h>
|
||||||
#include <LibGUI/GPainter.h>
|
#include <LibGUI/GPainter.h>
|
||||||
|
#include <LibGUI/GTextBox.h>
|
||||||
#include <Kernel/KeyCode.h>
|
#include <Kernel/KeyCode.h>
|
||||||
|
|
||||||
GAbstractView::GAbstractView(GWidget* parent)
|
GAbstractView::GAbstractView(GWidget* parent)
|
||||||
|
@ -11,6 +12,7 @@ GAbstractView::GAbstractView(GWidget* parent)
|
||||||
|
|
||||||
GAbstractView::~GAbstractView()
|
GAbstractView::~GAbstractView()
|
||||||
{
|
{
|
||||||
|
delete m_edit_widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GAbstractView::set_model(RetainPtr<GModel>&& model)
|
void GAbstractView::set_model(RetainPtr<GModel>&& model)
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include <LibGUI/GScrollableWidget.h>
|
#include <LibGUI/GScrollableWidget.h>
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
|
|
||||||
|
class GTextBox;
|
||||||
|
|
||||||
class GAbstractView : public GScrollableWidget {
|
class GAbstractView : public GScrollableWidget {
|
||||||
friend class GModel;
|
friend class GModel;
|
||||||
public:
|
public:
|
||||||
|
@ -14,6 +16,9 @@ public:
|
||||||
GModel* model() { return m_model.ptr(); }
|
GModel* model() { return m_model.ptr(); }
|
||||||
const GModel* model() const { return m_model.ptr(); }
|
const GModel* model() const { return m_model.ptr(); }
|
||||||
|
|
||||||
|
bool is_editable() const { return m_editable; }
|
||||||
|
void set_editable(bool editable) { m_editable = editable; }
|
||||||
|
|
||||||
virtual bool accepts_focus() const override { return true; }
|
virtual bool accepts_focus() const override { return true; }
|
||||||
virtual void did_update_model();
|
virtual void did_update_model();
|
||||||
virtual void did_update_selection();
|
virtual void did_update_selection();
|
||||||
|
@ -25,6 +30,10 @@ public:
|
||||||
protected:
|
protected:
|
||||||
virtual void model_notification(const GModelNotification&);
|
virtual void model_notification(const GModelNotification&);
|
||||||
|
|
||||||
|
bool m_editable { false };
|
||||||
|
GModelIndex m_edit_index;
|
||||||
|
GTextBox* m_edit_widget { nullptr };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RetainPtr<GModel> m_model;
|
RetainPtr<GModel> m_model;
|
||||||
};
|
};
|
||||||
|
|
|
@ -57,6 +57,8 @@ public:
|
||||||
virtual GModelIndex index(int row, int column = 0, const GModelIndex& = GModelIndex()) const { return create_index(row, column); }
|
virtual GModelIndex index(int row, int column = 0, const GModelIndex& = GModelIndex()) const { return create_index(row, column); }
|
||||||
virtual void activate(const GModelIndex&) { }
|
virtual void activate(const GModelIndex&) { }
|
||||||
virtual GModelIndex sibling(int row, int column, const GModelIndex& parent) const;
|
virtual GModelIndex sibling(int row, int column, const GModelIndex& parent) const;
|
||||||
|
virtual bool is_editable(const GModelIndex&) const { return false; }
|
||||||
|
virtual void set_data(const GModelIndex&, const GVariant&) { }
|
||||||
|
|
||||||
bool is_valid(const GModelIndex& index) const
|
bool is_valid(const GModelIndex& index) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <LibGUI/GModel.h>
|
#include <LibGUI/GModel.h>
|
||||||
#include <LibGUI/GScrollBar.h>
|
#include <LibGUI/GScrollBar.h>
|
||||||
#include <LibGUI/GPainter.h>
|
#include <LibGUI/GPainter.h>
|
||||||
|
#include <LibGUI/GTextBox.h>
|
||||||
#include <Kernel/KeyCode.h>
|
#include <Kernel/KeyCode.h>
|
||||||
|
|
||||||
GTableView::GTableView(GWidget* parent)
|
GTableView::GTableView(GWidget* parent)
|
||||||
|
@ -38,6 +39,21 @@ void GTableView::did_update_model()
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rect GTableView::cell_content_rect(int row, int column) const
|
||||||
|
{
|
||||||
|
auto row_rect = this->row_rect(row);
|
||||||
|
int x = 0;
|
||||||
|
for (int i = 0; i < column; ++i)
|
||||||
|
x += column_width(i) + horizontal_padding() * 2;
|
||||||
|
|
||||||
|
return { horizontal_padding() + row_rect.x() + x, row_rect.y(), column_width(column), item_height() };
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect GTableView::cell_content_rect(const GModelIndex& index) const
|
||||||
|
{
|
||||||
|
return cell_content_rect(index.row(), index.column());
|
||||||
|
}
|
||||||
|
|
||||||
Rect GTableView::row_rect(int item_index) const
|
Rect GTableView::row_rect(int item_index) const
|
||||||
{
|
{
|
||||||
return { 0, header_height() + (item_index * item_height()), max(content_size().width(), width()), item_height() };
|
return { 0, header_height() + (item_index * item_height()), max(content_size().width(), width()), item_height() };
|
||||||
|
@ -87,9 +103,13 @@ void GTableView::mousedown_event(GMouseEvent& event)
|
||||||
|
|
||||||
if (event.button() == GMouseButton::Left) {
|
if (event.button() == GMouseButton::Left) {
|
||||||
auto adjusted_position = event.position().translated(0, vertical_scrollbar().value());
|
auto adjusted_position = event.position().translated(0, vertical_scrollbar().value());
|
||||||
for (int i = 0; i < item_count(); ++i) {
|
for (int row = 0, row_count = model()->row_count(); row < row_count; ++row) {
|
||||||
if (row_rect(i).contains(adjusted_position)) {
|
if (!row_rect(row).contains(adjusted_position))
|
||||||
model()->set_selected_index(model()->index(i, 0));
|
continue;
|
||||||
|
for (int column = 0, column_count = model()->column_count(); column < column_count; ++column) {
|
||||||
|
if (!cell_content_rect(row, column).contains(adjusted_position))
|
||||||
|
continue;
|
||||||
|
model()->set_selected_index(model()->index(row, column));
|
||||||
update();
|
update();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -300,6 +320,38 @@ void GTableView::doubleclick_event(GMouseEvent& event)
|
||||||
return;
|
return;
|
||||||
if (event.button() == GMouseButton::Left) {
|
if (event.button() == GMouseButton::Left) {
|
||||||
mousedown_event(event);
|
mousedown_event(event);
|
||||||
model()->activate(model()->selected_index());
|
if (is_editable())
|
||||||
|
begin_editing(model()->selected_index());
|
||||||
|
else
|
||||||
|
model()->activate(model()->selected_index());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GTableView::begin_editing(const GModelIndex& index)
|
||||||
|
{
|
||||||
|
ASSERT(is_editable());
|
||||||
|
ASSERT(model());
|
||||||
|
if (m_edit_index == index)
|
||||||
|
return;
|
||||||
|
if (!model()->is_editable(index))
|
||||||
|
return;
|
||||||
|
if (m_edit_widget)
|
||||||
|
delete m_edit_widget;
|
||||||
|
m_edit_index = index;
|
||||||
|
m_edit_widget = new GTextBox(this);
|
||||||
|
m_edit_widget->set_text(model()->data(index, GModel::Role::Display).to_string());
|
||||||
|
m_edit_widget->set_relative_rect(cell_content_rect(index));
|
||||||
|
m_edit_widget->set_focus(true);
|
||||||
|
m_edit_widget->on_return_pressed = [this] {
|
||||||
|
ASSERT(model());
|
||||||
|
model()->set_data(m_edit_index, m_edit_widget->text());
|
||||||
|
stop_editing();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void GTableView::stop_editing()
|
||||||
|
{
|
||||||
|
m_edit_index = { };
|
||||||
|
m_edit_widget->delete_later();
|
||||||
|
m_edit_widget = nullptr;
|
||||||
|
}
|
||||||
|
|
|
@ -30,6 +30,9 @@ public:
|
||||||
bool is_column_hidden(int) const;
|
bool is_column_hidden(int) const;
|
||||||
void set_column_hidden(int, bool);
|
void set_column_hidden(int, bool);
|
||||||
|
|
||||||
|
void begin_editing(const GModelIndex&);
|
||||||
|
void stop_editing();
|
||||||
|
|
||||||
virtual const char* class_name() const override { return "GTableView"; }
|
virtual const char* class_name() const override { return "GTableView"; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -45,6 +48,8 @@ private:
|
||||||
Rect header_rect(int) const;
|
Rect header_rect(int) const;
|
||||||
int column_width(int) const;
|
int column_width(int) const;
|
||||||
void update_content_size();
|
void update_content_size();
|
||||||
|
Rect cell_content_rect(const GModelIndex&) const;
|
||||||
|
Rect cell_content_rect(int row, int column) const;
|
||||||
|
|
||||||
Vector<bool> m_column_visibility;
|
Vector<bool> m_column_visibility;
|
||||||
int m_horizontal_padding { 5 };
|
int m_horizontal_padding { 5 };
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue