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) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 8ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h" 95e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h" 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/ui_resources.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkCanvas.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkColor.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkPaint.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/accessibility/accessible_view_state.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/animation/slide_animation.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/events/event.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/point.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kSlideValueChangeDurationMS = 150; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kBarImagesActive[] = { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_SLIDER_ACTIVE_LEFT, 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_SLIDER_ACTIVE_CENTER, 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_SLIDER_PRESSED_CENTER, 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_SLIDER_PRESSED_RIGHT, 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kBarImagesDisabled[] = { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_SLIDER_DISABLED_LEFT, 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_SLIDER_DISABLED_CENTER, 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_SLIDER_DISABLED_CENTER, 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_SLIDER_DISABLED_RIGHT, 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The image chunks. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum BorderElements { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LEFT, 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CENTER_LEFT, 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CENTER_RIGHT, 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RIGHT, 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Slider::Slider(SliderListener* listener, Orientation orientation) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : listener_(listener), 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) orientation_(orientation), 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_(0.f), 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keyboard_increment_(0.1f), 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) animating_value_(0.f), 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_is_valid_(false), 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accessibility_events_enabled_(true), 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) focus_border_color_(0), 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bar_active_images_(kBarImagesActive), 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bar_disabled_images_(kBarImagesDisabled) { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnableCanvasFlippingForRTLUI(true); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_focusable(true); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateState(true); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Slider::~Slider() { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::SetValue(float value) { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetValueInternal(value, VALUE_CHANGED_BY_API); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::SetKeyboardIncrement(float increment) { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keyboard_increment_ = increment; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::SetValueInternal(float value, SliderChangeReason reason) { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool old_value_valid = value_is_valid_; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_is_valid_ = true; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value < 0.0) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = 0.0; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (value > 1.0) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = 1.0; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value_ == value) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float old_value = value_; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_ = value; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (listener_) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listener_->SliderValueChanged(this, value_, old_value, reason); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (old_value_valid && base::MessageLoop::current()) { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do not animate when setting the value of the slider for the first time. 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There is no message-loop when running tests. So we cannot animate then. 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) animating_value_ = old_value; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) move_animation_.reset(new ui::SlideAnimation(this)); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) move_animation_->SetSlideDuration(kSlideValueChangeDurationMS); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) move_animation_->Show(); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AnimationProgressed(move_animation_.get()); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (accessibility_events_enabled_ && GetWidget()) { 106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) NotifyAccessibilityEvent( 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ui::AccessibilityTypes::EVENT_VALUE_CHANGED, true); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::PrepareForMove(const gfx::Point& point) { 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Try to remember the position of the mouse cursor on the button. 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Insets inset = GetInsets(); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect content = GetContentsBounds(); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float value = move_animation_.get() && move_animation_->is_animating() ? 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) animating_value_ : value_; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For the horizontal orientation. 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int thumb_x = value * (content.width() - thumb_->width()); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int candidate_x = (base::i18n::IsRTL() ? 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) width() - (point.x() - inset.left()) : 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) point.x() - inset.left()) - thumb_x; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (candidate_x >= 0 && candidate_x < thumb_->width()) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) initial_button_offset_.set_x(candidate_x); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) initial_button_offset_.set_x(thumb_->width() / 2); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For the vertical orientation. 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int thumb_y = (1.0 - value) * (content.height() - thumb_->height()); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int candidate_y = point.y() - thumb_y; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (candidate_y >= 0 && candidate_y < thumb_->height()) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) initial_button_offset_.set_y(candidate_y); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) initial_button_offset_.set_y(thumb_->height() / 2); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::MoveButtonTo(const gfx::Point& point) { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Insets inset = GetInsets(); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Calculate the value. 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (orientation_ == HORIZONTAL) { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int amount = base::i18n::IsRTL() ? 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) width() - inset.left() - point.x() - initial_button_offset_.x() : 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) point.x() - inset.left() - initial_button_offset_.x(); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetValueInternal(static_cast<float>(amount) / 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (width() - inset.width() - thumb_->width()), 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VALUE_CHANGED_BY_USER); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetValueInternal( 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1.0f - static_cast<float>(point.y() - initial_button_offset_.y()) / 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (height() - thumb_->height()), 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VALUE_CHANGED_BY_USER); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::UpdateState(bool control_on) { 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (control_on) { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thumb_ = rb.GetImageNamed(IDR_SLIDER_ACTIVE_THUMB).ToImageSkia(); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < 4; ++i) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) images_[i] = rb.GetImageNamed(bar_active_images_[i]).ToImageSkia(); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thumb_ = rb.GetImageNamed(IDR_SLIDER_DISABLED_THUMB).ToImageSkia(); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < 4; ++i) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) images_[i] = rb.GetImageNamed(bar_disabled_images_[i]).ToImageSkia(); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bar_height_ = images_[LEFT]->height(); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::SetAccessibleName(const string16& name) { 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accessible_name_ = name; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size Slider::GetPreferredSize() { 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kSizeMajor = 200; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kSizeMinor = 40; 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (orientation_ == HORIZONTAL) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::Size(std::max(width(), kSizeMajor), kSizeMinor); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::Size(kSizeMinor, std::max(height(), kSizeMajor)); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::OnPaint(gfx::Canvas* canvas) { 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect content = GetContentsBounds(); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float value = move_animation_.get() && move_animation_->is_animating() ? 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) animating_value_ : value_; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (orientation_ == HORIZONTAL) { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Paint slider bar with image resources. 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Inset the slider bar a little bit, so that the left or the right end of 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the slider bar will not be exposed under the thumb button when the thumb 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // button slides to the left most or right most position. 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kBarInsetX = 2; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bar_width = content.width() - kBarInsetX * 2; 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bar_cy = content.height() / 2 - bar_height_ / 2; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int w = content.width() - thumb_->width(); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int full = value * w; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int middle = std::max(full, images_[LEFT]->width()); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->Save(); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->Translate(gfx::Vector2d(kBarInsetX, bar_cy)); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawImageInt(*images_[LEFT], 0, 0); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawImageInt(*images_[RIGHT], 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bar_width - images_[RIGHT]->width(), 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0); 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->TileImageInt(*images_[CENTER_LEFT], 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) images_[LEFT]->width(), 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) middle - images_[LEFT]->width(), 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bar_height_); 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->TileImageInt(*images_[CENTER_RIGHT], 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) middle, 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bar_width - middle - images_[RIGHT]->width(), 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bar_height_); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->Restore(); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Paint slider thumb. 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int button_cx = content.x() + full; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int thumb_y = content.height() / 2 - thumb_->height() / 2; 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawImageInt(*thumb_, button_cx, thumb_y); 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(jennyz): draw vertical slider bar with resources. 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(sad): The painting code should use NativeTheme for various 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // platforms. 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kButtonRadius = thumb_->width() / 2; 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kLineThickness = bar_height_ / 2; 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkColor kFullColor = SkColorSetARGB(125, 0, 0, 0); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkColor kEmptyColor = SkColorSetARGB(50, 0, 0, 0); 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int h = content.height() - thumb_->height(); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int full = value * h; 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int empty = h - full; 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x = content.width() / 2 - kLineThickness / 2; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->FillRect(gfx::Rect(x, content.y() + kButtonRadius, 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kLineThickness, empty), 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kEmptyColor); 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->FillRect(gfx::Rect(x, content.y() + empty + 2 * kButtonRadius, 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kLineThickness, full), 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kFullColor); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(mtomasz): We draw a thumb here because so far it is the same 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for horizontal and vertical orientations. If it is different, then 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we will need a separate resource. 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int button_cy = content.y() + h - full; 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int thumb_x = content.width() / 2 - thumb_->width() / 2; 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawImageInt(*thumb_, thumb_x, button_cy); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) View::OnPaint(canvas); 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Slider::OnMousePressed(const ui::MouseEvent& event) { 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!event.IsOnlyLeftMouseButton()) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (listener_) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listener_->SliderDragStarted(this); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrepareForMove(event.location()); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MoveButtonTo(event.location()); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Slider::OnMouseDragged(const ui::MouseEvent& event) { 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MoveButtonTo(event.location()); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::OnMouseReleased(const ui::MouseEvent& event) { 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (listener_) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listener_->SliderDragEnded(this); 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Slider::OnKeyPressed(const ui::KeyEvent& event) { 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (orientation_ == HORIZONTAL) { 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.key_code() == ui::VKEY_LEFT) { 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetValueInternal(value_ - keyboard_increment_, VALUE_CHANGED_BY_USER); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (event.key_code() == ui::VKEY_RIGHT) { 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetValueInternal(value_ + keyboard_increment_, VALUE_CHANGED_BY_USER); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.key_code() == ui::VKEY_DOWN) { 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetValueInternal(value_ - keyboard_increment_, VALUE_CHANGED_BY_USER); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (event.key_code() == ui::VKEY_UP) { 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetValueInternal(value_ + keyboard_increment_, VALUE_CHANGED_BY_USER); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Slider::OnGestureEvent(ui::GestureEvent* event) { 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event->type() == ui::ET_GESTURE_TAP_DOWN) { 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrepareForMove(event->location()); 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MoveButtonTo(event->location()); 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) event->SetHandled(); 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (event->type() == ui::ET_GESTURE_SCROLL_UPDATE || 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) event->type() == ui::ET_GESTURE_SCROLL_END) { 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MoveButtonTo(event->location()); 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) event->SetHandled(); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::AnimationProgressed(const ui::Animation* animation) { 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) animating_value_ = animation->CurrentValueBetween(animating_value_, value_); 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::GetAccessibleState(ui::AccessibleViewState* state) { 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->role = ui::AccessibilityTypes::ROLE_SLIDER; 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->name = accessible_name_; 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->value = UTF8ToUTF16( 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::StringPrintf("%d%%", (int)(value_ * 100 + 0.5))); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Slider::OnPaintFocusBorder(gfx::Canvas* canvas) { 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!focus_border_color_) { 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) View::OnPaintFocusBorder(canvas); 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (HasFocus() && (focusable() || IsAccessibilityFocusable())) { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawRect(gfx::Rect(1, 1, width() - 3, height() - 3), 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) focus_border_color_); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace views 329