blob: c1d3263583bdc04efc17c5dd69bcb3945038b5be [file]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_TABS_VERTICAL_VERTICAL_TAB_GROUP_HEADER_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_TABS_VERTICAL_VERTICAL_TAB_GROUP_HEADER_VIEW_H_
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ui/tabs/vertical_tab_strip_state_controller.h"
#include "chrome/browser/ui/views/tabs/tab_group_editor_bubble_tracker.h"
#include "chrome/browser/ui/views/tabs/tab_strip_types.h"
#include "components/tab_groups/tab_group_visual_data.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/views/context_menu_controller.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/layout/flex_layout_view.h"
namespace tabs {
class VerticalTabStripStateController;
}
namespace tab_groups {
class TabGroupVisualData;
}
namespace views {
class LabelButton;
class ImageView;
class Label;
} // namespace views
// The view for the tab group header. It displays the tab group
// title, editor icon and the collapsed/expand icon.
class VerticalTabGroupHeaderView : public views::FlexLayoutView,
public views::ContextMenuController,
public views::FocusChangeListener {
METADATA_HEADER(VerticalTabGroupHeaderView, views::FlexLayoutView)
public:
class Delegate {
public:
virtual ~Delegate() = default;
virtual void ToggleCollapsedState(
ToggleTabGroupCollapsedStateOrigin origin) = 0;
virtual views::Widget* ShowGroupEditorBubble(
bool stop_context_menu_propagation) = 0;
virtual std::u16string GetGroupContentString() const = 0;
virtual void InitHeaderDrag(const ui::MouseEvent& event) = 0;
virtual bool ContinueHeaderDrag(const ui::MouseEvent& event) = 0;
virtual void CancelHeaderDrag() = 0;
virtual void HideHoverCard() const = 0;
virtual void ShiftGroupUp() = 0;
virtual void ShiftGroupDown() = 0;
};
VerticalTabGroupHeaderView(
Delegate& delegate,
tabs::VerticalTabStripStateController* state_controller,
const tab_groups::TabGroupVisualData* tab_group_visual_data);
VerticalTabGroupHeaderView(const VerticalTabGroupHeaderView&) = delete;
VerticalTabGroupHeaderView& operator=(const VerticalTabGroupHeaderView&) =
delete;
~VerticalTabGroupHeaderView() override;
// views::View:
bool OnKeyPressed(const ui::KeyEvent& event) override;
bool OnMousePressed(const ui::MouseEvent& event) override;
bool OnMouseDragged(const ui::MouseEvent& event) override;
void OnMouseReleased(const ui::MouseEvent& event) override;
void OnGestureEvent(ui::GestureEvent* event) override;
void OnMouseMoved(const ui::MouseEvent& event) override;
void OnMouseEntered(const ui::MouseEvent& event) override;
void OnMouseExited(const ui::MouseEvent& event) override;
void OnFocus() override;
void OnBlur() override;
void AddedToWidget() override;
void RemovedFromWidget() override;
// views::FocusChangeListener:
void OnWillChangeFocus(views::View* focused_before,
views::View* focused_now) override;
void OnDidChangeFocus(views::View* focused_before,
views::View* focused_now) override;
// views::ContextMenuController:
void ShowContextMenuForViewImpl(
views::View* source,
const gfx::Point& point,
ui::mojom::MenuSourceType source_type) override;
void OnDataChanged(
const tab_groups::TabGroupVisualData* tab_group_visual_data,
bool is_shared);
void OnAttentionStateChanged(bool needs_attention);
views::LabelButton* editor_bubble_button() { return editor_bubble_button_; }
views::ImageView* collapse_icon_for_testing() { return collapse_icon_; }
views::ImageView* attention_indicator_for_testing() {
return attention_indicator_;
}
private:
void UpdateEditorBubbleButtonVisibility();
// Bypasses the synchronous IsMouseHovered() check which can be stale on Linux
// Wayland/X11 due to asynchronous cursor updates during mouse exit events.
void SetEditorBubbleButtonVisibilityOnHover(bool is_hovered);
void ShowEditorBubble();
void UpdateAccessibleName();
void UpdateTooltipText();
void UpdateIsCollapsed();
SkColor GetForegroundColor() const;
tab_groups::TabGroupVisualData tab_group_visual_data_;
bool needs_attention_ = false;
bool is_shared_ = false;
// The sync icon that is displayed in the tab group header of saved groups in
// the tabstrip.
const raw_ptr<views::ImageView> sync_icon_ = nullptr;
const raw_ptr<views::Label> group_header_label_ = nullptr;
// The circle indicator rendered after the title when a tab group needs
// attention.
const raw_ptr<views::ImageView> attention_indicator_ = nullptr;
const raw_ptr<views::LabelButton> editor_bubble_button_ = nullptr;
const raw_ptr<views::ImageView> collapse_icon_ = nullptr;
const raw_ref<Delegate> delegate_;
TabGroupEditorBubbleTracker editor_bubble_tracker_;
base::CallbackListSubscription editor_bubble_opened_subscription_;
base::CallbackListSubscription editor_bubble_closed_subscription_;
base::WeakPtrFactory<VerticalTabGroupHeaderView> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_UI_VIEWS_TABS_VERTICAL_VERTICAL_TAB_GROUP_HEADER_VIEW_H_