1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 19:07:35 +00:00

Move VisualBuilder into a new DevTools directory.

This commit is contained in:
Andreas Kling 2019-05-08 13:53:34 +02:00
parent 6b40b081b2
commit 3ae9fc5d88
18 changed files with 3 additions and 3 deletions

View file

@ -1,3 +0,0 @@
*.o
*.d
VisualBuilder

View file

@ -1,28 +0,0 @@
include ../../Makefile.common
OBJS = \
VBForm.o \
VBWidget.o \
VBWidgetRegistry.o \
VBWidgetPropertyModel.o \
VBProperty.o \
VBPropertiesWindow.o \
main.o
APP = VisualBuilder
DEFINES += -DUSERLAND
all: $(APP)
$(APP): $(OBJS)
$(LD) -o $(APP) $(LDFLAGS) $(OBJS) -lgui -lcore -lc
.cpp.o:
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
-include $(OBJS:%.o=%.d)
clean:
@echo "CLEAN"; rm -f $(APPS) $(OBJS) *.d

View file

@ -1,373 +0,0 @@
#include "VBForm.h"
#include "VBWidget.h"
#include "VBProperty.h"
#include <LibGUI/GPainter.h>
#include <LibGUI/GMenu.h>
#include <LibGUI/GAction.h>
#include <LibGUI/GMessageBox.h>
#include <LibCore/CFile.h>
static VBForm* s_current;
VBForm* VBForm::current()
{
return s_current;
}
VBForm::VBForm(const String& name, GWidget* parent)
: GWidget(parent)
, m_name(name)
{
s_current = this;
set_fill_with_background_color(true);
set_background_color(Color::LightGray);
set_greedy_for_hits(true);
auto box1 = VBWidget::create(VBWidgetType::GSpinBox, *this);
box1->set_rect({ 10, 10, 81, 21 });
m_widgets.append(move(box1));
auto box2 = VBWidget::create(VBWidgetType::GTextEditor, *this);
box2->set_rect({ 100, 100, 161, 161 });
m_widgets.append(move(box2));
auto button1 = VBWidget::create(VBWidgetType::GButton, *this);
button1->set_rect({ 200, 50, 81, 21 });
m_widgets.append(move(button1));
auto groupbox1 = VBWidget::create(VBWidgetType::GGroupBox, *this);
groupbox1->set_rect({ 300, 150, 161, 51 });
m_widgets.append(move(groupbox1));
m_context_menu = make<GMenu>("Context menu");
m_context_menu->add_action(GAction::create("Move to front", [this] (auto&) {
if (auto* widget = single_selected_widget())
widget->gwidget()->move_to_front();
}));
m_context_menu->add_action(GAction::create("Move to back", [this] (auto&) {
if (auto* widget = single_selected_widget())
widget->gwidget()->move_to_back();
}));
m_context_menu->add_action(GAction::create("Delete", [this] (auto&) {
delete_selected_widgets();
}));
}
void VBForm::context_menu_event(GContextMenuEvent& event)
{
m_context_menu->popup(event.screen_position());
}
void VBForm::insert_widget(VBWidgetType type)
{
auto widget = VBWidget::create(type, *this);
widget->set_rect({ m_next_insertion_position, { m_grid_size * 10 + 1, m_grid_size * 5 + 1 } });
m_next_insertion_position.move_by(m_grid_size, m_grid_size);
m_widgets.append(move(widget));
}
VBForm::~VBForm()
{
}
void VBForm::paint_event(GPaintEvent& event)
{
GPainter painter(*this);
painter.add_clip_rect(event.rect());
for (int y = 0; y < height(); y += m_grid_size) {
for (int x = 0; x < width(); x += m_grid_size) {
painter.set_pixel({ x, y }, Color::from_rgb(0x404040));
}
}
}
void VBForm::second_paint_event(GPaintEvent& event)
{
GPainter painter(*this);
painter.add_clip_rect(event.rect());
for (auto& widget : m_widgets) {
if (widget->is_selected()) {
for_each_direction([&] (Direction direction) {
painter.fill_rect(widget->grabber_rect(direction), Color::Black);
});
}
}
}
bool VBForm::is_selected(const VBWidget& widget) const
{
// FIXME: Fix HashTable and remove this const_cast.
return m_selected_widgets.contains(const_cast<VBWidget*>(&widget));
}
VBWidget* VBForm::widget_at(const Point& position)
{
auto* gwidget = child_at(position);
if (!gwidget)
return nullptr;
return m_gwidget_map.get(gwidget);
}
void VBForm::grabber_mousedown_event(GMouseEvent& event, Direction grabber)
{
m_transform_event_origin = event.position();
for_each_selected_widget([] (auto& widget) { widget.capture_transform_origin_rect(); });
m_resize_direction = grabber;
}
void VBForm::keydown_event(GKeyEvent& event)
{
if (event.key() == KeyCode::Key_Delete) {
delete_selected_widgets();
return;
}
if (event.key() == KeyCode::Key_Tab) {
if (m_widgets.is_empty())
return;
if (m_selected_widgets.is_empty()) {
set_single_selected_widget(m_widgets.first());
update();
return;
}
int selected_widget_index = 0;
for (; selected_widget_index < m_widgets.size(); ++selected_widget_index) {
if (m_widgets[selected_widget_index] == *m_selected_widgets.begin())
break;
}
++selected_widget_index;
if (selected_widget_index == m_widgets.size())
selected_widget_index = 0;
set_single_selected_widget(m_widgets[selected_widget_index]);
update();
return;
}
if (!m_selected_widgets.is_empty()) {
switch (event.key()) {
case KeyCode::Key_Up:
update();
for_each_selected_widget([this] (auto& widget) { widget.gwidget()->move_by(0, -m_grid_size); });
break;
case KeyCode::Key_Down:
update();
for_each_selected_widget([this] (auto& widget) { widget.gwidget()->move_by(0, m_grid_size); });
break;
case KeyCode::Key_Left:
update();
for_each_selected_widget([this] (auto& widget) { widget.gwidget()->move_by(-m_grid_size, 0); });
break;
case KeyCode::Key_Right:
update();
for_each_selected_widget([this] (auto& widget) { widget.gwidget()->move_by(m_grid_size, 0); });
break;
}
return;
}
}
void VBForm::set_single_selected_widget(VBWidget* widget)
{
if (!widget) {
if (!m_selected_widgets.is_empty()) {
m_selected_widgets.clear();
on_widget_selected(nullptr);
update();
}
return;
}
m_selected_widgets.clear();
m_selected_widgets.set(widget);
on_widget_selected(m_selected_widgets.size() == 1 ? widget : nullptr);
update();
}
void VBForm::add_to_selection(VBWidget& widget)
{
m_selected_widgets.set(&widget);
update();
}
void VBForm::remove_from_selection(VBWidget& widget)
{
m_selected_widgets.remove(&widget);
update();
}
void VBForm::mousedown_event(GMouseEvent& event)
{
if (m_resize_direction == Direction::None) {
bool hit_grabber = false;
for_each_selected_widget([&] (auto& widget) {
auto grabber = widget.grabber_at(event.position());
if (grabber != Direction::None) {
hit_grabber = true;
return grabber_mousedown_event(event, grabber);
}
});
if (hit_grabber)
return;
}
auto* widget = widget_at(event.position());
if (!widget) {
set_single_selected_widget(nullptr);
return;
}
if (event.button() == GMouseButton::Left || event.button() == GMouseButton::Right) {
m_transform_event_origin = event.position();
if (event.modifiers() == Mod_Ctrl)
remove_from_selection(*widget);
else if (event.modifiers() == Mod_Shift)
add_to_selection(*widget);
else if (!m_selected_widgets.contains(widget))
set_single_selected_widget(widget);
for_each_selected_widget([] (auto& widget) { widget.capture_transform_origin_rect(); });
on_widget_selected(single_selected_widget());
}
}
void VBForm::mousemove_event(GMouseEvent& event)
{
if (event.buttons() & GMouseButton::Left) {
if (m_resize_direction == Direction::None) {
update();
auto delta = event.position() - m_transform_event_origin;
for_each_selected_widget([&] (auto& widget) {
auto new_rect = widget.transform_origin_rect().translated(delta);
new_rect.set_x(new_rect.x() - (new_rect.x() % m_grid_size));
new_rect.set_y(new_rect.y() - (new_rect.y() % m_grid_size));
widget.set_rect(new_rect);
});
return;
}
int diff_x = event.x() - m_transform_event_origin.x();
int diff_y = event.y() - m_transform_event_origin.y();
int change_x = 0;
int change_y = 0;
int change_w = 0;
int change_h = 0;
switch (m_resize_direction) {
case Direction::DownRight:
change_w = diff_x;
change_h = diff_y;
break;
case Direction::Right:
change_w = diff_x;
break;
case Direction::UpRight:
change_w = diff_x;
change_y = diff_y;
change_h = -diff_y;
break;
case Direction::Up:
change_y = diff_y;
change_h = -diff_y;
break;
case Direction::UpLeft:
change_x = diff_x;
change_w = -diff_x;
change_y = diff_y;
change_h = -diff_y;
break;
case Direction::Left:
change_x = diff_x;
change_w = -diff_x;
break;
case Direction::DownLeft:
change_x = diff_x;
change_w = -diff_x;
change_h = diff_y;
break;
case Direction::Down:
change_h = diff_y;
break;
default:
ASSERT_NOT_REACHED();
}
update();
for_each_selected_widget([&] (auto& widget) {
auto new_rect = widget.transform_origin_rect();
Size minimum_size { 5, 5 };
new_rect.set_x(new_rect.x() + change_x);
new_rect.set_y(new_rect.y() + change_y);
new_rect.set_width(max(minimum_size.width(), new_rect.width() + change_w));
new_rect.set_height(max(minimum_size.height(), new_rect.height() + change_h));
new_rect.set_x(new_rect.x() - (new_rect.x() % m_grid_size));
new_rect.set_y(new_rect.y() - (new_rect.y() % m_grid_size));
new_rect.set_width(new_rect.width() - (new_rect.width() % m_grid_size) + 1);
new_rect.set_height(new_rect.height() - (new_rect.height() % m_grid_size) + 1);
widget.set_rect(new_rect);
});
}
}
void VBForm::write_to_file(const String& path)
{
CFile file(path);
if (!file.open(CIODevice::WriteOnly)) {
GMessageBox box(String::format("Could not open '%s' for writing", path.characters()), "Error", window());
box.exec();
return;
}
file.printf("[Form]\n");
file.printf("Name=%s\n", m_name.characters());
file.printf("\n");
int i = 0;
for (auto& widget : m_widgets) {
file.printf("[Widget %d]\n", i++);
widget->for_each_property([&] (auto& property) {
file.printf("%s=%s\n", property.name().characters(), property.value().to_string().characters());
});
file.printf("\n");
}
}
void VBForm::dump()
{
dbgprintf("[Form]\n");
dbgprintf("Name=%s\n", m_name.characters());
dbgprintf("\n");
int i = 0;
for (auto& widget : m_widgets) {
dbgprintf("[Widget %d]\n", i++);
widget->for_each_property([] (auto& property) {
dbgprintf("%s=%s\n", property.name().characters(), property.value().to_string().characters());
});
dbgprintf("\n");
}
}
void VBForm::mouseup_event(GMouseEvent& event)
{
if (event.button() == GMouseButton::Left) {
m_transform_event_origin = { };
m_resize_direction = Direction::None;
}
}
void VBForm::delete_selected_widgets()
{
Vector<VBWidget*> to_delete;
for_each_selected_widget([&] (auto& widget) {
to_delete.append(&widget);
});
for (auto& widget : to_delete)
m_widgets.remove_first_matching([&widget] (auto& entry) { return entry == widget; } );
on_widget_selected(single_selected_widget());
}
template<typename Callback>
void VBForm::for_each_selected_widget(Callback callback)
{
for (auto& widget : m_selected_widgets)
callback(*widget);
}
VBWidget* VBForm::single_selected_widget()
{
if (m_selected_widgets.size() != 1)
return nullptr;
return *m_selected_widgets.begin();
}

