blob: 573716dc9e5b1fab31cff3bfcd4ff07f7de77616 [file] [log] [blame]
// 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 'dart:async';
import 'dart:sky' as sky;
import 'package:sky/painting/radial_reaction.dart';
import 'package:sky/painting/shadows.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/theme/shadows.dart';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/theme.dart';
import 'package:sky/widgets/framework.dart';
import 'package:sky/rendering/toggleable.dart';
export 'package:sky/rendering/toggleable.dart' show ValueChanged;
const sky.Color _kThumbOffColor = const sky.Color(0xFFFAFAFA);
const sky.Color _kTrackOffColor = const sky.Color(0x42000000);
const double _kSwitchWidth = 35.0;
const double _kThumbRadius = 10.0;
const double _kSwitchHeight = _kThumbRadius * 2.0;
const double _kTrackHeight = 14.0;
const double _kTrackRadius = _kTrackHeight / 2.0;
const double _kTrackWidth =
_kSwitchWidth - (_kThumbRadius - _kTrackRadius) * 2.0;
const Duration _kCheckDuration = const Duration(milliseconds: 200);
const Size _kSwitchSize = const Size(_kSwitchWidth + 2.0, _kSwitchHeight + 2.0);
const double _kReactionRadius = _kSwitchWidth / 2.0;
class Switch extends LeafRenderObjectWrapper {
Switch({ Key key, this.value, this.onChanged })
: super(key: key);
final bool value;
final ValueChanged onChanged;
_RenderSwitch get renderObject => super.renderObject;
_RenderSwitch createNode() => new _RenderSwitch(
value: value,
thumbColor: null,
onChanged: onChanged
);
void syncRenderObject(Switch old) {
super.syncRenderObject(old);
renderObject.value = value;
renderObject.onChanged = onChanged;
renderObject.thumbColor = Theme.of(this).accentColor;
}
}
class _RenderSwitch extends RenderToggleable {
_RenderSwitch({
bool value,
Color thumbColor: _kThumbOffColor,
ValueChanged onChanged
}) : _thumbColor = thumbColor,
super(value: value, onChanged: onChanged, size: _kSwitchSize) {}
Color _thumbColor;
Color get thumbColor => _thumbColor;
void set thumbColor(Color value) {
if (value == _thumbColor) return;
_thumbColor = value;
markNeedsPaint();
}
RadialReaction _radialReaction;
EventDisposition handleEvent(sky.Event event, BoxHitTestEntry entry) {
if (event is sky.PointerEvent) {
if (event.type == 'pointerdown') {
_showRadialReaction(entry.localPosition);
return combineEventDispositions(EventDisposition.processed,
super.handleEvent(event, entry));
}
if (event.type == 'pointerup') {
_hideRadialReaction();
return combineEventDispositions(EventDisposition.processed,
super.handleEvent(event, entry));
}
}
return super.handleEvent(event, entry);
}
void _showRadialReaction(Point startLocation) {
if (_radialReaction != null)
return;
_radialReaction = new RadialReaction(
center: new Point(_kSwitchSize.width / 2.0, _kSwitchSize.height / 2.0),
radius: _kReactionRadius,
startPosition: startLocation)
..addListener(markNeedsPaint)
..show();
}
Future _hideRadialReaction() async {
if (_radialReaction == null)
return;
await _radialReaction.hide();
_radialReaction = null;
}
void paint(PaintingContext context, Offset offset) {
final PaintingCanvas canvas = context.canvas;
sky.Color thumbColor = _kThumbOffColor;
sky.Color trackColor = _kTrackOffColor;
if (value) {
thumbColor = _thumbColor;
trackColor = new sky.Color(_thumbColor.value & 0x80FFFFFF);
}
// Draw the track rrect
sky.Paint paint = new sky.Paint()..color = trackColor;
paint.setStyle(sky.PaintingStyle.fill);
sky.Rect rect = new sky.Rect.fromLTWH(offset.dx,
offset.dy + _kSwitchHeight / 2.0 - _kTrackHeight / 2.0, _kTrackWidth,
_kTrackHeight);
sky.RRect rrect = new sky.RRect()
..setRectXY(rect, _kTrackRadius, _kTrackRadius);
canvas.drawRRect(rrect, paint);
if (_radialReaction != null)
_radialReaction.paint(canvas, offset);
// Draw the raised thumb with a shadow
paint.color = thumbColor;
var builder = new ShadowDrawLooperBuilder();
for (BoxShadow boxShadow in shadows[1]) builder.addShadow(
boxShadow.offset, boxShadow.color, boxShadow.blur);
paint.setDrawLooper(builder.build());
// The thumb contracts slightly during the animation
double inset = 2.0 - (position.value - 0.5).abs() * 2.0;
Point thumbPos = new Point(offset.dx +
_kTrackRadius +
position.value * (_kTrackWidth - _kTrackRadius * 2),
offset.dy + _kSwitchHeight / 2.0);
canvas.drawCircle(thumbPos, _kThumbRadius - inset, paint);
}
}