15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/slider.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <algorithm> 8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 10ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h" 115e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkCanvas.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkColor.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkPaint.h" 16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/accessibility/ax_view_state.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 18d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/events/event.h" 19d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/slide_animation.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/point.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h" 2303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "ui/resources/grit/ui_resources.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kSlideValueChangeDurationMS = 150; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kBarImagesActive[] = { 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_SLIDER_ACTIVE_LEFT, 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_SLIDER_ACTIVE_CENTER, 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_SLIDER_PRESSED_CENTER, 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_SLIDER_PRESSED_RIGHT, 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kBarImagesDisabled[] = { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_SLIDER_DISABLED_LEFT, 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_SLIDER_DISABLED_CENTER, 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_SLIDER_DISABLED_CENTER, 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_SLIDER_DISABLED_RIGHT, 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The image chunks. 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum BorderElements { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LEFT, 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CENTER_LEFT, 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CENTER_RIGHT, 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RIGHT, 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} // namespace 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Slider::Slider(SliderListener* listener, Orientation orientation) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : listener_(listener), 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) orientation_(orientation), 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_(0.f), 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keyboard_increment_(0.1f), 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) animating_value_(0.f), 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_is_valid_(false), 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accessibility_events_enabled_(true), 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) focus_border_color_(0), 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bar_active_images_(kBarImagesActive), 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bar_disabled_images_(kBarImagesDisabled) { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnableCanvasFlippingForRTLUI(true); 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetFocusable(true); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateState(true); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Slider::~Slider() { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::SetValue(float value) { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetValueInternal(value, VALUE_CHANGED_BY_API); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::SetKeyboardIncrement(float increment) { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keyboard_increment_ = increment; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::SetValueInternal(float value, SliderChangeReason reason) { 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool old_value_valid = value_is_valid_; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_is_valid_ = true; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value < 0.0) 86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) value = 0.0; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (value > 1.0) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = 1.0; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value_ == value) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float old_value = value_; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_ = value; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (listener_) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listener_->SliderValueChanged(this, value_, old_value, reason); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (old_value_valid && base::MessageLoop::current()) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do not animate when setting the value of the slider for the first time. 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There is no message-loop when running tests. So we cannot animate then. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) animating_value_ = old_value; 100d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) move_animation_.reset(new gfx::SlideAnimation(this)); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) move_animation_->SetSlideDuration(kSlideValueChangeDurationMS); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) move_animation_->Show(); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AnimationProgressed(move_animation_.get()); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (accessibility_events_enabled_ && GetWidget()) { 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) NotifyAccessibilityEvent( 109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ui::AX_EVENT_VALUE_CHANGED, true); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::PrepareForMove(const gfx::Point& point) { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Try to remember the position of the mouse cursor on the button. 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Insets inset = GetInsets(); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect content = GetContentsBounds(); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float value = move_animation_.get() && move_animation_->is_animating() ? 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) animating_value_ : value_; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For the horizontal orientation. 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int thumb_x = value * (content.width() - thumb_->width()); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int candidate_x = (base::i18n::IsRTL() ? 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) width() - (point.x() - inset.left()) : 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) point.x() - inset.left()) - thumb_x; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (candidate_x >= 0 && candidate_x < thumb_->width()) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) initial_button_offset_.set_x(candidate_x); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) initial_button_offset_.set_x(thumb_->width() / 2); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For the vertical orientation. 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int thumb_y = (1.0 - value) * (content.height() - thumb_->height()); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int candidate_y = point.y() - thumb_y; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (candidate_y >= 0 && candidate_y < thumb_->height()) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) initial_button_offset_.set_y(candidate_y); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) initial_button_offset_.set_y(thumb_->height() / 2); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::MoveButtonTo(const gfx::Point& point) { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Insets inset = GetInsets(); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Calculate the value. 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (orientation_ == HORIZONTAL) { 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int amount = base::i18n::IsRTL() ? 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) width() - inset.left() - point.x() - initial_button_offset_.x() : 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) point.x() - inset.left() - initial_button_offset_.x(); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetValueInternal(static_cast<float>(amount) / 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (width() - inset.width() - thumb_->width()), 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VALUE_CHANGED_BY_USER); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetValueInternal( 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1.0f - static_cast<float>(point.y() - initial_button_offset_.y()) / 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (height() - thumb_->height()), 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VALUE_CHANGED_BY_USER); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::UpdateState(bool control_on) { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (control_on) { 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thumb_ = rb.GetImageNamed(IDR_SLIDER_ACTIVE_THUMB).ToImageSkia(); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < 4; ++i) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) images_[i] = rb.GetImageNamed(bar_active_images_[i]).ToImageSkia(); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thumb_ = rb.GetImageNamed(IDR_SLIDER_DISABLED_THUMB).ToImageSkia(); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < 4; ++i) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) images_[i] = rb.GetImageNamed(bar_disabled_images_[i]).ToImageSkia(); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bar_height_ = images_[LEFT]->height(); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void Slider::SetAccessibleName(const base::string16& name) { 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accessible_name_ = name; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 176a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void Slider::OnPaintFocus(gfx::Canvas* canvas) { 177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!HasFocus()) 178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 180a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!focus_border_color_) { 181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) canvas->DrawFocusRect(GetLocalBounds()); 182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } else if (HasFocus()) { 183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) canvas->DrawSolidFocusRect( 184a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) gfx::Rect(1, 1, width() - 3, height() - 3), 185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) focus_border_color_); 186a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 188a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)gfx::Size Slider::GetPreferredSize() const { 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kSizeMajor = 200; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kSizeMinor = 40; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (orientation_ == HORIZONTAL) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::Size(std::max(width(), kSizeMajor), kSizeMinor); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::Size(kSizeMinor, std::max(height(), kSizeMajor)); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::OnPaint(gfx::Canvas* canvas) { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect content = GetContentsBounds(); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float value = move_animation_.get() && move_animation_->is_animating() ? 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) animating_value_ : value_; 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (orientation_ == HORIZONTAL) { 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Paint slider bar with image resources. 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Inset the slider bar a little bit, so that the left or the right end of 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the slider bar will not be exposed under the thumb button when the thumb 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // button slides to the left most or right most position. 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kBarInsetX = 2; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bar_width = content.width() - kBarInsetX * 2; 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bar_cy = content.height() / 2 - bar_height_ / 2; 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int w = content.width() - thumb_->width(); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int full = value * w; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int middle = std::max(full, images_[LEFT]->width()); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->Save(); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->Translate(gfx::Vector2d(kBarInsetX, bar_cy)); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawImageInt(*images_[LEFT], 0, 0); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawImageInt(*images_[RIGHT], 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bar_width - images_[RIGHT]->width(), 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0); 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->TileImageInt(*images_[CENTER_LEFT], 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) images_[LEFT]->width(), 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) middle - images_[LEFT]->width(), 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bar_height_); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->TileImageInt(*images_[CENTER_RIGHT], 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) middle, 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bar_width - middle - images_[RIGHT]->width(), 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bar_height_); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->Restore(); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Paint slider thumb. 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int button_cx = content.x() + full; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int thumb_y = content.height() / 2 - thumb_->height() / 2; 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawImageInt(*thumb_, button_cx, thumb_y); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(jennyz): draw vertical slider bar with resources. 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(sad): The painting code should use NativeTheme for various 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // platforms. 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kButtonRadius = thumb_->width() / 2; 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kLineThickness = bar_height_ / 2; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkColor kFullColor = SkColorSetARGB(125, 0, 0, 0); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkColor kEmptyColor = SkColorSetARGB(50, 0, 0, 0); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int h = content.height() - thumb_->height(); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int full = value * h; 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int empty = h - full; 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x = content.width() / 2 - kLineThickness / 2; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->FillRect(gfx::Rect(x, content.y() + kButtonRadius, 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kLineThickness, empty), 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kEmptyColor); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->FillRect(gfx::Rect(x, content.y() + empty + 2 * kButtonRadius, 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kLineThickness, full), 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kFullColor); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(mtomasz): We draw a thumb here because so far it is the same 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for horizontal and vertical orientations. If it is different, then 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we will need a separate resource. 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int button_cy = content.y() + h - full; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int thumb_x = content.width() / 2 - thumb_->width() / 2; 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawImageInt(*thumb_, thumb_x, button_cy); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) View::OnPaint(canvas); 266a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) OnPaintFocus(canvas); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Slider::OnMousePressed(const ui::MouseEvent& event) { 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!event.IsOnlyLeftMouseButton()) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 272f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) OnSliderDragStarted(); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrepareForMove(event.location()); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MoveButtonTo(event.location()); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Slider::OnMouseDragged(const ui::MouseEvent& event) { 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MoveButtonTo(event.location()); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::OnMouseReleased(const ui::MouseEvent& event) { 284f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) OnSliderDragEnded(); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Slider::OnKeyPressed(const ui::KeyEvent& event) { 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (orientation_ == HORIZONTAL) { 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.key_code() == ui::VKEY_LEFT) { 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetValueInternal(value_ - keyboard_increment_, VALUE_CHANGED_BY_USER); 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (event.key_code() == ui::VKEY_RIGHT) { 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetValueInternal(value_ + keyboard_increment_, VALUE_CHANGED_BY_USER); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.key_code() == ui::VKEY_DOWN) { 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetValueInternal(value_ - keyboard_increment_, VALUE_CHANGED_BY_USER); 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (event.key_code() == ui::VKEY_UP) { 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetValueInternal(value_ + keyboard_increment_, VALUE_CHANGED_BY_USER); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 308a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid Slider::OnFocus() { 309a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch View::OnFocus(); 310a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch SchedulePaint(); 311a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 312a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 313a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid Slider::OnBlur() { 314a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch View::OnBlur(); 315a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch SchedulePaint(); 316a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 317a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Slider::OnGestureEvent(ui::GestureEvent* event) { 319f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) switch (event->type()) { 320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // In a multi point gesture only the touch point will generate 321f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // an ET_GESTURE_TAP_DOWN event. 322f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case ui::ET_GESTURE_TAP_DOWN: 323f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) OnSliderDragStarted(); 324f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) PrepareForMove(event->location()); 325f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Intentional fall through to next case. 326f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case ui::ET_GESTURE_SCROLL_BEGIN: 327f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case ui::ET_GESTURE_SCROLL_UPDATE: 328f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) MoveButtonTo(event->location()); 329f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) event->SetHandled(); 330f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) break; 331f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case ui::ET_GESTURE_END: 332f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) MoveButtonTo(event->location()); 333f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) event->SetHandled(); 334f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (event->details().touch_points() <= 1) 335f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) OnSliderDragEnded(); 336f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) break; 337f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) default: 338f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) break; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 342d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void Slider::AnimationProgressed(const gfx::Animation* animation) { 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) animating_value_ = animation->CurrentValueBetween(animating_value_, value_); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 347a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void Slider::GetAccessibleState(ui::AXViewState* state) { 348a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state->role = ui::AX_ROLE_SLIDER; 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->name = accessible_name_; 3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) state->value = base::UTF8ToUTF16( 351f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::StringPrintf("%d%%", static_cast<int>(value_ * 100 + 0.5))); 352f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 353f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 354f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void Slider::OnSliderDragStarted() { 355f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (listener_) 356f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) listener_->SliderDragStarted(this); 357f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 358f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 359f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void Slider::OnSliderDragEnded() { 360f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (listener_) 361f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) listener_->SliderDragEnded(this); 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace views 365