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:
kleines Filmröllchen 2022-03-18 22:57:05 +01:00 committed by Andreas Kling
parent 0410414455
commit 7e34b88ed4
Notes: sideshowbarker 2024-07-17 14:35:04 +09:00
7 changed files with 34 additions and 17 deletions

View file

@ -22,10 +22,12 @@
@GUI::TreeView {
name: "browse_view"
title: "Browse"
}
@GUI::Widget {
name: "search_container"
title: "Search"
layout: @GUI::VerticalBoxLayout {}
@GUI::TextBox {

View file

@ -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));

View file

@ -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);

View file

@ -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>();

View file

@ -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)

View file

@ -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;
}

View file

@ -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;
});