Ladybird: Add a context menu to the tab bar

This shows the following actions:

* Reload Tab
* Duplicate Tab
* Move Tab
  * Move to Start
  * Move to End
* Close Tab
* Close Other Tabs
  * Close Tabs to Left
  * Close Tabs to Right
  * Close Other Tabs
This commit is contained in:
Jamie Mansfield 2024-04-28 15:07:23 +01:00 committed by Andreas Kling
parent 56ed3d5e21
commit 17fc995ee4
6 changed files with 98 additions and 1 deletions

View File

@ -625,6 +625,11 @@ void BrowserWindow::close_tab(int index)
close();
}
void BrowserWindow::move_tab(int old_index, int new_index)
{
m_tabs_container->tabBar()->moveTab(old_index, new_index);
}
void BrowserWindow::open_file()
{
m_current_tab->open_file();

View File

@ -34,6 +34,7 @@ public:
WebContentView& view() const { return m_current_tab->view(); }
int tab_count() { return m_tabs_container->count(); }
int tab_index(Tab*);
Tab& create_new_tab(Web::HTML::ActivateTab activate_tab);
@ -98,6 +99,7 @@ public slots:
Tab& new_child_tab(Web::HTML::ActivateTab, Tab& parent, Web::HTML::WebViewHints, Optional<u64> page_index);
void activate_tab(int index);
void close_tab(int index);
void move_tab(int old_index, int new_index);
void close_current_tab();
void open_next_tab();
void open_previous_tab();

View File

@ -1,6 +1,7 @@
/*
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2022, Matthew Costa <ucosty@gmail.com>
* Copyright (c) 2024, Jamie Mansfield <jmansfield@cadixdev.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -405,6 +406,69 @@ Tab::Tab(BrowserWindow* window, WebContentOptions const& web_content_options, St
emit navigation_buttons_state_changed(tab_index());
};
auto* reload_tab_action = new QAction("&Reload Tab", this);
QObject::connect(reload_tab_action, &QAction::triggered, this, [this]() {
reload();
});
auto* duplicate_tab_action = new QAction("&Duplicate Tab", this);
QObject::connect(duplicate_tab_action, &QAction::triggered, this, [this]() {
m_window->new_tab_from_url(view().url(), Web::HTML::ActivateTab::Yes);
});
auto* move_to_start_action = new QAction("Move to &Start", this);
QObject::connect(move_to_start_action, &QAction::triggered, this, [this]() {
m_window->move_tab(tab_index(), 0);
});
auto* move_to_end_action = new QAction("Move to &End", this);
QObject::connect(move_to_end_action, &QAction::triggered, this, [this]() {
m_window->move_tab(tab_index(), m_window->tab_count() - 1);
});
auto* close_tab_action = new QAction("&Close Tab", this);
QObject::connect(close_tab_action, &QAction::triggered, this, [this]() {
view().on_close();
});
auto* close_tabs_to_left_action = new QAction("C&lose Tabs to Left", this);
QObject::connect(close_tabs_to_left_action, &QAction::triggered, this, [this]() {
for (auto i = tab_index() - 1; i >= 0; i--) {
m_window->close_tab(i);
}
});
auto* close_tabs_to_right_action = new QAction("Close Tabs to R&ight", this);
QObject::connect(close_tabs_to_right_action, &QAction::triggered, this, [this]() {
for (auto i = m_window->tab_count() - 1; i > tab_index(); i--) {
m_window->close_tab(i);
}
});
auto* close_other_tabs_action = new QAction("Cl&ose Other Tabs", this);
QObject::connect(close_other_tabs_action, &QAction::triggered, this, [this]() {
for (auto i = m_window->tab_count() - 1; i >= 0; i--) {
if (i == tab_index())
continue;
m_window->close_tab(i);
}
});
m_context_menu = new QMenu("Context menu", this);
m_context_menu->addAction(reload_tab_action);
m_context_menu->addAction(duplicate_tab_action);
m_context_menu->addSeparator();
auto* move_tab_menu = m_context_menu->addMenu("Mo&ve Tab");
move_tab_menu->addAction(move_to_start_action);
move_tab_menu->addAction(move_to_end_action);
m_context_menu->addSeparator();
m_context_menu->addAction(close_tab_action);
auto* close_multiple_tabs_menu = m_context_menu->addMenu("Close &Multiple Tabs");
close_multiple_tabs_menu->addAction(close_tabs_to_left_action);
close_multiple_tabs_menu->addAction(close_tabs_to_right_action);
close_multiple_tabs_menu->addAction(close_other_tabs_action);
auto* search_selected_text_action = new QAction("&Search for <query>", this);
search_selected_text_action->setIcon(load_icon_from_uri("resource://icons/16x16/find.png"sv));
QObject::connect(search_selected_text_action, &QAction::triggered, this, [this]() {

View File

@ -54,6 +54,8 @@ public:
QIcon const& favicon() const { return m_favicon; }
QString const& title() const { return m_title; }
QMenu* context_menu() const { return m_context_menu; }
void update_navigation_buttons_state();
public slots:
@ -91,6 +93,8 @@ private:
QLabel* m_hover_label { nullptr };
QIcon m_favicon;
QMenu* m_context_menu { nullptr };
QMenu* m_page_context_menu { nullptr };
Optional<String> m_page_context_menu_search_text;

View File

@ -1,16 +1,25 @@
/*
* Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
* Copyright (c) 2024, Jamie Mansfield <jmansfield@cadixdev.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "Tab.h"
#include <AK/StdLibExtras.h>
#include <AK/TypeCasts.h>
#include <Ladybird/Qt/TabBar.h>
#include <QContextMenuEvent>
#include <QEvent>
#include <QPushButton>
namespace Ladybird {
TabBar::TabBar(QWidget* parent)
: QTabBar(parent)
{
}
QSize TabBar::tabSizeHint(int index) const
{
auto width = this->width() / count();
@ -22,11 +31,19 @@ QSize TabBar::tabSizeHint(int index) const
return hint;
}
void TabBar::contextMenuEvent(QContextMenuEvent* event)
{
auto* tab_widget = verify_cast<QTabWidget>(this->parent());
auto* tab = verify_cast<Tab>(tab_widget->widget(tabAt(event->pos())));
if (tab)
tab->context_menu()->exec(event->globalPos());
}
TabWidget::TabWidget(QWidget* parent)
: QTabWidget(parent)
{
// This must be called first, otherwise several of the options below have no effect.
setTabBar(new TabBar());
setTabBar(new TabBar(this));
setDocumentMode(true);
setElideMode(Qt::TextElideMode::ElideRight);

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
* Copyright (c) 2024, Jamie Mansfield <jmansfield@cadixdev.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -10,6 +11,7 @@
#include <QTabBar>
#include <QTabWidget>
class QContextMenuEvent;
class QEvent;
class QIcon;
class QWidget;
@ -20,7 +22,10 @@ class TabBar : public QTabBar {
Q_OBJECT
public:
explicit TabBar(QWidget* parent = nullptr);
virtual QSize tabSizeHint(int index) const override;
virtual void contextMenuEvent(QContextMenuEvent* event) override;
};
class TabWidget : public QTabWidget {