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

ash / wm / desks / desk_textfield.cc [blame]

// Copyright 2021 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/wm/desks/desk_textfield.h"

#include "ash/shell.h"
#include "ash/style/style_util.h"
#include "ash/wm/overview/overview_grid.h"
#include "base/task/single_thread_task_runner.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/gfx/canvas.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/background.h"
#include "ui/views/widget/widget.h"

namespace ash {

namespace {

constexpr int kDeskTextfieldMinHeight = 16;

}  // namespace

DeskTextfield::DeskTextfield(Type type) : SystemTextfield(type) {
  views::Builder<DeskTextfield>(this).SetCursorEnabled(true).BuildChildren();

  GetRenderText()->SetElideBehavior(gfx::ELIDE_TAIL);
  text_changed_subscription_ = AddTextChangedCallback(base::BindRepeating(
      &DeskTextfield::UpdateTooltipText, base::Unretained(this)));
  UpdateTooltipText();
}

DeskTextfield::~DeskTextfield() = default;

// static
constexpr size_t DeskTextfield::kMaxLength;

// static
void DeskTextfield::CommitChanges(views::Widget* widget) {
  auto* focus_manager = widget->GetFocusManager();
  focus_manager->ClearFocus();
  // Avoid having the focus restored to the same view when the parent view is
  // refocused.
  focus_manager->SetStoredFocusView(nullptr);
}

gfx::Size DeskTextfield::CalculatePreferredSize(
    const views::SizeBounds& available_size) const {
  const std::u16string& text = GetText();
  int width = 0;
  int height = 0;
  gfx::Canvas::SizeStringInt(text, GetFontList(), &width, &height, 0,
                             gfx::Canvas::NO_ELLIPSIS);
  gfx::Size size{width + GetCaretBounds().width(), height};
  const auto insets = GetInsets();
  size.Enlarge(insets.width(), insets.height());
  size.SetToMax(gfx::Size(0, kDeskTextfieldMinHeight));
  return size;
}

bool DeskTextfield::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
  // The default behavior of the tab key is that it moves the focus to the next
  // available view. This is done in either in `OverviewSession::OnKeyEvent()`
  // or `DeskBarController::OnKeyEvent()`.
  return event.key_code() == ui::VKEY_TAB;
}

ui::Cursor DeskTextfield::GetCursor(const ui::MouseEvent& event) {
  return ui::mojom::CursorType::kIBeam;
}

void DeskTextfield::OnFocus() {
  GetRenderText()->SetElideBehavior(gfx::NO_ELIDE);
  SystemTextfield::OnFocus();
}

void DeskTextfield::OnBlur() {
  GetRenderText()->SetElideBehavior(gfx::ELIDE_TAIL);
  SystemTextfield::OnBlur();

  // Avoid having the focus restored to the same DeskNameView when the desk bar
  // widget is refocused. Use a post task to avoid calling
  // `FocusManager::SetStoredFocusView()` while `FocusManager::ClearFocus()` is
  // still being activated. In this case, we want to set the stored focus view
  // to nullptr after the stack of the call to `FocusManager::ClearFocus()`
  // returns completely.
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(
                     [](base::WeakPtr<views::Widget> w) {
                       if (w) {
                         w->GetFocusManager()->SetStoredFocusView(nullptr);
                       }
                     },
                     GetWidget()->GetWeakPtr()));
}

void DeskTextfield::OnDragEntered(const ui::DropTargetEvent& event) {
  GetRenderText()->SetElideBehavior(gfx::NO_ELIDE);
  views::Textfield::OnDragEntered(event);
}

void DeskTextfield::OnDragExited() {
  GetRenderText()->SetElideBehavior(gfx::ELIDE_TAIL);
  views::Textfield::OnDragExited();
}

void DeskTextfield::OnBoundsChanged(const gfx::Rect& previous_bounds) {
  SystemTextfield::OnBoundsChanged(previous_bounds);
  UpdateTooltipText();
}

void DeskTextfield::PreferredSizeChanged() {
  SystemTextfield::PreferredSizeChanged();
  UpdateTooltipText();
}

void DeskTextfield::UpdateTooltipText() {
  if (GetPreferredSize().width() > width()) {
    SetCachedTooltipText(GetText());
  } else {
    SetCachedTooltipText(std::u16string());
  }
}

BEGIN_METADATA(DeskTextfield)
END_METADATA

}  // namespace ash