File: tabbed_pane.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (402 lines) | stat: -rw-r--r-- 14,598 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_VIEWS_CONTROLS_TABBED_PANE_TABBED_PANE_H_
#define UI_VIEWS_CONTROLS_TABBED_PANE_TABBED_PANE_H_

#include <memory>
#include <string>
#include <string_view>
#include <utility>

#include "base/callback_list.h"
#include "base/memory/raw_ptr.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/gfx/animation/animation_delegate.h"
#include "ui/gfx/animation/linear_animation.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/vector_icon_types.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/layout/flex_layout_view.h"
#include "ui/views/metadata/view_factory.h"

namespace views {

class Label;
class TabbedPaneTab;
class TabbedPaneListener;
class TabbedPaneTabStrip;

namespace test {
class TabbedPaneAccessibilityMacTest;
class TabbedPaneWithWidgetTest;
}  // namespace test

// TabbedPane is a view that shows tabs. When the user clicks on a tab, the
// associated view is displayed.
// Support for horizontal-highlight and vertical-border modes is limited and
// may require additional polish.
class VIEWS_EXPORT TabbedPane : public FlexLayoutView {
  METADATA_HEADER(TabbedPane, FlexLayoutView)

 public:
  // The orientation of the tab alignment.
  enum class Orientation {
    kHorizontal,
    kVertical,
  };

  // The style of the tab strip.
  enum class TabStripStyle {
    kBorder,           // Draw border around the selected tab.
    kHighlight,        // Highlight background and text of the selected tab.
    kCompactWithIcon,  // Draw an icon, shrink the highlight bar to icon+text
    kWithIcon,         // Draw an icon, expand the highlight bar to entire tab.
  };

  explicit TabbedPane(Orientation orientation = Orientation::kHorizontal,
                      TabStripStyle style = TabStripStyle::kBorder,
                      bool scrollable = false);

  TabbedPane(const TabbedPane&) = delete;
  TabbedPane& operator=(const TabbedPane&) = delete;

  ~TabbedPane() override;

  TabbedPaneListener* GetListener() const;
  void SetListener(TabbedPaneListener* listener);

  // Returns the index of the currently selected tab, or
  // TabStrip::kNoSelectedTab if no tab is selected.
  size_t GetSelectedTabIndex() const;

  // Returns the number of tabs.
  size_t GetTabCount() const;

  // Adds a new tab at the end of this TabbedPane with the specified |title|.
  // |contents| is the view displayed when the tab is selected and is owned by
  // the TabbedPane.
  template <typename T>
  T* AddTab(const std::u16string& title,
            std::unique_ptr<T> contents,
            const gfx::VectorIcon* tab_icon = nullptr) {
    return AddTabAtIndex(GetTabCount(), title, std::move(contents), tab_icon);
  }

  // Adds a new tab at |index| with |title|. |contents| is the view displayed
  // when the tab is selected and is owned by the TabbedPane. If the tabbed pane
  // is currently empty, the new tab is selected.
  template <typename T>
  T* AddTabAtIndex(size_t index,
                   const std::u16string& title,
                   std::unique_ptr<T> contents,
                   const gfx::VectorIcon* tab_icon = nullptr) {
    T* result = contents.get();
    AddTabInternal(index, title, std::move(contents), tab_icon);
    return result;
  }

  // Selects the tab at |index|, which must be valid.
  void SelectTabAt(size_t index, bool animate = true);

  // Selects |tab| (the tabstrip view, not its content) if it is valid.
  void SetTabContentVisibility(size_t tab_index, bool visible);

  // Calls the FocusManager (if it exists), and gives focus to the view at
  // |tab_index|.
  void MaybeSetFocusedView(size_t tab_index);

  // Gets the scroll view containing the tab strip, if it exists
  ScrollView* GetScrollView();

  // Gets the orientation of the tab alignment.
  Orientation GetOrientation() const;

  // Gets the style of the tab strip.
  TabStripStyle GetStyle() const;

  // Returns the tab at the given index.
  TabbedPaneTab* GetTabAt(size_t index);

  // Returns the View associated with a specific tab.
  const views::View* GetTabContents(size_t index) const;
  views::View* GetTabContentsForTesting(size_t index);

  // Updates the view's accessible name based on the currently selected tab's
  // title.
  void UpdateAccessibleName();

  // Sets whether a divider will be drawn underneath the Tab Strip.
  void SetDrawTabDivider(bool draw);

 private:
  friend class FocusTraversalTest;
  friend class TabbedPaneTab;
  friend class TabbedPaneTabStrip;
  friend class test::TabbedPaneWithWidgetTest;
  friend class test::TabbedPaneAccessibilityMacTest;

  // Adds a new tab at |index| with |title|. |contents| is the view displayed
  // when the tab is selected and is owned by the TabbedPane. If the tabbed pane
  // is currently empty, the new tab is selected.
  void AddTabInternal(size_t index,
                      const std::u16string& title,
                      std::unique_ptr<View> contents,
                      const gfx::VectorIcon* tab_icon = nullptr);

  // Get the TabbedPaneTab (the tabstrip view, not its content) at the selected
  // index.
  TabbedPaneTab* GetSelectedTab();

  // View:
  gfx::Size CalculatePreferredSize(
      const SizeBounds& available_size) const override;

  // The tab strip and contents container. The child indices of these members
  // correspond to match each TabbedPaneTab with its respective content View.
  raw_ptr<TabbedPaneTabStrip> tab_strip_ = nullptr;
  raw_ptr<View> contents_ = nullptr;

  // The scroll view containing the tab strip, if |scrollable| is specified on
  // creation.
  raw_ptr<ScrollView> scroll_view_ = nullptr;
};

// The tab view shown in the tab strip.
class VIEWS_EXPORT TabbedPaneTab : public View {
  METADATA_HEADER(TabbedPaneTab, View)

 public:
  static constexpr int kDefaultIconSize = 16;
  static constexpr int kDefaultTitleLeftMargin = kDefaultIconSize / 2;
  static constexpr int kDefaultHorizontalTabHeight = 32;
  static constexpr int kMinimumVerticalTabWidth = 192;

  TabbedPaneTab(TabbedPaneTabStrip* tab_strip,
                const std::u16string& title,
                const gfx::VectorIcon* tab_icon);

  TabbedPaneTab(const TabbedPaneTab&) = delete;
  TabbedPaneTab& operator=(const TabbedPaneTab&) = delete;

  ~TabbedPaneTab() override;

  bool selected() const { return selected_; }
  void SetSelected(bool selected);

  std::u16string_view GetTitleText() const;
  void SetTitleText(std::u16string_view text);

  void SetTitleMargin(const gfx::Insets& margin);
  void SetIconMargin(const gfx::Insets& margin);
  void SetTabOutsets(const gfx::Outsets& outsets);
  void SetHeight(int height);

  // Overridden from View:
  bool OnMousePressed(const ui::MouseEvent& event) override;
  void OnMouseEntered(const ui::MouseEvent& event) override;
  void OnMouseExited(const ui::MouseEvent& event) override;
  void OnGestureEvent(ui::GestureEvent* event) override;
  gfx::Size CalculatePreferredSize(
      const SizeBounds& available_size) const override;
  bool HandleAccessibleAction(const ui::AXActionData& action_data) override;
  void OnFocus() override;
  void OnBlur() override;
  bool OnKeyPressed(const ui::KeyEvent& event) override;
  void OnThemeChanged() override;

  void UpdateEnabledColor(bool enabled);

 private:
  enum class State {
    kInactive,
    kActive,
    kHovered,
  };

  void SetState(State state);

  // Called whenever |state_| changes.
  void OnStateChanged();

  // views::View:
  void OnPaint(gfx::Canvas* canvas) override;

  void UpdatePreferredTitleWidth();
  void UpdateTitleColor();

  void UpdateIconColor();

  void UpdateAccessibleName();
  void UpdateAccessibleSelection();

  ui::ImageModel GetImageModelForTab(ui::ColorId color_id) const;
  ui::ColorId GetIconTitleColor() const;

  raw_ptr<TabbedPaneTabStrip> tab_strip_;
  raw_ptr<const gfx::VectorIcon> icon_for_tab_;
  raw_ptr<ImageView> icon_view_ = nullptr;
  raw_ptr<Label> title_ = nullptr;
  gfx::Outsets tab_outsets_ = gfx::Outsets::VH(0, 0);
  // The preferred title width is the maximum width between inactive and active
  // states (font changes). See UpdatePreferredTitleWidth() for more details.
  int preferred_title_width_;
  int height_ = kDefaultHorizontalTabHeight;
  State state_ = State::kActive;
  bool selected_ = false;

  base::CallbackListSubscription title_text_changed_callback_;
};

// The tab strip shown above/left of the tab contents.
class VIEWS_EXPORT TabbedPaneTabStrip : public View,
                                        public gfx::AnimationDelegate {
  METADATA_HEADER(TabbedPaneTabStrip, View)

 public:
  // The return value of GetSelectedTabIndex() when no tab is selected.
  static constexpr size_t kNoSelectedTab = static_cast<size_t>(-1);

  TabbedPaneTabStrip(TabbedPane::Orientation orientation,
                     TabbedPane::TabStripStyle style,
                     raw_ptr<TabbedPane> tabbed_pane);

  TabbedPaneTabStrip(const TabbedPaneTabStrip&) = delete;
  TabbedPaneTabStrip& operator=(const TabbedPaneTabStrip&) = delete;

  ~TabbedPaneTabStrip() override;

  TabbedPaneListener* listener() { return listener_; }
  void set_listener(TabbedPaneListener* listener) { listener_ = listener; }

  // Adds a new TabbedPaneTab as a child of this View. This method should only
  // be used when TabbedPaneTabStrip is instantiated as a standalone component.
  TabbedPaneTab* AddTab(const std::u16string& title,
                        const gfx::VectorIcon* tab_icon);
  TabbedPaneTab* AddTabAt(const std::u16string& title,
                          const gfx::VectorIcon* tab_icon,
                          size_t index);

  // AnimationDelegate:
  void AnimationProgressed(const gfx::Animation* animation) override;
  void AnimationEnded(const gfx::Animation* animation) override;

  // Called by TabbedPaneTabStrip when the selected tab changes. This function
  // is only called if |from_tab| is not null, i.e., there was a previously
  // selected tab.
  void OnSelectedTabChanged(TabbedPaneTab* from_tab,
                            TabbedPaneTab* to_tab,
                            bool animate = true);

  // Attempts to select the provided tab. Returns true if the new tab was
  // selected, or false if no work was done (i.e., |new_selected_tab| is the
  // currently selected tab).
  bool SelectTab(TabbedPaneTab* new_selected_tab, bool animate = true);

  // Updates the visibility of the content associated with the tab at
  // |tab_index| if there is a |tabbed_pane_| parented to this view.
  void MaybeUpdateTabContentVisibility(size_t tab_index, bool visible);

  // Dispatches an accessibility event to the parent |tabbed_pane_| if it
  // exists, otherwise the event is dispatched on behalf of this View.
  void NotifyNewAccessibilityEvent(ax::mojom::Event event_type,
                                   bool send_native_event);

  // Moves the selection by |delta| tabs, where negative delta means leftwards
  // and positive delta means rightwards. Returns whether the move was
  // performed. This only fails if the delta results in currently selected tab.
  bool MoveSelectionBy(int delta);

  TabbedPaneTab* GetSelectedTab() const;
  TabbedPaneTab* GetTabAtDeltaFromSelected(int delta) const;
  TabbedPaneTab* GetTabAtIndex(size_t index) const;
  size_t GetIndexForTab(TabbedPaneTab* index) const;
  size_t GetSelectedTabIndex() const;
  size_t GetTabCount() const;

  // Sets the default flex of the tab strip. Useful for adding custom padding
  // instead of expecting the tab strip to stretch across its parent container.
  void SetDefaultFlex(int flex);

  // Sets how far apart the tabs will be positioned.
  void SetTabSpacing(int spacing);

  TabbedPane::Orientation GetOrientation() const;
  TabbedPane::TabStripStyle GetStyle() const;

  // Returns whether an Icon should be rendered for the TabbedPaneTab children.
  bool HasIconStyle() const;

  // Updates its own accessible name, and also calls TabbedPane's
  // UpdateAccessibleName method if |tabbed_pane_| is defined.
  void UpdateAccessibleName();

  // Sets whether a divider will be drawn underneath the Tab Strip.
  void SetDrawTabDivider(bool draw);

 protected:
  // View:
  void OnPaintBorder(gfx::Canvas* canvas) override;

 private:
  struct Coordinates {
    int start, end;
  };

  // Returns the beginning and ending distances for the icon+label in a tab.
  // start is the distance from the origin to the left-side of the icon,
  // and end is the distance from the origin to the right-side of the text.
  //                    (x) Label
  // -------start-------^       ^
  // -------end-----------------^
  Coordinates GetIconLabelStartEndingX(TabbedPaneTab* tab);

  // view::View
  bool AcceleratorPressed(const ui::Accelerator& accelerator) override;

  // The orientation of the tab alignment.
  const TabbedPane::Orientation orientation_;

  // The style of the tab strip.
  const TabbedPane::TabStripStyle style_;

  // Animations for expanding and contracting the selection bar. When changing
  // selections, the selection bar first grows to encompass both the old and new
  // selections, then shrinks to encompass only the new selection. The rates of
  // expansion and contraction each follow the cubic bezier curves used in
  // gfx::Tween; see TabStrip::OnPaintBorder for details.
  std::unique_ptr<gfx::LinearAnimation> expand_animation_ =
      std::make_unique<gfx::LinearAnimation>(this);
  std::unique_ptr<gfx::LinearAnimation> contract_animation_ =
      std::make_unique<gfx::LinearAnimation>(this);

  // The x-coordinate ranges of the old selection and the new selection.
  Coordinates animating_from_;
  Coordinates animating_to_;

  // A listener notified when tab selection changes. Weak, not owned.
  raw_ptr<TabbedPaneListener> listener_ = nullptr;

  // An optional parent container which connects Tabs in the TabStrip to
  // content views.
  raw_ptr<TabbedPane> tabbed_pane_;

  // Whether to draw the unselected divider below the tabs. Useful for when
  // the caller wants to use a custom divider instead.
  bool draw_tab_divider_ = true;
};

BEGIN_VIEW_BUILDER(VIEWS_EXPORT, TabbedPane, FlexLayoutView)
VIEW_BUILDER_METHOD_ALIAS(AddTab,
                          AddTab<View>,
                          const std::u16string&,
                          std::unique_ptr<View>,
                          const gfx::VectorIcon*)
END_VIEW_BUILDER

}  // namespace views

DEFINE_VIEW_BUILDER(VIEWS_EXPORT, TabbedPane)

#endif  // UI_VIEWS_CONTROLS_TABBED_PANE_TABBED_PANE_H_