blob: 713b2bc18eb420efc97fb8892e585a5d8b88ceca [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// 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 <map>
#include <vector>
#include "base/callback.h"
#include "base/callback_forward.h"
#include "base/optional.h"
#include "base/timer/timer.h"
#include "chrome/browser/ui/tabs/tab_types.h"
#include "chrome/browser/ui/views/tabs/tab_animation_state.h"
#include "chrome/browser/ui/views/tabs/tab_strip_layout.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 TabGroupId;
class TabStripController;
// 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>*()>;
using GetGroupHeadersCallback =
base::RepeatingCallback<std::map<TabGroupId, TabGroupHeader*>()>;
TabStripLayoutHelper(const TabStripController* controller,
GetTabsCallback get_tabs_callback,
GetGroupHeadersCallback get_group_headers_callback,
base::RepeatingClosure on_animation_progressed);
~TabStripLayoutHelper();
// Returns a vector of all tabs in the strip, including both closing tabs
// and tabs still in the model.
std::vector<Tab*> GetTabs();
// Returns whether any animations for tabs or group headers are in progress.
bool IsAnimating() const;
int active_tab_width() { return active_tab_width_; }
int inactive_tab_width() { return inactive_tab_width_; }
int first_non_pinned_tab_index() { return first_non_pinned_tab_index_; }
int first_non_pinned_tab_x() { return first_non_pinned_tab_x_; }
// Returns the number of pinned tabs in the tabstrip.
int GetPinnedTabCount() const;
// Inserts a new tab at |index|, without animation. |tab_removed_callback|
// will be invoked if the tab is removed at the end of a remove animation.
void InsertTabAtNoAnimation(int model_index,
Tab* tab,
base::OnceClosure tab_removed_callback,
TabPinned pinned);
// Inserts a new tab at |index|, with animation. |tab_removed_callback| will
// be invoked if the tab is removed at the end of a remove animation.
void InsertTabAt(int model_index,
Tab* tab,
base::OnceClosure tab_removed_callback,
TabPinned pinned);
// Marks the tab at |model_index| as closed without animating it. Use when
// the tab has been removed from the model but the old animation style owns
// animating it.
// TODO(958173): Remove this when the old animation style is removed.
void RemoveTabNoAnimation(int model_index, Tab* tab);
// Marks the tab at |model_index| as closing and animates it closed.
void RemoveTab(int model_index, Tab* tab);
// Called when the tabstrip enters tab closing mode, wherein tabs should
// resize differently to control which tab ends up under the cursor.
// Assumes that the available width will never be smaller than this value
// for the duration of this tab closing session, i.e. that resizing the
// tabstrip will only happen after ExitTabClosingMode().
void EnterTabClosingMode(int available_width);
// Called when the tabstrip has left tab closing mode or when falling back
// to the old animation system while in closing mode. Returns the current
// available width.
base::Optional<int> ExitTabClosingMode();
// Invoked when |tab| has been destroyed by TabStrip (i.e. the remove
// animation has completed).
void OnTabDestroyed(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(base::Optional<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|. |header_removed_callback| will be
// invoked if the group is removed at the end of a remove animation.
void InsertGroupHeader(TabGroupId group,
TabGroupHeader* header,
base::OnceClosure header_removed_callback);
// Removes the group header for |group|.
void RemoveGroupHeader(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(TabGroupId group);
// Changes the active tab from |prev_active_index| to |new_active_index|.
void SetActiveTab(int prev_active_index, int new_active_index);
// Finishes all in-progress animations.
void CompleteAnimations();
// TODO(958173): Temporary method that completes running animations
// without invoking the callback to destroy removed tabs. Use to hand
// off animation (and removed tab destruction) responsibilities from
// this animator to elsewhere without teleporting tabs or destroying
// the same tab more than once.
void CompleteAnimationsWithoutDestroyingTabs();
// Generates and sets the ideal bounds for the views in |tabs| and
// |group_headers|. Updates the cached widths in |active_tab_width_| and
// |inactive_tab_width_|.
// TODO(958173): The notion of ideal bounds is going away. Delete this.
void UpdateIdealBounds(int available_width);
// Generates and sets the ideal bounds for |tabs|. Updates
// the cached values in |first_non_pinned_tab_index_| and
// |first_non_pinned_tab_x_|.
// TODO(958173): The notion of ideal bounds is going away. Delete this.
void UpdateIdealBoundsForPinnedTabs();
// Lays out tabs and group headers to their current bounds. Returns the
// x-coordinate of the trailing edge of the trailing-most tab.
int LayoutTabs(base::Optional<int> available_width);
private:
struct TabSlot;
// Given a tab's |model_index| and |group|, returns the index of its
// corresponding TabSlot in |slots_|.
int GetSlotIndexForTabModelIndex(int model_index,
base::Optional<TabGroupId> group) const;
// Given a group ID, returns the index of its header's corresponding TabSlot
// in |slots_|.
int GetSlotIndexForGroupHeader(TabGroupId group) const;
// Returns the current width constraints for each View.
std::vector<TabWidthConstraints> GetCurrentTabWidthConstraints() const;
// Runs an animation for the View at |slot_index| towards |target_state|.
void AnimateSlot(int slot_index, TabAnimationState target_state);
// Called when animations progress.
void TickAnimations();
// Deletes the data in |slots_| corresponding to fully closed tabs.
void RemoveClosedTabs();
// Recalculate |cached_slots_|, called whenever state changes.
void UpdateCachedTabSlots();
// Compares |cached_slots_| to the TabAnimations in |animator_| and DCHECKs if
// the TabAnimation::ViewType do not match. Prevents bugs that could cause the
// wrong callback being run when a tab or group is deleted.
void VerifyAnimationsMatchTabSlots() const;
// Updates the value of either |active_tab_width_| or |inactive_tab_width_|,
// as appropriate.
void UpdateCachedTabWidth(int tab_index, int tab_width, bool active);
// The tabstrip may enter 'closing mode' when tabs are closed with the mouse.
// In closing mode, the ideal widths of tabs are manipulated to control which
// tab ends up under the cursor after each remove animation completes - the
// next tab to the right, if it exists, or the next tab to the left otherwise.
// Returns true if any width constraint is currently being enforced.
bool WidthsConstrainedForClosingMode();
// The owning tabstrip's controller.
const TabStripController* const controller_;
// Callbacks to get the necessary View objects from the owning tabstrip.
GetTabsCallback get_tabs_callback_;
GetGroupHeadersCallback get_group_headers_callback_;
// Timer used to run animations on Views..
base::RepeatingTimer animation_timer_;
// Called when animations progress.
base::RepeatingClosure on_animation_progressed_;
// Current collation of tabs and group headers, along with necessary data to
// run layout and animations for those Views.
std::vector<TabSlot> slots_;
// When in tab closing mode, if we want the next tab to the right to end up
// under the cursor, each tab needs to stay the same size. When defined,
// this specifies that size.
base::Optional<TabWidthOverride> tab_width_override_;
// When in tab closing mode, if we want the next tab to the left to end up
// under the cursor, the overall space taken by tabs needs to stay the same.
// When defined, this specifies that size.
base::Optional<int> tabstrip_width_override_;
// The current widths of tabs. If the space for tabs is not evenly divisible
// into these widths, the initial tabs in the strip will be 1 px larger.
int active_tab_width_;
int inactive_tab_width_;
int first_non_pinned_tab_index_;
int first_non_pinned_tab_x_;
DISALLOW_COPY_AND_ASSIGN(TabStripLayoutHelper);
};
#endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_LAYOUT_HELPER_H_