View file

@ -1,60 +0,0 @@
#pragma once
#include <LibGUI/GWidget.h>
#include <AK/Vector.h>
#include "VBWidget.h"
class VBForm : public GWidget {
friend class VBWidget;
public:
explicit VBForm(const String& name, GWidget* parent = nullptr);
virtual ~VBForm() override;
static VBForm* current();
String name() const { return m_name; }
void set_name(const String& name) { m_name = name; }
bool is_selected(const VBWidget&) const;
VBWidget* widget_at(const Point&);
void set_should_snap_to_grip(bool snap) { m_should_snap_to_grid = snap; }
bool should_snap_to_grid() const { return m_should_snap_to_grid; }
void insert_widget(VBWidgetType);
Function<void(VBWidget*)> on_widget_selected;
void write_to_file(const String& path);
void dump();
protected:
virtual void paint_event(GPaintEvent&) override;
virtual void second_paint_event(GPaintEvent&) override;
virtual void mousedown_event(GMouseEvent&) override;
virtual void mousemove_event(GMouseEvent&) override;
virtual void mouseup_event(GMouseEvent&) override;
virtual void context_menu_event(GContextMenuEvent&) override;
virtual void keydown_event(GKeyEvent&) override;
private:
void grabber_mousedown_event(GMouseEvent&, Direction grabber);
void set_single_selected_widget(VBWidget*);
void add_to_selection(VBWidget&);
void remove_from_selection(VBWidget&);
void delete_selected_widgets();
template<typename Callback> void for_each_selected_widget(Callback);
VBWidget* single_selected_widget();
String m_name;
int m_grid_size { 5 };
bool m_should_snap_to_grid { true };
Vector<Retained<VBWidget>> m_widgets;
HashMap<GWidget*, VBWidget*> m_gwidget_map;
HashTable<VBWidget*> m_selected_widgets;
Point m_transform_event_origin;
Point m_next_insertion_position;
Direction m_resize_direction { Direction::None };
OwnPtr<GMenu> m_context_menu;
};

