From 389a55fe36bd6d577b37664f7819628f6f42b25d Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Wed, 29 May 2024 20:12:21 +0100 Subject: [PATCH] Ladybird/Qt: Add a find in page widget --- Ladybird/CMakeLists.txt | 1 + Ladybird/Icons/down.tvg | Bin 0 -> 48 bytes Ladybird/Icons/up.tvg | Bin 0 -> 48 bytes Ladybird/Qt/BrowserWindow.cpp | 17 +++++ Ladybird/Qt/BrowserWindow.h | 8 +++ Ladybird/Qt/FindInPageWidget.cpp | 104 +++++++++++++++++++++++++++++++ Ladybird/Qt/FindInPageWidget.h | 47 ++++++++++++++ Ladybird/Qt/Tab.cpp | 15 ++++- Ladybird/Qt/Tab.h | 7 ++- Ladybird/Qt/ladybird.qrc | 2 + 10 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 Ladybird/Icons/down.tvg create mode 100644 Ladybird/Icons/up.tvg create mode 100644 Ladybird/Qt/FindInPageWidget.cpp create mode 100644 Ladybird/Qt/FindInPageWidget.h diff --git a/Ladybird/CMakeLists.txt b/Ladybird/CMakeLists.txt index fb07b58956..88ccc6d22d 100644 --- a/Ladybird/CMakeLists.txt +++ b/Ladybird/CMakeLists.txt @@ -115,6 +115,7 @@ if (ENABLE_QT) Qt/BrowserWindow.cpp Qt/EventLoopImplementationQt.cpp Qt/EventLoopImplementationQtEventTarget.cpp + Qt/FindInPageWidget.cpp Qt/Icon.cpp Qt/InspectorWidget.cpp Qt/LocationEdit.cpp diff --git a/Ladybird/Icons/down.tvg b/Ladybird/Icons/down.tvg new file mode 100644 index 0000000000000000000000000000000000000000..1ba5d8f812fec1454d07640f3c6a9765ed77a0b5 GIT binary patch literal 48 ucmWm1$qB$9006;JqZmlU>MX?m!GrzG&Jpxez)Ixgp?dkRnsWCe9u*r^^8!%- literal 0 HcmV?d00001 diff --git a/Ladybird/Icons/up.tvg b/Ladybird/Icons/up.tvg new file mode 100644 index 0000000000000000000000000000000000000000..1bf23712375e271e8d2ac106baf6da71a0cf704e GIT binary patch literal 48 vcmWm1Q3`+{6ac|_ni^u#={iXFhf?-u_I<*=3VfN84Ni?~YwCLs(o*#US3?3{ literal 0 HcmV?d00001 diff --git a/Ladybird/Qt/BrowserWindow.cpp b/Ladybird/Qt/BrowserWindow.cpp index d5084a69f8..bfa76b4c08 100644 --- a/Ladybird/Qt/BrowserWindow.cpp +++ b/Ladybird/Qt/BrowserWindow.cpp @@ -152,6 +152,15 @@ BrowserWindow::BrowserWindow(Vector const& initial_urls, WebView::Cook edit_menu->addSeparator(); + m_find_in_page_action = new QAction("&Find in Page...", this); + m_find_in_page_action->setIcon(load_icon_from_uri("resource://icons/16x16/find.png"sv)); + m_find_in_page_action->setShortcuts(QKeySequence::keyBindings(QKeySequence::StandardKey::Find)); + + edit_menu->addAction(m_find_in_page_action); + QObject::connect(m_find_in_page_action, &QAction::triggered, this, &BrowserWindow::show_find_in_page); + + edit_menu->addSeparator(); + auto* settings_action = new QAction("&Settings", this); settings_action->setIcon(load_icon_from_uri("resource://icons/16x16/settings.png"sv)); settings_action->setShortcuts(QKeySequence::keyBindings(QKeySequence::StandardKey::Preferences)); @@ -894,6 +903,14 @@ void BrowserWindow::select_all() m_current_tab->view().select_all(); } +void BrowserWindow::show_find_in_page() +{ + if (!m_current_tab) + return; + + m_current_tab->show_find_in_page(); +} + void BrowserWindow::paste() { if (!m_current_tab) diff --git a/Ladybird/Qt/BrowserWindow.h b/Ladybird/Qt/BrowserWindow.h index 3e5a313e04..449835de4f 100644 --- a/Ladybird/Qt/BrowserWindow.h +++ b/Ladybird/Qt/BrowserWindow.h @@ -8,6 +8,7 @@ #pragma once #include "Tab.h" +#include #include #include #include @@ -78,6 +79,11 @@ public: return *m_select_all_action; } + QAction& find_action() + { + return *m_find_in_page_action; + } + QAction& paste_action() { return *m_paste_action; @@ -119,6 +125,7 @@ public slots: void reset_zoom(); void update_zoom_menu(); void select_all(); + void show_find_in_page(); void paste(); void copy_selected_text(); @@ -172,6 +179,7 @@ private: QAction* m_copy_selection_action { nullptr }; QAction* m_paste_action { nullptr }; QAction* m_select_all_action { nullptr }; + QAction* m_find_in_page_action { nullptr }; QAction* m_view_source_action { nullptr }; QAction* m_inspect_dom_node_action { nullptr }; diff --git a/Ladybird/Qt/FindInPageWidget.cpp b/Ladybird/Qt/FindInPageWidget.cpp new file mode 100644 index 0000000000..b814c7df39 --- /dev/null +++ b/Ladybird/Qt/FindInPageWidget.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2024, Tim Ledbetter + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "FindInPageWidget.h" +#include "Icon.h" +#include "StringUtils.h" +#include +#include + +namespace Ladybird { + +FindInPageWidget::FindInPageWidget(Tab* tab, WebContentView* content_view) + : QWidget(static_cast(tab), Qt::Widget) + , m_tab(tab) + , m_content_view(content_view) +{ + setFocusPolicy(Qt::FocusPolicy::StrongFocus); + + auto* layout = new QHBoxLayout(this); + setLayout(layout); + layout->setContentsMargins(5, 5, 5, 5); + layout->setAlignment(Qt::AlignmentFlag::AlignLeft); + + m_find_text = new QLineEdit(this); + m_find_text->setFocusPolicy(Qt::FocusPolicy::StrongFocus); + m_find_text->setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Fixed); + m_find_text->setMinimumWidth(50); + m_find_text->setMaximumWidth(250); + connect(m_find_text, &QLineEdit::textChanged, this, &FindInPageWidget::find_text_changed); + + m_previous_button = new QPushButton(this); + m_previous_button->setFixedWidth(30); + m_previous_button->setIcon(create_tvg_icon_with_theme_colors("up", palette())); + connect(m_previous_button, &QPushButton::clicked, this, [this] { + m_content_view->find_in_page_previous_match(); + }); + + m_next_button = new QPushButton(this); + m_next_button->setFixedWidth(30); + m_next_button->setIcon(create_tvg_icon_with_theme_colors("down", palette())); + connect(m_next_button, &QPushButton::clicked, this, [this] { + m_content_view->find_in_page_next_match(); + }); + + m_exit_button = new QPushButton(this); + m_exit_button->setFixedWidth(30); + m_exit_button->setIcon(create_tvg_icon_with_theme_colors("close", palette())); + connect(m_exit_button, &QPushButton::clicked, this, [this] { + setVisible(false); + }); + + layout->addWidget(m_find_text, 1); + layout->addWidget(m_previous_button); + layout->addWidget(m_next_button); + layout->addStretch(1); + layout->addWidget(m_exit_button); +} + +FindInPageWidget::~FindInPageWidget() = default; + +void FindInPageWidget::find_text_changed() +{ + auto converted_text = ak_string_from_qstring(m_find_text->text()); + m_content_view->find_in_page(converted_text); +} + +void FindInPageWidget::keyPressEvent(QKeyEvent* event) +{ + switch (event->key()) { + case Qt::Key_Escape: + setVisible(false); + break; + case Qt::Key_Return: + m_next_button->click(); + break; + default: + event->ignore(); + break; + } +} + +void FindInPageWidget::focusInEvent(QFocusEvent* event) +{ + QWidget::focusInEvent(event); + m_find_text->setFocus(); + m_find_text->selectAll(); +} + +void FindInPageWidget::showEvent(QShowEvent*) +{ + if (m_tab && m_tab->isVisible()) + m_tab->update_hover_label(); +} + +void FindInPageWidget::hideEvent(QHideEvent*) +{ + if (m_tab && m_tab->isVisible()) + m_tab->update_hover_label(); +} + +} diff --git a/Ladybird/Qt/FindInPageWidget.h b/Ladybird/Qt/FindInPageWidget.h new file mode 100644 index 0000000000..0a3550aa58 --- /dev/null +++ b/Ladybird/Qt/FindInPageWidget.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024, Tim Ledbetter + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include "WebContentView.h" +#include +#include +#include +#include + +namespace Ladybird { + +class WebContentView; + +class FindInPageWidget final : public QWidget { + Q_OBJECT + +public: + FindInPageWidget(Tab* tab, WebContentView* content_view); + + virtual ~FindInPageWidget() override; + +public slots: + +private: + virtual void keyPressEvent(QKeyEvent*) override; + virtual void focusInEvent(QFocusEvent*) override; + virtual void showEvent(QShowEvent*) override; + virtual void hideEvent(QHideEvent*) override; + + void find_text_changed(); + + Tab* m_tab { nullptr }; + WebContentView* m_content_view { nullptr }; + + QLineEdit* m_find_text { nullptr }; + QPushButton* m_previous_button { nullptr }; + QPushButton* m_next_button { nullptr }; + QPushButton* m_exit_button { nullptr }; + QAction* m_copy_attribute_value_action { nullptr }; +}; + +} diff --git a/Ladybird/Qt/Tab.cpp b/Ladybird/Qt/Tab.cpp index a8f82c2607..882d940b76 100644 --- a/Ladybird/Qt/Tab.cpp +++ b/Ladybird/Qt/Tab.cpp @@ -56,6 +56,8 @@ Tab::Tab(BrowserWindow* window, WebContentOptions const& web_content_options, St m_layout->setContentsMargins(0, 0, 0, 0); m_view = new WebContentView(this, web_content_options, webdriver_content_ipc_path, parent_client, page_index); + m_find_in_page = new FindInPageWidget(this, m_view); + m_find_in_page->setVisible(false); m_toolbar = new QToolBar(this); m_location_edit = new LocationEdit(this); @@ -70,6 +72,7 @@ Tab::Tab(BrowserWindow* window, WebContentOptions const& web_content_options, St m_layout->addWidget(m_toolbar); m_layout->addWidget(m_view); + m_layout->addWidget(m_find_in_page); m_hamburger_button = new QToolButton(m_toolbar); m_hamburger_button->setText("Show &Menu"); @@ -887,7 +890,11 @@ void Tab::resizeEvent(QResizeEvent* event) void Tab::update_hover_label() { m_hover_label->resize(QFontMetrics(m_hover_label->font()).boundingRect(m_hover_label->text()).adjusted(-4, -2, 4, 2).size()); - m_hover_label->move(6, height() - m_hover_label->height() - 8); + auto hover_label_height = height() - m_hover_label->height() - 8; + if (m_find_in_page->isVisible()) + hover_label_height -= m_find_in_page->height() - 4; + + m_hover_label->move(6, hover_label_height); m_hover_label->raise(); } @@ -933,6 +940,12 @@ void Tab::show_inspector_window(InspectorTarget inspector_target) m_inspector_widget->select_default_node(); } +void Tab::show_find_in_page() +{ + m_find_in_page->setVisible(true); + m_find_in_page->setFocus(); +} + void Tab::close_sub_widgets() { auto close_widget_window = [](auto* widget) { diff --git a/Ladybird/Qt/Tab.h b/Ladybird/Qt/Tab.h index 7fd7ec837a..7568d4b285 100644 --- a/Ladybird/Qt/Tab.h +++ b/Ladybird/Qt/Tab.h @@ -9,6 +9,7 @@ #include "LocationEdit.h" #include "WebContentView.h" +#include #include #include #include @@ -51,6 +52,8 @@ public: }; void show_inspector_window(InspectorTarget = InspectorTarget::Document); + void show_find_in_page(); + QIcon const& favicon() const { return m_favicon; } QString const& title() const { return m_title; } @@ -60,6 +63,8 @@ public: QToolButton* hamburger_button() const { return m_hamburger_button; } + void update_hover_label(); + public slots: void focus_location_editor(); void location_edit_return_pressed(); @@ -76,7 +81,6 @@ private: virtual bool event(QEvent*) override; void recreate_toolbar_icons(); - void update_hover_label(); void open_link(URL::URL const&); void open_link_in_new_tab(URL::URL const&); @@ -92,6 +96,7 @@ private: QAction* m_reset_zoom_button_action { nullptr }; LocationEdit* m_location_edit { nullptr }; WebContentView* m_view { nullptr }; + FindInPageWidget* m_find_in_page { nullptr }; BrowserWindow* m_window { nullptr }; QString m_title; QLabel* m_hover_label { nullptr }; diff --git a/Ladybird/Qt/ladybird.qrc b/Ladybird/Qt/ladybird.qrc index b8c6daed50..87bb36a8ec 100644 --- a/Ladybird/Qt/ladybird.qrc +++ b/Ladybird/Qt/ladybird.qrc @@ -7,5 +7,7 @@ ../Icons/hamburger.tvg ../Icons/new_tab.tvg ../Icons/reload.tvg + ../Icons/up.tvg + ../Icons/down.tvg