blob: 63ea37d20bc93619258e8e10d4b7af624b03579b [file] [log] [blame]
// Copyright 2017 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/views/layout/layout_provider.h"
#include "base/logging.h"
#include "ui/base/material_design/material_design_controller.h"
#include "ui/gfx/font_list.h"
#include "ui/views/style/typography.h"
#include "ui/views/views_delegate.h"
namespace views {
namespace {
LayoutProvider* g_layout_delegate = nullptr;
} // namespace
LayoutProvider::LayoutProvider() {
g_layout_delegate = this;
}
LayoutProvider::~LayoutProvider() {
if (this == g_layout_delegate)
g_layout_delegate = nullptr;
}
// static
LayoutProvider* LayoutProvider::Get() {
return g_layout_delegate;
}
// static
int LayoutProvider::GetControlHeightForFont(int context,
int style,
const gfx::FontList& font) {
return std::max(views::style::GetLineHeight(context, style),
font.GetHeight()) +
Get()->GetDistanceMetric(DISTANCE_CONTROL_VERTICAL_TEXT_PADDING) * 2;
}
gfx::Insets LayoutProvider::GetInsetsMetric(int metric) const {
DCHECK_GE(metric, VIEWS_INSETS_START);
DCHECK_LT(metric, VIEWS_INSETS_MAX);
switch (metric) {
case InsetsMetric::INSETS_DIALOG:
case InsetsMetric::INSETS_DIALOG_SUBSECTION:
return gfx::Insets(13, 13);
case InsetsMetric::INSETS_DIALOG_BUTTON_ROW: {
const gfx::Insets dialog_insets = GetInsetsMetric(INSETS_DIALOG);
return gfx::Insets(0, dialog_insets.left(), dialog_insets.bottom(),
dialog_insets.right());
}
case InsetsMetric::INSETS_DIALOG_TITLE: {
const gfx::Insets dialog_insets = GetInsetsMetric(INSETS_DIALOG);
return gfx::Insets(dialog_insets.top(), dialog_insets.left(), 0,
dialog_insets.right());
}
case InsetsMetric::INSETS_TOOLTIP_BUBBLE:
return gfx::Insets(8);
case InsetsMetric::INSETS_CHECKBOX_RADIO_BUTTON:
return gfx::Insets(5, 6);
case InsetsMetric::INSETS_VECTOR_IMAGE_BUTTON:
return gfx::Insets(4);
case InsetsMetric::INSETS_LABEL_BUTTON:
return gfx::Insets(5, 6);
}
NOTREACHED();
return gfx::Insets();
}
int LayoutProvider::GetDistanceMetric(int metric) const {
DCHECK_GE(metric, VIEWS_DISTANCE_START);
DCHECK_LT(metric, VIEWS_DISTANCE_MAX);
switch (metric) {
case DistanceMetric::DISTANCE_BUTTON_HORIZONTAL_PADDING:
return 16;
case DistanceMetric::DISTANCE_BUTTON_MAX_LINKABLE_WIDTH:
return 0;
case DistanceMetric::DISTANCE_CLOSE_BUTTON_MARGIN:
return 7;
case DistanceMetric::DISTANCE_CONTROL_VERTICAL_TEXT_PADDING:
return 4;
case DistanceMetric::DISTANCE_DIALOG_BUTTON_MINIMUM_WIDTH:
return 75;
case DistanceMetric::DISTANCE_DIALOG_CONTENT_MARGIN_BOTTOM_CONTROL:
case DistanceMetric::DISTANCE_DIALOG_CONTENT_MARGIN_BOTTOM_TEXT:
case DistanceMetric::DISTANCE_DIALOG_CONTENT_MARGIN_TOP_CONTROL:
case DistanceMetric::DISTANCE_DIALOG_CONTENT_MARGIN_TOP_TEXT:
return 13;
case DistanceMetric::DISTANCE_RELATED_BUTTON_HORIZONTAL:
return 6;
case DistanceMetric::DISTANCE_RELATED_CONTROL_HORIZONTAL:
return 8;
case DistanceMetric::DISTANCE_RELATED_CONTROL_VERTICAL:
return 8;
case DistanceMetric::DISTANCE_RELATED_LABEL_HORIZONTAL:
return 10;
case DistanceMetric::DISTANCE_DIALOG_SCROLLABLE_AREA_MAX_HEIGHT:
return 160;
case DistanceMetric::DISTANCE_TABLE_CELL_HORIZONTAL_MARGIN:
return 10;
case DistanceMetric::DISTANCE_TEXTFIELD_HORIZONTAL_TEXT_PADDING:
return 4;
case DistanceMetric::DISTANCE_UNRELATED_CONTROL_VERTICAL:
return 20;
}
NOTREACHED();
return 0;
}
const TypographyProvider& LayoutProvider::GetTypographyProvider() const {
return typography_provider_;
}
int LayoutProvider::GetSnappedDialogWidth(int min_width) const {
// This is an arbitrary value, but it's a good arbitrary value. Some dialogs
// have very small widths for their contents views, which causes ugly
// title-wrapping where a two-word title is split across multiple lines or
// similar. To prevent that, forbid any snappable dialog from being narrower
// than this value. In principle it's possible to factor in the title width
// here, but it is not really worth the complexity.
return std::max(min_width, 320);
}
gfx::Insets LayoutProvider::GetDialogInsetsForContentType(
DialogContentType leading,
DialogContentType trailing) const {
const int top_margin =
leading == CONTROL
? GetDistanceMetric(DISTANCE_DIALOG_CONTENT_MARGIN_TOP_CONTROL)
: GetDistanceMetric(DISTANCE_DIALOG_CONTENT_MARGIN_TOP_TEXT);
const int bottom_margin =
trailing == CONTROL
? GetDistanceMetric(DISTANCE_DIALOG_CONTENT_MARGIN_BOTTOM_CONTROL)
: GetDistanceMetric(DISTANCE_DIALOG_CONTENT_MARGIN_BOTTOM_TEXT);
const gfx::Insets dialog_insets = GetInsetsMetric(INSETS_DIALOG);
return gfx::Insets(top_margin, dialog_insets.left(), bottom_margin,
dialog_insets.right());
}
int LayoutProvider::GetCornerRadiusMetric(EmphasisMetric emphasis_metric,
const gfx::Size& size) const {
const bool touch_ui = ui::MaterialDesignController::touch_ui();
switch (emphasis_metric) {
case views::EMPHASIS_NONE:
NOTREACHED();
return 0;
case EMPHASIS_LOW:
case EMPHASIS_MEDIUM:
return touch_ui ? 4 : 2;
case EMPHASIS_HIGH:
return touch_ui ? 8 : 4;
case EMPHASIS_MAXIMUM:
return touch_ui ? std::min(size.width(), size.height()) / 2 : 4;
}
}
int LayoutProvider::GetShadowElevationMetric(
EmphasisMetric emphasis_metric) const {
// Return a value similar to the (deprecated) default shadow style for bubbles
// and dialogs.
return 3;
}
gfx::ShadowValues LayoutProvider::MakeShadowValues(int elevation,
SkColor color) const {
return gfx::ShadowValue::MakeMdShadowValues(elevation, color);
}
} // namespace views