VBForm.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. #include "VBForm.h"
  2. #include "VBProperty.h"
  3. #include "VBWidget.h"
  4. #include <AK/JsonArray.h>
  5. #include <AK/JsonObject.h>
  6. #include <LibCore/CFile.h>
  7. #include <LibGUI/GAction.h>
  8. #include <LibGUI/GMenu.h>
  9. #include <LibGUI/GMessageBox.h>
  10. #include <LibGUI/GPainter.h>
  11. static VBForm* s_current;
  12. VBForm* VBForm::current()
  13. {
  14. return s_current;
  15. }
  16. VBForm::VBForm(const String& name, GWidget* parent)
  17. : GWidget(parent)
  18. , m_name(name)
  19. {
  20. s_current = this;
  21. set_fill_with_background_color(true);
  22. set_background_color(Color::LightGray);
  23. set_greedy_for_hits(true);
  24. auto box1 = VBWidget::create(VBWidgetType::GSpinBox, *this);
  25. box1->set_rect({ 10, 10, 81, 21 });
  26. m_widgets.append(move(box1));
  27. auto box2 = VBWidget::create(VBWidgetType::GTextEditor, *this);
  28. box2->set_rect({ 100, 100, 161, 161 });
  29. m_widgets.append(move(box2));
  30. auto button1 = VBWidget::create(VBWidgetType::GButton, *this);
  31. button1->set_rect({ 200, 50, 81, 21 });
  32. m_widgets.append(move(button1));
  33. auto groupbox1 = VBWidget::create(VBWidgetType::GGroupBox, *this);
  34. groupbox1->set_rect({ 300, 150, 161, 51 });
  35. m_widgets.append(move(groupbox1));
  36. m_context_menu = make<GMenu>("Context menu");
  37. m_context_menu->add_action(GAction::create("Move to front", [this](auto&) {
  38. if (auto* widget = single_selected_widget())
  39. widget->gwidget()->move_to_front();
  40. }));
  41. m_context_menu->add_action(GAction::create("Move to back", [this](auto&) {
  42. if (auto* widget = single_selected_widget())
  43. widget->gwidget()->move_to_back();
  44. }));
  45. m_context_menu->add_action(GAction::create("Delete", [this](auto&) {
  46. delete_selected_widgets();
  47. }));
  48. }
  49. void VBForm::context_menu_event(GContextMenuEvent& event)
  50. {
  51. m_context_menu->popup(event.screen_position());
  52. }
  53. void VBForm::insert_widget(VBWidgetType type)
  54. {
  55. auto widget = VBWidget::create(type, *this);
  56. widget->set_rect({ m_next_insertion_position, { m_grid_size * 10 + 1, m_grid_size * 5 + 1 } });
  57. m_next_insertion_position.move_by(m_grid_size, m_grid_size);
  58. m_widgets.append(move(widget));
  59. }
  60. VBForm::~VBForm()
  61. {
  62. }
  63. void VBForm::paint_event(GPaintEvent& event)
  64. {
  65. GPainter painter(*this);
  66. painter.add_clip_rect(event.rect());
  67. for (int y = 0; y < height(); y += m_grid_size) {
  68. for (int x = 0; x < width(); x += m_grid_size) {
  69. painter.set_pixel({ x, y }, Color::from_rgb(0x404040));
  70. }
  71. }
  72. }
  73. void VBForm::second_paint_event(GPaintEvent& event)
  74. {
  75. GPainter painter(*this);
  76. painter.add_clip_rect(event.rect());
  77. for (auto& widget : m_widgets) {
  78. if (widget->is_selected()) {
  79. for_each_direction([&](Direction direction) {
  80. painter.fill_rect(widget->grabber_rect(direction), Color::Black);
  81. });
  82. }
  83. }
  84. }
  85. bool VBForm::is_selected(const VBWidget& widget) const
  86. {
  87. // FIXME: Fix HashTable and remove this const_cast.
  88. return m_selected_widgets.contains(const_cast<VBWidget*>(&widget));
  89. }
  90. VBWidget* VBForm::widget_at(const Point& position)
  91. {
  92. auto* gwidget = child_at(position);
  93. if (!gwidget)
  94. return nullptr;
  95. return m_gwidget_map.get(gwidget);
  96. }
  97. void VBForm::grabber_mousedown_event(GMouseEvent& event, Direction grabber)
  98. {
  99. m_transform_event_origin = event.position();
  100. for_each_selected_widget([](auto& widget) { widget.capture_transform_origin_rect(); });
  101. m_resize_direction = grabber;
  102. }
  103. void VBForm::keydown_event(GKeyEvent& event)
  104. {
  105. if (event.key() == KeyCode::Key_Delete) {
  106. delete_selected_widgets();
  107. return;
  108. }
  109. if (event.key() == KeyCode::Key_Tab) {
  110. if (m_widgets.is_empty())
  111. return;
  112. if (m_selected_widgets.is_empty()) {
  113. set_single_selected_widget(m_widgets.first());
  114. update();
  115. return;
  116. }
  117. int selected_widget_index = 0;
  118. for (; selected_widget_index < m_widgets.size(); ++selected_widget_index) {
  119. if (m_widgets[selected_widget_index] == *m_selected_widgets.begin())
  120. break;
  121. }
  122. ++selected_widget_index;
  123. if (selected_widget_index == m_widgets.size())
  124. selected_widget_index = 0;
  125. set_single_selected_widget(m_widgets[selected_widget_index]);
  126. update();
  127. return;
  128. }
  129. if (!m_selected_widgets.is_empty()) {
  130. switch (event.key()) {
  131. case KeyCode::Key_Up:
  132. update();
  133. for_each_selected_widget([this](auto& widget) { widget.gwidget()->move_by(0, -m_grid_size); });
  134. break;
  135. case KeyCode::Key_Down:
  136. update();
  137. for_each_selected_widget([this](auto& widget) { widget.gwidget()->move_by(0, m_grid_size); });
  138. break;
  139. case KeyCode::Key_Left:
  140. update();
  141. for_each_selected_widget([this](auto& widget) { widget.gwidget()->move_by(-m_grid_size, 0); });
  142. break;
  143. case KeyCode::Key_Right:
  144. update();
  145. for_each_selected_widget([this](auto& widget) { widget.gwidget()->move_by(m_grid_size, 0); });
  146. break;
  147. }
  148. return;
  149. }
  150. }
  151. void VBForm::set_single_selected_widget(VBWidget* widget)
  152. {
  153. if (!widget) {
  154. if (!m_selected_widgets.is_empty()) {
  155. m_selected_widgets.clear();
  156. on_widget_selected(nullptr);
  157. update();
  158. }
  159. return;
  160. }
  161. m_selected_widgets.clear();
  162. m_selected_widgets.set(widget);
  163. on_widget_selected(m_selected_widgets.size() == 1 ? widget : nullptr);
  164. update();
  165. }
  166. void VBForm::add_to_selection(VBWidget& widget)
  167. {
  168. m_selected_widgets.set(&widget);
  169. update();
  170. }
  171. void VBForm::remove_from_selection(VBWidget& widget)
  172. {
  173. m_selected_widgets.remove(&widget);
  174. update();
  175. }
  176. void VBForm::mousedown_event(GMouseEvent& event)
  177. {
  178. if (m_resize_direction == Direction::None) {
  179. bool hit_grabber = false;
  180. for_each_selected_widget([&](auto& widget) {
  181. auto grabber = widget.grabber_at(event.position());
  182. if (grabber != Direction::None) {
  183. hit_grabber = true;
  184. return grabber_mousedown_event(event, grabber);
  185. }
  186. });
  187. if (hit_grabber)
  188. return;
  189. }
  190. auto* widget = widget_at(event.position());
  191. if (!widget) {
  192. set_single_selected_widget(nullptr);
  193. return;
  194. }
  195. if (event.button() == GMouseButton::Left || event.button() == GMouseButton::Right) {
  196. m_transform_event_origin = event.position();
  197. if (event.modifiers() == Mod_Ctrl)
  198. remove_from_selection(*widget);
  199. else if (event.modifiers() == Mod_Shift)
  200. add_to_selection(*widget);
  201. else if (!m_selected_widgets.contains(widget))
  202. set_single_selected_widget(widget);
  203. for_each_selected_widget([](auto& widget) { widget.capture_transform_origin_rect(); });
  204. on_widget_selected(single_selected_widget());
  205. }
  206. }
  207. void VBForm::mousemove_event(GMouseEvent& event)
  208. {
  209. if (event.buttons() & GMouseButton::Left) {
  210. if (m_resize_direction == Direction::None) {
  211. update();
  212. auto delta = event.position() - m_transform_event_origin;
  213. for_each_selected_widget([&](auto& widget) {
  214. auto new_rect = widget.transform_origin_rect().translated(delta);
  215. new_rect.set_x(new_rect.x() - (new_rect.x() % m_grid_size));
  216. new_rect.set_y(new_rect.y() - (new_rect.y() % m_grid_size));
  217. widget.set_rect(new_rect);
  218. });
  219. return;
  220. }
  221. int diff_x = event.x() - m_transform_event_origin.x();
  222. int diff_y = event.y() - m_transform_event_origin.y();
  223. int change_x = 0;
  224. int change_y = 0;
  225. int change_w = 0;
  226. int change_h = 0;
  227. switch (m_resize_direction) {
  228. case Direction::DownRight:
  229. change_w = diff_x;
  230. change_h = diff_y;
  231. break;
  232. case Direction::Right:
  233. change_w = diff_x;
  234. break;
  235. case Direction::UpRight:
  236. change_w = diff_x;
  237. change_y = diff_y;
  238. change_h = -diff_y;
  239. break;
  240. case Direction::Up:
  241. change_y = diff_y;
  242. change_h = -diff_y;
  243. break;
  244. case Direction::UpLeft:
  245. change_x = diff_x;
  246. change_w = -diff_x;
  247. change_y = diff_y;
  248. change_h = -diff_y;
  249. break;
  250. case Direction::Left:
  251. change_x = diff_x;
  252. change_w = -diff_x;
  253. break;
  254. case Direction::DownLeft:
  255. change_x = diff_x;
  256. change_w = -diff_x;
  257. change_h = diff_y;
  258. break;
  259. case Direction::Down:
  260. change_h = diff_y;
  261. break;
  262. default:
  263. ASSERT_NOT_REACHED();
  264. }
  265. update();
  266. for_each_selected_widget([&](auto& widget) {
  267. auto new_rect = widget.transform_origin_rect();
  268. Size minimum_size { 5, 5 };
  269. new_rect.set_x(new_rect.x() + change_x);
  270. new_rect.set_y(new_rect.y() + change_y);
  271. new_rect.set_width(max(minimum_size.width(), new_rect.width() + change_w));
  272. new_rect.set_height(max(minimum_size.height(), new_rect.height() + change_h));
  273. new_rect.set_x(new_rect.x() - (new_rect.x() % m_grid_size));
  274. new_rect.set_y(new_rect.y() - (new_rect.y() % m_grid_size));
  275. new_rect.set_width(new_rect.width() - (new_rect.width() % m_grid_size) + 1);
  276. new_rect.set_height(new_rect.height() - (new_rect.height() % m_grid_size) + 1);
  277. widget.set_rect(new_rect);
  278. });
  279. }
  280. }
  281. void VBForm::write_to_file(const String& path)
  282. {
  283. CFile file(path);
  284. if (!file.open(CIODevice::WriteOnly)) {
  285. GMessageBox::show(String::format("Could not open '%s' for writing", path.characters()), "Error", GMessageBox::Type::Error, window());
  286. return;
  287. }
  288. JsonObject form_object;
  289. form_object.set("name", m_name);
  290. JsonArray widget_array;
  291. for (auto& widget : m_widgets) {
  292. JsonObject widget_object;
  293. widget->for_each_property([&](auto& property) {
  294. if (property.value().is_bool())
  295. widget_object.set(property.name(), property.value().to_bool());
  296. else if (property.value().is_int())
  297. widget_object.set(property.name(), property.value().to_int());
  298. else
  299. widget_object.set(property.name(), property.value().to_string());
  300. });
  301. widget_array.append(widget_object);
  302. }
  303. form_object.set("widgets", widget_array);
  304. file.write(form_object.to_string());
  305. }
  306. void VBForm::dump()
  307. {
  308. dbgprintf("[Form]\n");
  309. dbgprintf("Name=%s\n", m_name.characters());
  310. dbgprintf("\n");
  311. int i = 0;
  312. for (auto& widget : m_widgets) {
  313. dbgprintf("[Widget %d]\n", i++);
  314. widget->for_each_property([](auto& property) {
  315. dbgprintf("%s=%s\n", property.name().characters(), property.value().to_string().characters());
  316. });
  317. dbgprintf("\n");
  318. }
  319. }
  320. void VBForm::mouseup_event(GMouseEvent& event)
  321. {
  322. if (event.button() == GMouseButton::Left) {
  323. m_transform_event_origin = {};
  324. m_resize_direction = Direction::None;
  325. }
  326. }
  327. void VBForm::delete_selected_widgets()
  328. {
  329. Vector<VBWidget*> to_delete;
  330. for_each_selected_widget([&](auto& widget) {
  331. to_delete.append(&widget);
  332. });
  333. for (auto& widget : to_delete)
  334. m_widgets.remove_first_matching([&widget](auto& entry) { return entry == widget; });
  335. on_widget_selected(single_selected_widget());
  336. }
  337. template<typename Callback>
  338. void VBForm::for_each_selected_widget(Callback callback)
  339. {
  340. for (auto& widget : m_selected_widgets)
  341. callback(*widget);
  342. }
  343. VBWidget* VBForm::single_selected_widget()
  344. {
  345. if (m_selected_widgets.size() != 1)
  346. return nullptr;
  347. return *m_selected_widgets.begin();
  348. }