1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 05:48:12 +00:00

LibGUI: Add a simple GWidget class registry/factory

You can now register a GWidget subclass with REGISTER_GWIDGET(class)
and it will be available for factory construction through the new
GWidgetClassRegistration interface.

To obtain a GWidgetClassRegistration for a given class name, you call
GWidgetClassRegistration::find(class_name). You can also iterate over
all the registered classes using GWCR::for_each(callback).

This will be very useful for implementing a proper GUI designer, and
also in the future for things like script bindings.

NOTE: All of the registrations are done in GWidget.cpp at the moment
since I ran into trouble with the fricken linker pruning the global
constructors this mechanism relies on. :^)
This commit is contained in:
Andreas Kling 2019-11-10 10:58:03 +01:00
parent a353d16ff4
commit ca538b6cee
10 changed files with 109 additions and 8 deletions

View file

@ -1,12 +1,17 @@
#include <LibDraw/GraphicsBitmap.h>
#include <LibGUI/GPainter.h>
#include <LibGUI/GRadioButton.h>
#include <LibDraw/GraphicsBitmap.h>
static RefPtr<GraphicsBitmap> s_unfilled_circle_bitmap;
static RefPtr<GraphicsBitmap> s_filled_circle_bitmap;
static RefPtr<GraphicsBitmap> s_changing_filled_circle_bitmap;
static RefPtr<GraphicsBitmap> s_changing_unfilled_circle_bitmap;
GRadioButton::GRadioButton(GWidget* parent)
: GRadioButton({}, parent)
{
}
GRadioButton::GRadioButton(const StringView& text, GWidget* parent)
: GAbstractButton(text, parent)
{

View file

@ -10,7 +10,8 @@ public:
virtual void click() override;
protected:
GRadioButton(const StringView& text, GWidget* parent);
explicit GRadioButton(GWidget* parent);
explicit GRadioButton(const StringView& text, GWidget* parent);
virtual void paint_event(GPaintEvent&) override;
private:

View file

@ -1,8 +1,8 @@
#include <LibGUI/GPainter.h>
#include <LibGUI/GScrollBar.h>
#include <LibDraw/CharacterBitmap.h>
#include <LibDraw/GraphicsBitmap.h>
#include <LibDraw/StylePainter.h>
#include <LibGUI/GPainter.h>
#include <LibGUI/GScrollBar.h>
static const char* s_up_arrow_bitmap_data = {
" "
@ -57,6 +57,11 @@ static CharacterBitmap* s_down_arrow_bitmap;
static CharacterBitmap* s_left_arrow_bitmap;
static CharacterBitmap* s_right_arrow_bitmap;
GScrollBar::GScrollBar(GWidget* parent)
: GScrollBar(Orientation::Vertical, parent)
{
}
GScrollBar::GScrollBar(Orientation orientation, GWidget* parent)
: GWidget(parent)
, m_orientation(orientation)

View file

@ -38,6 +38,7 @@ public:
};
private:
explicit GScrollBar(GWidget* parent);
explicit GScrollBar(Orientation, GWidget* parent);
virtual void paint_event(GPaintEvent&) override;

View file

@ -2,6 +2,11 @@
#include <LibGUI/GPainter.h>
#include <LibGUI/GSlider.h>
GSlider::GSlider(GWidget* parent)
: GSlider(Orientation::Horizontal, parent)
{
}
GSlider::GSlider(Orientation orientation, GWidget* parent)
: GWidget(parent)
, m_orientation(orientation)

View file

@ -44,7 +44,8 @@ public:
Function<void(int)> on_value_changed;
protected:
GSlider(Orientation, GWidget*);
explicit GSlider(GWidget*);
explicit GSlider(Orientation, GWidget*);
virtual void paint_event(GPaintEvent&) override;
virtual void mousedown_event(GMouseEvent&) override;

View file

@ -15,6 +15,11 @@
//#define DEBUG_GTEXTEDITOR
GTextEditor::GTextEditor(GWidget* parent)
: GTextEditor(Type::MultiLine, parent)
{
}
GTextEditor::GTextEditor(Type type, GWidget* parent)
: GScrollableWidget(parent)
, m_type(type)

View file

@ -102,7 +102,8 @@ public:
void set_cursor(const GTextPosition&);
protected:
GTextEditor(Type, GWidget* parent);
explicit GTextEditor(GWidget* parent);
explicit GTextEditor(Type, GWidget* parent);
virtual void did_change_font() override;
virtual void paint_event(GPaintEvent&) override;

View file

@ -12,6 +12,59 @@
#include <LibGUI/GWindowServerConnection.h>
#include <unistd.h>
#include <LibGUI/GButton.h>
#include <LibGUI/GCheckBox.h>
#include <LibGUI/GGroupBox.h>
#include <LibGUI/GLabel.h>
#include <LibGUI/GRadioButton.h>
#include <LibGUI/GScrollBar.h>
#include <LibGUI/GSlider.h>
#include <LibGUI/GSpinBox.h>
#include <LibGUI/GTextBox.h>
REGISTER_GWIDGET(GButton)
REGISTER_GWIDGET(GCheckBox)
REGISTER_GWIDGET(GGroupBox)
REGISTER_GWIDGET(GLabel)
REGISTER_GWIDGET(GRadioButton)
REGISTER_GWIDGET(GScrollBar)
REGISTER_GWIDGET(GSlider)
REGISTER_GWIDGET(GSpinBox)
REGISTER_GWIDGET(GTextBox)
REGISTER_GWIDGET(GWidget)
static HashMap<String, GWidgetClassRegistration*>& widget_classes()
{
static HashMap<String, GWidgetClassRegistration*>* map;
if (!map)
map = new HashMap<String, GWidgetClassRegistration*>;
return *map;
}
GWidgetClassRegistration::GWidgetClassRegistration(const String& class_name, Function<NonnullRefPtr<GWidget>(GWidget*)> factory)
: m_class_name(class_name)
, m_factory(move(factory))
{
widget_classes().set(class_name, this);
}
GWidgetClassRegistration::~GWidgetClassRegistration()
{
ASSERT_NOT_REACHED();
}
void GWidgetClassRegistration::for_each(Function<void(const GWidgetClassRegistration&)> callback)
{
for (auto& it : widget_classes()) {
callback(*it.value);
}
}
const GWidgetClassRegistration* GWidgetClassRegistration::find(const String& class_name)
{
return widget_classes().get(class_name).value_or(nullptr);
}
GWidget::GWidget(GWidget* parent)
: CObject(parent, true)
, m_font(Font::default_font())

View file

@ -1,8 +1,8 @@
#pragma once
#include <AK/String.h>
#include <AK/Badge.h>
#include <AK/HashMap.h>
#include <AK/String.h>
#include <LibCore/CElapsedTimer.h>
#include <LibCore/CObject.h>
#include <LibDraw/Color.h>
@ -12,6 +12,10 @@
#include <LibGUI/GEvent.h>
#include <LibGUI/GShortcut.h>
#define REGISTER_GWIDGET(class_name) \
extern GWidgetClassRegistration registration_##class_name; \
GWidgetClassRegistration registration_##class_name(#class_name, [](GWidget* parent) { return class_name::construct(parent); });
class GraphicsBitmap;
class GAction;
class GLayout;
@ -42,6 +46,26 @@ enum class VerticalDirection {
Down
};
class GWidget;
class GWidgetClassRegistration {
AK_MAKE_NONCOPYABLE(GWidgetClassRegistration)
AK_MAKE_NONMOVABLE(GWidgetClassRegistration)
public:
GWidgetClassRegistration(const String& class_name, Function<NonnullRefPtr<GWidget>(GWidget*)> factory);
~GWidgetClassRegistration();
String class_name() const { return m_class_name; }
NonnullRefPtr<GWidget> construct(GWidget* parent) const { return m_factory(parent); }
static void for_each(Function<void(const GWidgetClassRegistration&)>);
static const GWidgetClassRegistration* find(const String& class_name);
private:
String m_class_name;
Function<NonnullRefPtr<GWidget>(GWidget*)> m_factory;
};
class GWidget : public CObject {
C_OBJECT(GWidget)
public: