| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library android_extension; | 5 library android_extension; |
| 6 | 6 import 'dart:async'; |
| 7 class CanvasElement { | 7 |
| 8 // A VERY simplified DOM. |
| 9 |
| 10 class BodyElement { |
| 11 List _nodes; |
| 12 get nodes => _nodes; |
| 13 BodyElement() : _nodes = new List(); |
| 14 } |
| 15 |
| 16 // The OpenGLUI "equivalent" of HtmlDocument. |
| 17 class Document { |
| 18 BodyElement _body; |
| 19 get body => _body; |
| 20 Document._internal() : _body = new BodyElement(); |
| 21 } |
| 22 |
| 23 Document document = new Document._internal(); |
| 24 |
| 25 // Event handling. This is very kludgy for now, especially the |
| 26 // bare-bones Stream stuff! |
| 27 |
| 28 class Event { |
| 29 final String type; |
| 30 Event(String type) : this.type = type; |
| 31 } |
| 32 |
| 33 class KeyEvent extends Event { |
| 34 final bool altKey; |
| 35 final bool ctrlKey; |
| 36 final bool shiftKey; |
| 37 final int keyCode; |
| 38 |
| 39 KeyEvent(String type, int keycode, bool alt, bool ctrl, bool shift) |
| 40 : super(type), |
| 41 keyCode = keycode, |
| 42 altKey = alt, |
| 43 ctrlKey = ctrl, |
| 44 shiftKey = shift { |
| 45 } |
| 46 } |
| 47 |
| 48 class MouseEvent extends Event { |
| 49 final int screenX, screenY; |
| 50 final int clientX, clientY; |
| 51 |
| 52 MouseEvent(String type, int x, int y) |
| 53 : super(type), |
| 54 screenX = x, |
| 55 screenY = y, |
| 56 clientX = x, |
| 57 clientY = y { |
| 58 } |
| 59 } |
| 60 |
| 61 typedef void EventListener(Event event); |
| 62 |
| 63 Map<String,List<Function>> _listeners = new Map(); |
| 64 |
| 65 class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> { |
| 66 int _pauseCount = 0; |
| 67 Object _target; |
| 68 final String _eventType; |
| 69 var _onData; |
| 70 |
| 71 _EventStreamSubscription(this._target, this._eventType, this._onData) { |
| 72 _tryResume(); |
| 73 } |
| 74 |
| 75 void cancel() { |
| 76 if (_canceled) { |
| 77 throw new StateError("Subscription has been canceled."); |
| 78 } |
| 79 |
| 80 _unlisten(); |
| 81 // Clear out the target to indicate this is complete. |
| 82 _target = null; |
| 83 _onData = null; |
| 84 } |
| 85 |
| 86 bool get _canceled => _target == null; |
| 87 |
| 88 void onData(void handleData(T event)) { |
| 89 if (_canceled) { |
| 90 throw new StateError("Subscription has been canceled."); |
| 91 } |
| 92 // Remove current event listener. |
| 93 _unlisten(); |
| 94 |
| 95 _onData = handleData |
| 96 _tryResume(); |
| 97 } |
| 98 |
| 99 /// Has no effect. |
| 100 void onError(void handleError(AsyncError error)) {} |
| 101 |
| 102 /// Has no effect. |
| 103 void onDone(void handleDone()) {} |
| 104 |
| 105 void pause([Future resumeSignal]) { |
| 106 if (_canceled) { |
| 107 throw new StateError("Subscription has been canceled."); |
| 108 } |
| 109 ++_pauseCount; |
| 110 _unlisten(); |
| 111 |
| 112 if (resumeSignal != null) { |
| 113 resumeSignal.whenComplete(resume); |
| 114 } |
| 115 } |
| 116 |
| 117 bool get _paused => _pauseCount > 0; |
| 118 |
| 119 void resume() { |
| 120 if (_canceled) { |
| 121 throw new StateError("Subscription has been canceled."); |
| 122 } |
| 123 if (!_paused) { |
| 124 throw new StateError("Subscription is not paused."); |
| 125 } |
| 126 --_pauseCount; |
| 127 _tryResume(); |
| 128 } |
| 129 |
| 130 void _tryResume() { |
| 131 if (_onData != null && !_paused) { |
| 132 if (!_listeners.containsKey(_eventType)) { |
| 133 _listeners[_eventType] = new List(); |
| 134 } |
| 135 var event_listeners = _listeners[_eventType]; |
| 136 for (var i = 0; i < event_listeners.length; i++) { |
| 137 if (event_listeners[i] == null) { |
| 138 event_listeners[i] = _onData; |
| 139 return; |
| 140 } |
| 141 } |
| 142 event_listeners.add(_onData); |
| 143 } |
| 144 } |
| 145 |
| 146 void _unlisten() { |
| 147 if (_onData != null) { |
| 148 if (!_listeners.containsKey(_eventType)) { |
| 149 var event_listeners = _listeners[_eventType]; |
| 150 for (var i = 0; i < event_listeners.length; i++) { |
| 151 if (event_listeners[i] == _onData) { |
| 152 event_listeners[i] = null; |
| 153 break; |
| 154 } |
| 155 } |
| 156 } |
| 157 } |
| 158 } |
| 159 } |
| 160 |
| 161 class _EventStream<T extends Event> extends Stream<T> { |
| 162 final Object _target; |
| 163 final String _eventType; |
| 164 |
| 165 _EventStream(this._target, this._eventType); |
| 166 |
| 167 // DOM events are inherently multi-subscribers. |
| 168 Stream<T> asBroadcastStream() => this; |
| 169 bool get isBroadcast => true; |
| 170 |
| 171 StreamSubscription<T> listen(void onData(T event), |
| 172 { void onError(AsyncError error), |
| 173 void onDone(), |
| 174 bool unsubscribeOnError}) { |
| 175 |
| 176 return new _EventStreamSubscription<T>( |
| 177 this._target, this._eventType, onData); |
| 178 } |
| 179 } |
| 180 |
| 181 class Node { |
| 182 Stream<KeyEvent> get onKeyDown => new _EventStream(this, 'keydown'); |
| 183 Stream<KeyEvent> get onKeyUp => new _EventStream(this, 'keyup'); |
| 184 Stream<MouseEvent> get onMouseDown => new _EventStream(this, 'mousedown'); |
| 185 Stream<MouseEvent> get onMouseMove => new _EventStream(this, 'mousemove'); |
| 186 Stream<MouseEvent> get onMouseUp => new _EventStream(this, 'mouseup'); |
| 187 } |
| 188 |
| 189 // TODO(gram): If we support more than one on-screen canvas, we will |
| 190 // need to filter dispatched events by the target Node. |
| 191 _dispatchEvent(String event_type, Event e) { |
| 192 if (!_listeners.containsKey(event_type)) return; |
| 193 var event_listeners = _listeners[event_type]; |
| 194 for (var i = 0; i < event_listeners.length; i++) { |
| 195 if (event_listeners[i] != null) { |
| 196 event_listeners[i](e); |
| 197 } |
| 198 } |
| 199 } |
| 200 |
| 201 _dispatchKeyEvent(String type, int keyCode, bool alt, bool ctrl, bool shift) => |
| 202 _dispatchEvent(type, new KeyEvent(type, keyCode, alt, ctrl, shift)); |
| 203 |
| 204 _dispatchMouseEvent(String type, double x, double y) => |
| 205 _dispatchEvent(type, new MouseEvent(type, x.toInt(), y.toInt())); |
| 206 |
| 207 // These next few are called by vmglue.cc. |
| 208 onKeyDown_(int when, int keyCode, bool alt, bool ctrl, bool shift, int repeat) |
| 209 => _dispatchKeyEvent('keydown', keyCode, alt, ctrl, shift); |
| 210 |
| 211 onKeyUp_(int when, int keyCode, bool alt, bool ctrl, bool shift, int repeat) => |
| 212 _dispatchKeyEvent('keyup', keyCode, alt, ctrl, shift); |
| 213 |
| 214 onMouseDown_(int when, double x, double y) => |
| 215 _dispatchMouseEvent('mousedown', x, y); |
| 216 |
| 217 onMouseMove_(int when, double x, double y) => |
| 218 _dispatchMouseEvent('mousemove', x, y); |
| 219 |
| 220 onMouseUp_(int when, double x, double y) => |
| 221 _dispatchMouseEvent('mouseup', x, y); |
| 222 |
| 223 class CanvasElement extends Node { |
| 8 int _height; | 224 int _height; |
| 9 int _width; | 225 int _width; |
| 10 | 226 |
| 11 get height => _height; | 227 get height => _height; |
| 12 get width => _width; | 228 get width => _width; |
| 13 | 229 |
| 14 CanvasRenderingContext2D _context2d; | 230 CanvasRenderingContext2D _context2d; |
| 15 WebGLRenderingContext _context3d; | 231 WebGLRenderingContext _context3d; |
| 16 | 232 |
| 17 // For use with drawImage, we want to support a src property | 233 // For use with drawImage, we want to support a src property |
| 18 // like ImageElement, which maps to the context handle in native | 234 // like ImageElement, which maps to the context handle in native |
| 19 // code. | 235 // code. |
| 20 get src => "context2d://${_context2d.handle}"; | 236 get src => "context2d://${_context2d.handle}"; |
| 21 | 237 |
| 22 CanvasElement({int width, int height}) { | 238 CanvasElement({int width, int height}) |
| 239 : super() { |
| 23 _width = (width == null) ? getDeviceScreenWidth() : width; | 240 _width = (width == null) ? getDeviceScreenWidth() : width; |
| 24 _height = (height == null) ? getDeviceScreenHeight() : height; | 241 _height = (height == null) ? getDeviceScreenHeight() : height; |
| 25 } | 242 } |
| 26 | 243 |
| 27 CanvasRenderingContext getContext(String contextId) { | 244 CanvasRenderingContext getContext(String contextId) { |
| 28 if (contextId == "2d") { | 245 if (contextId == "2d") { |
| 29 if (_context2d == null) { | 246 if (_context2d == null) { |
| 30 _context2d = new CanvasRenderingContext2D(this, _width, _height); | 247 _context2d = new CanvasRenderingContext2D(this, _width, _height); |
| 31 } | 248 } |
| 32 return _context2d; | 249 return _context2d; |
| (...skipping 703 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 736 num dirtyWidth, num dirtyHeight]) { | 953 num dirtyWidth, num dirtyHeight]) { |
| 737 throw new Exception('Unimplemented webkitGetImageDataHD'); | 954 throw new Exception('Unimplemented webkitGetImageDataHD'); |
| 738 } | 955 } |
| 739 | 956 |
| 740 // TODO(vsm): Kill. | 957 // TODO(vsm): Kill. |
| 741 noSuchMethod(invocation) { | 958 noSuchMethod(invocation) { |
| 742 throw new Exception('Unimplemented/unknown ${invocation.memberName}'); | 959 throw new Exception('Unimplemented/unknown ${invocation.memberName}'); |
| 743 } | 960 } |
| 744 } | 961 } |
| 745 | 962 |
| OLD | NEW |