| // Copyright 2017 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/app_list/app_list_util.h" |
| |
| #include "ash/app_list/model/app_list_folder_item.h" |
| #include "ash/app_list/model/app_list_item.h" |
| #include "ash/constants/ash_constants.h" |
| #include "ash/constants/ash_features.h" |
| #include "ash/style/ash_color_provider.h" |
| #include "ui/events/event.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/gfx/geometry/skia_conversions.h" |
| #include "ui/gfx/geometry/vector2d.h" |
| #include "ui/gfx/image/image_skia.h" |
| #include "ui/gfx/image/image_skia_operations.h" |
| #include "ui/views/accessibility/view_accessibility.h" |
| #include "ui/views/controls/textfield/textfield.h" |
| #include "ui/views/focus/focus_manager.h" |
| #include "ui/views/view.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| // The cardified apps grid and app icons should scale down by this factor. |
| constexpr float kAppsGridCardifiedScale = 0.9f; |
| |
| } // namespace |
| |
| bool IsUnhandledUnmodifiedEvent(const ui::KeyEvent& event) { |
| if (event.handled() || event.type() != ui::ET_KEY_PRESSED) |
| return false; |
| |
| if (event.IsShiftDown() || event.IsControlDown() || event.IsAltDown()) |
| return false; |
| |
| return true; |
| } |
| |
| bool IsUnhandledLeftRightKeyEvent(const ui::KeyEvent& event) { |
| if (!IsUnhandledUnmodifiedEvent(event)) |
| return false; |
| |
| return event.key_code() == ui::VKEY_LEFT || |
| event.key_code() == ui::VKEY_RIGHT; |
| } |
| |
| bool IsUnhandledUpDownKeyEvent(const ui::KeyEvent& event) { |
| if (!IsUnhandledUnmodifiedEvent(event)) |
| return false; |
| |
| return event.key_code() == ui::VKEY_UP || event.key_code() == ui::VKEY_DOWN; |
| } |
| |
| bool IsUnhandledArrowKeyEvent(const ui::KeyEvent& event) { |
| if (!IsUnhandledUnmodifiedEvent(event)) |
| return false; |
| |
| return IsArrowKeyEvent(event); |
| } |
| |
| bool IsArrowKeyEvent(const ui::KeyEvent& event) { |
| return IsArrowKey(event.key_code()); |
| } |
| |
| bool IsArrowKey(const ui::KeyboardCode& key_code) { |
| return key_code == ui::VKEY_DOWN || key_code == ui::VKEY_RIGHT || |
| key_code == ui::VKEY_LEFT || key_code == ui::VKEY_UP; |
| } |
| |
| bool IsFolderItem(AppListItem* item) { |
| return item->GetItemType() == AppListFolderItem::kItemType; |
| } |
| |
| bool LeftRightKeyEventShouldExitText(views::Textfield* textfield, |
| const ui::KeyEvent& key_event) { |
| DCHECK(IsUnhandledLeftRightKeyEvent(key_event)); |
| |
| if (textfield->GetText().empty()) |
| return true; |
| |
| if (textfield->HasSelection()) |
| return false; |
| |
| if (textfield->GetCursorPosition() != 0 && |
| textfield->GetCursorPosition() != textfield->GetText().length()) { |
| return false; |
| } |
| |
| // For RTL language, the beginning position of the cursor will be at the right |
| // side and it grows towards left as we are typing. |
| const bool text_rtl = |
| textfield->GetTextDirection() == base::i18n::RIGHT_TO_LEFT; |
| const bool cursor_at_beginning = textfield->GetCursorPosition() == 0; |
| const bool move_cursor_reverse = |
| (text_rtl && key_event.key_code() == ui::VKEY_RIGHT) || |
| (!text_rtl && key_event.key_code() == ui::VKEY_LEFT); |
| |
| if ((cursor_at_beginning && !move_cursor_reverse) || |
| (!cursor_at_beginning && move_cursor_reverse)) { |
| // Cursor is at either the beginning or the end of the textfield, and it |
| // will move inward. |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool ProcessLeftRightKeyTraversalForTextfield(views::Textfield* textfield, |
| const ui::KeyEvent& key_event) { |
| DCHECK(IsUnhandledLeftRightKeyEvent(key_event)); |
| |
| if (!LeftRightKeyEventShouldExitText(textfield, key_event)) |
| return false; |
| |
| const bool move_focus_reverse = base::i18n::IsRTL() |
| ? key_event.key_code() == ui::VKEY_RIGHT |
| : key_event.key_code() == ui::VKEY_LEFT; |
| |
| // Move focus outside the textfield. |
| textfield->GetFocusManager()->AdvanceFocus(move_focus_reverse); |
| return true; |
| } |
| |
| gfx::ImageSkia CreateIconWithCircleBackground(const gfx::ImageSkia& icon) { |
| DCHECK_EQ(icon.width(), icon.height()); |
| return gfx::ImageSkiaOperations::CreateImageWithCircleBackground( |
| icon.width() / 2, |
| AshColorProvider::Get()->GetBaseLayerColor( |
| AshColorProvider::BaseLayerType::kOpaque), |
| icon); |
| } |
| |
| void PaintFocusBar(gfx::Canvas* canvas, |
| const gfx::Point& content_origin, |
| int height, |
| SkColor color) { |
| SkPath path; |
| gfx::Rect focus_bar_bounds(content_origin.x() - kFocusBarThickness, |
| content_origin.y(), kFocusBarThickness * 2, |
| height); |
| path.addRRect(SkRRect::MakeRectXY(RectToSkRect(focus_bar_bounds), |
| kFocusBarThickness, kFocusBarThickness)); |
| canvas->ClipPath(path, true); |
| |
| cc::PaintFlags flags; |
| flags.setAntiAlias(true); |
| flags.setColor(color); |
| flags.setStyle(cc::PaintFlags::kStroke_Style); |
| flags.setStrokeWidth(kFocusBarThickness); |
| gfx::Point top_point = content_origin + gfx::Vector2d(kFocusBarThickness, 0); |
| gfx::Point bottom_point = |
| content_origin + gfx::Vector2d(kFocusBarThickness, height); |
| canvas->DrawLine(top_point, bottom_point, flags); |
| } |
| |
| void SetViewIgnoredForAccessibility(views::View* view, bool ignored) { |
| auto& view_accessibility = view->GetViewAccessibility(); |
| view_accessibility.OverrideIsLeaf(ignored); |
| view_accessibility.OverrideIsIgnored(ignored); |
| view->NotifyAccessibilityEvent(ax::mojom::Event::kTreeChanged, true); |
| } |
| |
| float GetAppsGridCardifiedScale() { |
| return kAppsGridCardifiedScale; |
| } |
| |
| } // namespace ash |