mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 20:47:45 +00:00
Move VisualBuilder into a new DevTools directory.
This commit is contained in:
parent
6b40b081b2
commit
3ae9fc5d88
18 changed files with 3 additions and 3 deletions
3
DevTools/VisualBuilder/.gitignore
vendored
Normal file
3
DevTools/VisualBuilder/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
*.o
|
||||
*.d
|
||||
VisualBuilder
|
28
DevTools/VisualBuilder/Makefile
Normal file
28
DevTools/VisualBuilder/Makefile
Normal file
|
@ -0,0 +1,28 @@
|
|||
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
|
||||
|
373
DevTools/VisualBuilder/VBForm.cpp
Normal file
373
DevTools/VisualBuilder/VBForm.cpp
Normal file
|
@ -0,0 +1,373 @@
|
|||
#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();
|
||||
}
|
60
DevTools/VisualBuilder/VBForm.h
Normal file
60
DevTools/VisualBuilder/VBForm.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
#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;
|
||||
};
|
24
DevTools/VisualBuilder/VBPropertiesWindow.cpp
Normal file
24
DevTools/VisualBuilder/VBPropertiesWindow.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#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()
|
||||
{
|
||||
}
|
18
DevTools/VisualBuilder/VBPropertiesWindow.h
Normal file
18
DevTools/VisualBuilder/VBPropertiesWindow.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#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 };
|
||||
};
|
33
DevTools/VisualBuilder/VBProperty.cpp
Normal file
33
DevTools/VisualBuilder/VBProperty.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
#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();
|
||||
}
|
33
DevTools/VisualBuilder/VBProperty.h
Normal file
33
DevTools/VisualBuilder/VBProperty.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#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 };
|
||||
};
|
197
DevTools/VisualBuilder/VBWidget.cpp
Normal file
197
DevTools/VisualBuilder/VBWidget.cpp
Normal file
|
@ -0,0 +1,197 @@
|
|||
#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();
|
||||
}
|
73
DevTools/VisualBuilder/VBWidget.h
Normal file
73
DevTools/VisualBuilder/VBWidget.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
#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;
|
||||
};
|
72
DevTools/VisualBuilder/VBWidgetPropertyModel.cpp
Normal file
72
DevTools/VisualBuilder/VBWidgetPropertyModel.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
#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();
|
||||
}
|
32
DevTools/VisualBuilder/VBWidgetPropertyModel.h
Normal file
32
DevTools/VisualBuilder/VBWidgetPropertyModel.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#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;
|
||||
};
|
99
DevTools/VisualBuilder/VBWidgetRegistry.cpp
Normal file
99
DevTools/VisualBuilder/VBWidgetRegistry.cpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
#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;
|
||||
}
|
21
DevTools/VisualBuilder/VBWidgetRegistry.h
Normal file
21
DevTools/VisualBuilder/VBWidgetRegistry.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#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>>&);
|
||||
};
|
16
DevTools/VisualBuilder/VBWidgetType.h
Normal file
16
DevTools/VisualBuilder/VBWidgetType.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
enum class VBWidgetType {
|
||||
None = 0,
|
||||
GWidget,
|
||||
GButton,
|
||||
GLabel,
|
||||
GSpinBox,
|
||||
GTextEditor,
|
||||
GProgressBar,
|
||||
GCheckBox,
|
||||
GScrollBar,
|
||||
GGroupBox,
|
||||
GSlider,
|
||||
__Count
|
||||
};
|
150
DevTools/VisualBuilder/main.cpp
Normal file
150
DevTools/VisualBuilder/main.cpp
Normal file
|
@ -0,0 +1,150 @@
|
|||
#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;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue