DevTools: Remove VisualBuilder and FormCompiler

This functionality is being moved to HackStudio so let's not confuse
people by keeping the old stuff around.
This commit is contained in:
Andreas Kling 2020-10-01 20:06:18 +02:00
parent 6c9a3ecf42
commit 0245e0f03a
Notes: sideshowbarker 2024-07-19 02:06:58 +09:00
26 changed files with 1 additions and 2033 deletions

View file

@ -7,7 +7,6 @@ alias ms=Minesweeper
alias sh=Shell
alias sn=Snake
alias tb=Taskbar
alias vb=VisualBuilder
alias wg=WidgetGallery
alias te=TextEditor
alias he=HexEditor

View file

@ -10,7 +10,6 @@ jpeg=/bin/QuickShow
html=/bin/Browser
wav=/bin/SoundPlayer
txt=/bin/TextEditor
frm=/bin/VisualBuilder
font=/bin/FontEditor
hackstudio=/bin/HackStudio
*=/bin/TextEditor

View file

@ -1,11 +0,0 @@
[App]
Name=Visual Builder
Executable=/bin/VisualBuilder
Category=Development
[Icons]
16x16=/res/icons/16x16/app-visual-builder.png
32x32=/res/icons/32x32/app-visual-builder.png
[Launcher]
FileTypes=frm

Binary file not shown.

Before

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 605 B

View file

@ -51,8 +51,7 @@ Serenity includes several development tools to enable you to create new
applications for Serenity. You can build a new graphical tool, craft a new
server, hack on a kernel, hammer the browser... the possibilities are endless!
This is all possibly by using HackStudio, Visual Builder, Terminal, and the
(optional) GNU tools.
This is all possibly by using HackStudio, Terminal, and the (optional) GNU tools.
* Multimedia
$ /res/icons/16x16/audio-volume-medium.png

View file

@ -80,7 +80,6 @@ include_directories(.)
add_subdirectory(Meta/Lagom)
add_subdirectory(DevTools/IPCCompiler)
add_subdirectory(DevTools/FormCompiler)
add_subdirectory(Libraries/LibWeb/CodeGenerators)
add_subdirectory(AK/Tests)

View file

@ -2,4 +2,3 @@ add_subdirectory(HackStudio)
add_subdirectory(Inspector)
add_subdirectory(Profiler)
add_subdirectory(UserspaceEmulator)
add_subdirectory(VisualBuilder)

View file

@ -1,6 +0,0 @@
set(SOURCES
main.cpp
)
add_executable(FormCompiler ${SOURCES})
target_link_libraries(FormCompiler LagomCore)

View file

@ -1 +0,0 @@
{"name":"Form1","widgets":[{"name":"w1","tooltip":null,"backcolor":"#d4d0c8ff","forecolor":"#000000ff","text":"Hello world!","class":"GLabel","autofill":true,"enabled":true,"visible":true,"x":5,"height":26,"y":5,"width":121},{"name":"w2","tooltip":null,"backcolor":"#d4d0c8ff","forecolor":"#000000ff","text":"Lefty","class":"GButton","autofill":false,"enabled":true,"visible":true,"x":5,"height":26,"y":40,"width":51},{"name":"w3","tooltip":null,"backcolor":"#d4d0c8ff","forecolor":"#000000ff","text":"Righty","class":"GButton","autofill":false,"enabled":true,"visible":true,"x":80,"height":26,"y":40,"width":51},{"name":"w4","enabled":true,"forecolor":"#000000ff","checked":false,"autofill":false,"x":150,"tooltip":null,"height":26,"width":91,"y":5,"class":"GCheckBox","text":"Awesome","backcolor":"#d4d0c8ff","visible":true},{"name":"w5","enabled":true,"forecolor":"#000000ff","checked":false,"autofill":false,"x":150,"tooltip":null,"height":26,"width":51,"y":30,"class":"GCheckBox","text":"Cool","backcolor":"#d4d0c8ff","visible":true}]}

View file

@ -1,124 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <AK/JsonArray.h>
#include <AK/JsonObject.h>
#include <AK/JsonValue.h>
#include <AK/LogStream.h>
#include <AK/StringBuilder.h>
#include <LibCore/File.h>
#include <stdio.h>
int main(int argc, char** argv)
{
if (argc != 2) {
printf("usage: %s <form-file>\n", argv[0]);
return 0;
}
auto file = Core::File::construct(argv[1]);
if (!file->open(Core::IODevice::ReadOnly)) {
fprintf(stderr, "Error: Cannot open %s: %s\n", argv[1], file->error_string());
return 1;
}
auto file_contents = file->read_all();
auto json_result = JsonValue::from_string(file_contents);
ASSERT(json_result.has_value());
auto json = json_result.value();
if (!json.is_object()) {
fprintf(stderr, "Malformed input\n");
return 1;
}
auto name = json.as_object().get("name").to_string();
auto widgets = json.as_object().get("widgets");
if (!widgets.is_array()) {
fprintf(stderr, "Malformed input\n");
return 1;
}
out() << "#pragma once";
widgets.as_array().for_each([&](auto& value) {
const JsonObject& widget_object = value.as_object();
auto class_name = widget_object.get("class").to_string();
StringBuilder builder;
auto parts = class_name.split(':');
builder.append(parts.last());
out() << "#include <LibGUI/" << builder.to_string() << ".h>";
});
out() << "struct UI_" << name << " {";
out() << " RefPtr<GUI::Widget> main_widget;";
widgets.as_array().for_each([&](auto& value) {
ASSERT(value.is_object());
const JsonObject& widget_object = value.as_object();
auto name = widget_object.get("name").to_string();
auto class_name = widget_object.get("class").to_string();
out() << " RefPtr<" << class_name << "> " << name << ";";
});
out() << " UI_" << name << "();";
out() << "};";
out() << "UI_" << name << "::UI_" << name << "()";
out() << "{";
out() << " main_widget = GUI::Widget::construct();";
out() << " main_widget->set_fill_with_background_color(true);";
widgets.as_array().for_each([&](auto& value) {
ASSERT(value.is_object());
const JsonObject& widget_object = value.as_object();
auto name = widget_object.get("name").to_string();
auto class_name = widget_object.get("class").to_string();
out() << " " << name << " = main_widget->add<" << class_name << ">();";
widget_object.for_each_member([&](auto& property_name, const JsonValue& property_value) {
if (property_name == "class")
return;
String value;
if (property_value.is_null())
value = "{}";
else
value = property_value.serialized<StringBuilder>();
out() << " " << name << "->set_" << property_name << "(" << value << ");";
});
out() << "";
});
out() << "}";
return 0;
}

View file

@ -1,12 +0,0 @@
set(SOURCES
main.cpp
VBForm.cpp
VBPropertiesWindow.cpp
VBProperty.cpp
VBWidget.cpp
VBWidgetPropertyModel.cpp
VBWidgetRegistry.cpp
)
serenity_bin(VisualBuilder)
target_link_libraries(VisualBuilder LibGUI)

View file

@ -1,527 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "VBForm.h"
#include "VBProperty.h"
#include "VBWidget.h"
#include "VBWidgetRegistry.h"
#include <AK/JsonArray.h>
#include <AK/JsonObject.h>
#include <AK/StringBuilder.h>
#include <LibCore/File.h>
#include <LibGUI/Action.h>
#include <LibGUI/BoxLayout.h>
#include <LibGUI/Menu.h>
#include <LibGUI/MessageBox.h>
#include <LibGUI/Painter.h>
static VBForm* s_current;
VBForm* VBForm::current()
{
return s_current;
}
VBForm::VBForm(const String& name)
: m_name(name)
{
s_current = this;
set_fill_with_background_color(true);
set_greedy_for_hits(true);
m_context_menu = GUI::Menu::construct();
m_context_menu->add_action(GUI::CommonActions::make_move_to_front_action([this](auto&) {
if (auto* widget = single_selected_widget())
widget->gwidget()->move_to_front();
}));
m_context_menu->add_action(GUI::CommonActions::make_move_to_back_action([this](auto&) {
if (auto* widget = single_selected_widget())
widget->gwidget()->move_to_back();
}));
m_context_menu->add_separator();
m_context_menu->add_action(GUI::Action::create("Lay out horizontally", Gfx::Bitmap::load_from_file("/res/icons/16x16/layout-horizontally.png"), [this](auto&) {
if (auto* widget = single_selected_widget()) {
dbg() << "Giving " << *widget->gwidget() << " a horizontal box layout";
widget->gwidget()->set_layout<GUI::HorizontalBoxLayout>();
}
}));
m_context_menu->add_action(GUI::Action::create("Lay out vertically", Gfx::Bitmap::load_from_file("/res/icons/16x16/layout-vertically.png"), [this](auto&) {
if (auto* widget = single_selected_widget()) {
dbg() << "Giving " << *widget->gwidget() << " a vertical box layout";
widget->gwidget()->set_layout<GUI::VerticalBoxLayout>();
}
}));
m_context_menu->add_separator();
m_context_menu->add_action(GUI::CommonActions::make_delete_action([this](auto&) {
delete_selected_widgets();
}));
}
void VBForm::context_menu_event(GUI::ContextMenuEvent& event)
{
m_context_menu->popup(event.screen_position());
}
void VBForm::insert_widget(VBWidgetType type)
{
auto* insertion_parent = single_selected_widget();
auto widget = VBWidget::create(type, *this, insertion_parent);
Gfx::IntPoint insertion_position = m_next_insertion_position;
if (insertion_parent)
insertion_position.move_by(insertion_parent->gwidget()->window_relative_rect().location());
widget->set_rect({ 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(GUI::PaintEvent& event)
{
GUI::Painter 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(GUI::PaintEvent& event)
{
GUI::Painter painter(*this);
painter.add_clip_rect(event.rect());
for (auto& widget : m_widgets) {
if (widget.is_selected()) {
for_each_direction([&](auto direction) {
bool in_layout = widget.is_in_layout();
auto grabber_rect = widget.grabber_rect(direction);
painter.fill_rect(grabber_rect, in_layout ? Color::White : Color::Black);
if (in_layout)
painter.draw_rect(grabber_rect, 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 Gfx::IntPoint& position)
{
auto result = hit_test(position, GUI::Widget::ShouldRespectGreediness::No);
if (!result.widget)
return nullptr;
auto* gwidget = result.widget;
while (gwidget) {
if (auto* widget = m_gwidget_map.get(gwidget).value_or(nullptr))
return widget;
gwidget = gwidget->parent_widget();
}
return nullptr;
}
void VBForm::grabber_mousedown_event(GUI::MouseEvent& 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(GUI::KeyEvent& 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;
}
size_t 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) {
if (widget.is_in_layout())
return;
widget.gwidget()->move_by(0, -m_grid_size);
});
break;
case KeyCode::Key_Down:
update();
for_each_selected_widget([this](auto& widget) {
if (widget.is_in_layout())
return;
widget.gwidget()->move_by(0, m_grid_size);
});
break;
case KeyCode::Key_Left:
update();
for_each_selected_widget([this](auto& widget) {
if (widget.is_in_layout())
return;
widget.gwidget()->move_by(-m_grid_size, 0);
});
break;
case KeyCode::Key_Right:
update();
for_each_selected_widget([this](auto& widget) {
if (widget.is_in_layout())
return;
widget.gwidget()->move_by(m_grid_size, 0);
});
break;
default:
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(GUI::MouseEvent& event)
{
if (m_resize_direction == Direction::None) {
bool hit_grabber = false;
for_each_selected_widget([&](auto& widget) {
if (widget.is_in_layout())
return;
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() == GUI::MouseButton::Left || event.button() == GUI::MouseButton::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(GUI::MouseEvent& event)
{
if (event.buttons() & GUI::MouseButton::Left) {
if (m_resize_direction == Direction::None) {
update();
auto delta = event.position() - m_transform_event_origin;
for_each_selected_widget([&](auto& widget) {
if (widget.is_in_layout())
return;
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) {
if (widget.is_in_layout())
return;
auto new_rect = widget.transform_origin_rect();
Gfx::IntSize 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);
});
set_cursor_type_from_grabber(m_resize_direction);
} else {
for (auto& widget : m_selected_widgets) {
if (widget->is_in_layout())
continue;
auto grabber_at = widget->grabber_at(event.position());
set_cursor_type_from_grabber(grabber_at);
if (grabber_at != Direction::None)
break;
}
}
}
void VBForm::load_from_file(const String& path)
{
auto file = Core::File::construct(path);
if (!file->open(Core::IODevice::ReadOnly)) {
GUI::MessageBox::show(window(), String::format("Could not open '%s' for reading", path.characters()), "Error", GUI::MessageBox::Type::Error);
return;
}
auto file_contents = file->read_all();
auto form_json = JsonValue::from_string(file_contents);
ASSERT(form_json.has_value());
if (!form_json.value().is_object()) {
GUI::MessageBox::show(window(), String::format("Could not parse '%s'", path.characters()), "Error", GUI::MessageBox::Type::Error);
return;
}
m_name = form_json.value().as_object().get("name").to_string();
auto widgets = form_json.value().as_object().get("widgets").as_array();
widgets.for_each([&](const JsonValue& widget_value) {
auto& widget_object = widget_value.as_object();
auto widget_class = widget_object.get("class").as_string();
auto widget_type = widget_type_from_class_name(widget_class);
// FIXME: Construct VBWidget within the right parent..
auto vbwidget = VBWidget::create(widget_type, *this, nullptr);
widget_object.for_each_member([&](auto& property_name, const JsonValue& property_value) {
(void)property_name;
(void)property_value;
VBProperty& property = vbwidget->property(property_name);
dbgprintf("Set property %s.%s to '%s'\n", widget_class.characters(), property_name.characters(), property_value.to_string().characters());
property.set_value(property_value);
});
m_widgets.append(vbwidget);
});
}
void VBForm::write_to_file(const String& path)
{
auto file = Core::File::construct(path);
if (!file->open(Core::IODevice::WriteOnly)) {
GUI::MessageBox::show(window(), String::format("Could not open '%s' for writing", path.characters()), "Error", GUI::MessageBox::Type::Error);
return;
}
JsonObject form_object;
form_object.set("name", m_name);
JsonArray widget_array;
for (auto& widget : m_widgets) {
JsonObject widget_object;
widget.for_each_property([&](auto& property) {
if (property.value().is_bool())
widget_object.set(property.name(), property.value().to_bool());
else if (property.value().is_i32())
widget_object.set(property.name(), property.value().to_i32());
else if (property.value().is_i64())
widget_object.set(property.name(), property.value().to_i64());
else
widget_object.set(property.name(), property.value().to_string());
});
widget_array.append(widget_object);
}
form_object.set("widgets", widget_array);
file->write(form_object.to_string());
}
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(GUI::MouseEvent& event)
{
if (event.button() == GUI::MouseButton::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);
});
if (to_delete.is_empty())
return;
for (auto& widget : to_delete)
m_widgets.remove_first_matching([&widget](auto& entry) { return entry == widget; });
on_widget_selected(single_selected_widget());
update();
}
template<typename Callback>
void VBForm::for_each_selected_widget(Callback callback)
{
for (auto& widget : m_selected_widgets)
callback(*widget);
}
void VBForm::set_cursor_type_from_grabber(Direction grabber)
{
if (grabber == m_mouse_direction_type)
return;
switch (grabber) {
case Direction::Up:
case Direction::Down:
window()->set_cursor(Gfx::StandardCursor::ResizeVertical);
break;
case Direction::Left:
case Direction::Right:
window()->set_cursor(Gfx::StandardCursor::ResizeHorizontal);
break;
case Direction::UpLeft:
case Direction::DownRight:
window()->set_cursor(Gfx::StandardCursor::ResizeDiagonalTLBR);
break;
case Direction::UpRight:
case Direction::DownLeft:
window()->set_cursor(Gfx::StandardCursor::ResizeDiagonalBLTR);
break;
case Direction::None:
window()->set_cursor(Gfx::StandardCursor::None);
break;
}
m_mouse_direction_type = grabber;
}
VBWidget* VBForm::single_selected_widget()
{
if (m_selected_widgets.size() != 1)
return nullptr;
return *m_selected_widgets.begin();
}

View file

@ -1,93 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "VBWidget.h"
#include <AK/NonnullRefPtrVector.h>
#include <LibGUI/Widget.h>
class VBForm : public GUI::Widget {
C_OBJECT(VBForm)
friend class VBWidget;
public:
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 Gfx::IntPoint&);
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 load_from_file(const String& path);
void write_to_file(const String& path);
void dump();
protected:
virtual void paint_event(GUI::PaintEvent&) override;
virtual void second_paint_event(GUI::PaintEvent&) override;
virtual void mousedown_event(GUI::MouseEvent&) override;
virtual void mousemove_event(GUI::MouseEvent&) override;
virtual void mouseup_event(GUI::MouseEvent&) override;
virtual void context_menu_event(GUI::ContextMenuEvent&) override;
virtual void keydown_event(GUI::KeyEvent&) override;
private:
explicit VBForm(const String& name);
void grabber_mousedown_event(GUI::MouseEvent&, 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);
void set_cursor_type_from_grabber(Direction grabber);
VBWidget* single_selected_widget();
String m_name;
int m_grid_size { 5 };
bool m_should_snap_to_grid { true };
NonnullRefPtrVector<VBWidget> m_widgets;
HashMap<GUI::Widget*, VBWidget*> m_gwidget_map;
HashTable<VBWidget*> m_selected_widgets;
Gfx::IntPoint m_transform_event_origin;
Gfx::IntPoint m_next_insertion_position;
Direction m_resize_direction { Direction::None };
Direction m_mouse_direction_type { Direction::None };
RefPtr<GUI::Menu> m_context_menu;
};

View file

@ -1,110 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "VBPropertiesWindow.h"
#include "VBWidgetPropertyModel.h"
#include <LibGUI/BoxLayout.h>
#include <LibGUI/ComboBox.h>
#include <LibGUI/ModelEditingDelegate.h>
#include <LibGUI/TableView.h>
#include <LibGUI/TextBox.h>
#include <LibGUI/Widget.h>
class BoolValuesModel final : public GUI::Model {
public:
virtual int row_count(const GUI::ModelIndex&) const override { return 2; }
virtual int column_count(const GUI::ModelIndex&) const override { return 1; }
virtual void update() override { }
virtual GUI::Variant data(const GUI::ModelIndex& index, GUI::ModelRole role) const override
{
if (role != GUI::ModelRole::Display)
return {};
switch (index.row()) {
case 0:
return "false";
case 1:
return "true";
}
ASSERT_NOT_REACHED();
}
};
class BoolModelEditingDelegate : public GUI::ModelEditingDelegate {
public:
BoolModelEditingDelegate() { }
virtual ~BoolModelEditingDelegate() override { }
virtual RefPtr<GUI::Widget> create_widget() override
{
auto combo = GUI::ComboBox::construct();
combo->set_only_allow_values_from_model(true);
combo->set_model(adopt(*new BoolValuesModel));
combo->on_return_pressed = [this] { commit(); };
combo->on_change = [this](auto&, auto&) { commit(); };
return combo;
}
virtual GUI::Variant value() const override { return static_cast<const GUI::ComboBox*>(widget())->text() == "true"; }
virtual void set_value(const GUI::Variant& value) override { static_cast<GUI::ComboBox*>(widget())->set_text(value.to_string()); }
virtual void will_begin_editing() override
{
auto& combo = *static_cast<GUI::ComboBox*>(widget());
combo.select_all();
combo.open();
}
};
VBPropertiesWindow::VBPropertiesWindow()
{
set_title("Properties");
set_rect(780, 200, 240, 280);
set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/app-visual-builder.png"));
auto& widget = set_main_widget<GUI::Widget>();
widget.set_fill_with_background_color(true);
widget.set_layout<GUI::VerticalBoxLayout>();
widget.layout()->set_margins({ 2, 2, 2, 2 });
m_table_view = widget.add<GUI::TableView>();
m_table_view->set_column_headers_visible(false);
m_table_view->set_editable(true);
m_table_view->aid_create_editing_delegate = [this](auto& index) -> OwnPtr<GUI::ModelEditingDelegate> {
if (!m_table_view->model())
return nullptr;
auto type_index = m_table_view->model()->index(index.row(), VBWidgetPropertyModel::Column::Type);
auto type = type_index.data(GUI::ModelRole::Custom).to_i32();
switch ((GUI::Variant::Type)type) {
case GUI::Variant::Type::Bool:
return make<BoolModelEditingDelegate>();
default:
return make<GUI::StringModelEditingDelegate>();
}
};
}
VBPropertiesWindow::~VBPropertiesWindow()
{
}

View file

@ -1,42 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <LibGUI/Window.h>
class VBPropertiesWindow final : public GUI::Window {
C_OBJECT(VBPropertiesWindow)
public:
VBPropertiesWindow();
virtual ~VBPropertiesWindow() override;
GUI::TableView& table_view() { return *m_table_view; }
const GUI::TableView& table_view() const { return *m_table_view; }
private:
RefPtr<GUI::TableView> m_table_view;
};

View file

@ -1,59 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "VBProperty.h"
#include "VBWidget.h"
VBProperty::VBProperty(VBWidget& widget, const String& name, const GUI::Variant& value)
: m_widget(widget)
, m_name(name)
, m_value(value)
{
}
VBProperty::VBProperty(VBWidget& widget, const String& name, Function<GUI::Variant(const GUI::Widget&)>&& getter, Function<void(GUI::Widget&, const GUI::Variant&)>&& 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 GUI::Variant& 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,60 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <AK/Function.h>
#include <AK/String.h>
#include <LibGUI/Forward.h>
#include <LibGUI/Variant.h>
class VBWidget;
class VBProperty {
friend class VBWidget;
public:
VBProperty(VBWidget&, const String& name, const GUI::Variant& value);
VBProperty(VBWidget&, const String& name, Function<GUI::Variant(const GUI::Widget&)>&& getter, Function<void(GUI::Widget&, const GUI::Variant&)>&& setter);
~VBProperty();
String name() const { return m_name; }
const GUI::Variant& value() const { return m_value; }
void set_value(const GUI::Variant&);
bool is_readonly() const { return m_readonly; }
void set_readonly(bool b) { m_readonly = b; }
void sync();
private:
VBWidget& m_widget;
String m_name;
GUI::Variant m_value;
Function<GUI::Variant(const GUI::Widget&)> m_getter;
Function<void(GUI::Widget&, const GUI::Variant&)> m_setter;
bool m_readonly { false };
};

View file

@ -1,244 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "VBWidget.h"
#include "VBForm.h"
#include "VBProperty.h"
#include "VBWidgetPropertyModel.h"
#include "VBWidgetRegistry.h"
#include <LibGUI/Button.h>
#include <LibGUI/CheckBox.h>
#include <LibGUI/GroupBox.h>
#include <LibGUI/Label.h>
#include <LibGUI/Painter.h>
#include <LibGUI/ProgressBar.h>
#include <LibGUI/RadioButton.h>
#include <LibGUI/ScrollBar.h>
#include <LibGUI/Slider.h>
#include <LibGUI/SpinBox.h>
#include <LibGUI/TextEditor.h>
VBWidget::VBWidget(VBWidgetType type, VBForm& form, VBWidget* parent)
: m_type(type)
, m_form(form)
, m_property_model(VBWidgetPropertyModel::create(*this))
{
auto* widget_parent = parent ? parent->gwidget() : &form;
m_gwidget = VBWidgetRegistry::build_gwidget(*this, type, widget_parent, 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);
m_gwidget->parent()->remove_child(*m_gwidget);
}
Gfx::IntRect VBWidget::rect() const
{
return m_gwidget->window_relative_rect();
}
void VBWidget::set_rect(const Gfx::IntRect& rect)
{
if (rect == m_gwidget->window_relative_rect())
return;
auto new_window_relative_rect = rect;
if (m_gwidget->parent())
new_window_relative_rect.move_by(-m_gwidget->parent_widget()->window_relative_rect().location());
m_gwidget->set_relative_rect(new_window_relative_rect);
synchronize_properties();
}
bool VBWidget::is_selected() const
{
return m_form.is_selected(*this);
}
Gfx::IntRect 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 Gfx::IntPoint& 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<GUI::Variant(const GUI::Widget&)>&& getter, Function<void(GUI::Widget&, const GUI::Variant&)>&& 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) -> GUI::Variant { return ((const gclass&)widget).getter(); }, \
[](auto& widget, auto& value) { ((gclass&)widget).setter(value.to_##variant_type()); })
void VBWidget::setup_properties()
{
VB_ADD_PROPERTY(Core::Object, "name", name, set_name, string);
VB_ADD_PROPERTY(GUI::Widget, "width", width, set_width, i32);
VB_ADD_PROPERTY(GUI::Widget, "height", height, set_height, i32);
VB_ADD_PROPERTY(GUI::Widget, "x", x, set_x, i32);
VB_ADD_PROPERTY(GUI::Widget, "y", y, set_y, i32);
VB_ADD_PROPERTY(GUI::Widget, "visible", is_visible, set_visible, bool);
VB_ADD_PROPERTY(GUI::Widget, "enabled", is_enabled, set_enabled, bool);
VB_ADD_PROPERTY(GUI::Widget, "tooltip", tooltip, set_tooltip, string);
VB_ADD_PROPERTY(GUI::Widget, "backcolor", background_color, set_background_color, color);
VB_ADD_PROPERTY(GUI::Widget, "forecolor", foreground_color, set_foreground_color, color);
VB_ADD_PROPERTY(GUI::Widget, "autofill", fill_with_background_color, set_fill_with_background_color, bool);
if (m_type == VBWidgetType::GLabel) {
VB_ADD_PROPERTY(GUI::Label, "text", text, set_text, string);
}
if (m_type == VBWidgetType::GButton) {
VB_ADD_PROPERTY(GUI::Button, "text", text, set_text, string);
}
if (m_type == VBWidgetType::GGroupBox) {
VB_ADD_PROPERTY(GUI::GroupBox, "title", title, set_title, string);
}
if (m_type == VBWidgetType::GScrollBar) {
VB_ADD_PROPERTY(GUI::ScrollBar, "min", min, set_min, i32);
VB_ADD_PROPERTY(GUI::ScrollBar, "max", max, set_max, i32);
VB_ADD_PROPERTY(GUI::ScrollBar, "value", value, set_value, i32);
VB_ADD_PROPERTY(GUI::ScrollBar, "step", step, set_step, i32);
}
if (m_type == VBWidgetType::GSpinBox) {
VB_ADD_PROPERTY(GUI::SpinBox, "min", min, set_min, i32);
VB_ADD_PROPERTY(GUI::SpinBox, "max", max, set_max, i32);
VB_ADD_PROPERTY(GUI::SpinBox, "value", value, set_value, i32);
}
if (m_type == VBWidgetType::GProgressBar) {
VB_ADD_PROPERTY(GUI::ProgressBar, "min", min, set_min, i32);
VB_ADD_PROPERTY(GUI::ProgressBar, "max", max, set_max, i32);
VB_ADD_PROPERTY(GUI::ProgressBar, "value", value, set_value, i32);
}
if (m_type == VBWidgetType::GSlider) {
VB_ADD_PROPERTY(GUI::Slider, "min", min, set_min, i32);
VB_ADD_PROPERTY(GUI::Slider, "max", max, set_max, i32);
VB_ADD_PROPERTY(GUI::Slider, "value", value, set_value, i32);
}
if (m_type == VBWidgetType::GTextEditor) {
VB_ADD_PROPERTY(GUI::TextEditor, "text", text, set_text, string);
VB_ADD_PROPERTY(GUI::TextEditor, "ruler_visible", is_ruler_visible, set_ruler_visible, bool);
}
if (m_type == VBWidgetType::GCheckBox) {
VB_ADD_PROPERTY(GUI::CheckBox, "text", text, set_text, string);
VB_ADD_PROPERTY(GUI::CheckBox, "checked", is_checked, set_checked, bool);
}
if (m_type == VBWidgetType::GRadioButton) {
VB_ADD_PROPERTY(GUI::RadioButton, "text", text, set_text, string);
VB_ADD_PROPERTY(GUI::RadioButton, "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, GUI::Variant()));
return m_properties.last();
}
void VBWidget::property_did_change()
{
m_form.update();
}
void VBWidget::capture_transform_origin_rect()
{
m_transform_origin_rect = rect();
}
bool VBWidget::is_in_layout() const
{
if (auto* parent_widget = m_gwidget->parent_widget()) {
if (parent_widget->layout())
return true;
}
return false;
}

View file

@ -1,112 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "VBWidgetType.h"
#include <AK/Function.h>
#include <AK/HashMap.h>
#include <AK/NonnullOwnPtrVector.h>
#include <AK/NonnullRefPtr.h>
#include <AK/RefCounted.h>
#include <AK/Weakable.h>
#include <LibGUI/Widget.h>
#include <LibGfx/Rect.h>
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 RefCounted<VBWidget>
, public Weakable<VBWidget> {
friend class VBWidgetPropertyModel;
public:
static NonnullRefPtr<VBWidget> create(VBWidgetType type, VBForm& form, VBWidget* parent) { return adopt(*new VBWidget(type, form, parent)); }
~VBWidget();
bool is_selected() const;
Gfx::IntRect rect() const;
void set_rect(const Gfx::IntRect&);
Gfx::IntRect grabber_rect(Direction) const;
Direction grabber_at(const Gfx::IntPoint&) const;
GUI::Widget* 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();
Gfx::IntRect transform_origin_rect() const { return m_transform_origin_rect; }
void capture_transform_origin_rect();
bool is_in_layout() const;
private:
VBWidget(VBWidgetType, VBForm&, VBWidget* parent);
void add_property(const String& name, Function<GUI::Variant(const GUI::Widget&)>&& getter, Function<void(GUI::Widget&, const GUI::Variant&)>&& setter);
VBWidgetType m_type { VBWidgetType::None };
VBForm& m_form;
RefPtr<GUI::Widget> m_gwidget;
NonnullOwnPtrVector<VBProperty> m_properties;
NonnullRefPtr<VBWidgetPropertyModel> m_property_model;
Gfx::IntRect m_transform_origin_rect;
};

View file

@ -1,117 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "VBWidgetPropertyModel.h"
#include "VBProperty.h"
#include "VBWidget.h"
#include <LibGfx/Font.h>
VBWidgetPropertyModel::VBWidgetPropertyModel(VBWidget& widget)
: m_widget(widget)
{
}
VBWidgetPropertyModel::~VBWidgetPropertyModel()
{
}
int VBWidgetPropertyModel::row_count(const GUI::ModelIndex&) 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";
case Column::Type:
return "Type";
default:
ASSERT_NOT_REACHED();
}
}
GUI::Variant VBWidgetPropertyModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
{
if (role == GUI::ModelRole::TextAlignment) {
return Gfx::TextAlignment::CenterLeft;
}
if (role == GUI::ModelRole::Font) {
if (index.column() == Column::Name)
return Gfx::Font::default_bold_font();
return {};
}
if (role == GUI::ModelRole::Custom) {
auto& property = m_widget.m_properties[index.row()];
if (index.column() == Column::Type)
return (int)property.value().type();
return {};
}
if (role == GUI::ModelRole::Display) {
auto& property = m_widget.m_properties[index.row()];
switch (index.column()) {
case Column::Name:
return property.name();
case Column::Value:
return property.value();
case Column::Type:
return to_string(property.value().type());
}
ASSERT_NOT_REACHED();
}
if (role == GUI::ModelRole::ForegroundColor) {
auto& property = m_widget.m_properties[index.row()];
switch (index.column()) {
case Column::Name:
return Color::Black;
case Column::Type:
return Color::Blue;
case Column::Value:
return property.is_readonly() ? Color(Color::MidGray) : Color(Color::Black);
}
ASSERT_NOT_REACHED();
}
return {};
}
void VBWidgetPropertyModel::set_data(const GUI::ModelIndex& index, const GUI::Variant& 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 GUI::ModelIndex& index) const
{
if (index.column() != Column::Value)
return false;
auto& property = m_widget.m_properties[index.row()];
return !property.is_readonly();
}

View file

@ -1,58 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <LibGUI/Model.h>
class VBWidget;
class VBProperty;
class VBWidgetPropertyModel : public GUI::Model {
public:
enum Column {
Name = 0,
Value,
Type,
__Count
};
static NonnullRefPtr<VBWidgetPropertyModel> create(VBWidget& widget) { return adopt(*new VBWidgetPropertyModel(widget)); }
virtual ~VBWidgetPropertyModel() override;
virtual int row_count(const GUI::ModelIndex&) const override;
virtual int column_count(const GUI::ModelIndex&) const override { return Column::__Count; }
virtual String column_name(int column) const override;
virtual GUI::Variant data(const GUI::ModelIndex&, GUI::ModelRole) const override;
virtual void update() override { did_update(); }
virtual bool is_editable(const GUI::ModelIndex&) const override;
virtual void set_data(const GUI::ModelIndex&, const GUI::Variant&) override;
private:
explicit VBWidgetPropertyModel(VBWidget&);
VBWidget& m_widget;
};

View file

@ -1,161 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "VBWidgetRegistry.h"
#include "VBProperty.h"
#include <LibGUI/Button.h>
#include <LibGUI/CheckBox.h>
#include <LibGUI/GroupBox.h>
#include <LibGUI/Label.h>
#include <LibGUI/ProgressBar.h>
#include <LibGUI/RadioButton.h>
#include <LibGUI/ScrollBar.h>
#include <LibGUI/Slider.h>
#include <LibGUI/SpinBox.h>
#include <LibGUI/TextEditor.h>
String to_class_name(VBWidgetType type)
{
switch (type) {
case VBWidgetType::GWidget:
return "GUI::Widget";
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::GRadioButton:
return "GRadioButton";
case VBWidgetType::GScrollBar:
return "GScrollBar";
case VBWidgetType::GGroupBox:
return "GGroupBox";
case VBWidgetType::GSlider:
return "GSlider";
default:
ASSERT_NOT_REACHED();
}
}
VBWidgetType widget_type_from_class_name(const StringView& name)
{
if (name == "GUI::Widget")
return VBWidgetType::GWidget;
if (name == "GButton")
return VBWidgetType::GButton;
if (name == "GLabel")
return VBWidgetType::GLabel;
if (name == "GSpinBox")
return VBWidgetType::GSpinBox;
if (name == "GTextEditor")
return VBWidgetType::GTextEditor;
if (name == "GProgressBar")
return VBWidgetType::GProgressBar;
if (name == "GCheckBox")
return VBWidgetType::GCheckBox;
if (name == "GRadioButton")
return VBWidgetType::GRadioButton;
if (name == "GScrollBar")
return VBWidgetType::GScrollBar;
if (name == "GGroupBox")
return VBWidgetType::GGroupBox;
if (name == "GSlider")
return VBWidgetType::GSlider;
ASSERT_NOT_REACHED();
}
static RefPtr<GUI::Widget> build_gwidget(VBWidgetType type, GUI::Widget* parent)
{
switch (type) {
case VBWidgetType::GWidget:
return parent->add<GUI::Widget>();
case VBWidgetType::GScrollBar:
return parent->add<GUI::ScrollBar>(Orientation::Vertical);
case VBWidgetType::GGroupBox:
return parent->add<GUI::GroupBox>("groupbox_1");
case VBWidgetType::GLabel: {
auto& label = parent->add<GUI::Label>();
label.set_fill_with_background_color(true);
label.set_text("label_1");
return label;
}
case VBWidgetType::GButton: {
auto& button = parent->add<GUI::Button>();
button.set_text("button_1");
return button;
}
case VBWidgetType::GSpinBox: {
auto& box = parent->add<GUI::SpinBox>();
box.set_range(0, 100);
box.set_value(0);
return box;
}
case VBWidgetType::GTextEditor: {
auto& editor = parent->add<GUI::TextEditor>();
editor.set_ruler_visible(false);
return editor;
}
case VBWidgetType::GProgressBar: {
auto& bar = parent->add<GUI::ProgressBar>();
bar.set_format(GUI::ProgressBar::Format::NoText);
bar.set_range(0, 100);
bar.set_value(50);
return bar;
}
case VBWidgetType::GSlider: {
auto& slider = parent->add<GUI::HorizontalSlider>();
slider.set_range(0, 100);
slider.set_value(50);
return slider;
}
case VBWidgetType::GCheckBox: {
auto& box = parent->add<GUI::CheckBox>();
box.set_text("checkbox_1");
return box;
}
case VBWidgetType::GRadioButton:
return parent->add<GUI::RadioButton>("radio_1");
default:
ASSERT_NOT_REACHED();
return nullptr;
}
}
RefPtr<GUI::Widget> VBWidgetRegistry::build_gwidget(VBWidget& widget, VBWidgetType type, GUI::Widget* parent, NonnullOwnPtrVector<VBProperty>& properties)
{
auto gwidget = ::build_gwidget(type, parent);
auto property = make<VBProperty>(widget, "class", to_class_name(type));
property->set_readonly(true);
properties.append(move(property));
return gwidget;
}

View file

@ -1,52 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "VBWidgetType.h"
#include <AK/HashMap.h>
#include <AK/NonnullOwnPtrVector.h>
#include <AK/OwnPtr.h>
#include <AK/String.h>
#include <LibGUI/Widget.h>
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 RefPtr<GUI::Widget> build_gwidget(VBWidget&, VBWidgetType, GUI::Widget* parent, NonnullOwnPtrVector<VBProperty>&);
};
String to_class_name(VBWidgetType);
VBWidgetType widget_type_from_class_name(const StringView&);

View file

@ -1,43 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
enum class VBWidgetType {
None = 0,
GWidget,
GButton,
GLabel,
GSpinBox,
GTextEditor,
GProgressBar,
GCheckBox,
GRadioButton,
GScrollBar,
GGroupBox,
GSlider,
__Count
};

View file

@ -1,195 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "VBForm.h"
#include "VBPropertiesWindow.h"
#include "VBWidget.h"
#include "VBWidgetPropertyModel.h"
#include <LibGUI/AboutDialog.h>
#include <LibGUI/Action.h>
#include <LibGUI/Application.h>
#include <LibGUI/BoxLayout.h>
#include <LibGUI/Button.h>
#include <LibGUI/Menu.h>
#include <LibGUI/MenuBar.h>
#include <LibGUI/TableView.h>
#include <LibGUI/Widget.h>
#include <LibGUI/Window.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static RefPtr<GUI::Window> make_toolbox_window();
int main(int argc, char** argv)
{
auto app = GUI::Application::construct(argc, argv);
auto propbox = VBPropertiesWindow::construct();
auto form1 = VBForm::construct("Form1");
form1->on_widget_selected = [&](VBWidget* widget) {
propbox->table_view().set_model(widget ? &widget->property_model() : nullptr);
};
auto menubar = GUI::MenuBar::construct();
auto& app_menu = menubar->add_menu("Visual Builder");
app_menu.add_action(GUI::CommonActions::make_quit_action([](auto&) {
GUI::Application::the()->quit();
return;
}));
auto& file_menu = menubar->add_menu("File");
file_menu.add_action(GUI::Action::create("Dump Form", [&](auto&) {
form1->dump();
}));
file_menu.add_action(GUI::Action::create("Save Form...", { Mod_Ctrl, Key_S }, [&](auto&) {
form1->write_to_file("/tmp/form.frm");
}));
auto window = GUI::Window::construct();
window->set_title(form1->name());
window->set_rect(120, 200, 640, 400);
window->set_main_widget(form1);
window->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/app-visual-builder.png"));
window->show();
auto& help_menu = menubar->add_menu("Help");
help_menu.add_action(GUI::Action::create("About", [&](auto&) {
GUI::AboutDialog::show("Visual Builder", Gfx::Bitmap::load_from_file("/res/icons/32x32/app-visual-builder.png"), window);
}));
app->set_menubar(move(menubar));
auto toolbox = make_toolbox_window();
toolbox->show();
propbox->show();
if (argc == 2) {
form1->load_from_file(argv[1]);
}
return app->exec();
}
RefPtr<GUI::Window> make_toolbox_window()
{
auto window = GUI::Window::construct();
window->set_title("Widgets");
window->set_rect(20, 200, 80, 300);
window->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/app-visual-builder.png"));
auto& widget = window->set_main_widget<GUI::Widget>();
widget.set_fill_with_background_color(true);
widget.set_layout<GUI::VerticalBoxLayout>();
widget.layout()->set_spacing(0);
auto& label_button = widget.add<GUI::Button>();
label_button.set_button_style(Gfx::ButtonStyle::CoolBar);
label_button.set_tooltip("GLabel");
label_button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/visualbuilder/label.png"));
label_button.on_click = [](auto) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GLabel);
};
auto& button_button = widget.add<GUI::Button>();
button_button.set_button_style(Gfx::ButtonStyle::CoolBar);
button_button.set_tooltip("GButton");
button_button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/visualbuilder/button.png"));
button_button.on_click = [](auto) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GButton);
};
auto& spinbox_button = widget.add<GUI::Button>();
spinbox_button.set_button_style(Gfx::ButtonStyle::CoolBar);
spinbox_button.set_tooltip("GSpinBox");
spinbox_button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/visualbuilder/spinbox.png"));
spinbox_button.on_click = [](auto) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GSpinBox);
};
auto& editor_button = widget.add<GUI::Button>();
editor_button.set_button_style(Gfx::ButtonStyle::CoolBar);
editor_button.set_tooltip("GTextEditor");
editor_button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/visualbuilder/textbox.png"));
editor_button.on_click = [](auto) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GTextEditor);
};
auto& progress_bar_button = widget.add<GUI::Button>();
progress_bar_button.set_button_style(Gfx::ButtonStyle::CoolBar);
progress_bar_button.set_tooltip("GProgressBar");
progress_bar_button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/visualbuilder/progressbar.png"));
progress_bar_button.on_click = [](auto) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GProgressBar);
};
auto& slider_button = widget.add<GUI::Button>();
slider_button.set_button_style(Gfx::ButtonStyle::CoolBar);
slider_button.set_tooltip("GSlider");
slider_button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/visualbuilder/slider.png"));
slider_button.on_click = [](auto) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GSlider);
};
auto& checkbox_button = widget.add<GUI::Button>();
checkbox_button.set_button_style(Gfx::ButtonStyle::CoolBar);
checkbox_button.set_tooltip("GCheckBox");
checkbox_button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/visualbuilder/checkbox.png"));
checkbox_button.on_click = [](auto) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GCheckBox);
};
auto& radiobutton_button = widget.add<GUI::Button>();
radiobutton_button.set_button_style(Gfx::ButtonStyle::CoolBar);
radiobutton_button.set_tooltip("GRadioButton");
radiobutton_button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/serenity/filled-radio-circle.png"));
radiobutton_button.on_click = [](auto) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GRadioButton);
};
auto& scrollbar_button = widget.add<GUI::Button>();
scrollbar_button.set_button_style(Gfx::ButtonStyle::CoolBar);
scrollbar_button.set_tooltip("GScrollBar");
scrollbar_button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/visualbuilder/scrollbar.png"));
scrollbar_button.on_click = [](auto) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GScrollBar);
};
auto& groupbox_button = widget.add<GUI::Button>();
groupbox_button.set_button_style(Gfx::ButtonStyle::CoolBar);
groupbox_button.set_tooltip("GGroupBox");
groupbox_button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/visualbuilder/groupbox.png"));
groupbox_button.on_click = [](auto) {
if (auto* form = VBForm::current())
form->insert_widget(VBWidgetType::GGroupBox);
};
return window;
}