diff --git a/Ladybird/DOMNodeProperties.h b/Ladybird/DOMNodeProperties.h new file mode 100644 index 00000000000..d7880b8c304 --- /dev/null +++ b/Ladybird/DOMNodeProperties.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022, MacDue + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Ladybird { + +struct DOMNodeProperties { + String computed_style_json; + String resolved_style_json; + String custom_properties_json; +}; + +} diff --git a/Ladybird/InspectorWidget.cpp b/Ladybird/InspectorWidget.cpp index 5f3b1503695..d936df9cb83 100644 --- a/Ladybird/InspectorWidget.cpp +++ b/Ladybird/InspectorWidget.cpp @@ -6,9 +6,16 @@ #define AK_DONT_REPLACE_STD -#include "InspectorWidget.h" #include +#include + +#include "InspectorWidget.h" #include +#include +#include +#include +#include +#include #include #include @@ -17,12 +24,15 @@ namespace Ladybird { InspectorWidget::InspectorWidget() { setLayout(new QVBoxLayout); - m_tree_view = new QTreeView; - m_tree_view->setHeaderHidden(true); - m_tree_view->expandToDepth(3); - layout()->addWidget(m_tree_view); - m_tree_view->setModel(&m_dom_model); - QObject::connect(m_tree_view->selectionModel(), &QItemSelectionModel::selectionChanged, + auto splitter = new QSplitter(this); + layout()->addWidget(splitter); + splitter->setOrientation(Qt::Vertical); + auto tree_view = new QTreeView; + tree_view->setHeaderHidden(true); + tree_view->expandToDepth(3); + splitter->addWidget(tree_view); + tree_view->setModel(&m_dom_model); + QObject::connect(tree_view->selectionModel(), &QItemSelectionModel::selectionChanged, [this](QItemSelection const& selected, QItemSelection const&) { auto indexes = selected.indexes(); if (indexes.size()) { @@ -30,16 +40,49 @@ InspectorWidget::InspectorWidget() set_selection(index); } }); + + auto add_table_tab = [&](auto* tab_widget, auto& model, auto name) { + auto container = new QWidget; + auto table_view = new QTableView; + table_view->setModel(&model); + container->setLayout(new QVBoxLayout); + container->layout()->addWidget(table_view); + table_view->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + table_view->verticalHeader()->setVisible(false); + table_view->horizontalHeader()->setVisible(false); + tab_widget->addTab(container, name); + }; + + auto node_tabs = new QTabWidget; + add_table_tab(node_tabs, m_computed_style_model, "Computed"); + add_table_tab(node_tabs, m_resolved_style_model, "Resolved"); + add_table_tab(node_tabs, m_custom_properties_model, "Variables"); + splitter->addWidget(node_tabs); +} + +void InspectorWidget::set_dom_json(StringView dom_json) +{ + m_dom_model.set_underlying_model(WebView::DOMTreeModel::create(dom_json)); } void InspectorWidget::clear_dom_json() { m_dom_model.set_underlying_model(nullptr); + clear_style_json(); } -void InspectorWidget::set_dom_json(StringView dom_json) +void InspectorWidget::load_style_json(StringView computed_style_json, StringView resolved_style_json, StringView custom_properties_json) { - m_dom_model.set_underlying_model(::WebView::DOMTreeModel::create(dom_json)); + m_computed_style_model.set_underlying_model(WebView::StylePropertiesModel::create(computed_style_json)); + m_resolved_style_model.set_underlying_model(WebView::StylePropertiesModel::create(resolved_style_json)); + m_custom_properties_model.set_underlying_model(WebView::StylePropertiesModel::create(custom_properties_json)); +} + +void InspectorWidget::clear_style_json() +{ + m_computed_style_model.set_underlying_model(nullptr); + m_resolved_style_model.set_underlying_model(nullptr); + m_custom_properties_model.set_underlying_model(nullptr); } void InspectorWidget::closeEvent(QCloseEvent* event) @@ -70,7 +113,13 @@ void InspectorWidget::set_selection(GUI::ModelIndex index) m_selection = selection; VERIFY(on_dom_node_inspected); - on_dom_node_inspected(m_selection.dom_node_id, m_selection.pseudo_element); + auto maybe_inspected_node_properties = on_dom_node_inspected(m_selection.dom_node_id, m_selection.pseudo_element); + if (!maybe_inspected_node_properties.is_error()) { + auto properties = maybe_inspected_node_properties.release_value(); + load_style_json(properties.computed_style_json, properties.resolved_style_json, properties.custom_properties_json); + } else { + clear_style_json(); + } } } diff --git a/Ladybird/InspectorWidget.h b/Ladybird/InspectorWidget.h index ab367784be5..6c566c5efd7 100644 --- a/Ladybird/InspectorWidget.h +++ b/Ladybird/InspectorWidget.h @@ -6,6 +6,7 @@ #pragma once +#include "DOMNodeProperties.h" #include "ModelTranslator.h" #include #include @@ -13,6 +14,7 @@ #include class QTreeView; +class QTableView; namespace Ladybird { @@ -31,16 +33,22 @@ public: void clear_dom_json(); void set_dom_json(StringView dom_json); - Function)> on_dom_node_inspected; + void load_style_json(StringView computed_style_json, StringView resolved_style_json, StringView custom_properties_json); + void clear_style_json(); + + Function(i32, Optional)> on_dom_node_inspected; Function on_close; private: void set_selection(GUI::ModelIndex); void closeEvent(QCloseEvent*) override; - QTreeView* m_tree_view { nullptr }; - ModelTranslator m_dom_model {}; Selection m_selection; + + ModelTranslator m_dom_model {}; + ModelTranslator m_computed_style_model {}; + ModelTranslator m_resolved_style_model {}; + ModelTranslator m_custom_properties_model {}; }; } diff --git a/Ladybird/WebContentView.cpp b/Ladybird/WebContentView.cpp index 8530770a28a..cb49bc5b756 100644 --- a/Ladybird/WebContentView.cpp +++ b/Ladybird/WebContentView.cpp @@ -511,7 +511,7 @@ void WebContentView::ensure_inspector_widget() }; m_inspector_widget->on_dom_node_inspected = [&](auto id, auto pseudo_element) { - inspect_dom_node(id, pseudo_element); + return inspect_dom_node(id, pseudo_element); }; } @@ -531,15 +531,21 @@ void WebContentView::inspect_dom_tree() client().async_inspect_dom_tree(); } -void WebContentView::inspect_dom_node(i32 node_id, Optional pseudo_element) +ErrorOr WebContentView::inspect_dom_node(i32 node_id, Optional pseudo_element) { - // TODO: Use and display response - (void)client().inspect_dom_node(node_id, pseudo_element); + auto response = client().inspect_dom_node(node_id, pseudo_element); + if (!response.has_style()) + return Error::from_string_view("Inspected node returned no style"sv); + return Ladybird::DOMNodeProperties { + .computed_style_json = TRY(String::from_deprecated_string(response.take_computed_style())), + .resolved_style_json = TRY(String::from_deprecated_string(response.take_resolved_style())), + .custom_properties_json = TRY(String::from_deprecated_string(response.take_custom_properties())), + }; } void WebContentView::clear_inspected_dom_node() { - inspect_dom_node(0, {}); + (void)inspect_dom_node(0, {}); } void WebContentView::show_inspector() diff --git a/Ladybird/WebContentView.h b/Ladybird/WebContentView.h index a48de1d5de9..9bd2a463ad2 100644 --- a/Ladybird/WebContentView.h +++ b/Ladybird/WebContentView.h @@ -23,6 +23,8 @@ #include #include +#include "DOMNodeProperties.h" + class QTextEdit; class QLineEdit; @@ -189,9 +191,9 @@ private: bool is_inspector_open() const; void inspect_dom_tree(); - void inspect_dom_node(i32 node_id, Optional pseudo_element); void clear_inspected_dom_node(); void clear_inspector_callbacks(); + ErrorOr inspect_dom_node(i32 node_id, Optional pseudo_element); qreal m_inverse_pixel_scaling_ratio { 1.0 }; bool m_should_show_line_box_borders { false };