| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "ui/app_list/views/page_switcher.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "base/macros.h" | |
| 10 #include "third_party/skia/include/core/SkPath.h" | |
| 11 #include "ui/app_list/app_list_constants.h" | |
| 12 #include "ui/app_list/pagination_model.h" | |
| 13 #include "ui/gfx/animation/throb_animation.h" | |
| 14 #include "ui/gfx/canvas.h" | |
| 15 #include "ui/gfx/geometry/insets.h" | |
| 16 #include "ui/gfx/skia_util.h" | |
| 17 #include "ui/views/controls/button/custom_button.h" | |
| 18 #include "ui/views/layout/box_layout.h" | |
| 19 | |
| 20 namespace app_list { | |
| 21 | |
| 22 namespace { | |
| 23 | |
| 24 const int kPreferredHeight = 58; | |
| 25 | |
| 26 const int kMaxButtonSpacing = 18; | |
| 27 const int kMinButtonSpacing = 4; | |
| 28 const int kMaxButtonWidth = 68; | |
| 29 const int kMinButtonWidth = 28; | |
| 30 const int kButtonHeight = 6; | |
| 31 const int kButtonCornerRadius = 2; | |
| 32 const int kButtonStripPadding = 20; | |
| 33 | |
| 34 class PageSwitcherButton : public views::CustomButton { | |
| 35 public: | |
| 36 explicit PageSwitcherButton(views::ButtonListener* listener) | |
| 37 : views::CustomButton(listener), | |
| 38 button_width_(kMaxButtonWidth), | |
| 39 selected_range_(0) { | |
| 40 } | |
| 41 ~PageSwitcherButton() override {} | |
| 42 | |
| 43 void SetSelectedRange(double selected_range) { | |
| 44 if (selected_range_ == selected_range) | |
| 45 return; | |
| 46 | |
| 47 selected_range_ = selected_range; | |
| 48 SchedulePaint(); | |
| 49 } | |
| 50 | |
| 51 void set_button_width(int button_width) { button_width_ = button_width; } | |
| 52 | |
| 53 // Overridden from views::View: | |
| 54 gfx::Size CalculatePreferredSize() const override { | |
| 55 return gfx::Size(button_width_, kButtonHeight); | |
| 56 } | |
| 57 | |
| 58 void PaintButtonContents(gfx::Canvas* canvas) override { | |
| 59 if (state() == STATE_HOVERED) | |
| 60 PaintButton(canvas, kPagerHoverColor); | |
| 61 else | |
| 62 PaintButton(canvas, kPagerNormalColor); | |
| 63 } | |
| 64 | |
| 65 void OnGestureEvent(ui::GestureEvent* event) override { | |
| 66 CustomButton::OnGestureEvent(event); | |
| 67 | |
| 68 if (event->type() == ui::ET_GESTURE_TAP_DOWN) | |
| 69 SetState(views::CustomButton::STATE_HOVERED); | |
| 70 else if (event->type() == ui::ET_GESTURE_TAP_CANCEL || | |
| 71 event->type() == ui::ET_GESTURE_TAP) | |
| 72 SetState(views::CustomButton::STATE_NORMAL); | |
| 73 SchedulePaint(); | |
| 74 } | |
| 75 | |
| 76 private: | |
| 77 // Paints a button that has two rounded corner at bottom. | |
| 78 void PaintButton(gfx::Canvas* canvas, SkColor base_color) { | |
| 79 gfx::Rect rect(GetContentsBounds()); | |
| 80 rect.ClampToCenteredSize(gfx::Size(button_width_, kButtonHeight)); | |
| 81 | |
| 82 SkPath path; | |
| 83 path.addRoundRect(gfx::RectToSkRect(rect), | |
| 84 SkIntToScalar(kButtonCornerRadius), | |
| 85 SkIntToScalar(kButtonCornerRadius)); | |
| 86 | |
| 87 cc::PaintFlags flags; | |
| 88 flags.setAntiAlias(true); | |
| 89 flags.setStyle(cc::PaintFlags::kFill_Style); | |
| 90 flags.setColor(base_color); | |
| 91 canvas->DrawPath(path, flags); | |
| 92 | |
| 93 int selected_start_x = 0; | |
| 94 int selected_width = 0; | |
| 95 if (selected_range_ > 0) { | |
| 96 selected_width = selected_range_ * rect.width(); | |
| 97 } else if (selected_range_ < 0) { | |
| 98 selected_width = -selected_range_ * rect.width(); | |
| 99 selected_start_x = rect.right() - selected_width; | |
| 100 } | |
| 101 | |
| 102 if (selected_width) { | |
| 103 gfx::Rect selected_rect(rect); | |
| 104 selected_rect.set_x(selected_start_x); | |
| 105 selected_rect.set_width(selected_width); | |
| 106 | |
| 107 SkPath selected_path; | |
| 108 selected_path.addRoundRect(gfx::RectToSkRect(selected_rect), | |
| 109 SkIntToScalar(kButtonCornerRadius), | |
| 110 SkIntToScalar(kButtonCornerRadius)); | |
| 111 flags.setColor(kPagerSelectedColor); | |
| 112 canvas->DrawPath(selected_path, flags); | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 int button_width_; | |
| 117 | |
| 118 // [-1, 1] range that represents the portion of the button that should be | |
| 119 // painted with kSelectedColor. Positive range starts from left side and | |
| 120 // negative range starts from the right side. | |
| 121 double selected_range_; | |
| 122 | |
| 123 DISALLOW_COPY_AND_ASSIGN(PageSwitcherButton); | |
| 124 }; | |
| 125 | |
| 126 // Gets PageSwitcherButton at |index| in |buttons|. | |
| 127 PageSwitcherButton* GetButtonByIndex(views::View* buttons, int index) { | |
| 128 return static_cast<PageSwitcherButton*>(buttons->child_at(index)); | |
| 129 } | |
| 130 | |
| 131 } // namespace | |
| 132 | |
| 133 PageSwitcher::PageSwitcher(PaginationModel* model) | |
| 134 : model_(model), | |
| 135 buttons_(new views::View) { | |
| 136 AddChildView(buttons_); | |
| 137 | |
| 138 TotalPagesChanged(); | |
| 139 SelectedPageChanged(-1, model->selected_page()); | |
| 140 model_->AddObserver(this); | |
| 141 } | |
| 142 | |
| 143 PageSwitcher::~PageSwitcher() { | |
| 144 model_->RemoveObserver(this); | |
| 145 } | |
| 146 | |
| 147 int PageSwitcher::GetPageForPoint(const gfx::Point& point) const { | |
| 148 if (!buttons_->bounds().Contains(point)) | |
| 149 return -1; | |
| 150 | |
| 151 gfx::Point buttons_point(point); | |
| 152 views::View::ConvertPointToTarget(this, buttons_, &buttons_point); | |
| 153 | |
| 154 for (int i = 0; i < buttons_->child_count(); ++i) { | |
| 155 const views::View* button = buttons_->child_at(i); | |
| 156 if (button->bounds().Contains(buttons_point)) | |
| 157 return i; | |
| 158 } | |
| 159 | |
| 160 return -1; | |
| 161 } | |
| 162 | |
| 163 void PageSwitcher::UpdateUIForDragPoint(const gfx::Point& point) { | |
| 164 int page = GetPageForPoint(point); | |
| 165 | |
| 166 const int button_count = buttons_->child_count(); | |
| 167 if (page >= 0 && page < button_count) { | |
| 168 PageSwitcherButton* button = | |
| 169 static_cast<PageSwitcherButton*>(buttons_->child_at(page)); | |
| 170 button->SetState(views::CustomButton::STATE_HOVERED); | |
| 171 return; | |
| 172 } | |
| 173 | |
| 174 for (int i = 0; i < button_count; ++i) { | |
| 175 PageSwitcherButton* button = | |
| 176 static_cast<PageSwitcherButton*>(buttons_->child_at(i)); | |
| 177 button->SetState(views::CustomButton::STATE_NORMAL); | |
| 178 } | |
| 179 } | |
| 180 | |
| 181 gfx::Size PageSwitcher::CalculatePreferredSize() const { | |
| 182 // Always return a size with correct height so that container resize is not | |
| 183 // needed when more pages are added. | |
| 184 return gfx::Size(buttons_->GetPreferredSize().width(), | |
| 185 kPreferredHeight); | |
| 186 } | |
| 187 | |
| 188 void PageSwitcher::Layout() { | |
| 189 gfx::Rect rect(GetContentsBounds()); | |
| 190 | |
| 191 CalculateButtonWidthAndSpacing(rect.width()); | |
| 192 | |
| 193 // Makes |buttons_| horizontally center and vertically fill. | |
| 194 gfx::Size buttons_size(buttons_->GetPreferredSize()); | |
| 195 gfx::Rect buttons_bounds(rect.CenterPoint().x() - buttons_size.width() / 2, | |
| 196 rect.y(), | |
| 197 buttons_size.width(), | |
| 198 rect.height()); | |
| 199 buttons_->SetBoundsRect(gfx::IntersectRects(rect, buttons_bounds)); | |
| 200 } | |
| 201 | |
| 202 void PageSwitcher::CalculateButtonWidthAndSpacing(int contents_width) { | |
| 203 const int button_count = buttons_->child_count(); | |
| 204 if (!button_count) | |
| 205 return; | |
| 206 | |
| 207 contents_width -= 2 * kButtonStripPadding; | |
| 208 | |
| 209 int button_width = kMinButtonWidth; | |
| 210 int button_spacing = kMinButtonSpacing; | |
| 211 if (button_count > 1) { | |
| 212 button_spacing = (contents_width - button_width * button_count) / | |
| 213 (button_count - 1); | |
| 214 button_spacing = std::min(kMaxButtonSpacing, | |
| 215 std::max(kMinButtonSpacing, button_spacing)); | |
| 216 } | |
| 217 | |
| 218 button_width = (contents_width - (button_count - 1) * button_spacing) / | |
| 219 button_count; | |
| 220 button_width = std::min(kMaxButtonWidth, | |
| 221 std::max(kMinButtonWidth, button_width)); | |
| 222 | |
| 223 buttons_->SetLayoutManager(new views::BoxLayout( | |
| 224 views::BoxLayout::kHorizontal, gfx::Insets(0, kButtonStripPadding), | |
| 225 button_spacing)); | |
| 226 for (int i = 0; i < button_count; ++i) { | |
| 227 PageSwitcherButton* button = | |
| 228 static_cast<PageSwitcherButton*>(buttons_->child_at(i)); | |
| 229 button->set_button_width(button_width); | |
| 230 } | |
| 231 } | |
| 232 | |
| 233 void PageSwitcher::ButtonPressed(views::Button* sender, | |
| 234 const ui::Event& event) { | |
| 235 for (int i = 0; i < buttons_->child_count(); ++i) { | |
| 236 if (sender == static_cast<views::Button*>(buttons_->child_at(i))) { | |
| 237 model_->SelectPage(i, true /* animate */); | |
| 238 break; | |
| 239 } | |
| 240 } | |
| 241 } | |
| 242 | |
| 243 void PageSwitcher::TotalPagesChanged() { | |
| 244 buttons_->RemoveAllChildViews(true); | |
| 245 for (int i = 0; i < model_->total_pages(); ++i) { | |
| 246 PageSwitcherButton* button = new PageSwitcherButton(this); | |
| 247 button->SetSelectedRange(i == model_->selected_page() ? 1 : 0); | |
| 248 buttons_->AddChildView(button); | |
| 249 } | |
| 250 buttons_->SetVisible(model_->total_pages() > 1); | |
| 251 Layout(); | |
| 252 } | |
| 253 | |
| 254 void PageSwitcher::SelectedPageChanged(int old_selected, int new_selected) { | |
| 255 if (old_selected >= 0 && old_selected < buttons_->child_count()) | |
| 256 GetButtonByIndex(buttons_, old_selected)->SetSelectedRange(0); | |
| 257 if (new_selected >= 0 && new_selected < buttons_->child_count()) | |
| 258 GetButtonByIndex(buttons_, new_selected)->SetSelectedRange(1); | |
| 259 } | |
| 260 | |
| 261 void PageSwitcher::TransitionStarted() { | |
| 262 } | |
| 263 | |
| 264 void PageSwitcher::TransitionChanged() { | |
| 265 const int current_page = model_->selected_page(); | |
| 266 const int target_page = model_->transition().target_page; | |
| 267 | |
| 268 double progress = model_->transition().progress; | |
| 269 double remaining = progress - 1; | |
| 270 | |
| 271 if (current_page > target_page) { | |
| 272 remaining = -remaining; | |
| 273 progress = -progress; | |
| 274 } | |
| 275 | |
| 276 GetButtonByIndex(buttons_, current_page)->SetSelectedRange(remaining); | |
| 277 if (model_->is_valid_page(target_page)) | |
| 278 GetButtonByIndex(buttons_, target_page)->SetSelectedRange(progress); | |
| 279 } | |
| 280 | |
| 281 } // namespace app_list | |
| OLD | NEW |