From 45cbbc0faeebae967efe8ae013b83a85be13beaa Mon Sep 17 00:00:00 2001 From: Collin Jackson Date: Thu, 4 Jun 2015 17:24:38 -0700 Subject: [PATCH] =?UTF-8?q?Implement=20radio=20button=20for=20Sky=E2=80=99?= =?UTF-8?q?s=20fn2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit R=abarth@chromium.org, eseidel@chromium.org, abarth Review URL: https://codereview.chromium.org/1157573012 --- engine/core/painting/Paint.h | 6 +++ engine/core/painting/Paint.idl | 8 ++++ examples/stocks2/lib/stock_app.dart | 38 +++++++-------- sdk/lib/framework/components2/radio.dart | 60 ++++++++++++------------ sdk/lib/framework/fn2.dart | 20 ++++++++ sdk/lib/framework/rendering/box.dart | 27 +++++++++++ 6 files changed, 109 insertions(+), 50 deletions(-) diff --git a/engine/core/painting/Paint.h b/engine/core/painting/Paint.h index 71ac4057320..c9b7e1657b2 100644 --- a/engine/core/painting/Paint.h +++ b/engine/core/painting/Paint.h @@ -33,6 +33,12 @@ public: SkColor color() const { return m_paint.getColor(); } void setColor(SkColor color) { m_paint.setColor(color); } + unsigned short style() const { return m_paint.getStyle(); } + void setStyle(unsigned short style) { m_paint.setStyle(static_cast(style)); } + + SkScalar strokeWidth() const { return m_paint.getStrokeWidth(); } + void setStrokeWidth(SkScalar strokeWidth) { m_paint.setStrokeWidth(strokeWidth); } + void setARGB(unsigned a, unsigned r, unsigned g, unsigned b) { m_paint.setARGB(a, r, g, b); diff --git a/engine/core/painting/Paint.idl b/engine/core/painting/Paint.idl index 27f4b20b353..f86cc754515 100644 --- a/engine/core/painting/Paint.idl +++ b/engine/core/painting/Paint.idl @@ -5,6 +5,14 @@ [ Constructor(), ] interface Paint { + // Style + const unsigned short FILL_STYLE = 0; + const unsigned short STROKE_STYLE = 1; + const unsigned short STROKE_AND_FILL_STYLE = 2; + + // TODO(jackson): we could wrap this enum like we did for |color| + attribute unsigned short style; + attribute float strokeWidth; attribute boolean isAntiAlias; attribute Color color; diff --git a/examples/stocks2/lib/stock_app.dart b/examples/stocks2/lib/stock_app.dart index baf7b917190..26f44a094fa 100644 --- a/examples/stocks2/lib/stock_app.dart +++ b/examples/stocks2/lib/stock_app.dart @@ -13,7 +13,7 @@ import 'package:sky/framework/components2/menu_item.dart'; import 'package:sky/framework/components2/input.dart'; // import 'package:sky/framework/components2/modal_overlay.dart'; // import 'package:sky/framework/components2/popup_menu.dart'; -// import 'package:sky/framework/components2/radio.dart'; +import 'package:sky/framework/components2/radio.dart'; import 'package:sky/framework/components2/scaffold.dart'; import 'package:sky/framework/fn2.dart'; import 'package:sky/framework/theme2/typography.dart' as typography; @@ -110,8 +110,6 @@ class StocksApp extends App { }); } - // static FlexBoxParentData _flex1 = new FlexBoxParentData()..flex = 1; - Drawer buildDrawer() { return new Drawer( controller: _drawerController, @@ -127,23 +125,23 @@ class StocksApp extends App { icon: 'action/account_balance', children: [new Text('Account Balance')]), new MenuDivider(key: 'div1'), - // new MenuItem( - // key: 'Optimistic Menu Item', - // icon: 'action/thumb_up', - // onGestureTap: (event) => _handleStockModeChange(StockMode.optimistic), - // children: [ - // new ParentDataNode(new Text('Optimistic'), _flex1), - // new Radio(key: 'optimistic-radio', value: StockMode.optimistic, groupValue: _stockMode, onChanged: _handleStockModeChange) - // ]), - // new MenuItem( - // key: 'Pessimistic Menu Item', - // icon: 'action/thumb_down', - // onGestureTap: (event) => _handleStockModeChange(StockMode.pessimistic), - // children: [ - // new ParentDataNode(new Text('Pessimistic'), _flex1), - // new Radio(key: 'pessimistic-radio', value: StockMode.pessimistic, groupValue: _stockMode, onChanged: _handleStockModeChange) - // ]), - // new MenuDivider(key: 'div2'), + new MenuItem( + key: 'Optimistic Menu Item', + icon: 'action/thumb_up', + onGestureTap: (event) => _handleStockModeChange(StockMode.optimistic), + children: [ + new FlexExpandingChild(new Text('Optimistic'), 1), + new Radio(key: 'optimistic-radio', value: StockMode.optimistic, groupValue: _stockMode, onChanged: _handleStockModeChange) + ]), + new MenuItem( + key: 'Pessimistic Menu Item', + icon: 'action/thumb_down', + onGestureTap: (event) => _handleStockModeChange(StockMode.pessimistic), + children: [ + new FlexExpandingChild(new Text('Pessimistic'), 1), + new Radio(key: 'pessimistic-radio', value: StockMode.pessimistic, groupValue: _stockMode, onChanged: _handleStockModeChange) + ]), + new MenuDivider(key: 'div2'), new MenuItem( key: 'Settings', icon: 'action/settings', diff --git a/sdk/lib/framework/components2/radio.dart b/sdk/lib/framework/components2/radio.dart index b065dfe87f2..33d4fb2e26c 100644 --- a/sdk/lib/framework/components2/radio.dart +++ b/sdk/lib/framework/components2/radio.dart @@ -2,7 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:sky/framework/theme2/colors.dart' as colors; + +import 'dart:sky' as sky; import '../fn2.dart'; +import '../rendering/box.dart'; +import '../rendering/object.dart'; import 'button_base.dart'; import 'ink_well.dart'; @@ -13,31 +18,6 @@ class Radio extends ButtonBase { Object groupValue; ValueChanged onChanged; - static final Style _style = new Style(''' - width: 14px; - height: 14px; - border-radius: 7px; - border: 1px solid blue; - margin: 0 5px;''' - ); - - static final Style _highlightStyle = new Style(''' - width: 14px; - height: 14px; - border-radius: 7px; - border: 1px solid blue; - margin: 0 5px; - background-color: orange;''' - ); - - static final Style _dotStyle = new Style(''' - width: 10px; - height: 10px; - border-radius: 5px; - background-color: black; - margin: 2px;''' - ); - Radio({ Object key, this.onChanged, @@ -46,12 +26,32 @@ class Radio extends ButtonBase { }) : super(key: key); UINode buildContent() { + // TODO(jackson): This should change colors with the theme + sky.Color color = highlight ? colors.Purple[500] : const sky.Color(0x8A000000); + const double diameter = 16.0; + const double outerRadius = diameter / 2; + const double innerRadius = 5.0; return new EventListenerNode( - new StyleNode( - new InkWell( - children: value == groupValue ? [new Container(style: _dotStyle)] : [] - ), - highlight ? _highlightStyle : _style + new Container( + margin: const EdgeDims.symmetric(horizontal: 5.0), + desiredSize: new sky.Size(diameter, diameter), + child: new CustomPaint( + callback: (RenderObjectDisplayList canvas) { + + sky.Paint paint = new sky.Paint()..color = color; + + // Draw the outer circle + paint.style = 1; // SkPaint::STROKE_STYLE; + paint.strokeWidth = 2.0; + canvas.drawCircle(outerRadius, outerRadius, outerRadius, paint); + + // Draw the inner circle + if (value == groupValue) { + paint.style = 0; // SkPaint::FILL_STYLE; + canvas.drawCircle(outerRadius, outerRadius, innerRadius, paint); + } + } + ) ), onGestureTap: _handleClick ); diff --git a/sdk/lib/framework/fn2.dart b/sdk/lib/framework/fn2.dart index fd39b820509..540566963cd 100644 --- a/sdk/lib/framework/fn2.dart +++ b/sdk/lib/framework/fn2.dart @@ -441,6 +441,26 @@ class SizeObserver extends OneChildRenderObjectWrapper { } } +// TODO(jackson) need a mechanism for marking the RenderCustomPaint as needing paint +class CustomPaint extends OneChildRenderObjectWrapper { + RenderCustomPaint root; + final CustomPaintCallback callback; + + CustomPaint({ this.callback, UINode child, Object key }) + : super(child: child, key: key); + + RenderCustomPaint createNode() => new RenderCustomPaint(callback: callback); + + void syncRenderObject(CustomPaint old) { + super.syncRenderObject(old); + root.callback = callback; + } + + void _remove() { + root.callback = null; + super._remove(); + } +} final List _emptyList = new List(); diff --git a/sdk/lib/framework/rendering/box.dart b/sdk/lib/framework/rendering/box.dart index c6c878354a1..41f9ed5af36 100644 --- a/sdk/lib/framework/rendering/box.dart +++ b/sdk/lib/framework/rendering/box.dart @@ -666,6 +666,33 @@ class RenderShadowedBox extends RenderProxyBox { } } +typedef void CustomPaintCallback(RenderObjectDisplayList canvas); + +class RenderCustomPaint extends RenderProxyBox { + + RenderCustomPaint({ + CustomPaintCallback callback, + RenderBox child + }) : super(child) { + assert(callback != null); + _callback = callback; + } + + CustomPaintCallback _callback; + void set callback (CustomPaintCallback value) { + assert(value != null); + if (_callback == value) + return; + _callback = value; + markNeedsPaint(); + } + + void paint(RenderObjectDisplayList canvas) { + _callback(canvas); + super.paint(canvas); + } +} + // RENDER VIEW LAYOUT MANAGER class ViewConstraints {