[Tree Tabs] Show tree toggle button when mouse hovered even when close button is hidden by pref (#35283)

Show tree toggle button when mouse hovered even when close button is hidden by pref

When close button is hidden by pref, tree toggle button should be shown
when mouse hovered on the tab. Without this, tree toggle button is never
shown so users cannot collapse the tree tab node.
This commit is contained in:
Sangwoo Ko
2026-04-08 03:23:22 +02:00
committed by GitHub
parent a681d1a569
commit d0feaf416a
4 changed files with 48 additions and 3 deletions
+11 -3
View File
@@ -276,7 +276,7 @@ void BraveTab::UpdateIconVisibility() {
}
if (tree_toggle_button_ && HasTreeTabNodeDescendants() &&
showing_close_button_) {
(showing_close_button_ || mouse_hovered_)) {
// We show tree toggle button instead of close button when there are
// descendants. We need to update the icon to show the correct collapsed
// state, here. The toggle button's visibility is updated in Layout().
@@ -310,7 +310,7 @@ void BraveTab::LayoutTreeToggleButton() {
tree_toggle_button_->SetBoundsRect(close_button_->bounds());
close_button_->SetVisible(false);
tree_toggle_button_->SetVisible(true);
} else if (has_descendants && node->collapsed()) {
} else if (has_descendants && (node->collapsed() || mouse_hovered_)) {
// In this case, we always show tree toggle button in order to indicate that
// this tab has descendants hidden by collapsed state.
// Here, showing_close_button_ is false and the bounds of the close button
@@ -338,7 +338,7 @@ void BraveTab::LayoutTreeToggleButton() {
close_button_actual_size.height()));
tree_toggle_button_->SetVisible(true);
} else {
// Otherwise, hide the button.
// Otherwise, hide the button.
tree_toggle_button_->SetVisible(false);
}
}
@@ -535,6 +535,14 @@ TabNestingInfo BraveTab::GetTabNestingInfo() const {
return {.tree_height = GetTreeHeight(), .level = GetTreeTabNode()->level()};
}
void BraveTab::MaybeUpdateHoverStatus(const ui::MouseEvent& event) {
Tab::MaybeUpdateHoverStatus(event);
if (tree_tab_node().has_value()) {
LayoutTreeToggleButton();
}
}
bool BraveTab::IsInCollapsedTreeTabNode() const {
if (!tree_tab_node().has_value()) {
return false;
+4
View File
@@ -77,6 +77,7 @@ class BraveTab : public Tab {
TabSizeInfo GetTabSizeInfo() const override;
TabNestingInfo GetTabNestingInfo() const override;
bool IsInCollapsedTreeTabNode() const override;
void MaybeUpdateHoverStatus(const ui::MouseEvent& event) override;
// Returns whether this tab should have an accent painted.
bool ShouldPaintTabAccent() const;
@@ -127,6 +128,9 @@ class BraveTab : public Tab {
TreeToggleButtonAlwaysVisibleWhenCollapsedAndHasDescendants);
FRIEND_TEST_ALL_PREFIXES(containers::ContainersBrowserTest,
SmallAccentIconViewVisibility);
FRIEND_TEST_ALL_PREFIXES(
BraveTabTestWithTreeTab,
TreeToggleButtonVisibleMouseHoveredEvenWhenCloseButtonHiddenByPref);
bool IsAtMinWidthForVerticalTabStrip() const;
@@ -497,6 +497,37 @@ TEST_F(BraveTabTestWithTreeTab,
EXPECT_TRUE(tab.tree_toggle_button_->GetVisible());
}
TEST_F(BraveTabTestWithTreeTab,
TreeToggleButtonVisibleMouseHoveredEvenWhenCloseButtonHiddenByPref) {
testing::NiceMock<MockTabSlotController> tab_slot_controller;
auto node_id = tree_tab::TreeTabNodeId::GenerateNew();
tabs::TreeTabNodeTabCollection collection(
node_id, std::make_unique<MockTabInterfaceWithWeakPtr>(),
base::DoNothing(), base::DoNothing());
collection.node().set_height_for_test(100);
collection.node().set_collapsed(false);
EXPECT_CALL(tab_slot_controller, GetTreeTabNode(testing::_))
.WillRepeatedly(testing::Return(&collection.node()));
tab_slot_controller.set_should_always_hide_close_button(true);
auto widget = CreateTestWidget(views::Widget::InitParams::CLIENT_OWNS_WIDGET);
BraveTab tab(tabs::TabHandle(1), &tab_slot_controller);
widget->SetContentsView(&tab);
tab.set_tree_tab_node(node_id);
tab.SetBoundsRect({0, 0, 200, 50});
views::test::RunScheduledLayout(&tab);
ASSERT_FALSE(tab.showing_close_button_for_test());
EXPECT_FALSE(tab.tree_toggle_button_->GetVisible());
tab.MaybeUpdateHoverStatus(ui::MouseEvent(ui::EventType::kMouseMoved,
gfx::Point(100, 25), gfx::Point(),
base::TimeTicks(), 0, 0));
ASSERT_FALSE(tab.showing_close_button_for_test());
EXPECT_TRUE(tab.tree_toggle_button_->GetVisible());
}
TEST_F(BraveTabTest, TabMinWidthFloorPixels) {
EXPECT_EQ(10, BraveTab::GetTabMinWidthForMode(
brave_tabs::TabMinWidthMode::kDefault, 10, 100));
@@ -60,9 +60,11 @@ struct ControllableCloseButtonState final {
#define ShouldRenderAsNormalTab virtual ShouldRenderAsNormalTab
#define MaybeAdjustLeftForPinnedTab virtual MaybeAdjustLeftForPinnedTab
#define IsActive virtual IsActive
#define MaybeUpdateHoverStatus virtual MaybeUpdateHoverStatus
#include <chrome/browser/ui/views/tabs/tab.h> // IWYU pragma: export
#undef MaybeUpdateHoverStatus
#undef IsActive
#undef MaybeAdjustLeftForPinnedTab
#undef ShouldRenderAsNormalTab