ScrollableContainerWidget.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /*
  2. * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibGUI/Layout.h>
  7. #include <LibGUI/ScrollableContainerWidget.h>
  8. REGISTER_WIDGET(GUI, ScrollableContainerWidget)
  9. namespace GUI {
  10. ScrollableContainerWidget::ScrollableContainerWidget()
  11. {
  12. REGISTER_BOOL_PROPERTY("scrollbars_enabled", is_scrollbars_enabled, set_scrollbars_enabled);
  13. REGISTER_BOOL_PROPERTY("should_hide_unnecessary_scrollbars", should_hide_unnecessary_scrollbars, set_should_hide_unnecessary_scrollbars);
  14. }
  15. ScrollableContainerWidget::~ScrollableContainerWidget()
  16. {
  17. }
  18. void ScrollableContainerWidget::did_scroll()
  19. {
  20. AbstractScrollableWidget::did_scroll();
  21. update_widget_position();
  22. }
  23. void ScrollableContainerWidget::update_widget_position()
  24. {
  25. if (!m_widget)
  26. return;
  27. m_widget->move_to(-horizontal_scrollbar().value() + content_margins().left(), -vertical_scrollbar().value() + content_margins().top());
  28. }
  29. void ScrollableContainerWidget::update_widget_size()
  30. {
  31. if (!m_widget)
  32. return;
  33. m_widget->do_layout();
  34. if (m_widget->is_shrink_to_fit() && m_widget->layout()) {
  35. auto new_size = Widget::content_size();
  36. auto preferred_size = m_widget->layout()->preferred_size();
  37. if (preferred_size.width() != -1)
  38. new_size.set_width(preferred_size.width());
  39. if (preferred_size.height() != -1)
  40. new_size.set_height(preferred_size.height());
  41. m_widget->resize(new_size);
  42. set_content_size(new_size);
  43. } else {
  44. auto inner_size = Widget::content_size();
  45. auto min_size = m_widget->min_size();
  46. auto new_size = Gfx::Size {
  47. max(inner_size.width(), min_size.width()),
  48. max(inner_size.height(), min_size.height())
  49. };
  50. m_widget->resize(new_size);
  51. set_content_size(new_size);
  52. }
  53. }
  54. void ScrollableContainerWidget::resize_event(GUI::ResizeEvent& event)
  55. {
  56. AbstractScrollableWidget::resize_event(event);
  57. update_widget_position();
  58. update_widget_size();
  59. }
  60. void ScrollableContainerWidget::set_widget(GUI::Widget* widget)
  61. {
  62. if (m_widget == widget)
  63. return;
  64. if (m_widget)
  65. remove_child(*m_widget);
  66. m_widget = widget;
  67. if (m_widget) {
  68. add_child(*m_widget);
  69. m_widget->move_to_back();
  70. }
  71. update_widget_size();
  72. update_widget_position();
  73. }
  74. bool ScrollableContainerWidget::load_from_json(const JsonObject& json, RefPtr<Core::Object> (*unregistered_child_handler)(const String&))
  75. {
  76. json.for_each_member([&](auto& key, auto& value) {
  77. set_property(key, value);
  78. });
  79. auto layout_value = json.get("layout");
  80. if (!layout_value.is_null()) {
  81. dbgln("Layout specified in ScrollableContainerWidget, this is not supported.");
  82. return false;
  83. }
  84. auto content_widget_value = json.get("content_widget");
  85. if (!content_widget_value.is_null() && !content_widget_value.is_object()) {
  86. dbgln("content widget is not an object");
  87. return false;
  88. }
  89. if (!json.get("children").is_null()) {
  90. dbgln("children specified for ScrollableContainerWidget, but only 1 widget as content_widget is supported");
  91. return false;
  92. }
  93. if (content_widget_value.is_object()) {
  94. auto& content_widget = content_widget_value.as_object();
  95. auto class_name = content_widget.get("class");
  96. if (!class_name.is_string()) {
  97. dbgln("Invalid content widget class name");
  98. return false;
  99. }
  100. RefPtr<Core::Object> child;
  101. if (auto* registration = Core::ObjectClassRegistration::find(class_name.as_string())) {
  102. child = registration->construct();
  103. } else {
  104. child = unregistered_child_handler(class_name.as_string());
  105. }
  106. if (!child)
  107. return false;
  108. auto widget_ptr = verify_cast<GUI::Widget>(child.ptr());
  109. set_widget(widget_ptr);
  110. child->load_from_json(content_widget, unregistered_child_handler);
  111. return true;
  112. }
  113. return true;
  114. }
  115. }