blob: 43a4bd54fd528945bfe304af353fcce7bafa68e7 [file] [log] [blame]
// Copyright (c) 2013 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.
#include "ui/app_list/views/folder_header_view.h"
#include <algorithm>
#include "ash/app_list/model/app_list_folder_item.h"
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/app_list/app_list_constants.h"
#include "ui/app_list/app_list_features.h"
#include "ui/app_list/app_list_switches.h"
#include "ui/app_list/app_list_util.h"
#include "ui/app_list/views/app_list_folder_view.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/text_elider.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/painter.h"
namespace app_list {
namespace {
constexpr int kPreferredWidth = 360;
constexpr int kPreferredHeight = 48;
constexpr int kBottomSeparatorHeight = 1;
constexpr int kMaxFolderNameWidth = 300;
constexpr int kMaxFolderNameWidthFullScreen = 236;
} // namespace
class FolderHeaderView::FolderNameView : public views::Textfield {
public:
FolderNameView() { SetBorder(views::CreateEmptyBorder(1, 1, 1, 1)); }
~FolderNameView() override {}
void OnFocus() override {
SelectAll(false);
Textfield::OnFocus();
}
private:
DISALLOW_COPY_AND_ASSIGN(FolderNameView);
};
FolderHeaderView::FolderHeaderView(FolderHeaderViewDelegate* delegate)
: folder_item_(nullptr),
folder_name_view_(new FolderNameView),
folder_name_placeholder_text_(
ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER)),
delegate_(delegate),
folder_name_visible_(true),
is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()) {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
gfx::FontList font_list = rb.GetFontList(ui::ResourceBundle::MediumFont);
folder_name_view_->set_placeholder_text_color(kFolderTitleHintTextColor);
folder_name_view_->set_placeholder_text(folder_name_placeholder_text_);
folder_name_view_->SetBorder(views::NullBorder());
if (is_fullscreen_app_list_enabled_) {
// Make folder name font size 14px.
folder_name_view_->SetFontList(font_list.DeriveWithSizeDelta(-1));
folder_name_view_->SetBackgroundColor(SK_ColorTRANSPARENT);
folder_name_view_->SetTextColor(kGridTitleColor);
} else {
folder_name_view_->SetFontList(font_list);
folder_name_view_->SetBackgroundColor(kContentsBackgroundColor);
folder_name_view_->SetTextColor(kFolderTitleColor);
}
folder_name_view_->set_controller(this);
AddChildView(folder_name_view_);
}
FolderHeaderView::~FolderHeaderView() {
if (folder_item_)
folder_item_->RemoveObserver(this);
}
void FolderHeaderView::SetFolderItem(AppListFolderItem* folder_item) {
if (folder_item_)
folder_item_->RemoveObserver(this);
folder_item_ = folder_item;
if (!folder_item_)
return;
folder_item_->AddObserver(this);
folder_name_view_->SetEnabled(folder_item_->folder_type() !=
AppListFolderItem::FOLDER_TYPE_OEM);
Update();
}
void FolderHeaderView::UpdateFolderNameVisibility(bool visible) {
folder_name_visible_ = visible;
Update();
SchedulePaint();
}
void FolderHeaderView::OnFolderItemRemoved() {
folder_item_ = NULL;
}
void FolderHeaderView::SetTextFocus() {
folder_name_view_->RequestFocus();
}
bool FolderHeaderView::HasTextFocus() const {
return folder_name_view_->HasFocus();
}
void FolderHeaderView::Update() {
if (!folder_item_)
return;
folder_name_view_->SetVisible(folder_name_visible_);
if (folder_name_visible_) {
base::string16 folder_name = base::UTF8ToUTF16(folder_item_->name());
base::string16 elided_folder_name = GetElidedFolderName(folder_name);
folder_name_view_->SetText(elided_folder_name);
UpdateFolderNameAccessibleName();
}
Layout();
}
void FolderHeaderView::UpdateFolderNameAccessibleName() {
// Sets |folder_name_view_|'s accessible name to the placeholder text if
// |folder_name_view_| is blank; otherwise, clear the accessible name, the
// accessible state's value is set to be folder_name_view_->text() by
// TextField.
base::string16 accessible_name = folder_name_view_->text().empty()
? folder_name_placeholder_text_
: base::string16();
folder_name_view_->SetAccessibleName(accessible_name);
}
const base::string16& FolderHeaderView::GetFolderNameForTest() {
return folder_name_view_->text();
}
void FolderHeaderView::SetFolderNameForTest(const base::string16& name) {
folder_name_view_->SetText(name);
}
bool FolderHeaderView::IsFolderNameEnabledForTest() const {
return folder_name_view_->enabled();
}
gfx::Size FolderHeaderView::CalculatePreferredSize() const {
const int preferred_height = is_fullscreen_app_list_enabled_
? kPreferredHeight +
kBottomSeparatorBottomPadding +
AppsGridView::GetTilePadding().top()
: kPreferredHeight;
return gfx::Size(kPreferredWidth, preferred_height);
}
views::View* FolderHeaderView::GetFolderNameViewForTest() const {
return folder_name_view_;
}
int FolderHeaderView::GetMaxFolderNameWidth() const {
return is_fullscreen_app_list_enabled_ ? kMaxFolderNameWidthFullScreen
: kMaxFolderNameWidth;
}
base::string16 FolderHeaderView::GetElidedFolderName(
const base::string16& folder_name) const {
// Enforce the maximum folder name length.
base::string16 name = folder_name.substr(0, kMaxFolderNameChars);
// Get maximum text width for fitting into |folder_name_view_|.
int text_width = GetMaxFolderNameWidth() -
folder_name_view_->GetCaretBounds().width() -
folder_name_view_->GetInsets().width();
base::string16 elided_name = gfx::ElideText(
name, folder_name_view_->GetFontList(), text_width, gfx::ELIDE_TAIL);
return elided_name;
}
void FolderHeaderView::Layout() {
gfx::Rect rect(GetContentsBounds());
if (rect.IsEmpty())
return;
gfx::Rect text_bounds(rect);
base::string16 text = folder_item_ && !folder_item_->name().empty()
? base::UTF8ToUTF16(folder_item_->name())
: folder_name_placeholder_text_;
int text_width =
gfx::Canvas::GetStringWidth(text, folder_name_view_->GetFontList()) +
folder_name_view_->GetCaretBounds().width() +
folder_name_view_->GetInsets().width();
text_width = std::min(text_width, GetMaxFolderNameWidth());
text_bounds.set_x(rect.x() + (rect.width() - text_width) / 2);
text_bounds.set_width(text_width);
text_bounds.ClampToCenteredSize(gfx::Size(
text_bounds.width(), folder_name_view_->GetPreferredSize().height()));
folder_name_view_->SetBoundsRect(text_bounds);
}
bool FolderHeaderView::OnKeyPressed(const ui::KeyEvent& event) {
if (event.key_code() == ui::VKEY_RETURN)
delegate_->GiveBackFocusToSearchBox();
return false;
}
void FolderHeaderView::OnPaint(gfx::Canvas* canvas) {
views::View::OnPaint(canvas);
gfx::Rect rect(GetContentsBounds());
if (rect.IsEmpty() || !folder_name_visible_)
return;
// Draw bottom separator line.
rect.Inset(is_fullscreen_app_list_enabled_
? kAppsGridLeftRightPadding +
(-AppsGridView::GetTilePadding().left()) +
kBottomSeparatorLeftRightPadding
: kAppsGridPadding,
0);
int extra_bottom_padding =
is_fullscreen_app_list_enabled_
? kBottomSeparatorBottomPadding + AppsGridView::GetTilePadding().top()
: 0;
rect.set_y(rect.bottom() - kBottomSeparatorHeight - extra_bottom_padding);
rect.set_height(kBottomSeparatorHeight);
SkColor color = is_fullscreen_app_list_enabled_ ? kBottomSeparatorColor
: kBottomSeparatorColor;
canvas->FillRect(rect, color);
}
void FolderHeaderView::ContentsChanged(views::Textfield* sender,
const base::string16& new_contents) {
// Temporarily remove from observer to ignore data change caused by us.
if (!folder_item_)
return;
folder_item_->RemoveObserver(this);
// Enforce the maximum folder name length in UI.
std::string name = base::UTF16ToUTF8(
folder_name_view_->text().substr(0, kMaxFolderNameChars));
if (name != folder_item_->name())
delegate_->SetItemName(folder_item_, name);
folder_item_->AddObserver(this);
UpdateFolderNameAccessibleName();
Layout();
}
bool FolderHeaderView::HandleKeyEvent(views::Textfield* sender,
const ui::KeyEvent& key_event) {
if (!CanProcessLeftRightKeyTraversal(key_event))
return false;
return ProcessLeftRightKeyTraversalForTextfield(folder_name_view_, key_event);
}
void FolderHeaderView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
delegate_->NavigateBack(folder_item_, event);
}
void FolderHeaderView::ItemNameChanged() {
Update();
}
} // namespace app_list