LibGUI: Fully support TabWidget in GML
TabWidgets couldn't be used in GML properly, as the GML creation routines didn't actually call the necessary functions in the TabWidget to get a new tab added. This commit fixes that by making the name of the tab a normal property, the previously introduced "title", which can be trivially set from GML. Therefore, try_add_widget() loses an argument (while try_add_tab doesn't, because it newly constructs the widget). This allows us to get rid of the silly "fixing my widget tree after the fact" code in Help and will make it super easy to use TabWidget in future GML. :^)
This commit is contained in:
parent
0410414455
commit
7e34b88ed4
Notes:
sideshowbarker
2024-07-17 14:35:04 +09:00
Author: https://github.com/kleinesfilmroellchen Commit: https://github.com/SerenityOS/serenity/commit/7e34b88ed4 Pull-request: https://github.com/SerenityOS/serenity/pull/13125
7 changed files with 34 additions and 17 deletions
|
@ -22,10 +22,12 @@
|
|||
|
||||
@GUI::TreeView {
|
||||
name: "browse_view"
|
||||
title: "Browse"
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
name: "search_container"
|
||||
title: "Search"
|
||||
layout: @GUI::VerticalBoxLayout {}
|
||||
|
||||
@GUI::TextBox {
|
||||
|
|
|
@ -255,9 +255,6 @@ ErrorOr<void> MainWidget::initialize_fallibles(GUI::Window& window)
|
|||
TRY(m_context_menu->try_add_action(*m_copy_action));
|
||||
TRY(m_context_menu->try_add_action(*m_select_all_action));
|
||||
|
||||
TRY(m_tab_widget->try_add_widget("Browse", *m_browse_view));
|
||||
TRY(m_tab_widget->try_add_widget("Search", *m_search_container));
|
||||
|
||||
m_manual_model = TRY(ManualModel::create());
|
||||
m_browse_view->set_model(*m_manual_model);
|
||||
m_filter_model = TRY(GUI::FilteringProxyModel::create(*m_manual_model));
|
||||
|
|
|
@ -168,16 +168,20 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
auto& process_table_container = tabwidget.add_tab<GUI::Widget>("Processes");
|
||||
|
||||
auto performance_widget = build_performance_tab();
|
||||
tabwidget.add_widget("Performance", performance_widget);
|
||||
performance_widget->set_title("Performance");
|
||||
tabwidget.add_widget(performance_widget);
|
||||
|
||||
auto storage_widget = build_storage_widget();
|
||||
tabwidget.add_widget("Storage", storage_widget);
|
||||
storage_widget->set_title("Storage");
|
||||
tabwidget.add_widget(storage_widget);
|
||||
|
||||
auto network_stats_widget = NetworkStatisticsWidget::construct();
|
||||
tabwidget.add_widget("Network", network_stats_widget);
|
||||
network_stats_widget->set_title("Network");
|
||||
tabwidget.add_widget(network_stats_widget);
|
||||
|
||||
auto hardware_widget = build_hardware_tab();
|
||||
tabwidget.add_widget("Hardware", hardware_widget);
|
||||
hardware_widget->set_title("Hardware");
|
||||
tabwidget.add_widget(hardware_widget);
|
||||
|
||||
process_table_container.set_layout<GUI::VerticalBoxLayout>();
|
||||
process_table_container.layout()->set_margins(4);
|
||||
|
|
|
@ -61,8 +61,8 @@ DebugInfoWidget::DebugInfoWidget()
|
|||
m_backtrace_view = splitter.add<GUI::ListView>();
|
||||
auto& variables_tab_widget = splitter.add<GUI::TabWidget>();
|
||||
variables_tab_widget.set_tab_position(GUI::TabWidget::TabPosition::Bottom);
|
||||
variables_tab_widget.add_widget("Variables", build_variables_tab());
|
||||
variables_tab_widget.add_widget("Registers", build_registers_tab());
|
||||
variables_tab_widget.add_widget(build_variables_tab());
|
||||
variables_tab_widget.add_widget(build_registers_tab());
|
||||
|
||||
m_backtrace_view->on_selection_change = [this] {
|
||||
const auto& index = m_backtrace_view->selection().first();
|
||||
|
@ -132,6 +132,7 @@ RefPtr<GUI::Menu> DebugInfoWidget::get_context_menu_for_variable(const GUI::Mode
|
|||
NonnullRefPtr<GUI::Widget> DebugInfoWidget::build_variables_tab()
|
||||
{
|
||||
auto variables_widget = GUI::Widget::construct();
|
||||
variables_widget->set_title("Variables");
|
||||
variables_widget->set_layout<GUI::HorizontalBoxLayout>();
|
||||
|
||||
m_variables_view = variables_widget->add<GUI::TreeView>();
|
||||
|
@ -148,6 +149,7 @@ NonnullRefPtr<GUI::Widget> DebugInfoWidget::build_variables_tab()
|
|||
NonnullRefPtr<GUI::Widget> DebugInfoWidget::build_registers_tab()
|
||||
{
|
||||
auto registers_widget = GUI::Widget::construct();
|
||||
registers_widget->set_title("Registers");
|
||||
registers_widget->set_layout<GUI::HorizontalBoxLayout>();
|
||||
|
||||
m_registers_view = registers_widget->add<GUI::TableView>();
|
||||
|
|
|
@ -41,9 +41,9 @@ TabWidget::TabWidget()
|
|||
});
|
||||
}
|
||||
|
||||
ErrorOr<void> TabWidget::try_add_widget(String title, Widget& widget)
|
||||
ErrorOr<void> TabWidget::try_add_widget(Widget& widget)
|
||||
{
|
||||
m_tabs.append({ move(title), nullptr, &widget });
|
||||
m_tabs.append({ widget.title(), nullptr, &widget });
|
||||
add_child(widget);
|
||||
update_focus_policy();
|
||||
if (on_tab_count_change)
|
||||
|
@ -51,9 +51,9 @@ ErrorOr<void> TabWidget::try_add_widget(String title, Widget& widget)
|
|||
return {};
|
||||
}
|
||||
|
||||
void TabWidget::add_widget(String title, Widget& widget)
|
||||
void TabWidget::add_widget(Widget& widget)
|
||||
{
|
||||
MUST(try_add_widget(move(title), widget));
|
||||
MUST(try_add_widget(widget));
|
||||
}
|
||||
|
||||
void TabWidget::remove_widget(Widget& widget)
|
||||
|
|
|
@ -37,16 +37,17 @@ public:
|
|||
GUI::Margins const& container_margins() const { return m_container_margins; }
|
||||
void set_container_margins(GUI::Margins const&);
|
||||
|
||||
ErrorOr<void> try_add_widget(String, Widget&);
|
||||
ErrorOr<void> try_add_widget(Widget&);
|
||||
|
||||
void add_widget(String, Widget&);
|
||||
void add_widget(Widget&);
|
||||
void remove_widget(Widget&);
|
||||
|
||||
template<class T, class... Args>
|
||||
ErrorOr<NonnullRefPtr<T>> try_add_tab(String title, Args&&... args)
|
||||
{
|
||||
auto t = TRY(T::try_create(forward<Args>(args)...));
|
||||
TRY(try_add_widget(move(title), *t));
|
||||
t->set_title(move(title));
|
||||
TRY(try_add_widget(*t));
|
||||
return *t;
|
||||
}
|
||||
|
||||
|
@ -54,7 +55,8 @@ public:
|
|||
T& add_tab(String title, Args&&... args)
|
||||
{
|
||||
auto t = T::construct(forward<Args>(args)...);
|
||||
add_widget(move(title), *t);
|
||||
t->set_title(move(title));
|
||||
add_widget(*t);
|
||||
return *t;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <LibGUI/Layout.h>
|
||||
#include <LibGUI/Menu.h>
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibGUI/TabWidget.h>
|
||||
#include <LibGUI/Widget.h>
|
||||
#include <LibGUI/Window.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
|
@ -1132,6 +1133,7 @@ bool Widget::load_from_gml_ast(NonnullRefPtr<GUI::GML::Node> ast, RefPtr<Core::O
|
|||
}
|
||||
|
||||
auto& widget_class = *Core::ObjectClassRegistration::find("GUI::Widget");
|
||||
bool is_tab_widget = is<TabWidget>(*this);
|
||||
object->for_each_child_object_interruptible([&](auto child_data) {
|
||||
auto class_name = child_data->name();
|
||||
|
||||
|
@ -1147,9 +1149,17 @@ bool Widget::load_from_gml_ast(NonnullRefPtr<GUI::GML::Node> ast, RefPtr<Core::O
|
|||
}
|
||||
if (!child)
|
||||
return IterationDecision::Break;
|
||||
|
||||
add_child(*child);
|
||||
// This is possible as we ensure that Widget is a base class above.
|
||||
static_ptr_cast<Widget>(child)->load_from_gml_ast(child_data, unregistered_child_handler);
|
||||
|
||||
if (is_tab_widget) {
|
||||
// FIXME: We need to have the child added before loading it so that it can access us. But the TabWidget logic requires the child to not be present yet.
|
||||
remove_child(*child);
|
||||
reinterpret_cast<TabWidget*>(this)->add_widget(*static_ptr_cast<Widget>(child));
|
||||
}
|
||||
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue