Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(147)

Unified Diff: ui/views/controls/tabbed_pane/tabbed_pane.cc

Issue 2368283002: views: add focus to TabbedPane (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/views/controls/tabbed_pane/tabbed_pane.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/views/controls/tabbed_pane/tabbed_pane.cc
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane.cc b/ui/views/controls/tabbed_pane/tabbed_pane.cc
index b445db30b5cef9f364aaeb3f6be7651c51800c9f..ea1462f03d5fedd3ea01a979f6bcb1f38e888edf 100644
--- a/ui/views/controls/tabbed_pane/tabbed_pane.cc
+++ b/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -60,6 +60,11 @@ class Tab : public View {
bool selected() const { return contents_->visible(); }
void SetSelected(bool selected);
+ // This is a bit odd: since Tabs are not actually focusable, but rather the
Evan Stade 2016/09/26 16:28:36 Why make the tabstrip focusable instead of the tab
Elly Fong-Jones 2016/09/26 17:48:36 I thought it would end up being sort of semantical
+ // containing TabStrip is, Tabs need to be told when the TabStrip gains or
+ // loses focus so they can swap to/from the focus ring border.
+ void OnContainerFocusChanged();
+
// Overridden from View:
bool OnMousePressed(const ui::MouseEvent& event) override;
void OnMouseEntered(const ui::MouseEvent& event) override;
@@ -75,6 +80,9 @@ class Tab : public View {
// Called whenever |tab_state_| changes.
virtual void OnStateChanged();
+ // Returns whether the containing TabStrip has focus.
+ bool ContainerHasFocus();
+
private:
enum TabState {
TAB_INACTIVE,
@@ -252,6 +260,65 @@ void Tab::SetState(TabState tab_state) {
SchedulePaint();
}
+bool Tab::ContainerHasFocus() {
+ return tabbed_pane_->HasFocus();
+}
+
+void Tab::OnContainerFocusChanged() {
+ OnStateChanged();
+ SchedulePaint();
+}
+
+// The border used for MdTabs when they are both focused and selected: a
+// rectangle with the bottom side in a base color and the other sides in a
+// lightened version of the base color.
+class MdTabFocusRingBorder : public Border {
+ public:
+ MdTabFocusRingBorder(SkColor base_color);
Evan Stade 2016/09/26 16:28:35 why pass in a parameter? Why not view.GetNativeThe
Elly Fong-Jones 2016/09/26 17:48:36 Oh good call, reaching into the View did not occur
+ ~MdTabFocusRingBorder() override;
+
+ private:
+ void Paint(const View& view, gfx::Canvas* canvas) override;
+ gfx::Insets GetInsets() const override;
+ gfx::Size GetMinimumSize() const override;
+
+ SkColor base_color_;
+};
+
+MdTabFocusRingBorder::MdTabFocusRingBorder(SkColor base_color)
+ : base_color_(base_color) {}
+MdTabFocusRingBorder::~MdTabFocusRingBorder() {}
+
+void MdTabFocusRingBorder::Paint(const View& view, gfx::Canvas* canvas) {
+ gfx::Insets insets = GetInsets();
+ // TODO(ellyjones): should this 0x66 be part of NativeTheme somehow?
+ SkColor light_color = SkColorSetA(base_color_, 0x66);
+
+ SkPaint paint;
+ paint.setColor(light_color);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(2);
+
+ gfx::Rect bounds = gfx::Rect(0, 0, view.width(), view.height());
+ bounds.Inset(1, 1);
Evan Stade 2016/09/26 16:28:36 can this instead be stroke width / 2? Makes it mor
Elly Fong-Jones 2016/09/26 17:48:36 Done.
+
+ // Draw the lighter-colored stroke first, then draw the heavier stroke over
+ // the bottom of it. This is fine because the heavier stroke has 1.0 alpha, so
+ // the lighter stroke won't show through.
+ canvas->DrawRect(bounds, paint);
+ canvas->FillRect(gfx::Rect(0, view.height() - insets.bottom(), view.width(),
+ insets.bottom()),
+ base_color_);
+}
+
+gfx::Insets MdTabFocusRingBorder::GetInsets() const {
+ return gfx::Insets(2, 2);
+}
+
+gfx::Size MdTabFocusRingBorder::GetMinimumSize() const {
+ return gfx::Size(4, 4);
Evan Stade 2016/09/26 16:28:35 Is this necessary?
Elly Fong-Jones 2016/09/26 17:48:36 It seems to be - GetMinimumSize() is pure virtual
+}
+
MdTab::MdTab(TabbedPane* tabbed_pane,
const base::string16& title,
View* contents)
@@ -267,8 +334,14 @@ void MdTab::OnStateChanged() {
selected() ? ui::NativeTheme::kColorId_FocusedBorderColor
: ui::NativeTheme::kColorId_UnfocusedBorderColor);
int border_thickness = selected() ? 2 : 1;
Evan Stade 2016/09/26 16:28:35 seems a little weird that the border thickness dep
Elly Fong-Jones 2016/09/26 17:48:36 It does not seem to. It *is* a little weird - mayb
- SetBorder(
- Border::CreateSolidSidedBorder(0, 0, border_thickness, 0, border_color));
+ if (ContainerHasFocus() && selected()) {
+ SetBorder(
+ base::MakeUnique<MdTabFocusRingBorder>(GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_FocusedBorderColor)));
+ } else {
+ SetBorder(Border::CreateSolidSidedBorder(0, 0, border_thickness, 0,
+ border_color));
+ }
SkColor font_color = selected()
? theme->GetSystemColor(ui::NativeTheme::kColorId_CallToActionColor)
@@ -403,11 +476,6 @@ int TabbedPane::GetTabCount() {
return contents_->child_count();
}
-View* TabbedPane::GetSelectedTab() {
- return selected_tab_index() < 0 ?
- NULL : GetTabAt(selected_tab_index())->contents();
-}
-
void TabbedPane::AddTab(const base::string16& title, View* contents) {
AddTabAtIndex(tab_strip_->child_count(), title, contents);
}
@@ -435,8 +503,8 @@ void TabbedPane::SelectTabAt(int index) {
if (index == selected_tab_index())
return;
- if (selected_tab_index() >= 0)
- GetTabAt(selected_tab_index())->SetSelected(false);
+ if (GetSelectedTab())
+ GetSelectedTab()->SetSelected(false);
selected_tab_index_ = index;
Tab* tab = GetTabAt(index);
@@ -473,6 +541,21 @@ Tab* TabbedPane::GetTabAt(int index) {
return static_cast<Tab*>(tab_strip_->child_at(index));
}
+Tab* TabbedPane::GetSelectedTab() {
+ return selected_tab_index() >= 0 ? GetTabAt(selected_tab_index()) : nullptr;
+}
+
+bool TabbedPane::MoveSelectionBy(int delta) {
+ const int tab_count = GetTabCount();
+ if (tab_count <= 1)
+ return false;
+ int next_selected_index = (selected_tab_index() + delta) % tab_count;
+ if (next_selected_index < 0)
+ next_selected_index += tab_count;
+ SelectTabAt(next_selected_index);
+ return true;
+}
+
void TabbedPane::Layout() {
const gfx::Size size = tab_strip_->GetPreferredSize();
tab_strip_->SetBounds(0, 0, width(), size.height());
@@ -495,16 +578,16 @@ void TabbedPane::ViewHierarchyChanged(
bool TabbedPane::AcceleratorPressed(const ui::Accelerator& accelerator) {
// Handle Ctrl+Tab and Ctrl+Shift+Tab navigation of pages.
DCHECK(accelerator.key_code() == ui::VKEY_TAB && accelerator.IsCtrlDown());
- const int tab_count = GetTabCount();
- if (tab_count <= 1)
+ return MoveSelectionBy(accelerator.IsShiftDown() ? -1 : 1);
+}
+
+bool TabbedPane::OnKeyPressed(const ui::KeyEvent& event) {
+ if (!HasFocus())
return false;
- const int increment = accelerator.IsShiftDown() ? -1 : 1;
- int next_tab_index = (selected_tab_index() + increment) % tab_count;
- // Wrap around.
- if (next_tab_index < 0)
- next_tab_index += tab_count;
- SelectTabAt(next_tab_index);
- return true;
+ ui::DomKey key = event.GetDomKey();
+ if (key != ui::DomKey::ARROW_LEFT && key != ui::DomKey::ARROW_RIGHT)
+ return false;
+ return MoveSelectionBy(key == ui::DomKey::ARROW_LEFT ? 1 : -1);
}
const char* TabbedPane::GetClassName() const {
@@ -514,13 +597,21 @@ const char* TabbedPane::GetClassName() const {
void TabbedPane::OnFocus() {
View::OnFocus();
- View* selected_tab = GetSelectedTab();
- if (selected_tab) {
- selected_tab->NotifyAccessibilityEvent(
- ui::AX_EVENT_FOCUS, true);
+ Tab* selected = GetSelectedTab();
+ if (selected) {
+ selected->OnContainerFocusChanged();
+ if (selected->contents())
+ selected->contents()->NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true);
}
}
+void TabbedPane::OnBlur() {
+ View::OnBlur();
+ Tab* selected_tab = GetSelectedTab();
+ if (selected_tab)
+ selected_tab->OnContainerFocusChanged();
+}
+
void TabbedPane::GetAccessibleState(ui::AXViewState* state) {
state->role = ui::AX_ROLE_TAB_LIST;
}
« no previous file with comments | « ui/views/controls/tabbed_pane/tabbed_pane.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698