浏览代码

Merge remote-tracking branch 'upstream/master' into text_edit

/main
fzhangtj 6 年前
当前提交
fe782218
共有 21 个文件被更改,包括 907 次插入31 次删除
  1. 27
      LICENSE.md
  2. 145
      README.md
  3. 12
      Runtime/editor/editor_window.cs
  4. 26
      Runtime/engine/WidgetCanvas.cs
  5. 14
      Runtime/gestures/binding.cs
  6. 32
      Runtime/gestures/converter.cs
  7. 6
      Runtime/gestures/drag_details.cs
  8. 20
      Runtime/gestures/events.cs
  9. 46
      Runtime/gestures/monodrag.cs
  10. 6
      Runtime/gestures/pointer_router.cs
  11. 7
      Runtime/gestures/recognizer.cs
  12. 10
      Runtime/rendering/proxy_box.cs
  13. 12
      Runtime/ui/painting/canvas_impl.cs
  14. 19
      Runtime/ui/pointer.cs
  15. 485
      Runtime/ui/txt/paragraph.cs
  16. 10
      Runtime/widgets/basic.cs
  17. 8
      Runtime/widgets/gesture_detector.cs
  18. 18
      Runtime/widgets/scroll_activity.cs
  19. 15
      Runtime/widgets/scroll_position_with_single_context.cs
  20. 12
      Runtime/widgets/sliver.cs
  21. 8
      Samples/UIWidgetSample/UIWidgetSample.unity

27
LICENSE.md


[MyPackageName] copyright © [YEAR] Unity Technologies ApS
Copyright 2019 The UIWidget Authors. All rights reserved.
Copyright 2014 The Chromium Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Licensed under the Unity Companion License for Unity-dependent projects--see [Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License).
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the license for details on these and other terms and conditions.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

145
README.md


# UI Widgets
## Development
## Introduction
UIWidget is a plugin package for Unity Editor which helps developers to create, debug and deploy efficient,
cross-platform Apps using the Unity Engine.
UIWidget is mainly derived from Flutter @https://github.com/flutter/flutter. However, taking advantage of
the powerful Unity Engine, it offers developers many new features to improve their Apps
as well as the develop workflow significantly.
#### Efficiency
Using the latest Unity rendering SDKs, a UIWidget App can run very fast and keep >60fps in most times.
#### Cross-Platform
A UIWidget App can be deployed on all kinds of platforms including PCs, mobile devices and web page directly, like
any other Unity projects.
#### 3D-Support
Except for basic 2D UIs, developers are also able to include 3D Models, particle-systems to their UIWidget Apps.
#### Developer-Friendliness
A UIWidget App can be debug in the Unity Editor directly with many advanced tools like
CPU/GPU Profiling, FPS Profiling.
1. Start **Unity(2018.3 or above)**, create a local empty project.
1. In a console (or terminal) application, go to the newly created project folder, then clone this repo into the packages directory.
## Requirement
#### Unity
Install **Unity 2018.3** or above. You can download the latest Unity on https://unity3d.com/get-unity/download.
#### UIWidget Package
Visit our Github repository https://gitlab.cds.internal.unity3d.com/upm-packages/ui-widgets/com.unity.uiwidgets.git
to download the latest UIWidget package.
Move the downloaded package folder into the **Package** folder of your Unity project.
```none
Generally, you can make it using a console (or terminal) application by just a few commands as below:
```none
```
```
## Getting Start
#### i. Overview
In this tutorial, we will create a very simple UIWidget App as the kick-starter. The app contains
only a text label and a button. The text label will count the times of clicks upon the button.
First of all, please open or create a Unity Project and open it with Unity Editor.
#### ii. Scene Build
A UIWidget App is usually built upon a Unity UI Canvas. Please follow the steps to create a
UI Canvas in Unity.
1. Create a new Scene by "File -> New Scene";
1. Create a UI Canvas in the scene by "GameObject -> UI -> Canvas";
1. Add a Panel (i.e., **Panel 1**) to the UI Canvas by right click on the Canvas and select "UI -> Panel". Then remove the
**Image** Component from the Panel.
#### iii. Create Widget
A UIWidget App is written in **C# Scripts**. Please follow the steps to create an App and play it
in Unity Editor.
1. Create a new C# Script named "ExampleCanvas.cs" and paste the following codes into it.
```none
using System.Collections.Generic;
using Unity.UIWidgets.engine;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.material;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.widgets;
namespace UIWidgetsSample {
public class ExampleCanvas : WidgetCanvas {
protected override Widget getWidget() {
return new ExampleApp();
}
class ExampleApp : StatefulWidget {
public ExampleApp(Key key = null) : base(key) {
}
public override State createState() {
return new ExampleState();
}
}
class ExampleState : State<ExampleApp> {
int counter = 0;
public override Widget build(BuildContext context) {
return new Column(
children: new List<Widget> {
new Text("Counter: " + this.counter),
new GestureDetector(
onTap: () => {
this.setState(()
=> {
this.counter++;
});
},
child: new Container(
padding: EdgeInsets.symmetric(20, 20),
color: Colors.blue,
child: new Text("Click Me")
)
)
}
);
}
}
}
}
```
1. Save this script and attach it to **Panel 1** as its component.
1. Press the "Play" Button to start the App in Unity Editor.
#### iv. Build App
Finally, the UIWidget App can be built to packages for any specific platform by the following steps.
1. Open the Build Settings Panel by "File -> Build Settings..."
1. Choose a target platform and click "Build". Then the Unity Editor will automatically assemble
all relevant resources and generate the final App package.
## Code Style
## Learn
#### Samples
You can find many UIWidget App samples in the UIWidget package in the **Samples** folder.
Feel free to try them out and make modifications to see the results.
#### Wiki
The develop team is still working on the UIWidget Wiki. However, since UIWidget is mainly derived from Flutter,
you can refer to Flutter Wiki to access detailed descriptions of UIWidget APIs
from those of their Flutter counterparts.
## How to Contribute
If you want to join us, please contact us via Github and we will respond as soon as possible.
#### Code Style
1. **Import the Customized Code Cleanup Settings**: Open Preferences -> Manage Layers,
Choose 'Solution "\<YourProjectName\>" personal' and Click "Add Layer" ("+") -> "Open Settings File...".
and Open the file "UIWidgetCleanupPlugin.DotSettings" under \<YourProjectPath\>/Packages/com.unity.uiwidgets/"

3. **Refine Code Style Rules**: Edit the ".editorconfig" file under \<YourProjectPath\>/Packages/com.unity.uiwidgets/". Visit
https://www.jetbrains.com/help/rider/EditorConfig_Index.html for the detailed.
REF: https://www.jetbrains.com/help/rider/Sharing_Configuration_Options.html

12
Runtime/editor/editor_window.cs


physicalY: evt.mousePosition.y * this._devicePixelRatio
);
}
else if (evt.type == EventType.ScrollWheel) {
pointerData = new ScrollData(
timeStamp: Timer.timespanSinceStartup,
change: PointerChange.scroll,
kind: PointerDeviceKind.mouse,
device: evt.button,
physicalX: evt.mousePosition.x * this._devicePixelRatio,
physicalY: evt.mousePosition.y * this._devicePixelRatio,
scrollX: -evt.delta.x,
scrollY: -evt.delta.y
);
}
if (pointerData != null) {
this.onPointerEvent(new PointerDataPacket(new List<PointerData> {

26
Runtime/engine/WidgetCanvas.cs


Vector2 _lastMouseMove;
bool _mouseEntered;
const int mouseButtonNum = 3;
const int mouseScrollId = mouseButtonNum + 1;
protected override void OnEnable() {
base.OnEnable();

this.handleMouseMove();
}
if (this._mouseEntered) {
if (Input.mouseScrollDelta.y != 0) {
var pos = this.getPointPosition(Input.mousePosition);
this._windowAdapter.postPointerEvent(new ScrollData(
timeStamp: Timer.timespanSinceStartup,
change: PointerChange.scroll,
kind: PointerDeviceKind.mouse,
device: this.getScrollButton(),
physicalX: pos.x,
physicalY: pos.y,
scrollX: Input.mouseScrollDelta.x,
scrollY: Input.mouseScrollDelta.y * 5
));
}
}
this._lastMouseMove = Input.mousePosition;
D.assert(this._windowAdapter != null);

));
}
int getScrollButton() {
return mouseScrollId;
}
for (int key = 0; key < 3; key++) {
for (int key = 0; key < mouseButtonNum; key++) {
if (Input.GetMouseButton(key)) {
return key;
}

14
Runtime/gestures/binding.cs


this._handlePointerHoverEvent(evt);
}
if (evt is PointerScrollEvent) {
this._handlePointerScrollEvent(evt);
return;
}
HitTestResult result;
if (evt is PointerDownEvent) {
D.assert(!this._hitTests.ContainsKey(evt.pointer));

if (result != null) {
this.dispatchEvent(evt, result);
}
}
void _handlePointerScrollEvent(PointerEvent evt) {
this.pointerRouter.clearScrollRoute(evt.pointer);
HitTestResult result = new HitTestResult();
this.hitTest(result, evt.position);
this.dispatchEvent(evt, result);
}
void _handlePointerHoverEvent(PointerEvent evt) {

32
Runtime/gestures/converter.cs


int _pointer;
static int _pointerCount = 0;
// pointers 0 ~ 9 are preserved for special unique inputs
static int _pointerCount = 10;
// special pointer id:
// mouse scroll
const int scrollPointer = 5;
public void initScrollPointer() {
this._pointer = scrollPointer;
}
public void startNewPointer() {
_pointerCount += 1;

);
break;
}
case PointerChange.scroll: {
var _scrollData = (ScrollData) datum;
_PointerState state = _ensureStateForPointer(datum, position);
state.initScrollPointer();
if (state.lastPosition != position) {
state.lastPosition = position;
}
yield return new PointerScrollEvent(
timeStamp: timeStamp,
pointer: state.pointer,
kind: kind,
device: _scrollData.device,
position: position,
delta: new Offset(_scrollData.scrollX, _scrollData.scrollY) / devicePixelRatio
);
break;
}
case PointerChange.up:
case PointerChange.cancel: {
D.assert(_pointers.ContainsKey(datum.device));

6
Runtime/gestures/drag_details.cs


TimeSpan sourceTimeStamp,
Offset delta = null,
double? primaryDelta = null,
Offset globalPosition = null) {
Offset globalPosition = null,
bool isScroll = false) {
this.isScroll = isScroll;
D.assert(primaryDelta == null
|| primaryDelta == this.delta.dx && this.delta.dy == 0.0
|| primaryDelta == this.delta.dy && this.delta.dx == 0.0);

public readonly double? primaryDelta;
public readonly Offset globalPosition;
public readonly bool isScroll;
public override string ToString() {
return this.GetType() + "(" + this.delta + ")";

20
Runtime/gestures/events.cs


}
}
public class PointerScrollEvent : PointerEvent {
public PointerScrollEvent(
TimeSpan timeStamp,
int pointer = 0,
PointerDeviceKind kind = PointerDeviceKind.mouse,
int device = 0,
Offset position = null,
Offset delta = null)
: base(
timeStamp,
pointer: pointer,
kind: kind,
device: device,
position: position,
down: true,
delta: delta) {
}
}
public class PointerHoverEvent : PointerEvent {
public PointerHoverEvent(
TimeSpan timeStamp,

46
Runtime/gestures/monodrag.cs


readonly Dictionary<int, VelocityTracker> _velocityTrackers = new Dictionary<int, VelocityTracker>();
public override void addScrollPointer(PointerScrollEvent evt) {
this.startTrackingScrollerPointer(evt.pointer);
if (this._state == _DragState.ready) {
this._state = _DragState.possible;
this._initialPosition = evt.position;
if (this.onStart != null) {
this.invokeCallback<object>("onStart", () => {
this.onStart(new DragStartDetails(
sourceTimeStamp: evt.timeStamp,
globalPosition: this._initialPosition
));
return null;
});
}
}
}
public override void addPointer(PointerDownEvent evt) {
this.startTrackingPointer(evt.pointer);
this._velocityTrackers[evt.pointer] = new VelocityTracker();

var tracker = this._velocityTrackers[evt.pointer];
D.assert(tracker != null);
tracker.addPosition(evt.timeStamp, evt.position);
}
if (evt is PointerScrollEvent) {
Offset delta = evt.delta;
if (this.onUpdate != null) {
this.invokeCallback<object>("onUpdate", () => {
this.onUpdate(new DragUpdateDetails(
sourceTimeStamp: evt.timeStamp,
delta: this._getDeltaForDetails(delta),
primaryDelta: this._getPrimaryValueFromOffset(delta),
globalPosition: evt.position,
isScroll: true
));
return null;
});
}
this.invokeCallback<object>("onEnd", () => {
this.onEnd(new DragEndDetails(
velocity: Velocity.zero,
primaryVelocity: 0.0
));
return null;
}, debugReport: () => { return ""; }
);
this._state = _DragState.ready;
return;
}
if (evt is PointerMoveEvent) {

6
Runtime/gestures/pointer_router.cs


}
}
public void clearScrollRoute(int pointer) {
if (this._routeMap.ContainsKey(pointer)) {
this._routeMap.Remove(pointer);
}
}
public void addGlobalRoute(PointerRoute route) {
D.assert(!this._globalRoutes.Contains(route));
this._globalRoutes.Add(route);

7
Runtime/gestures/recognizer.cs


public abstract void addPointer(PointerDownEvent evt);
public virtual void addScrollPointer(PointerScrollEvent evt) {
}
public virtual void dispose() {
}

}
return GestureBinding.instance.gestureArena.add(pointer, this);
}
protected void startTrackingScrollerPointer(int pointer) {
GestureBinding.instance.pointerRouter.addRoute(pointer, this.handleEvent);
}
protected void startTrackingPointer(int pointer) {

10
Runtime/rendering/proxy_box.cs


public delegate void PointerLeaveEventListener(PointerLeaveEvent evt);
public delegate void PointerScrollEventListener(PointerScrollEvent evt);
public class RenderPointerListener : RenderProxyBoxWithHitTestBehavior {
public RenderPointerListener(
PointerDownEventListener onPointerDown = null,

PointerHoverEventListener onPointerHover = null,
PointerLeaveEventListener onPointerLeave = null,
PointerEnterEventListener onPointerEnter = null,
PointerScrollEventListener onPointerScroll = null,
HitTestBehavior behavior = HitTestBehavior.deferToChild,
RenderBox child = null
) : base(behavior: behavior, child: child) {

this.onPointerHover = onPointerHover;
this.onPointerLeave = onPointerLeave;
this.onPointerEnter = onPointerEnter;
this.onPointerScroll = onPointerScroll;
}
public PointerDownEventListener onPointerDown;

public PointerEnterEventListener onPointerEnter;
public PointerScrollEventListener onPointerScroll;
protected override void performResize() {
this.size = this.constraints.biggest;
}

if (this.onPointerEnter != null && evt is PointerEnterEvent) {
this.onPointerEnter((PointerEnterEvent) evt);
return;
}
if (this.onPointerScroll != null && evt is PointerScrollEvent) {
this.onPointerScroll((PointerScrollEvent) evt);
}
}

12
Runtime/ui/painting/canvas_impl.cs


var state = this._getState();
var mesh = ImageMeshGenerator.imageNineMesh(state.matrix, src, center, dst);
var mesh = ImageMeshGenerator.imageNineMesh(state.matrix, src, center, image.width, image.height, dst);
if (!this._applyClip(mesh.bounds)) {
return;

return new MeshMesh(matrix, vertices, _imageTriangles, uv);
}
public static MeshMesh imageNineMesh(Matrix3 matrix, Rect src, Rect center, Rect dst) {
public static MeshMesh imageNineMesh(Matrix3 matrix, Rect src, Rect center, int srcWidth, int srcHeight, Rect dst) {
float x1 = x0 + (float) ((center.left - src.left) * dst.width);
float x2 = x3 - (float) ((src.right - center.right) * dst.width);
float x1 = x0 + (float) ((center.left - src.left) * srcWidth);
float x2 = x3 - (float) ((src.right - center.right) * srcWidth);
float y1 = y0 + (float) ((center.top - src.top) * dst.height);
float y2 = y3 - (float) ((src.bottom - center.bottom) * dst.height);
float y1 = y0 + (float) ((center.top - src.top) * srcHeight);
float y2 = y3 - (float) ((src.bottom - center.bottom) * srcHeight);
float tx0 = (float) src.left;
float tx1 = (float) center.left;

19
Runtime/ui/pointer.cs


down,
move,
up,
scroll
}
public enum PointerDeviceKind {

public int device;
public double physicalX;
public double physicalY;
}
public class ScrollData : PointerData {
public ScrollData(
TimeSpan timeStamp,
PointerChange change,
PointerDeviceKind kind,
int device,
double physicalX,
double physicalY,
double scrollX,
double scrollY) : base(timeStamp, change, kind, device, physicalX, physicalY) {
this.scrollX = scrollX;
this.scrollY = scrollY;
}
public double scrollX;
public double scrollY;
}
public class PointerDataPacket {

485
Runtime/ui/txt/paragraph.cs


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.foundation;

}
public List<TextBox> getRectsForRange(int start, int end) {
var lineBoxes = new SortedDictionary<int, List<TextBox>>();
var lineBoxes = new SplayTree<int, List<TextBox>>();
foreach (var run in this._codeUnitRuns) {
if (run.codeUnits.start >= end) {
break;

static bool _isUtf16Surrogate(int value) {
return (value & 0xF800) == 0xD800;
}
}
public class SplayTree<TKey, TValue> : IDictionary<TKey, TValue> where TKey : IComparable<TKey> {
SplayTreeNode root;
int count;
int version = 0;
public void Add(TKey key, TValue value) {
this.Set(key, value, throwOnExisting: true);
}
public void Add(KeyValuePair<TKey, TValue> item) {
this.Set(item.Key, item.Value, throwOnExisting: true);
}
void Set(TKey key, TValue value, bool throwOnExisting) {
if (this.count == 0) {
this.version++;
this.root = new SplayTreeNode(key, value);
this.count = 1;
return;
}
this.Splay(key);
var c = key.CompareTo(this.root.Key);
if (c == 0) {
if (throwOnExisting) {
throw new ArgumentException("An item with the same key already exists in the tree.");
}
this.version++;
this.root.Value = value;
return;
}
var n = new SplayTreeNode(key, value);
if (c < 0) {
n.LeftChild = this.root.LeftChild;
n.RightChild = this.root;
this.root.LeftChild = null;
}
else {
n.RightChild = this.root.RightChild;
n.LeftChild = this.root;
this.root.RightChild = null;
}
this.root = n;
this.count++;
this.Splay(key);
this.version++;
}
public void Clear() {
this.root = null;
this.count = 0;
this.version++;
}
public bool ContainsKey(TKey key) {
if (this.count == 0) {
return false;
}
this.Splay(key);
return key.CompareTo(this.root.Key) == 0;
}
public bool Contains(KeyValuePair<TKey, TValue> item) {
if (this.count == 0) {
return false;
}
this.Splay(item.Key);
return item.Key.CompareTo(this.root.Key) == 0 &&
(ReferenceEquals(this.root.Value, item.Value) ||
(!ReferenceEquals(item.Value, null) && item.Value.Equals(this.root.Value)));
}
public KeyValuePair<TKey, TValue> First() {
SplayTreeNode t = this.root;
if (t == null) {
throw new NullReferenceException("The root of this tree is null!");
}
while (t.LeftChild != null) {
t = t.LeftChild;
}
return new KeyValuePair<TKey, TValue>(t.Key, t.Value);
}
public KeyValuePair<TKey, TValue> FirstOrDefault() {
SplayTreeNode t = this.root;
if (t == null) {
return new KeyValuePair<TKey, TValue>(default(TKey), default(TValue));
}
while (t.LeftChild != null) {
t = t.LeftChild;
}
return new KeyValuePair<TKey, TValue>(t.Key, t.Value);
}
public KeyValuePair<TKey, TValue> Last() {
SplayTreeNode t = this.root;
if (t == null) {
throw new NullReferenceException("The root of this tree is null!");
}
while (t.RightChild != null) {
t = t.RightChild;
}
return new KeyValuePair<TKey, TValue>(t.Key, t.Value);
}
public KeyValuePair<TKey, TValue> LastOrDefault() {
SplayTreeNode t = this.root;
if (t == null) {
return new KeyValuePair<TKey, TValue>(default(TKey), default(TValue));
}
while (t.RightChild != null) {
t = t.RightChild;
}
return new KeyValuePair<TKey, TValue>(t.Key, t.Value);
}
void Splay(TKey key) {
SplayTreeNode l, r, t, y, header;
l = r = header = new SplayTreeNode(default(TKey), default(TValue));
t = this.root;
while (true) {
var c = key.CompareTo(t.Key);
if (c < 0) {
if (t.LeftChild == null) {
break;
}
if (key.CompareTo(t.LeftChild.Key) < 0) {
y = t.LeftChild;
t.LeftChild = y.RightChild;
y.RightChild = t;
t = y;
if (t.LeftChild == null) {
break;
}
}
r.LeftChild = t;
r = t;
t = t.LeftChild;
}
else if (c > 0) {
if (t.RightChild == null) {
break;
}
if (key.CompareTo(t.RightChild.Key) > 0) {
y = t.RightChild;
t.RightChild = y.LeftChild;
y.LeftChild = t;
t = y;
if (t.RightChild == null) {
break;
}
}
l.RightChild = t;
l = t;
t = t.RightChild;
}
else {
break;
}
}
l.RightChild = t.LeftChild;
r.LeftChild = t.RightChild;
t.LeftChild = header.RightChild;
t.RightChild = header.LeftChild;
this.root = t;
}
public bool Remove(TKey key) {
if (this.count == 0) {
return false;
}
this.Splay(key);
if (key.CompareTo(this.root.Key) != 0) {
return false;
}
if (this.root.LeftChild == null) {
this.root = this.root.RightChild;
}
else {
var swap = this.root.RightChild;
this.root = this.root.LeftChild;
this.Splay(key);
this.root.RightChild = swap;
}
this.version++;
this.count--;
return true;
}
public bool TryGetValue(TKey key, out TValue value) {
if (this.count == 0) {
value = default(TValue);
return false;
}
this.Splay(key);
if (key.CompareTo(this.root.Key) != 0) {
value = default(TValue);
return false;
}
value = this.root.Value;
return true;
}
public TValue this[TKey key] {
get {
if (this.count == 0) {
throw new KeyNotFoundException("The key was not found in the tree.");
}
this.Splay(key);
if (key.CompareTo(this.root.Key) != 0) {
throw new KeyNotFoundException("The key was not found in the tree.");
}
return this.root.Value;
}
set { this.Set(key, value, throwOnExisting: false); }
}
public int Count {
get { return this.count; }
}
public bool IsReadOnly {
get { return false; }
}
public bool Remove(KeyValuePair<TKey, TValue> item) {
if (this.count == 0) {
return false;
}
this.Splay(item.Key);
if (item.Key.CompareTo(this.root.Key) == 0 && (ReferenceEquals(this.root.Value, item.Value) ||
(!ReferenceEquals(item.Value, null) &&
item.Value.Equals(this.root.Value)))) {
return false;
}
if (this.root.LeftChild == null) {
this.root = this.root.RightChild;
}
else {
var swap = this.root.RightChild;
this.root = this.root.LeftChild;
this.Splay(item.Key);
this.root.RightChild = swap;
}
this.version++;
this.count--;
return true;
}
public void Trim(int depth) {
if (depth < 0) {
throw new ArgumentOutOfRangeException("depth", "The trim depth must not be negative.");
}
if (this.count == 0) {
return;
}
if (depth == 0) {
this.Clear();
}
else {
var prevCount = this.count;
this.count = this.Trim(this.root, depth - 1);
if (prevCount != this.count) {
this.version++;
}
}
}
int Trim(SplayTreeNode node, int depth) {
if (depth == 0) {
node.LeftChild = null;
node.RightChild = null;
return 1;
}
else {
int count = 1;
if (node.LeftChild != null) {
count += this.Trim(node.LeftChild, depth - 1);
}
if (node.RightChild != null) {
count += this.Trim(node.RightChild, depth - 1);
}
return count;
}
}
public ICollection<TKey> Keys {
get { return new TiedList<TKey>(this, this.version, this.AsList(node => node.Key)); }
}
public ICollection<TValue> Values {
get { return new TiedList<TValue>(this, this.version, this.AsList(node => node.Value)); }
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
this.AsList(node => new KeyValuePair<TKey, TValue>(node.Key, node.Value)).CopyTo(array, arrayIndex);
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
return new TiedList<KeyValuePair<TKey, TValue>>(this, this.version,
this.AsList(node => new KeyValuePair<TKey, TValue>(node.Key, node.Value))).GetEnumerator();
}
IList<TEnumerator> AsList<TEnumerator>(Func<SplayTreeNode, TEnumerator> selector) {
if (this.root == null) {
return new TEnumerator[0];
}
var result = new List<TEnumerator>(this.count);
this.PopulateList(this.root, result, selector);
return result;
}
void PopulateList<TEnumerator>(SplayTreeNode node, List<TEnumerator> list,
Func<SplayTreeNode, TEnumerator> selector) {
if (node.LeftChild != null) {
this.PopulateList(node.LeftChild, list, selector);
}
list.Add(selector(node));
if (node.RightChild != null) {
this.PopulateList(node.RightChild, list, selector);
}
}
IEnumerator IEnumerable.GetEnumerator() {
return this.GetEnumerator();
}
sealed class SplayTreeNode {
public readonly TKey Key;
public TValue Value;
public SplayTreeNode LeftChild;
public SplayTreeNode RightChild;
public SplayTreeNode(TKey key, TValue value) {
this.Key = key;
this.Value = value;
}
}
sealed class TiedList<T> : IList<T> {
readonly SplayTree<TKey, TValue> tree;
readonly int version;
readonly IList<T> backingList;
public TiedList(SplayTree<TKey, TValue> tree, int version, IList<T> backingList) {
if (tree == null) {
throw new ArgumentNullException("tree");
}
if (backingList == null) {
throw new ArgumentNullException("backingList");
}
this.tree = tree;
this.version = version;
this.backingList = backingList;
}
public int IndexOf(T item) {
if (this.tree.version != this.version) {
throw new InvalidOperationException("The collection has been modified.");
}
return this.backingList.IndexOf(item);
}
public void Insert(int index, T item) {
throw new NotSupportedException();
}
public void RemoveAt(int index) {
throw new NotSupportedException();
}
public T this[int index] {
get {
if (this.tree.version != this.version) {
throw new InvalidOperationException("The collection has been modified.");
}
return this.backingList[index];
}
set { throw new NotSupportedException(); }
}
public void Add(T item) {
throw new NotSupportedException();
}
public void Clear() {
throw new NotSupportedException();
}
public bool Contains(T item) {
if (this.tree.version != this.version) {
throw new InvalidOperationException("The collection has been modified.");
}
return this.backingList.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex) {
if (this.tree.version != this.version) {
throw new InvalidOperationException("The collection has been modified.");
}
this.backingList.CopyTo(array, arrayIndex);
}
public int Count {
get { return this.tree.count; }
}
public bool IsReadOnly {
get { return true; }
}
public bool Remove(T item) {
throw new NotSupportedException();
}
public IEnumerator<T> GetEnumerator() {
if (this.tree.version != this.version) {
throw new InvalidOperationException("The collection has been modified.");
}
foreach (var item in this.backingList) {
yield return item;
if (this.tree.version != this.version) {
throw new InvalidOperationException("The collection has been modified.");
}
}
}
IEnumerator IEnumerable.GetEnumerator() {
return this.GetEnumerator();
}
}
}
}

10
Runtime/widgets/basic.cs


PointerHoverEventListener onPointerHover = null,
PointerLeaveEventListener onPointerLeave = null,
PointerEnterEventListener onPointerEnter = null,
PointerScrollEventListener onPointerScroll = null,
HitTestBehavior behavior = HitTestBehavior.deferToChild,
Widget child = null
) : base(key: key, child: child) {

this.onPointerHover = onPointerHover;
this.onPointerLeave = onPointerLeave;
this.onPointerEnter = onPointerEnter;
this.onPointerScroll = onPointerScroll;
this.behavior = behavior;
}

public readonly PointerLeaveEventListener onPointerLeave;
public readonly PointerScrollEventListener onPointerScroll;
public readonly HitTestBehavior behavior;
public override RenderObject createRenderObject(BuildContext context) {

onPointerEnter: this.onPointerEnter,
onPointerLeave: this.onPointerLeave,
onPointerHover: this.onPointerHover,
onPointerScroll: this.onPointerScroll,
behavior: this.behavior
);
}

renderObject.onPointerEnter = this.onPointerEnter;
renderObject.onPointerHover = this.onPointerHover;
renderObject.onPointerLeave = this.onPointerLeave;
renderObject.onPointerScroll = this.onPointerScroll;
renderObject.behavior = this.behavior;
}

if (this.onPointerLeave != null) {
listeners.Add("leave");
}
if (this.onPointerScroll != null) {
listeners.Add("scroll");
}
properties.add(new EnumerableProperty<string>("listeners", listeners, ifEmpty: "<none>"));

8
Runtime/widgets/gesture_detector.cs


}
}
void _handlePointerScroll(PointerScrollEvent evt) {
D.assert(this._recognizers != null);
foreach (GestureRecognizer recognizer in this._recognizers.Values) {
recognizer.addScrollPointer(evt);
}
}
HitTestBehavior _defaultBehavior {
get { return this.widget.child == null ? HitTestBehavior.translucent : HitTestBehavior.deferToChild; }
}

Widget result = new Listener(
onPointerDown: this._handlePointerDown,
onPointerScroll: this._handlePointerScroll,
behavior: this.widget.behavior ?? this._defaultBehavior,
child: this.widget.child
);

18
Runtime/widgets/scroll_activity.cs


void applyUserOffset(double delta);
void applyUserScrollOffset(double delta);
void goIdle();
void goBallistic(double velocity);

D.assert(details.primaryDelta != null);
this._lastDetails = details;
double offset = details.primaryDelta.Value;
if (details.isScroll) {
if (offset == 0.0) {
return;
}
if (this._reversed) {
offset = -offset;
}
this.del.applyUserScrollOffset(offset);
return;
}
if (offset != 0.0) {
this._lastNonStationaryTimestamp = details.sourceTimeStamp;
}

15
Runtime/widgets/scroll_position_with_single_context.cs


}
}
public virtual void applyUserScrollOffset(double delta) {
this.updateUserScrollDirection(delta > 0.0 ? ScrollDirection.forward : ScrollDirection.reverse);
var pixel = this.pixels - this.physics.applyPhysicsToUserOffset(this, delta);
if (pixel < this.minScrollExtent) {
pixel = this.minScrollExtent;
}
if (pixel > this.maxScrollExtent) {
pixel = this.maxScrollExtent;
}
this.setPixels(pixel);
}
public virtual void applyUserOffset(double delta) {
this.updateUserScrollDirection(delta > 0.0 ? ScrollDirection.forward : ScrollDirection.reverse);
this.setPixels(this.pixels - this.physics.applyPhysicsToUserOffset(this, delta));

12
Runtime/widgets/sliver.cs


using Unity.UIWidgets.foundation;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.widgets {
public abstract class SliverChildDelegate {

}
Dictionary<int, Widget> _childWidgets = new Dictionary<int, Widget>();
SortedDictionary<int, Element> _childElements = new SortedDictionary<int, Element>();
SplayTree<int, Element> _childElements = new SplayTree<int, Element>();
RenderBox _currentBeforeChild;
protected override void performRebuild() {

int lastIndex = 0;
if (!this._childElements.isEmpty()) {
firstIndex = this._childElements.Keys.First();
lastIndex = this._childElements.Keys.Last();
firstIndex = this._childElements.First().Key;
lastIndex = this._childElements.Last().Key;
if (this._didUnderflow) {
lastIndex += 1;
}

public void didFinishLayout() {
D.assert(this.debugAssertChildListLocked());
int firstIndex = this._childElements.Keys.FirstOrDefault();
int lastIndex = this._childElements.Keys.LastOrDefault();
int firstIndex = this._childElements.FirstOrDefault().Key;
int lastIndex = this._childElements.LastOrDefault().Key;
this.widget.del.didFinishLayout(firstIndex, lastIndex);
}

8
Samples/UIWidgetSample/UIWidgetSample.unity


m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!224 &552752111
RectTransform:
m_ObjectHideFlags: 0

m_Father: {fileID: 304189374}
m_RootOrder: 6
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchorMin: {x: 0.5, y: 0}
m_AnchorMax: {x: 0.5, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 300, y: 500}
m_Pivot: {x: 0.5, y: 0.5}

m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
m_IsActive: 1
--- !u!224 &1387978527
RectTransform:
m_ObjectHideFlags: 0

正在加载...
取消
保存