View file

@ -1,24 +0,0 @@
#include "VBPropertiesWindow.h"
#include <LibGUI/GWidget.h>
#include <LibGUI/GBoxLayout.h>
#include <LibGUI/GTableView.h>
#include <LibGUI/GTextBox.h>
VBPropertiesWindow::VBPropertiesWindow()
{
set_title("Properties");
set_rect(780, 200, 240, 280);
auto* widget = new GWidget;
widget->set_fill_with_background_color(true);
widget->set_layout(make<GBoxLayout>(Orientation::Vertical));
set_main_widget(widget);
m_table_view = new GTableView(widget);
m_table_view->set_headers_visible(false);
m_table_view->set_editable(true);
}
VBPropertiesWindow::~VBPropertiesWindow()
{
}

View file

@ -1,18 +0,0 @@
#pragma once
#include <LibGUI/GWindow.h>
class GTableView;
class GTextBox;
class VBPropertiesWindow final : public GWindow {
public:
VBPropertiesWindow();
virtual ~VBPropertiesWindow() override;
GTableView& table_view() { return *m_table_view; }
const GTableView& table_view() const { return *m_table_view; }
private:
GTableView* m_table_view { nullptr };
};

View file

@ -1,33 +0,0 @@
#include "VBProperty.h"
#include "VBWidget.h"
VBProperty::VBProperty(VBWidget& widget, const String& name, const GVariant& value)
: m_widget(widget)
, m_name(name)
, m_value(value)
{
}
VBProperty::VBProperty(VBWidget& widget, const String& name, Function<GVariant(const GWidget&)>&& getter, Function<void(GWidget&, const GVariant&)>&& setter)
: m_widget(widget)
, m_name(name)
, m_getter(move(getter))
, m_setter(move(setter))
{
ASSERT(m_getter);
ASSERT(m_setter);
}
VBProperty::~VBProperty()
{
}
void VBProperty::set_value(const GVariant& value)
{
if (m_value == value)
return;
m_value = value;
if (m_setter)
m_setter(*m_widget.gwidget(), value);
m_widget.property_did_change();
}

View file

@ -1,33 +0,0 @@
#pragma once
#include <AK/AKString.h>
#include <AK/Function.h>
#include <LibGUI/GVariant.h>
class GWidget;
class VBWidget;
class VBProperty {
friend class VBWidget;
public:
VBProperty(VBWidget&, const String& name, const GVariant& value);
VBProperty(VBWidget&, const String& name, Function<GVariant(const GWidget&)>&& getter, Function<void(GWidget&, const GVariant&)>&& setter);
~VBProperty();
String name() const { return m_name; }
const GVariant& value() const { return m_value; }
void set_value(const GVariant&);
bool is_readonly() const { return m_readonly; }
void set_readonly(bool b) { m_readonly = b; }
void sync();
private:
VBWidget& m_widget;
String m_name;
GVariant m_value;
Function<GVariant(const GWidget&)> m_getter;
Function<void(GWidget&, const GVariant&)> m_setter;
bool m_readonly { false };
};

View file

@ -1,197 +0,0 @@
#include "VBWidget.h"
#include "VBForm.h"
#include "VBProperty.h"
#include "VBWidgetRegistry.h"
#include "VBWidgetPropertyModel.h"
#include <LibGUI/GPainter.h>
#include <LibGUI/GLabel.h>
#include <LibGUI/GButton.h>
#include <LibGUI/GScrollBar.h>
#include <LibGUI/GSpinBox.h>
#include <LibGUI/GTextEditor.h>
#include <LibGUI/GGroupBox.h>
#include <LibGUI/GCheckBox.h>
#include <LibGUI/GProgressBar.h>
#include <LibGUI/GSlider.h>
VBWidget::VBWidget(VBWidgetType type, VBForm& form)
: m_type(type)
, m_form(form)
, m_property_model(VBWidgetPropertyModel::create(*this))
{
m_gwidget = VBWidgetRegistry::build_gwidget(*this, type, &form, m_properties);
m_form.m_gwidget_map.set(m_gwidget, this);
setup_properties();
}
VBWidget::~VBWidget()
{
m_form.m_gwidget_map.remove(m_gwidget);
m_form.m_selected_widgets.remove(this);
delete m_gwidget;
}
Rect VBWidget::rect() const
{
return m_gwidget->relative_rect();
}
void VBWidget::set_rect(const Rect& rect)
{
if (rect == m_gwidget->relative_rect())
return;
m_gwidget->set_relative_rect(rect);
synchronize_properties();
}
bool VBWidget::is_selected() const
{
return m_form.is_selected(*this);
}
Rect VBWidget::grabber_rect(Direction direction) const
{
int grabber_size = 5;
int half_grabber_size = grabber_size / 2;
switch (direction) {
case Direction::Left:
return { rect().x() - half_grabber_size, rect().center().y() - half_grabber_size, grabber_size, grabber_size };
case Direction::UpLeft:
return { rect().x() - half_grabber_size, rect().y() - half_grabber_size, grabber_size, grabber_size };
case Direction::Up:
return { rect().center().x() - half_grabber_size, rect().y() - half_grabber_size, grabber_size, grabber_size };
case Direction::UpRight:
return { rect().right() - half_grabber_size, rect().y() - half_grabber_size, grabber_size, grabber_size };
case Direction::Right:
return { rect().right() - half_grabber_size, rect().center().y() - half_grabber_size, grabber_size, grabber_size };
case Direction::DownLeft:
return { rect().x() - half_grabber_size, rect().bottom() - half_grabber_size, grabber_size, grabber_size };
case Direction::Down:
return { rect().center().x() - half_grabber_size, rect().bottom() - half_grabber_size, grabber_size, grabber_size };
case Direction::DownRight:
return { rect().right() - half_grabber_size, rect().bottom() - half_grabber_size, grabber_size, grabber_size };
default:
ASSERT_NOT_REACHED();
}
}
Direction VBWidget::grabber_at(const Point& position) const
{
Direction found_grabber = Direction::None;
for_each_direction([&] (Direction direction) {
if (grabber_rect(direction).contains(position))
found_grabber = direction;
});
return found_grabber;
}
void VBWidget::for_each_property(Function<void(VBProperty&)> callback)
{
for (auto& it : m_properties) {
callback(*it);
}
}
void VBWidget::add_property(const String& name, Function<GVariant(const GWidget&)>&& getter, Function<void(GWidget&, const GVariant&)>&& setter)
{
auto& prop = property(name);
prop.m_getter = move(getter);
prop.m_setter = move(setter);
}
#define VB_ADD_PROPERTY(gclass, name, getter, setter, variant_type) \
add_property(name, \
[] (auto& widget) -> GVariant { return ((const gclass&)widget).getter(); }, \
[] (auto& widget, auto& value) { ((gclass&)widget).setter(value.to_ ## variant_type()); } \
)
void VBWidget::setup_properties()
{
VB_ADD_PROPERTY(GWidget, "width", width, set_width, int);
VB_ADD_PROPERTY(GWidget, "height", height, set_height, int);
VB_ADD_PROPERTY(GWidget, "x", x, set_x, int);
VB_ADD_PROPERTY(GWidget, "y", y, set_y, int);
VB_ADD_PROPERTY(GWidget, "visible", is_visible, set_visible, bool);
VB_ADD_PROPERTY(GWidget, "enabled", is_enabled, set_enabled, bool);
VB_ADD_PROPERTY(GWidget, "tooltip", tooltip, set_tooltip, string);
VB_ADD_PROPERTY(GWidget, "backcolor", background_color, set_background_color, color);
VB_ADD_PROPERTY(GWidget, "forecolor", foreground_color, set_foreground_color, color);
VB_ADD_PROPERTY(GWidget, "autofill", fill_with_background_color, set_fill_with_background_color, bool);
if (m_type == VBWidgetType::GLabel) {
VB_ADD_PROPERTY(GLabel, "text", text, set_text, string);
}
if (m_type == VBWidgetType::GButton) {
VB_ADD_PROPERTY(GButton, "caption", caption, set_caption, string);
}
if (m_type == VBWidgetType::GGroupBox) {
VB_ADD_PROPERTY(GGroupBox, "name", name, set_name, string);
}
if (m_type == VBWidgetType::GScrollBar) {
VB_ADD_PROPERTY(GScrollBar, "min", min, set_min, int);
VB_ADD_PROPERTY(GScrollBar, "max", max, set_max, int);
VB_ADD_PROPERTY(GScrollBar, "value", value, set_value, int);
VB_ADD_PROPERTY(GScrollBar, "step", step, set_step, int);
}
if (m_type == VBWidgetType::GSpinBox) {
VB_ADD_PROPERTY(GSpinBox, "min", min, set_min, int);
VB_ADD_PROPERTY(GSpinBox, "max", max, set_max, int);
VB_ADD_PROPERTY(GSpinBox, "value", value, set_value, int);
}
if (m_type == VBWidgetType::GProgressBar) {
VB_ADD_PROPERTY(GProgressBar, "min", min, set_min, int);
VB_ADD_PROPERTY(GProgressBar, "max", max, set_max, int);
VB_ADD_PROPERTY(GProgressBar, "value", value, set_value, int);
}
if (m_type == VBWidgetType::GSlider) {
VB_ADD_PROPERTY(GSlider, "min", min, set_min, int);
VB_ADD_PROPERTY(GSlider, "max", max, set_max, int);
VB_ADD_PROPERTY(GSlider, "value", value, set_value, int);
}
if (m_type == VBWidgetType::GTextEditor) {
VB_ADD_PROPERTY(GTextEditor, "text", text, set_text, string);
VB_ADD_PROPERTY(GTextEditor, "ruler_visible", is_ruler_visible, set_ruler_visible, bool);
}
if (m_type == VBWidgetType::GCheckBox) {
VB_ADD_PROPERTY(GCheckBox, "caption", caption, set_caption, string);
VB_ADD_PROPERTY(GCheckBox, "checked", is_checked, set_checked, bool);
}
}
void VBWidget::synchronize_properties()
{
for (auto& prop : m_properties) {
if (prop->m_getter)
prop->m_value = prop->m_getter(*gwidget());
}
m_property_model->update();
}
VBProperty& VBWidget::property(const String& name)
{
for (auto& prop : m_properties) {
if (prop->name() == name)
return *prop;
}
m_properties.append(make<VBProperty>(*this, name, GVariant()));
return *m_properties.last();
}
void VBWidget::property_did_change()
{
m_form.update();
}
void VBWidget::capture_transform_origin_rect()
{
m_transform_origin_rect = rect();
}

View file

@ -1,73 +0,0 @@
#pragma once
#include <SharedGraphics/Rect.h>
#include <AK/Retainable.h>
#include <AK/Retained.h>
#include <AK/Weakable.h>
#include <AK/HashMap.h>
#include <AK/Function.h>
#include "VBWidgetType.h"
class GPainter;
class GVariant;
class GWidget;
class VBForm;
class VBProperty;
class VBWidgetPropertyModel;
enum class Direction { None, Left, UpLeft, Up, UpRight, Right, DownRight, Down, DownLeft };
template<typename Callback>
inline void for_each_direction(Callback callback)
{
callback(Direction::Left);
callback(Direction::UpLeft);
callback(Direction::Up);
callback(Direction::UpRight);
callback(Direction::Right);
callback(Direction::DownRight);
callback(Direction::Down);
callback(Direction::DownLeft);
}
class VBWidget : public Retainable<VBWidget>, public Weakable<VBWidget> {
friend class VBWidgetPropertyModel;
public:
static Retained<VBWidget> create(VBWidgetType type, VBForm& form) { return adopt(*new VBWidget(type, form)); }
~VBWidget();
bool is_selected() const;
Rect rect() const;
void set_rect(const Rect&);
Rect grabber_rect(Direction) const;
Direction grabber_at(const Point&) const;
GWidget* gwidget() { return m_gwidget; }
VBProperty& property(const String&);
void for_each_property(Function<void(VBProperty&)>);
VBWidgetPropertyModel& property_model() { return *m_property_model; }
void setup_properties();
void synchronize_properties();
void property_did_change();
Rect transform_origin_rect() const { return m_transform_origin_rect; }
void capture_transform_origin_rect();
private:
VBWidget(VBWidgetType, VBForm&);
void add_property(const String& name, Function<GVariant(const GWidget&)>&& getter, Function<void(GWidget&, const GVariant&)>&& setter);
VBWidgetType m_type { VBWidgetType::None };
VBForm& m_form;
GWidget* m_gwidget { nullptr };
Vector<OwnPtr<VBProperty>> m_properties;
Retained<VBWidgetPropertyModel> m_property_model;
Rect m_transform_origin_rect;
};

View file

@ -1,72 +0,0 @@
#include "VBWidgetPropertyModel.h"
#include "VBWidget.h"
#include "VBProperty.h"
#include <SharedGraphics/Font.h>
VBWidgetPropertyModel::VBWidgetPropertyModel(VBWidget& widget)
: m_widget(widget)
{
}
VBWidgetPropertyModel::~VBWidgetPropertyModel()
{
}
int VBWidgetPropertyModel::row_count(const GModelIndex&) const
{
return m_widget.m_properties.size();
}
String VBWidgetPropertyModel::column_name(int column) const
{
switch (column) {
case Column::Name: return "Name";
case Column::Value: return "Value";
default: ASSERT_NOT_REACHED();
}
}
GModel::ColumnMetadata VBWidgetPropertyModel::column_metadata(int column) const
{
UNUSED_PARAM(column);
if (column == Column::Name)
return { 110, TextAlignment::CenterLeft, &Font::default_bold_font() };
return { 90, TextAlignment::CenterLeft };
}
GVariant VBWidgetPropertyModel::data(const GModelIndex& index, Role role) const
{
if (role == Role::Display) {
auto& property = *m_widget.m_properties[index.row()];
switch (index.column()) {
case Column::Name: return property.name();
case Column::Value: return property.value();
}
ASSERT_NOT_REACHED();
}
if (role == Role::ForegroundColor) {
auto& property = *m_widget.m_properties[index.row()];
switch (index.column()) {
case Column::Name: return Color::Black;
case Column::Value: return property.is_readonly() ? Color(Color::MidGray) : Color(Color::Black);
}
ASSERT_NOT_REACHED();
}
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();
}

View file

@ -1,32 +0,0 @@
#pragma once
#include <LibGUI/GModel.h>
class VBWidget;
class VBProperty;
class VBWidgetPropertyModel : public GModel {
public:
enum Column {
Name = 0,
Value,
__Count
};
static Retained<VBWidgetPropertyModel> create(VBWidget& widget) { return adopt(*new VBWidgetPropertyModel(widget)); }
virtual ~VBWidgetPropertyModel() override;
virtual int row_count(const GModelIndex&) const override;
virtual int column_count(const GModelIndex&) const override { return Column::__Count; }
virtual String column_name(int column) const override;
virtual ColumnMetadata column_metadata(int column) const override;
virtual GVariant data(const GModelIndex&, Role = Role::Display) const override;
virtual void update() override { did_update(); }
virtual bool is_editable(const GModelIndex&) const override;
virtual void set_data(const GModelIndex&, const GVariant&) override;
private:
explicit VBWidgetPropertyModel(VBWidget&);
VBWidget& m_widget;
};

View file

@ -1,99 +0,0 @@
#include "VBWidgetRegistry.h"
#include "VBProperty.h"
#include <LibGUI/GLabel.h>
#include <LibGUI/GButton.h>
#include <LibGUI/GSpinBox.h>
#include <LibGUI/GTextEditor.h>
#include <LibGUI/GProgressBar.h>
#include <LibGUI/GCheckBox.h>
#include <LibGUI/GScrollBar.h>
#include <LibGUI/GGroupBox.h>
#include <LibGUI/GSlider.h>
static String to_class_name(VBWidgetType type)
{
switch (type) {
case VBWidgetType::GWidget: return "GWidget";
case VBWidgetType::GButton: return "GButton";
case VBWidgetType::GLabel: return "GLabel";
case VBWidgetType::GSpinBox: return "GSpinBox";
case VBWidgetType::GTextEditor: return "GTextEditor";
case VBWidgetType::GProgressBar: return "GProgressBar";
case VBWidgetType::GCheckBox: return "GCheckBox";
case VBWidgetType::GScrollBar: return "GScrollBar";
case VBWidgetType::GGroupBox: return "GGroupBox";
case VBWidgetType::GSlider: return "GSlider";
default: ASSERT_NOT_REACHED();
}
}
static GWidget* build_gwidget(VBWidgetType type, GWidget* parent)
{
switch (type) {
case VBWidgetType::GWidget:
return new GWidget(parent);
case VBWidgetType::GScrollBar:
return new GScrollBar(Orientation::Vertical, parent);
case VBWidgetType::GGroupBox:
return new GGroupBox("groupbox_1", parent);
case VBWidgetType::GLabel: {
auto* label = new GLabel(parent);
label->set_fill_with_background_color(true);
label->set_text("label_1");
return label;
}
case VBWidgetType::GButton: {
auto* button = new GButton(parent);
button->set_caption("button_1");
return button;
}
case VBWidgetType::GSpinBox: {
auto* box = new GSpinBox(parent);
box->set_range(0, 100);
box->set_value(0);
return box;
}
case VBWidgetType::GTextEditor: {
auto* editor = new GTextEditor(GTextEditor::Type::MultiLine, parent);
editor->set_ruler_visible(false);
return editor;
}
case VBWidgetType::GProgressBar: {
auto* bar = new GProgressBar(parent);
bar->set_format(GProgressBar::Format::NoText);
bar->set_range(0, 100);
bar->set_value(50);
return bar;
}
case VBWidgetType::GSlider: {
auto* slider = new GSlider(parent);
slider->set_range(0, 100);
slider->set_value(50);
return slider;
}
case VBWidgetType::GCheckBox: {
auto* box = new GCheckBox(parent);
box->set_caption("checkbox_1");
return box;
}
default:
ASSERT_NOT_REACHED();
return nullptr;
}
}
GWidget* VBWidgetRegistry::build_gwidget(VBWidget& widget, VBWidgetType type, GWidget* parent, Vector<OwnPtr<VBProperty>>& properties)
{
auto* gwidget = ::build_gwidget(type, parent);
auto add_readonly_property = [&] (const String& name, const GVariant& value) {
auto property = make<VBProperty>(widget, name, value);
property->set_readonly(true);
properties.append(move(property));
};
auto add_property = [&] (const String& name, Function<GVariant(const GWidget&)>&& getter, Function<void(GWidget&, const GVariant&)>&& setter) {
auto property = make<VBProperty>(widget, name, move(getter), move(setter));
properties.append(move(property));
};
add_readonly_property("class", to_class_name(type));
return gwidget;
}

View file

@ -1,21 +0,0 @@
#pragma once
#include "VBWidgetType.h"
#include <AK/HashMap.h>
#include <AK/OwnPtr.h>
#include <AK/AKString.h>
class GWidget;
class VBProperty;
class VBWidget;
class VBWidgetRegistry {
public:
template<typename Callback> static void for_each_widget_type(Callback callback)
{
for (unsigned i = 1; i < (unsigned)VBWidgetType::__Count; ++i)
callback((VBWidgetType)i);
}
static GWidget* build_gwidget(VBWidget&, VBWidgetType, GWidget* parent, Vector<OwnPtr<VBProperty>>&);
};

View file

@ -1,16 +0,0 @@
#pragma once
enum class VBWidgetType {
None = 0,
GWidget,
GButton,
GLabel,
GSpinBox,
GTextEditor,
GProgressBar,
GCheckBox,
GScrollBar,
GGroupBox,
GSlider,
__Count
};

View file

@ -1,150 +0,0 @@
#include <LibGUI/GWindow.h>
#include <LibGUI/GWidget.h>
#include <LibGUI/GBoxLayout.h>
#include <LibGUI/GApplication.h>
#include <LibGUI/GMenuBar.h>
#include <LibGUI/GAction.h>
#include <LibGUI/GButton.h>
#include <LibGUI/GTableView.h>
#include "VBForm.h"
#include "VBWidget.h"
#include "VBWidgetPropertyModel.h"
#include "VBPropertiesWindow.h"
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
static GWindow* make_toolbox_window();
int main(int argc, char** argv)
{
GApplication app(argc, argv);
auto* propbox = new VBPropertiesWindow;
auto* form1 = new VBForm("Form1");
form1->on_widget_selected = [propbox] (VBWidget* widget) {
propbox->table_view().set_model(widget ? &widget->property_model() : nullptr);
};
auto menubar = make<GMenuBar>();
auto app_menu = make<GMenu>("Visual Builder");
app_menu->add_action(GAction::create("Quit", { Mod_Alt, Key_F4 }, [] (const GAction&) {
GApplication::the().quit(0);
return;
}));
menubar->add_menu(move(app_menu));
auto file_menu = make<GMenu>("File");
file_menu->add_action(GAction::create("Dump Form", [&] (auto&) {
form1->dump();
}));
file_menu->add_action(GAction::create("Save Form...", { Mod_Ctrl, Key_S }, [form1] (auto&) {
form1->write_to_file("/tmp/form.frm");
}));
menubar->add_menu(move(file_menu));
auto edit_menu = make<GMenu>("Edit");
menubar->add_menu(move(edit_menu));
auto help_menu = make<GMenu>("Help");
help_menu->add_action(GAction::create("About", [] (const GAction&) {
dbgprintf("FIXME: Implement Help/About\n");
}));
menubar->add_menu(move(help_menu));
app.set_menubar(move(menubar));
auto* window = new GWindow;
window->set_title(form1->name());
window->set_rect(120, 200, 640, 400);
window->set_main_widget(form1);
window->set_should_exit_event_loop_on_close(true);
window->show();
auto* toolbox = make_toolbox_window();
toolbox->show();
propbox->show();
return app.exec();
}
GWindow* make_toolbox_window()
{
auto* window = new GWindow;
window->set_title("Widgets");
window->set_rect(20, 200, 80, 300);
auto* widget = new GWidget;
widget->set_fill_with_background_color(true);
widget->set_layout(make<GBoxLayout>(Orientation::Vertical));
window->set_main_widget(widget);
auto* label_button = new GButton(widget);
label_button->set_tooltip("GLabel");
label_button->set_icon(GraphicsBitmap::load_from_file("/res/icons/vbwidgets/label.png"));
label_button->on_click = [] (GButton&) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GLabel);
};
auto* button_button = new GButton(widget);
button_button->set_tooltip("GButton");
button_button->set_icon(GraphicsBitmap::load_from_file("/res/icons/vbwidgets/button.png"));
button_button->on_click = [] (GButton&) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GButton);
};
auto* spinbox_button = new GButton(widget);
spinbox_button->set_tooltip("GSpinBox");
spinbox_button->set_icon(GraphicsBitmap::load_from_file("/res/icons/vbwidgets/spinbox.png"));
spinbox_button->on_click = [] (GButton&) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GSpinBox);
};
auto* editor_button = new GButton(widget);
editor_button->set_tooltip("GTextEditor");
editor_button->set_icon(GraphicsBitmap::load_from_file("/res/icons/vbwidgets/textbox.png"));
editor_button->on_click = [] (GButton&) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GTextEditor);
};
auto* progress_bar_button = new GButton(widget);
progress_bar_button->set_tooltip("GProgressBar");
progress_bar_button->set_icon(GraphicsBitmap::load_from_file("/res/icons/vbwidgets/progressbar.png"));
progress_bar_button->on_click = [] (GButton&) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GProgressBar);
};
auto* slider_button = new GButton(widget);
slider_button->set_tooltip("GSlider");
slider_button->set_icon(GraphicsBitmap::load_from_file("/res/icons/vbwidgets/slider.png"));
slider_button->on_click = [] (GButton&) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GSlider);
};
auto* checkbox_button = new GButton(widget);
checkbox_button->set_tooltip("GCheckBox");
checkbox_button->set_icon(GraphicsBitmap::load_from_file("/res/icons/vbwidgets/checkbox.png"));
checkbox_button->on_click = [] (GButton&) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GCheckBox);
};
auto* scrollbar_button = new GButton(widget);
scrollbar_button->set_tooltip("GScrollBar");
scrollbar_button->set_icon(GraphicsBitmap::load_from_file("/res/icons/vbwidgets/scrollbar.png"));
scrollbar_button->on_click = [] (GButton&) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GScrollBar);
};
auto* groupbox_button = new GButton(widget);
groupbox_button->set_tooltip("GGroupBox");
groupbox_button->set_icon(GraphicsBitmap::load_from_file("/res/icons/vbwidgets/groupbox.png"));
groupbox_button->on_click = [] (GButton&) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GGroupBox);
};
return window;
}