mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 09:58:11 +00:00
LibGUI: Add GModelSelection to help implementing multiple-select views
Each GAbstractView now has a GModelSelection backed by a simple HashTable<GModelIndex>. When the selection changes somehow, the view gets notified via the notify_selection_changed() callback. In the future it will probably make sense to move to using some kind of ranges as the internal representation instead.
This commit is contained in:
parent
19b69741ed
commit
82559e211d
5 changed files with 95 additions and 0 deletions
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
GAbstractView::GAbstractView(GWidget* parent)
|
GAbstractView::GAbstractView(GWidget* parent)
|
||||||
: GScrollableWidget(parent)
|
: GScrollableWidget(parent)
|
||||||
|
, m_selection(*this)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,3 +97,8 @@ void GAbstractView::activate(const GModelIndex& index)
|
||||||
if (on_activation)
|
if (on_activation)
|
||||||
on_activation(index);
|
on_activation(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GAbstractView::notify_selection_changed(Badge<GModelSelection>)
|
||||||
|
{
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
#include <LibGUI/GModel.h>
|
#include <LibGUI/GModel.h>
|
||||||
|
#include <LibGUI/GModelSelection.h>
|
||||||
#include <LibGUI/GScrollableWidget.h>
|
#include <LibGUI/GScrollableWidget.h>
|
||||||
|
|
||||||
class GModelEditingDelegate;
|
class GModelEditingDelegate;
|
||||||
|
@ -9,6 +10,7 @@ class GModelEditingDelegate;
|
||||||
class GAbstractView : public GScrollableWidget {
|
class GAbstractView : public GScrollableWidget {
|
||||||
C_OBJECT(GAbstractView)
|
C_OBJECT(GAbstractView)
|
||||||
friend class GModel;
|
friend class GModel;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit GAbstractView(GWidget* parent);
|
explicit GAbstractView(GWidget* parent);
|
||||||
virtual ~GAbstractView() override;
|
virtual ~GAbstractView() override;
|
||||||
|
@ -17,6 +19,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(); }
|
||||||
|
|
||||||
|
GModelSelection& selection() { return m_selection; }
|
||||||
|
const GModelSelection& selection() const { return m_selection; }
|
||||||
|
|
||||||
bool is_editable() const { return m_editable; }
|
bool is_editable() const { return m_editable; }
|
||||||
void set_editable(bool editable) { m_editable = editable; }
|
void set_editable(bool editable) { m_editable = editable; }
|
||||||
|
|
||||||
|
@ -37,6 +42,8 @@ public:
|
||||||
|
|
||||||
Function<OwnPtr<GModelEditingDelegate>(const GModelIndex&)> aid_create_editing_delegate;
|
Function<OwnPtr<GModelEditingDelegate>(const GModelIndex&)> aid_create_editing_delegate;
|
||||||
|
|
||||||
|
void notify_selection_changed(Badge<GModelSelection>);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void did_scroll() override;
|
virtual void did_scroll() override;
|
||||||
void activate(const GModelIndex&);
|
void activate(const GModelIndex&);
|
||||||
|
@ -50,5 +57,6 @@ protected:
|
||||||
private:
|
private:
|
||||||
RefPtr<GModel> m_model;
|
RefPtr<GModel> m_model;
|
||||||
OwnPtr<GModelEditingDelegate> m_editing_delegate;
|
OwnPtr<GModelEditingDelegate> m_editing_delegate;
|
||||||
|
GModelSelection m_selection;
|
||||||
bool m_activates_on_selection { false };
|
bool m_activates_on_selection { false };
|
||||||
};
|
};
|
||||||
|
|
39
Libraries/LibGUI/GModelSelection.cpp
Normal file
39
Libraries/LibGUI/GModelSelection.cpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#include <LibGUI/GAbstractView.h>
|
||||||
|
#include <LibGUI/GModelSelection.h>
|
||||||
|
|
||||||
|
void GModelSelection::set(const GModelIndex& index)
|
||||||
|
{
|
||||||
|
ASSERT(index.is_valid());
|
||||||
|
if (m_indexes.size() == 1 && m_indexes.contains(index))
|
||||||
|
return;
|
||||||
|
m_indexes.clear();
|
||||||
|
m_indexes.set(index);
|
||||||
|
m_view.notify_selection_changed({});
|
||||||
|
}
|
||||||
|
|
||||||
|
void GModelSelection::add(const GModelIndex& index)
|
||||||
|
{
|
||||||
|
ASSERT(index.is_valid());
|
||||||
|
if (m_indexes.contains(index))
|
||||||
|
return;
|
||||||
|
m_indexes.set(index);
|
||||||
|
m_view.notify_selection_changed({});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GModelSelection::remove(const GModelIndex& index)
|
||||||
|
{
|
||||||
|
ASSERT(index.is_valid());
|
||||||
|
if (!m_indexes.contains(index))
|
||||||
|
return false;
|
||||||
|
m_indexes.remove(index);
|
||||||
|
m_view.notify_selection_changed({});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GModelSelection::clear()
|
||||||
|
{
|
||||||
|
if (m_indexes.is_empty())
|
||||||
|
return;
|
||||||
|
m_indexes.clear();
|
||||||
|
m_view.notify_selection_changed({});
|
||||||
|
}
|
41
Libraries/LibGUI/GModelSelection.h
Normal file
41
Libraries/LibGUI/GModelSelection.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/HashTable.h>
|
||||||
|
#include <LibGUI/GModelIndex.h>
|
||||||
|
|
||||||
|
class GAbstractView;
|
||||||
|
|
||||||
|
class GModelSelection {
|
||||||
|
public:
|
||||||
|
GModelSelection(GAbstractView& view)
|
||||||
|
: m_view(view)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_empty() const { return m_indexes.is_empty(); }
|
||||||
|
bool contains(const GModelIndex& index) const { return m_indexes.contains(index); }
|
||||||
|
|
||||||
|
void set(const GModelIndex&);
|
||||||
|
void add(const GModelIndex&);
|
||||||
|
bool remove(const GModelIndex&);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
template<typename Callback>
|
||||||
|
void for_each_index(Callback callback)
|
||||||
|
{
|
||||||
|
for (auto& index : m_indexes)
|
||||||
|
callback(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: This doesn't guarantee that what you get is the lowest or "first" index selected..
|
||||||
|
GModelIndex first() const
|
||||||
|
{
|
||||||
|
if (m_indexes.is_empty())
|
||||||
|
return {};
|
||||||
|
return *m_indexes.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
GAbstractView& m_view;
|
||||||
|
HashTable<GModelIndex> m_indexes;
|
||||||
|
};
|
|
@ -54,6 +54,7 @@ OBJS = \
|
||||||
GComboBox.o \
|
GComboBox.o \
|
||||||
GJsonArrayModel.o \
|
GJsonArrayModel.o \
|
||||||
GAboutDialog.o \
|
GAboutDialog.o \
|
||||||
|
GModelSelection.o \
|
||||||
GWindow.o
|
GWindow.o
|
||||||
|
|
||||||
LIBRARY = libgui.a
|
LIBRARY = libgui.a
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue