VBForm.cpp 13 KB

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