Make castv2 performance test work.
[chromium-blink-merge.git] / ui / views / controls / table / table_header.cc
blob5473490f0d6f7460c78e5e7faafdd999412cef83
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/views/controls/table/table_header.h"
7 #include "third_party/skia/include/core/SkColor.h"
8 #include "ui/base/cursor/cursor.h"
9 #include "ui/gfx/canvas.h"
10 #include "ui/gfx/text_utils.h"
11 #include "ui/native_theme/native_theme.h"
12 #include "ui/views/background.h"
13 #include "ui/views/controls/table/table_utils.h"
14 #include "ui/views/controls/table/table_view.h"
15 #include "ui/views/native_cursor.h"
17 namespace views {
19 namespace {
21 const int kVerticalPadding = 4;
23 // The minimum width we allow a column to go down to.
24 const int kMinColumnWidth = 10;
26 // Distace from edge columns can be resized by.
27 const int kResizePadding = 5;
29 // Amount of space above/below the separator.
30 const int kSeparatorPadding = 4;
32 const SkColor kTextColor = SK_ColorBLACK;
33 const SkColor kBackgroundColor1 = SkColorSetRGB(0xF9, 0xF9, 0xF9);
34 const SkColor kBackgroundColor2 = SkColorSetRGB(0xE8, 0xE8, 0xE8);
35 const SkColor kSeparatorColor = SkColorSetRGB(0xAA, 0xAA, 0xAA);
37 // Size of the sort indicator (doesn't include padding).
38 const int kSortIndicatorSize = 8;
40 } // namespace
42 // static
43 const char TableHeader::kViewClassName[] = "TableHeader";
44 // static
45 const int TableHeader::kHorizontalPadding = 7;
46 // static
47 const int TableHeader::kSortIndicatorWidth = kSortIndicatorSize +
48 TableHeader::kHorizontalPadding * 2;
50 typedef std::vector<TableView::VisibleColumn> Columns;
52 TableHeader::TableHeader(TableView* table) : table_(table) {
53 set_background(Background::CreateVerticalGradientBackground(
54 kBackgroundColor1, kBackgroundColor2));
57 TableHeader::~TableHeader() {
60 void TableHeader::Layout() {
61 SetBounds(x(), y(), table_->width(), GetPreferredSize().height());
64 void TableHeader::OnPaint(gfx::Canvas* canvas) {
65 // Paint the background and a separator at the bottom. The separator color
66 // matches that of the border around the scrollview.
67 OnPaintBackground(canvas);
68 SkColor border_color = GetNativeTheme()->GetSystemColor(
69 ui::NativeTheme::kColorId_UnfocusedBorderColor);
70 canvas->DrawLine(gfx::Point(0, height() - 1),
71 gfx::Point(width(), height() - 1), border_color);
73 const Columns& columns = table_->visible_columns();
74 const int sorted_column_id = table_->sort_descriptors().empty() ? -1 :
75 table_->sort_descriptors()[0].column_id;
76 for (size_t i = 0; i < columns.size(); ++i) {
77 if (columns[i].width >= 2) {
78 const int separator_x = GetMirroredXInView(
79 columns[i].x + columns[i].width - 1);
80 canvas->DrawLine(gfx::Point(separator_x, kSeparatorPadding),
81 gfx::Point(separator_x, height() - kSeparatorPadding),
82 kSeparatorColor);
85 const int x = columns[i].x + kHorizontalPadding;
86 int width = columns[i].width - kHorizontalPadding - kHorizontalPadding;
87 if (width <= 0)
88 continue;
90 const int title_width =
91 gfx::GetStringWidth(columns[i].column.title, font_list_);
92 const bool paint_sort_indicator =
93 (columns[i].column.id == sorted_column_id &&
94 title_width + kSortIndicatorWidth <= width);
96 if (paint_sort_indicator &&
97 columns[i].column.alignment == ui::TableColumn::RIGHT) {
98 width -= kSortIndicatorWidth;
101 canvas->DrawStringRectWithFlags(
102 columns[i].column.title, font_list_, kTextColor,
103 gfx::Rect(GetMirroredXWithWidthInView(x, width), kVerticalPadding,
104 width, height() - kVerticalPadding * 2),
105 TableColumnAlignmentToCanvasAlignment(columns[i].column.alignment));
107 if (paint_sort_indicator) {
108 SkPaint paint;
109 paint.setColor(kTextColor);
110 paint.setStyle(SkPaint::kFill_Style);
111 paint.setAntiAlias(true);
113 int indicator_x = 0;
114 ui::TableColumn::Alignment alignment = columns[i].column.alignment;
115 if (base::i18n::IsRTL()) {
116 if (alignment == ui::TableColumn::LEFT)
117 alignment = ui::TableColumn::RIGHT;
118 else if (alignment == ui::TableColumn::RIGHT)
119 alignment = ui::TableColumn::LEFT;
121 switch (alignment) {
122 case ui::TableColumn::LEFT:
123 indicator_x = x + title_width;
124 break;
125 case ui::TableColumn::CENTER:
126 indicator_x = x + width / 2;
127 break;
128 case ui::TableColumn::RIGHT:
129 indicator_x = x + width;
130 break;
133 const int scale = base::i18n::IsRTL() ? -1 : 1;
134 indicator_x += (kSortIndicatorWidth - kSortIndicatorSize) / 2;
135 indicator_x = GetMirroredXInView(indicator_x);
136 int indicator_y = height() / 2 - kSortIndicatorSize / 2;
137 SkPath indicator_path;
138 if (table_->sort_descriptors()[0].ascending) {
139 indicator_path.moveTo(
140 SkIntToScalar(indicator_x),
141 SkIntToScalar(indicator_y + kSortIndicatorSize));
142 indicator_path.lineTo(
143 SkIntToScalar(indicator_x + kSortIndicatorSize * scale),
144 SkIntToScalar(indicator_y + kSortIndicatorSize));
145 indicator_path.lineTo(
146 SkIntToScalar(indicator_x + kSortIndicatorSize / 2 * scale),
147 SkIntToScalar(indicator_y));
148 } else {
149 indicator_path.moveTo(SkIntToScalar(indicator_x),
150 SkIntToScalar(indicator_y));
151 indicator_path.lineTo(
152 SkIntToScalar(indicator_x + kSortIndicatorSize * scale),
153 SkIntToScalar(indicator_y));
154 indicator_path.lineTo(
155 SkIntToScalar(indicator_x + kSortIndicatorSize / 2 * scale),
156 SkIntToScalar(indicator_y + kSortIndicatorSize));
158 indicator_path.close();
159 canvas->DrawPath(indicator_path, paint);
164 const char* TableHeader::GetClassName() const {
165 return kViewClassName;
168 gfx::Size TableHeader::GetPreferredSize() const {
169 return gfx::Size(1, kVerticalPadding * 2 + font_list_.GetHeight());
172 gfx::NativeCursor TableHeader::GetCursor(const ui::MouseEvent& event) {
173 return GetResizeColumn(GetMirroredXInView(event.x())) != -1 ?
174 GetNativeColumnResizeCursor() : View::GetCursor(event);
177 bool TableHeader::OnMousePressed(const ui::MouseEvent& event) {
178 if (event.IsOnlyLeftMouseButton()) {
179 StartResize(event);
180 return true;
183 // Return false so that context menus on ancestors work.
184 return false;
187 bool TableHeader::OnMouseDragged(const ui::MouseEvent& event) {
188 ContinueResize(event);
189 return true;
192 void TableHeader::OnMouseReleased(const ui::MouseEvent& event) {
193 const bool was_resizing = resize_details_ != NULL;
194 resize_details_.reset();
195 if (!was_resizing && event.IsOnlyLeftMouseButton())
196 ToggleSortOrder(event);
199 void TableHeader::OnMouseCaptureLost() {
200 if (is_resizing()) {
201 table_->SetVisibleColumnWidth(resize_details_->column_index,
202 resize_details_->initial_width);
204 resize_details_.reset();
207 void TableHeader::OnGestureEvent(ui::GestureEvent* event) {
208 switch (event->type()) {
209 case ui::ET_GESTURE_TAP:
210 if (!resize_details_.get())
211 ToggleSortOrder(*event);
212 break;
213 case ui::ET_GESTURE_SCROLL_BEGIN:
214 StartResize(*event);
215 break;
216 case ui::ET_GESTURE_SCROLL_UPDATE:
217 ContinueResize(*event);
218 break;
219 case ui::ET_GESTURE_SCROLL_END:
220 resize_details_.reset();
221 break;
222 default:
223 return;
225 event->SetHandled();
228 bool TableHeader::StartResize(const ui::LocatedEvent& event) {
229 if (is_resizing())
230 return false;
232 const int index = GetResizeColumn(GetMirroredXInView(event.x()));
233 if (index == -1)
234 return false;
236 resize_details_.reset(new ColumnResizeDetails);
237 resize_details_->column_index = index;
238 resize_details_->initial_x = event.root_location().x();
239 resize_details_->initial_width = table_->visible_columns()[index].width;
240 return true;
243 void TableHeader::ContinueResize(const ui::LocatedEvent& event) {
244 if (!is_resizing())
245 return;
247 const int scale = base::i18n::IsRTL() ? -1 : 1;
248 const int delta = scale *
249 (event.root_location().x() - resize_details_->initial_x);
250 table_->SetVisibleColumnWidth(
251 resize_details_->column_index,
252 std::max(kMinColumnWidth, resize_details_->initial_width + delta));
255 void TableHeader::ToggleSortOrder(const ui::LocatedEvent& event) {
256 if (table_->visible_columns().empty())
257 return;
259 const int x = GetMirroredXInView(event.x());
260 const int index = GetClosestVisibleColumnIndex(table_, x);
261 const TableView::VisibleColumn& column(table_->visible_columns()[index]);
262 if (x >= column.x && x < column.x + column.width && event.y() >= 0 &&
263 event.y() < height())
264 table_->ToggleSortOrder(index);
267 int TableHeader::GetResizeColumn(int x) const {
268 const Columns& columns(table_->visible_columns());
269 if (columns.empty())
270 return -1;
272 const int index = GetClosestVisibleColumnIndex(table_, x);
273 DCHECK_NE(-1, index);
274 const TableView::VisibleColumn& column(table_->visible_columns()[index]);
275 if (index > 0 && x >= column.x - kResizePadding &&
276 x <= column.x + kResizePadding) {
277 return index - 1;
279 const int max_x = column.x + column.width;
280 return (x >= max_x - kResizePadding && x <= max_x + kResizePadding) ?
281 index : -1;
284 } // namespace views