// 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); } }