VBForm.cpp 11 KB

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