blob: 5e0a5afaead9db4fe5e410d2b6467ff4be04bbc7 [file]
// Copyright 2015 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.
import 'package:flutter/gestures.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'colors.dart';
import 'theme.dart';
const double _kThumbRadius = 6.0;
const double _kReactionRadius = 16.0;
const double _kTrackWidth = 144.0;
const int _kReactionAlpha = 0x33;
class Slider extends StatelessComponent {
Slider({ Key key, this.value, this.onChanged })
: super(key: key);
final double value;
final ValueChanged<double> onChanged;
Widget build(BuildContext context) {
return new _SliderRenderObjectWidget(
value: value,
primaryColor: Theme.of(context).accentColor,
onChanged: onChanged
);
}
}
class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
_SliderRenderObjectWidget({ Key key, this.value, this.primaryColor, this.onChanged })
: super(key: key);
final double value;
final Color primaryColor;
final ValueChanged<double> onChanged;
_RenderSlider createRenderObject() => new _RenderSlider(
value: value,
primaryColor: primaryColor,
onChanged: onChanged
);
void updateRenderObject(_RenderSlider renderObject, _SliderRenderObjectWidget oldWidget) {
renderObject.value = value;
renderObject.primaryColor = primaryColor;
renderObject.onChanged = onChanged;
}
}
final Color _kInactiveTrackColor = Colors.grey[400];
final Color _kActiveTrackColor = Colors.grey[500];
class _RenderSlider extends RenderConstrainedBox {
_RenderSlider({
double value,
Color primaryColor,
this.onChanged
}) : _value = value,
_primaryColor = primaryColor,
super(additionalConstraints: const BoxConstraints.tightFor(width: _kTrackWidth + 2 * _kReactionRadius, height: 2 * _kReactionRadius)) {
assert(value != null && value >= 0.0 && value <= 1.0);
_drag = new HorizontalDragGestureRecognizer(router: FlutterBinding.instance.pointerRouter)
..onStart = _handleDragStart
..onUpdate = _handleDragUpdate
..onEnd = _handleDragEnd;
}
double get value => _value;
double _value;
void set value(double newValue) {
assert(newValue != null && newValue >= 0.0 && newValue <= 1.0);
if (newValue == _value)
return;
_value = newValue;
markNeedsPaint();
}
Color get primaryColor => _primaryColor;
Color _primaryColor;
void set primaryColor(Color value) {
if (value == _primaryColor)
return;
_primaryColor = value;
markNeedsPaint();
}
ValueChanged<double> onChanged;
double get _trackLength => size.width - 2.0 * _kReactionRadius;
HorizontalDragGestureRecognizer _drag;
bool _active = false;
double _currentDragValue = 0.0;
void _handleDragStart(Point globalPosition) {
if (onChanged != null) {
_active = true;
_currentDragValue = globalToLocal(globalPosition).x / _trackLength;
onChanged(_currentDragValue.clamp(0.0, 1.0));
markNeedsPaint();
}
}
void _handleDragUpdate(double delta) {
if (onChanged != null) {
_currentDragValue += delta / _trackLength;
onChanged(_currentDragValue.clamp(0.0, 1.0));
}
}
void _handleDragEnd(Offset velocity) {
if (_active) {
_active = false;
_currentDragValue = 0.0;
markNeedsPaint();
}
}
bool hitTestSelf(Point position) => true;
void handleEvent(InputEvent event, BoxHitTestEntry entry) {
if (event.type == 'pointerdown' && onChanged != null)
_drag.addPointer(event);
}
void paint(PaintingContext context, Offset offset) {
final Canvas canvas = context.canvas;
final double trackLength = _trackLength;
double trackCenter = offset.dy + size.height / 2.0;
double trackLeft = offset.dx + _kReactionRadius;
double trackTop = trackCenter - 1.0;
double trackBottom = trackCenter + 1.0;
double trackRight = trackLeft + trackLength;
double trackActive = trackLeft + trackLength * value;
Paint primaryPaint = new Paint()..color = _primaryColor;
Paint trackPaint = new Paint()..color = _active ? _kActiveTrackColor : _kInactiveTrackColor;
canvas.drawRect(new Rect.fromLTRB(trackLeft, trackTop, trackRight, trackBottom), trackPaint);
canvas.drawRect(new Rect.fromLTRB(trackLeft, trackTop, trackActive, trackBottom), primaryPaint);
Point activeLocation = new Point(trackActive, trackCenter);
if (_active) {
Paint reactionPaint = new Paint()..color = _primaryColor.withAlpha(_kReactionAlpha);
canvas.drawCircle(activeLocation, _kReactionRadius, reactionPaint);
}
canvas.drawCircle(activeLocation, _kThumbRadius, trackPaint);
}
}