mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:42:44 +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:
		
							parent
							
								
									a353d16ff4
								
							
						
					
					
						commit
						ca538b6cee
					
				
					 10 changed files with 109 additions and 8 deletions
				
			
		|  | @ -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) | ||||
| { | ||||
|  |  | |||
|  | @ -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: | ||||
|  |  | |||
|  | @ -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) | ||||
|  | @ -239,7 +244,7 @@ void GScrollBar::mousedown_event(GMouseEvent& event) | |||
|         return; | ||||
|     } | ||||
|     if (has_scrubber() && scrubber_rect().contains(event.position())) { | ||||
| 	m_scrubber_in_use = true; | ||||
|         m_scrubber_in_use = true; | ||||
|         m_scrubbing = true; | ||||
|         m_scrub_start_value = value(); | ||||
|         m_scrub_origin = event.position(); | ||||
|  |  | |||
|  | @ -38,6 +38,7 @@ public: | |||
|     }; | ||||
| 
 | ||||
| private: | ||||
|     explicit GScrollBar(GWidget* parent); | ||||
|     explicit GScrollBar(Orientation, GWidget* parent); | ||||
| 
 | ||||
|     virtual void paint_event(GPaintEvent&) override; | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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()) | ||||
|  |  | |||
|  | @ -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: | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling