blob: d3461404e0c19e8f01252f419c5d97c52e614fa2 [file] [log] [blame]
// Copyright 2019 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_TAB_STRIP_LAYOUT_HELPER_H_
#define CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_LAYOUT_HELPER_H_
#include <optional>
#include <vector>
#include "base/functional/callback.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ref.h"
#include "chrome/browser/ui/tabs/tab_types.h"
#include "chrome/browser/ui/views/tabs/tab_layout_state.h"
#include "chrome/browser/ui/views/tabs/tab_slot_view.h"
#include "chrome/browser/ui/views/tabs/tab_strip_layout.h"
#include "chrome/browser/ui/views/tabs/tab_strip_layout_types.h"
#include "chrome/browser/ui/views/tabs/tab_width_constraints.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/view_model.h"
class Tab;
class TabGroupHeader;
class TabContainerController;
namespace tab_groups {
class TabGroupId;
}
// Helper class for TabStrip, that is responsible for calculating and assigning
// layouts for tabs and group headers. It tracks animations and changes to the
// model so that it has all necessary information for layout purposes.
class TabStripLayoutHelper {
public:
using GetTabsCallback = base::RepeatingCallback<views::ViewModelT<Tab>*()>;
TabStripLayoutHelper(const TabContainerController& controller,
GetTabsCallback get_tabs_callback);
TabStripLayoutHelper(const TabStripLayoutHelper&) = delete;
TabStripLayoutHelper& operator=(const TabStripLayoutHelper&) = delete;
~TabStripLayoutHelper();
// Returns a vector of all tabs in the strip, including both closing tabs
// and tabs still in the model.
std::vector<Tab*> GetTabs() const;
// Get all tab slot views in visual order, including all tabs from
// GetTabs() and all tab group headers.
std::vector<TabSlotView*> GetTabSlotViews() const;
LayoutDomain layout_domain() { return tab_strip_layout_domain_; }
// Returns the number of pinned tabs in the tabstrip.
size_t GetPinnedTabCount() const;
// Returns a map of all tab groups and their bounds.
const std::map<tab_groups::TabGroupId, gfx::Rect>& group_header_ideal_bounds()
const {
return group_header_ideal_bounds_;
}
// Inserts a new tab at `index`.
void InsertTabAt(int model_index, Tab* tab, TabPinned pinned);
// Marks the tab at `model_index` as closing, but does not remove it from
// `slots_`.
void MarkTabAsClosing(int model_index, Tab* tab);
// Removes `tab` from `slots_`.
void RemoveTab(Tab* tab);
// Moves the tab at `prev_index` with group `moving_tab_group` to `new_index`.
// Also updates the group header's location if necessary.
void MoveTab(std::optional<tab_groups::TabGroupId> moving_tab_group,
int prev_index,
int new_index);
// Sets the tab at `index`'s pinned state to `pinned`.
void SetTabPinned(int model_index, TabPinned pinned);
// Inserts a new group header for `group`.
void InsertGroupHeader(tab_groups::TabGroupId group, TabGroupHeader* header);
// Removes the group header for `group`.
void RemoveGroupHeader(tab_groups::TabGroupId group);
// Ensures the group header for `group` is at the correct index. Should be
// called externally when group membership changes but nothing else about the
// layout does.
void UpdateGroupHeaderIndex(tab_groups::TabGroupId group);
// Changes the active tab from `prev_active_index` to `new_active_index`.
void SetActiveTab(std::optional<size_t> prev_active_index,
std::optional<size_t> new_active_index);
// Calculates the smallest width the tabs can occupy.
int CalculateMinimumWidth();
// Calculates the width the tabs would occupy if they have enough space.
int CalculatePreferredWidth();
// Generates and sets the ideal bounds for the views in `tabs` and
// `group_headers`. Returns the total width occupied by the new ideal bounds.
int UpdateIdealBounds(int available_width);
private:
struct TabSlot;
// Calculates the bounds each tab should occupy, subject to the provided
// width constraint.
std::pair<std::vector<gfx::Rect>, LayoutDomain> CalculateIdealBounds(
std::optional<int> available_width);
// Given `model_index` for a tab already present in `slots_`, return
// the corresponding index in `slots_`.
int GetSlotIndexForExistingTab(int model_index) const;
// For a new tab at `new_model_index`, get the insertion index in
// `slots_`. `group` is the new tab's group.
int GetSlotInsertionIndexForNewTab(
int new_model_index,
std::optional<tab_groups::TabGroupId> group) const;
// Returns the slot corresponding to the first tab in a group
// in the view.
std::optional<int> GetFirstTabSlotForGroup(
tab_groups::TabGroupId group) const;
// Used internally in the above two functions. For a tabstrip with N
// tabs, this takes 0 <= `model_index` <= N and returns the first
// possible slot corresponding to this model index.
//
// This means that if `model_index` is the first tab in a group, the
// returned slot index will point to the group header. For other tabs,
// the slot index corresponding to that tab will be returned. Finally,
// if `model_index` = N, slots_.size() will be returned.
int GetFirstSlotIndexForTabModelIndex(int model_index) const;
// Given a group ID, returns the index of its header's corresponding TabSlot
// in `slots_`.
int GetSlotIndexForGroupHeader(tab_groups::TabGroupId group) const;
// If the tab at `slot_index` is split, returns the index of the adjacent
// split tab. Otherwise returns `std::nullopt`.
std::optional<int> GetAdjacentSplitTab(int slot_index) const;
// True iff the slot at index `i` is a tab that is in a collapsed group.
bool SlotIsCollapsedTab(int i) const;
// The owning TabContainer's controller.
const raw_ref<const TabContainerController, DanglingUntriaged> controller_;
// Callback to get the necessary View objects from the owning tabstrip.
GetTabsCallback get_tabs_callback_;
// Current collation of tabs and group headers, along with necessary data to
// run layout and animations for those Views.
std::vector<TabSlot> slots_;
// Contains the ideal bounds of tab group headers.
std::map<tab_groups::TabGroupId, gfx::Rect> group_header_ideal_bounds_;
LayoutDomain tab_strip_layout_domain_;
};
#endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_LAYOUT_HELPER_H_