浏览代码
Merge branch 'gallery' into 'master'
Merge branch 'gallery' into 'master'
Gallery See merge request upm-packages/ui-widgets/com.unity.uiwidgets!137/main
Xingwei Zhu
6 年前
当前提交
fc08aae4
共有 55 个文件被更改,包括 5949 次插入 和 176 次删除
-
4Runtime/foundation/node.mixin.gen.cs
-
3Runtime/material/button.cs
-
14Runtime/material/button_theme.cs
-
2Runtime/material/list_tile.cs
-
3Runtime/material/outline_button.cs
-
2Runtime/material/tab_controller.cs
-
3Runtime/material/tabs.cs
-
23Runtime/rendering/stack.cs
-
11Runtime/widgets/transitions.cs
-
11Samples/UIWidgetsGallery/gallery/app.cs
-
32Samples/UIWidgetsGallery/gallery/demos.cs
-
262Samples/UIWidgetsGallery/gallery/home.cs
-
8Runtime/material/animated_icons.meta
-
241Runtime/widgets/animated_switcher.cs
-
11Runtime/widgets/animated_switcher.cs.meta
-
239Runtime/widgets/banner.cs
-
3Runtime/widgets/banner.cs.meta
-
91Runtime/widgets/visibility.cs
-
3Runtime/widgets/visibility.cs.meta
-
20Samples/UIWidgetsGallery/GalleryMain.cs
-
8Samples/UIWidgetsGallery/demo.meta
-
365Samples/UIWidgetsGallery/gallery/backdrop.cs
-
3Samples/UIWidgetsGallery/gallery/backdrop.cs.meta
-
215Samples/UIWidgetsGallery/gallery/demo.cs
-
3Samples/UIWidgetsGallery/gallery/demo.cs.meta
-
53Samples/UIWidgetsGallery/gallery/example_code_parser.cs
-
3Samples/UIWidgetsGallery/gallery/example_code_parser.cs.meta
-
427Samples/UIWidgetsGallery/gallery/syntax_highlighter.cs
-
3Samples/UIWidgetsGallery/gallery/syntax_highlighter.cs.meta
-
14Tests/Resources/GalleryIcons.ttf
-
22Tests/Resources/GalleryIcons.ttf.meta
-
25Tests/Resources/unity.png
-
88Tests/Resources/unity.png.meta
-
11Runtime/material/animated_icons/animated_icons.cs.meta
-
3Runtime/material/animated_icons/animated_icons_data.cs.meta
-
8Runtime/material/animated_icons/data.meta
-
1001Runtime/material/animated_icons/data/add_event.g.cs
-
11Runtime/material/animated_icons/data/add_event.g.cs.meta
-
1001Runtime/material/animated_icons/data/arrow_menu.g.cs
-
3Runtime/material/animated_icons/data/arrow_menu.g.cs.meta
-
1001Runtime/material/animated_icons/data/close_menu.g.cs
-
3Runtime/material/animated_icons/data/close_menu.g.cs.meta
-
223Runtime/material/animated_icons/animated_icons.cs
-
54Runtime/material/animated_icons/animated_icons_data.cs
-
8Samples/UIWidgetsGallery/demo/material.meta
-
11Samples/UIWidgetsGallery/demo/material/buttons_demo.cs.meta
-
382Samples/UIWidgetsGallery/demo/material/buttons_demo.cs
-
172Samples/UIWidgetsGallery/demo/colors_demo.cs
-
11Samples/UIWidgetsGallery/demo/colors_demo.cs.meta
-
7Samples/UIWidgetsGallery/main.cs
-
0/Samples/UIWidgetsGallery/GalleryMain.cs.meta
|
|||
fileFormatVersion: 2 |
|||
guid: fe9d2309a41964cba855171391dab665 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using RSG.Promises; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.painting; |
|||
|
|||
namespace Unity.UIWidgets.widgets { |
|||
class _ChildEntry { |
|||
public _ChildEntry( |
|||
AnimationController controller, |
|||
Animation<float> animation, |
|||
Widget transition, |
|||
Widget widgetChild |
|||
) { |
|||
D.assert(animation != null); |
|||
D.assert(transition != null); |
|||
D.assert(controller != null); |
|||
this.controller = controller; |
|||
this.animation = animation; |
|||
this.transition = transition; |
|||
this.widgetChild = widgetChild; |
|||
} |
|||
|
|||
public readonly AnimationController controller; |
|||
|
|||
public readonly Animation<float> animation; |
|||
|
|||
public Widget transition; |
|||
|
|||
public Widget widgetChild; |
|||
|
|||
public override string ToString() { |
|||
return "Entry#${shortHash(this)}($widgetChild)"; |
|||
} |
|||
} |
|||
|
|||
public delegate Widget AnimatedSwitcherTransitionBuilder(Widget child, Animation<float> animation); |
|||
|
|||
public delegate Widget AnimatedSwitcherLayoutBuilder(Widget currentChild, List<Widget> previousChildren); |
|||
|
|||
public class AnimatedSwitcher : StatefulWidget { |
|||
public AnimatedSwitcher( |
|||
Key key = null, |
|||
Widget child = null, |
|||
TimeSpan? duration = null, |
|||
Curve switchInCurve = null, |
|||
Curve switchOutCurve = null, |
|||
AnimatedSwitcherTransitionBuilder transitionBuilder = null, |
|||
AnimatedSwitcherLayoutBuilder layoutBuilder = null |
|||
) : base(key: key) { |
|||
D.assert(duration != null); |
|||
this.switchInCurve = switchInCurve ?? Curves.linear; |
|||
this.switchOutCurve = switchOutCurve ?? Curves.linear; |
|||
this.transitionBuilder = transitionBuilder ?? defaultTransitionBuilder; |
|||
this.layoutBuilder = layoutBuilder ?? defaultLayoutBuilder; |
|||
this.child = child; |
|||
this.duration = duration; |
|||
} |
|||
|
|||
public readonly Widget child; |
|||
|
|||
public readonly TimeSpan? duration; |
|||
|
|||
public readonly Curve switchInCurve; |
|||
|
|||
public readonly Curve switchOutCurve; |
|||
|
|||
public readonly AnimatedSwitcherTransitionBuilder transitionBuilder; |
|||
|
|||
public readonly AnimatedSwitcherLayoutBuilder layoutBuilder; |
|||
|
|||
public override State createState() { |
|||
return new _AnimatedSwitcherState(); |
|||
} |
|||
|
|||
public static Widget defaultTransitionBuilder(Widget child, Animation<float> animation) { |
|||
return new FadeTransition( |
|||
opacity: animation, |
|||
child: child |
|||
); |
|||
} |
|||
|
|||
public static Widget defaultLayoutBuilder(Widget currentChild, List<Widget> previousChildren) { |
|||
List<Widget> children = previousChildren; |
|||
if (currentChild != null) { |
|||
children = children.ToList(); |
|||
children.Add(currentChild); |
|||
} |
|||
|
|||
return new Stack( |
|||
children: children, |
|||
alignment: Alignment.center |
|||
); |
|||
} |
|||
} |
|||
|
|||
class _AnimatedSwitcherState : TickerProviderStateMixin<AnimatedSwitcher> { |
|||
_ChildEntry _currentEntry; |
|||
HashSet<_ChildEntry> _outgoingEntries = new HashSet<_ChildEntry>(); |
|||
List<Widget> _outgoingWidgets = new List<Widget>(); |
|||
int _childNumber = 0; |
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
this._addEntryForNewChild(animate: false); |
|||
} |
|||
|
|||
public override void didUpdateWidget(StatefulWidget _oldWidget) { |
|||
base.didUpdateWidget(_oldWidget); |
|||
AnimatedSwitcher oldWidget = _oldWidget as AnimatedSwitcher; |
|||
|
|||
if (this.widget.transitionBuilder != oldWidget.transitionBuilder) { |
|||
this._outgoingEntries.Each(this._updateTransitionForEntry); |
|||
if (this._currentEntry != null) { |
|||
this._updateTransitionForEntry(this._currentEntry); |
|||
} |
|||
|
|||
this._markChildWidgetCacheAsDirty(); |
|||
} |
|||
|
|||
bool hasNewChild = this.widget.child != null; |
|||
bool hasOldChild = this._currentEntry != null; |
|||
if (hasNewChild != hasOldChild || |
|||
hasNewChild && !Widget.canUpdate(this.widget.child, this._currentEntry.widgetChild)) { |
|||
this._childNumber += 1; |
|||
this._addEntryForNewChild(animate: true); |
|||
} |
|||
else if (this._currentEntry != null) { |
|||
D.assert(hasOldChild && hasNewChild); |
|||
D.assert(Widget.canUpdate(this.widget.child, this._currentEntry.widgetChild)); |
|||
this._currentEntry.widgetChild = this.widget.child; |
|||
this._updateTransitionForEntry(this._currentEntry); |
|||
this._markChildWidgetCacheAsDirty(); |
|||
} |
|||
} |
|||
|
|||
void _addEntryForNewChild(bool animate) { |
|||
D.assert(animate || this._currentEntry == null); |
|||
if (this._currentEntry != null) { |
|||
D.assert(animate); |
|||
D.assert(!this._outgoingEntries.Contains(this._currentEntry)); |
|||
this._outgoingEntries.Add(this._currentEntry); |
|||
this._currentEntry.controller.reverse(); |
|||
this._markChildWidgetCacheAsDirty(); |
|||
this._currentEntry = null; |
|||
} |
|||
|
|||
if (this.widget.child == null) { |
|||
return; |
|||
} |
|||
|
|||
AnimationController controller = new AnimationController( |
|||
duration: this.widget.duration, |
|||
vsync: this |
|||
); |
|||
Animation<float> animation = new CurvedAnimation( |
|||
parent: controller, |
|||
curve: this.widget.switchInCurve, |
|||
reverseCurve: this.widget.switchOutCurve |
|||
); |
|||
this._currentEntry = this._newEntry( |
|||
child: this.widget.child, |
|||
controller: controller, |
|||
animation: animation, |
|||
builder: this.widget.transitionBuilder |
|||
); |
|||
if (animate) { |
|||
controller.forward(); |
|||
} |
|||
else { |
|||
D.assert(this._outgoingEntries.isEmpty); |
|||
controller.setValue(1.0f); |
|||
} |
|||
} |
|||
|
|||
_ChildEntry _newEntry( |
|||
Widget child, |
|||
AnimatedSwitcherTransitionBuilder builder, |
|||
AnimationController controller, |
|||
Animation<float> animation |
|||
) { |
|||
_ChildEntry entry = new _ChildEntry( |
|||
widgetChild: child, |
|||
transition: KeyedSubtree.wrap(builder(child, animation), this._childNumber), |
|||
animation: animation, |
|||
controller: controller |
|||
); |
|||
animation.addStatusListener((AnimationStatus status) => { |
|||
if (status == AnimationStatus.dismissed) { |
|||
this.setState(() => { |
|||
D.assert(this.mounted); |
|||
D.assert(this._outgoingEntries.Contains(entry)); |
|||
this._outgoingEntries.Remove(entry); |
|||
this._markChildWidgetCacheAsDirty(); |
|||
}); |
|||
controller.dispose(); |
|||
} |
|||
}); |
|||
return entry; |
|||
} |
|||
|
|||
void _markChildWidgetCacheAsDirty() { |
|||
this._outgoingWidgets = null; |
|||
} |
|||
|
|||
void _updateTransitionForEntry(_ChildEntry entry) { |
|||
entry.transition = new KeyedSubtree( |
|||
key: entry.transition.key, |
|||
child: this.widget.transitionBuilder(entry.widgetChild, entry.animation) |
|||
); |
|||
} |
|||
|
|||
void _rebuildOutgoingWidgetsIfNeeded() { |
|||
this._outgoingWidgets = this._outgoingWidgets ?? new List<Widget>( |
|||
this._outgoingEntries.Select((_ChildEntry entry) => entry.transition) |
|||
); |
|||
D.assert(this._outgoingEntries.Count == this._outgoingWidgets.Count); |
|||
D.assert(this._outgoingEntries.isEmpty() || |
|||
this._outgoingEntries.Last().transition == this._outgoingWidgets.Last()); |
|||
} |
|||
|
|||
public override void dispose() { |
|||
if (this._currentEntry != null) { |
|||
this._currentEntry.controller.dispose(); |
|||
} |
|||
|
|||
foreach (_ChildEntry entry in this._outgoingEntries) { |
|||
entry.controller.dispose(); |
|||
} |
|||
|
|||
base.dispose(); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
this._rebuildOutgoingWidgetsIfNeeded(); |
|||
return this.widget.layoutBuilder(this._currentEntry?.transition, this._outgoingWidgets); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: bfa637befa3d147118ae1e48760e552d |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.ui; |
|||
using UnityEngine; |
|||
using Canvas = Unity.UIWidgets.ui.Canvas; |
|||
using Color = Unity.UIWidgets.ui.Color; |
|||
using Rect = Unity.UIWidgets.ui.Rect; |
|||
using TextStyle = Unity.UIWidgets.painting.TextStyle; |
|||
|
|||
namespace Unity.UIWidgets.widgets { |
|||
class BannerConstants { |
|||
public const float _kOffset = 40.0f; |
|||
public const float _kHeight = 12.0f; |
|||
public const float _kBottomOffset = _kOffset + 0.707f * _kHeight; |
|||
public static readonly Rect _kRect = Rect.fromLTWH(-_kOffset, _kOffset - _kHeight, _kOffset * 2.0f, _kHeight); |
|||
|
|||
public static readonly Color _kColor = new Color(0xA0B71C1C); |
|||
|
|||
public static readonly TextStyle _kTextStyle = new TextStyle( |
|||
color: new Color(0xFFFFFFFF), |
|||
fontSize: _kHeight * 0.85f, |
|||
fontWeight: FontWeight.w700, |
|||
height: 1.0f |
|||
); |
|||
} |
|||
|
|||
public enum BannerLocation { |
|||
topStart, |
|||
|
|||
topEnd, |
|||
|
|||
bottomStart, |
|||
|
|||
bottomEnd, |
|||
} |
|||
|
|||
public class BannerPainter : AbstractCustomPainter { |
|||
public BannerPainter( |
|||
string message, |
|||
BannerLocation? location, |
|||
Color color = null, |
|||
TextStyle textStyle = null |
|||
) { |
|||
D.assert(message != null); |
|||
D.assert(location != null); |
|||
this.color = color ?? BannerConstants._kColor; |
|||
this.message = message; |
|||
this.location = location; |
|||
this.textStyle = textStyle ?? BannerConstants._kTextStyle; |
|||
} |
|||
|
|||
public readonly string message; |
|||
|
|||
public readonly BannerLocation? location; |
|||
|
|||
public readonly Color color; |
|||
|
|||
public readonly TextStyle textStyle; |
|||
|
|||
readonly BoxShadow _shadow = new BoxShadow( |
|||
color: new Color(0x7F000000), |
|||
blurRadius: 6.0f |
|||
); |
|||
|
|||
bool _prepared = false; |
|||
TextPainter _textPainter; |
|||
Paint _paintShadow; |
|||
Paint _paintBanner; |
|||
|
|||
void _prepare() { |
|||
this._paintShadow = this._shadow.toPaint(); |
|||
this._paintBanner = new Paint(); |
|||
this._paintBanner.color = this.color; |
|||
this._textPainter = new TextPainter( |
|||
text: new TextSpan(style: this.textStyle, text: this.message), |
|||
textAlign: TextAlign.center |
|||
); |
|||
this._prepared = true; |
|||
} |
|||
|
|||
public override void paint(Canvas canvas, Size size) { |
|||
if (!this._prepared) { |
|||
this._prepare(); |
|||
} |
|||
|
|||
canvas.translate(this._translationX(size.width), this._translationY(size.height)); |
|||
canvas.rotate(this._rotation); |
|||
canvas.drawRect(BannerConstants._kRect, this._paintShadow); |
|||
canvas.drawRect(BannerConstants._kRect, this._paintBanner); |
|||
const float width = BannerConstants._kOffset * 2.0f; |
|||
this._textPainter.layout(minWidth: width, maxWidth: width); |
|||
this._textPainter.paint(canvas, |
|||
BannerConstants._kRect.topLeft + new Offset(0.0f, |
|||
(BannerConstants._kRect.height - this._textPainter.height) / 2.0f)); |
|||
} |
|||
|
|||
public override bool shouldRepaint(CustomPainter _oldDelegate) { |
|||
BannerPainter oldDelegate = _oldDelegate as BannerPainter; |
|||
return this.message != oldDelegate.message |
|||
|| this.location != oldDelegate.location |
|||
|| this.color != oldDelegate.color |
|||
|| this.textStyle != oldDelegate.textStyle; |
|||
} |
|||
|
|||
public override bool? hitTest(Offset position) { |
|||
return false; |
|||
} |
|||
|
|||
float _translationX(float width) { |
|||
switch (this.location) { |
|||
case BannerLocation.bottomEnd: |
|||
return width - BannerConstants._kBottomOffset; |
|||
case BannerLocation.topEnd: |
|||
return width; |
|||
case BannerLocation.bottomStart: |
|||
return BannerConstants._kBottomOffset; |
|||
case BannerLocation.topStart: |
|||
return 0.0f; |
|||
default: |
|||
throw new Exception("Unknown location: " + this.location); |
|||
} |
|||
} |
|||
|
|||
float _translationY(float height) { |
|||
D.assert(this.location != null); |
|||
switch (this.location) { |
|||
case BannerLocation.bottomStart: |
|||
case BannerLocation.bottomEnd: |
|||
return height - BannerConstants._kBottomOffset; |
|||
case BannerLocation.topStart: |
|||
case BannerLocation.topEnd: |
|||
return 0.0f; |
|||
default: |
|||
throw new Exception("Unknown location: " + this.location); |
|||
} |
|||
} |
|||
|
|||
float _rotation { |
|||
get { |
|||
switch (this.location) { |
|||
case BannerLocation.bottomStart: |
|||
case BannerLocation.topEnd: |
|||
return Mathf.PI / 4.0f; |
|||
case BannerLocation.bottomEnd: |
|||
case BannerLocation.topStart: |
|||
return -Mathf.PI / 4.0f; |
|||
default: |
|||
throw new Exception("Unknown location: " + this.location); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class Banner : StatelessWidget { |
|||
public Banner( |
|||
Key key = null, |
|||
Widget child = null, |
|||
string message = null, |
|||
BannerLocation? location = null, |
|||
Color color = null, |
|||
TextStyle textStyle = null |
|||
) : base(key: key) { |
|||
D.assert(message != null); |
|||
this.child = child; |
|||
this.message = message; |
|||
this.location = location; |
|||
this.color = color ?? BannerConstants._kColor; |
|||
this.textStyle = textStyle ?? BannerConstants._kTextStyle; |
|||
} |
|||
|
|||
public readonly Widget child; |
|||
|
|||
public readonly string message; |
|||
|
|||
public readonly BannerLocation? location; |
|||
|
|||
public readonly Color color; |
|||
|
|||
public readonly TextStyle textStyle; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
D.assert(WidgetsD.debugCheckHasDirectionality(context)); |
|||
return new CustomPaint( |
|||
foregroundPainter: new BannerPainter( |
|||
message: this.message, |
|||
location: this.location, |
|||
color: this.color, |
|||
textStyle: this.textStyle |
|||
), |
|||
child: this.child |
|||
); |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new StringProperty("message", this.message, showName: false)); |
|||
properties.add(new EnumProperty<BannerLocation?>("location", this.location)); |
|||
properties.add(new DiagnosticsProperty<Color>("color", this.color, showName: false)); |
|||
this.textStyle?.debugFillProperties(properties); |
|||
} |
|||
} |
|||
|
|||
public class CheckedModeBanner : StatelessWidget { |
|||
public CheckedModeBanner( |
|||
Key key = null, |
|||
Widget child = null |
|||
) : base(key: key) { |
|||
D.assert(child != null); |
|||
this.child = child; |
|||
} |
|||
|
|||
|
|||
public readonly Widget child; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
Widget result = this.child; |
|||
D.assert(() => { |
|||
result = new Banner( |
|||
child: result, |
|||
message: "DEBUG", |
|||
location: BannerLocation.topEnd |
|||
); |
|||
return true; |
|||
}); |
|||
return result; |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
string message = "disabled"; |
|||
D.assert(() => { |
|||
message = "'DEBUG'"; |
|||
return true; |
|||
}); |
|||
properties.add(DiagnosticsNode.message(message)); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: e2e859ca92594b5d98bcce5ce505ca7b |
|||
timeCreated: 1552882905 |
|
|||
using Unity.UIWidgets.foundation; |
|||
|
|||
namespace Unity.UIWidgets.widgets { |
|||
public class Visibility : StatelessWidget { |
|||
public Visibility( |
|||
Key key = null, |
|||
Widget child = null, |
|||
Widget replacement = null, |
|||
bool visible = true, |
|||
bool maintainState = false, |
|||
bool maintainAnimation = false, |
|||
bool maintainSize = false, |
|||
bool maintainInteractivity = false |
|||
) : base(key: key) { |
|||
D.assert(child != null); |
|||
D.assert(maintainState == true || maintainAnimation == false, |
|||
"Cannot maintain animations if the state is not also maintained."); |
|||
D.assert(maintainAnimation == true || maintainSize == false, |
|||
"Cannot maintain size if animations are not maintained."); |
|||
D.assert(maintainSize == true || maintainInteractivity == false, |
|||
"Cannot maintain interactivity if size is not maintained."); |
|||
this.replacement = replacement ?? SizedBox.shrink(); |
|||
this.child = child; |
|||
this.visible = visible; |
|||
this.maintainState = maintainState; |
|||
this.maintainAnimation = maintainAnimation; |
|||
this.maintainSize = maintainSize; |
|||
this.maintainInteractivity = maintainInteractivity; |
|||
} |
|||
|
|||
public readonly Widget child; |
|||
|
|||
public readonly Widget replacement; |
|||
|
|||
public readonly bool visible; |
|||
|
|||
public readonly bool maintainState; |
|||
|
|||
public readonly bool maintainAnimation; |
|||
|
|||
public readonly bool maintainSize; |
|||
|
|||
public readonly bool maintainInteractivity; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
if (this.maintainSize) { |
|||
Widget result = this.child; |
|||
if (!this.maintainInteractivity) { |
|||
result = new IgnorePointer( |
|||
child: this.child, |
|||
ignoring: !this.visible |
|||
); |
|||
} |
|||
|
|||
return new Opacity( |
|||
opacity: this.visible ? 1.0f : 0.0f, |
|||
child: result |
|||
); |
|||
} |
|||
|
|||
D.assert(!this.maintainInteractivity); |
|||
D.assert(!this.maintainSize); |
|||
if (this.maintainState) { |
|||
Widget result = this.child; |
|||
if (!this.maintainAnimation) { |
|||
result = new TickerMode(child: this.child, enabled: this.visible); |
|||
} |
|||
|
|||
return new Offstage( |
|||
child: result, |
|||
offstage: !this.visible |
|||
); |
|||
} |
|||
|
|||
D.assert(!this.maintainAnimation); |
|||
D.assert(!this.maintainState); |
|||
return this.visible ? this.child : this.replacement; |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new FlagProperty("visible", value: this.visible, ifFalse: "hidden", ifTrue: "visible")); |
|||
properties.add(new FlagProperty("maintainState", value: this.maintainState, ifFalse: "maintainState")); |
|||
properties.add(new FlagProperty("maintainAnimation", value: this.maintainAnimation, |
|||
ifFalse: "maintainAnimation")); |
|||
properties.add(new FlagProperty("maintainSize", value: this.maintainSize, ifFalse: "maintainSize")); |
|||
properties.add(new FlagProperty("maintainInteractivity", value: this.maintainInteractivity, |
|||
ifFalse: "maintainInteractivity")); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: f24846c5a2354d9a8b02bf83f3e8398e |
|||
timeCreated: 1552895385 |
|
|||
using UIWidgetsGallery.gallery; |
|||
using Unity.UIWidgets.engine; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
using UnityEngine; |
|||
|
|||
namespace UIWidgetsGallery { |
|||
public class GalleryMain : UIWidgetsPanel { |
|||
protected override Widget createWidget() { |
|||
return new GalleryApp(); |
|||
} |
|||
|
|||
protected override void Start() { |
|||
base.Start(); |
|||
FontManager.instance.addFont(Resources.Load<Font>("MaterialIcons-Regular")); |
|||
FontManager.instance.addFont(Resources.Load<Font>("GalleryIcons")); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 5159692a5f76049d49b05fb717c096e3 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.gestures; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
using UnityEngine; |
|||
|
|||
namespace UIWidgetsGallery.gallery { |
|||
class BackdropConstants { |
|||
public const float _kFrontHeadingHeight = 32.0f; |
|||
public const float _kFrontClosedHeight = 92.0f; |
|||
public const float _kBackAppBarHeight = 56.0f; |
|||
|
|||
public static readonly Animatable<BorderRadius> _kFrontHeadingBevelRadius = new BorderRadiusTween( |
|||
begin: BorderRadius.only( |
|||
topLeft: Radius.circular(12.0f), |
|||
topRight: Radius.circular(12.0f) |
|||
), |
|||
end: BorderRadius.only( |
|||
topLeft: Radius.circular(_kFrontHeadingHeight), |
|||
topRight: Radius.circular(_kFrontHeadingHeight) |
|||
) |
|||
); |
|||
} |
|||
|
|||
class _TappableWhileStatusIs : StatefulWidget { |
|||
public _TappableWhileStatusIs( |
|||
AnimationStatus status, |
|||
Key key = null, |
|||
AnimationController controller = null, |
|||
Widget child = null |
|||
) : base(key: key) { |
|||
this.controller = controller; |
|||
this.status = status; |
|||
this.child = child; |
|||
} |
|||
|
|||
public readonly AnimationController controller; |
|||
public readonly AnimationStatus status; |
|||
public readonly Widget child; |
|||
|
|||
public override State createState() { |
|||
return new _TappableWhileStatusIsState(); |
|||
} |
|||
} |
|||
|
|||
class _TappableWhileStatusIsState : State<_TappableWhileStatusIs> { |
|||
bool _active; |
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
this.widget.controller.addStatusListener(this._handleStatusChange); |
|||
this._active = this.widget.controller.status == this.widget.status; |
|||
} |
|||
|
|||
public override void dispose() { |
|||
this.widget.controller.removeStatusListener(this._handleStatusChange); |
|||
base.dispose(); |
|||
} |
|||
|
|||
void _handleStatusChange(AnimationStatus status) { |
|||
bool value = this.widget.controller.status == this.widget.status; |
|||
if (this._active != value) { |
|||
this.setState(() => { this._active = value; }); |
|||
} |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return new AbsorbPointer( |
|||
absorbing: !this._active, |
|||
child: this.widget.child |
|||
); |
|||
} |
|||
} |
|||
|
|||
class _CrossFadeTransition : AnimatedWidget { |
|||
public _CrossFadeTransition( |
|||
Key key = null, |
|||
Alignment alignment = null, |
|||
Animation<float> progress = null, |
|||
Widget child0 = null, |
|||
Widget child1 = null |
|||
) : base(key: key, listenable: progress) { |
|||
this.alignment = alignment ?? Alignment.center; |
|||
this.child0 = child0; |
|||
this.child1 = child1; |
|||
} |
|||
|
|||
public readonly Alignment alignment; |
|||
public readonly Widget child0; |
|||
public readonly Widget child1; |
|||
|
|||
protected override Widget build(BuildContext context) { |
|||
Animation<float> progress = this.listenable as Animation<float>; |
|||
|
|||
float opacity1 = new CurvedAnimation( |
|||
parent: new ReverseAnimation(progress), |
|||
curve: new Interval(0.5f, 1.0f) |
|||
).value; |
|||
|
|||
float opacity2 = new CurvedAnimation( |
|||
parent: progress, |
|||
curve: new Interval(0.5f, 1.0f) |
|||
).value; |
|||
|
|||
return new Stack( |
|||
alignment: this.alignment, |
|||
children: new List<Widget> { |
|||
new Opacity( |
|||
opacity: opacity1, |
|||
child: this.child1 |
|||
), |
|||
new Opacity( |
|||
opacity: opacity2, |
|||
child: this.child0 |
|||
) |
|||
} |
|||
); |
|||
} |
|||
} |
|||
|
|||
class _BackAppBar : StatelessWidget { |
|||
public _BackAppBar( |
|||
Key key = null, |
|||
Widget leading = null, |
|||
Widget title = null, |
|||
Widget trailing = null |
|||
) : base(key: key) { |
|||
D.assert(title != null); |
|||
this.leading = leading ?? new SizedBox(width: 56.0f); |
|||
this.title = title; |
|||
this.trailing = trailing; |
|||
} |
|||
|
|||
public readonly Widget leading; |
|||
public readonly Widget title; |
|||
public readonly Widget trailing; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
List<Widget> children = new List<Widget> { |
|||
new Container( |
|||
alignment: Alignment.center, |
|||
width: 56.0f, |
|||
child: this.leading |
|||
), |
|||
new Expanded( |
|||
child: this.title |
|||
), |
|||
}; |
|||
|
|||
if (this.trailing != null) { |
|||
children.Add( |
|||
new Container( |
|||
alignment: Alignment.center, |
|||
width: 56.0f, |
|||
child: this.trailing |
|||
) |
|||
); |
|||
} |
|||
|
|||
ThemeData theme = Theme.of(context); |
|||
|
|||
return IconTheme.merge( |
|||
data: theme.primaryIconTheme, |
|||
child: new DefaultTextStyle( |
|||
style: theme.primaryTextTheme.title, |
|||
child: new SizedBox( |
|||
height: BackdropConstants._kBackAppBarHeight, |
|||
child: new Row(children: children) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
public class Backdrop : StatefulWidget { |
|||
public Backdrop( |
|||
Widget frontAction = null, |
|||
Widget frontTitle = null, |
|||
Widget frontHeading = null, |
|||
Widget frontLayer = null, |
|||
Widget backTitle = null, |
|||
Widget backLayer = null |
|||
) { |
|||
this.frontAction = frontAction; |
|||
this.frontTitle = frontTitle; |
|||
this.frontHeading = frontHeading; |
|||
this.frontLayer = frontLayer; |
|||
this.backTitle = backTitle; |
|||
this.backLayer = backLayer; |
|||
} |
|||
|
|||
public readonly Widget frontAction; |
|||
public readonly Widget frontTitle; |
|||
public readonly Widget frontLayer; |
|||
public readonly Widget frontHeading; |
|||
public readonly Widget backTitle; |
|||
public readonly Widget backLayer; |
|||
|
|||
public override State createState() { |
|||
return new _BackdropState(); |
|||
} |
|||
} |
|||
|
|||
class _BackdropState : SingleTickerProviderStateMixin<Backdrop> { |
|||
GlobalKey _backdropKey = GlobalKey.key(debugLabel: "Backdrop"); |
|||
AnimationController _controller; |
|||
Animation<float> _frontOpacity; |
|||
|
|||
static Animatable<float> _frontOpacityTween = new FloatTween(begin: 0.2f, end: 1.0f) |
|||
.chain(new CurveTween(curve: new Interval(0.0f, 0.4f, curve: Curves.easeInOut))); |
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
this._controller = new AnimationController( |
|||
duration: new TimeSpan(0, 0, 0, 0, 300), |
|||
value: 1.0f, |
|||
vsync: this |
|||
); |
|||
this._frontOpacity = this._controller.drive(_frontOpacityTween); |
|||
} |
|||
|
|||
public override void dispose() { |
|||
this._controller.dispose(); |
|||
base.dispose(); |
|||
} |
|||
|
|||
float? _backdropHeight { |
|||
get { |
|||
RenderBox renderBox = (RenderBox) this._backdropKey.currentContext.findRenderObject(); |
|||
return Mathf.Max(0.0f, |
|||
renderBox.size.height - BackdropConstants._kBackAppBarHeight - |
|||
BackdropConstants._kFrontClosedHeight); |
|||
} |
|||
} |
|||
|
|||
void _handleDragUpdate(DragUpdateDetails details) { |
|||
this._controller.setValue(this._controller.value - |
|||
details.primaryDelta / (this._backdropHeight ?? details.primaryDelta) ?? 0.0f); |
|||
} |
|||
|
|||
void _handleDragEnd(DragEndDetails details) { |
|||
if (this._controller.isAnimating || this._controller.status == AnimationStatus.completed) { |
|||
return; |
|||
} |
|||
|
|||
float? flingVelocity = details.velocity.pixelsPerSecond.dy / this._backdropHeight; |
|||
if (flingVelocity < 0.0f) { |
|||
this._controller.fling(velocity: Mathf.Max(2.0f, -flingVelocity ?? 0.0f)); |
|||
} |
|||
else if (flingVelocity > 0.0f) { |
|||
this._controller.fling(velocity: Mathf.Min(-2.0f, -flingVelocity ?? 0.0f)); |
|||
} |
|||
else { |
|||
this._controller.fling(velocity: this._controller.value < 0.5 ? -2.0f : 2.0f); |
|||
} |
|||
} |
|||
|
|||
void _toggleFrontLayer() { |
|||
AnimationStatus status = this._controller.status; |
|||
bool isOpen = status == AnimationStatus.completed || status == AnimationStatus.forward; |
|||
this._controller.fling(velocity: isOpen ? -2.0f : 2.0f); |
|||
} |
|||
|
|||
Widget _buildStack(BuildContext context, BoxConstraints constraints) { |
|||
Animation<RelativeRect> frontRelativeRect = this._controller.drive(new RelativeRectTween( |
|||
begin: RelativeRect.fromLTRB(0.0f, constraints.biggest.height - BackdropConstants._kFrontClosedHeight, |
|||
0.0f, 0.0f), |
|||
end: RelativeRect.fromLTRB(0.0f, BackdropConstants._kBackAppBarHeight, 0.0f, 0.0f) |
|||
)); |
|||
|
|||
List<Widget> layers = new List<Widget> { |
|||
new Column( |
|||
crossAxisAlignment: CrossAxisAlignment.stretch, |
|||
children: new List<Widget> { |
|||
new _BackAppBar( |
|||
leading: this.widget.frontAction, |
|||
title: new _CrossFadeTransition( |
|||
progress: this._controller, |
|||
alignment: Alignment.centerLeft, |
|||
child0: this.widget.frontTitle, |
|||
child1: this.widget.backTitle |
|||
), |
|||
trailing: new IconButton( |
|||
onPressed: this._toggleFrontLayer, |
|||
tooltip: "Toggle options page", |
|||
icon: new AnimatedIcon( |
|||
icon: AnimatedIcons.close_menu, |
|||
progress: this._controller |
|||
) |
|||
) |
|||
), |
|||
new Expanded( |
|||
child: new Visibility( |
|||
child: this.widget.backLayer, |
|||
visible: this._controller.status != AnimationStatus.completed, |
|||
maintainState: true |
|||
) |
|||
) |
|||
} |
|||
), |
|||
new PositionedTransition( |
|||
rect: frontRelativeRect, |
|||
child: new AnimatedBuilder( |
|||
animation: this._controller, |
|||
builder: (BuildContext _context, Widget child) => { |
|||
return new PhysicalShape( |
|||
elevation: 12.0f, |
|||
color: Theme.of(_context).canvasColor, |
|||
clipper: new ShapeBorderClipper( |
|||
shape: new BeveledRectangleBorder( |
|||
borderRadius: BackdropConstants._kFrontHeadingBevelRadius.evaluate( |
|||
this._controller) |
|||
) |
|||
), |
|||
clipBehavior: Clip.antiAlias, |
|||
child: child |
|||
); |
|||
}, |
|||
child: new _TappableWhileStatusIs( |
|||
AnimationStatus.completed, |
|||
controller: this._controller, |
|||
child: new FadeTransition( |
|||
opacity: this._frontOpacity, |
|||
child: this.widget.frontLayer |
|||
) |
|||
) |
|||
) |
|||
) |
|||
}; |
|||
|
|||
if (this.widget.frontHeading != null) { |
|||
layers.Add( |
|||
new PositionedTransition( |
|||
rect: frontRelativeRect, |
|||
child: new Container( |
|||
alignment: Alignment.topLeft, |
|||
child: new GestureDetector( |
|||
behavior: HitTestBehavior.opaque, |
|||
onTap: this._toggleFrontLayer, |
|||
onVerticalDragUpdate: this._handleDragUpdate, |
|||
onVerticalDragEnd: this._handleDragEnd, |
|||
child: this.widget.frontHeading |
|||
) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
|
|||
return new Stack( |
|||
key: this._backdropKey, |
|||
children: layers |
|||
); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return new LayoutBuilder(builder: this._buildStack); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: f3ee24c4986845abb1356402632d8524 |
|||
timeCreated: 1552886622 |
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.service; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace UIWidgetsGallery.gallery { |
|||
class ComponentDemoTabData { |
|||
public ComponentDemoTabData( |
|||
Widget demoWidget = null, |
|||
string exampleCodeTag = null, |
|||
string description = null, |
|||
string tabName = null, |
|||
string documentationUrl = null |
|||
) { |
|||
this.demoWidget = demoWidget; |
|||
this.exampleCodeTag = exampleCodeTag; |
|||
this.description = description; |
|||
this.tabName = tabName; |
|||
this.documentationUrl = documentationUrl; |
|||
} |
|||
|
|||
public readonly Widget demoWidget; |
|||
public readonly string exampleCodeTag; |
|||
public readonly string description; |
|||
public readonly string tabName; |
|||
public readonly string documentationUrl; |
|||
|
|||
public static bool operator ==(ComponentDemoTabData left, ComponentDemoTabData right) { |
|||
return right.tabName == left.tabName |
|||
&& right.description == left.description |
|||
&& right.documentationUrl == left.documentationUrl; |
|||
} |
|||
|
|||
public static bool operator !=(ComponentDemoTabData left, ComponentDemoTabData right) { |
|||
return right.tabName != left.tabName |
|||
|| right.description != left.description |
|||
|| right.documentationUrl != left.documentationUrl; |
|||
} |
|||
|
|||
public override int GetHashCode() { |
|||
unchecked { |
|||
var hashCode = this.tabName.GetHashCode(); |
|||
hashCode = (hashCode * 397) ^ this.description.GetHashCode(); |
|||
hashCode = (hashCode * 397) ^ this.documentationUrl.GetHashCode(); |
|||
return hashCode; |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
class TabbedComponentDemoScaffold : StatelessWidget { |
|||
public TabbedComponentDemoScaffold( |
|||
string title = null, |
|||
List<ComponentDemoTabData> demos = null, |
|||
List<Widget> actions = null |
|||
) { |
|||
this.title = title; |
|||
this.demos = demos; |
|||
this.actions = actions; |
|||
} |
|||
|
|||
public readonly List<ComponentDemoTabData> demos; |
|||
public readonly string title; |
|||
public readonly List<Widget> actions; |
|||
|
|||
void _showExampleCode(BuildContext context) { |
|||
string tag = this.demos[DefaultTabController.of(context).index].exampleCodeTag; |
|||
if (tag != null) { |
|||
Navigator.push(context, new MaterialPageRoute( |
|||
builder: (BuildContext _context) => new FullScreenCodeDialog(exampleCodeTag: tag) |
|||
)); |
|||
} |
|||
} |
|||
|
|||
void _showApiDocumentation(BuildContext context) { |
|||
string url = this.demos[DefaultTabController.of(context).index].documentationUrl; |
|||
if (url != null) { |
|||
// TODO: find Unity equivalent
|
|||
// Open the URL in browser
|
|||
// launch(url, forceWebView: true);
|
|||
} |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
List<Widget> actions = this.actions ?? new List<Widget> { }; |
|||
actions.AddRange( |
|||
new List<Widget> { |
|||
new Builder( |
|||
builder: (BuildContext _context) => { |
|||
return new IconButton( |
|||
icon: new Icon(Icons.library_books), |
|||
onPressed: () => this._showApiDocumentation(_context) |
|||
); |
|||
} |
|||
), |
|||
new Builder( |
|||
builder: (BuildContext _context) => { |
|||
return new IconButton( |
|||
icon: new Icon(Icons.code), |
|||
tooltip: "Show example code", |
|||
onPressed: () => this._showExampleCode(_context) |
|||
); |
|||
} |
|||
) |
|||
} |
|||
); |
|||
return new DefaultTabController( |
|||
length: this.demos.Count, |
|||
child: new Scaffold( |
|||
appBar: new AppBar( |
|||
title: new Text(this.title), |
|||
actions: actions, |
|||
bottom: new TabBar( |
|||
isScrollable: true, |
|||
tabs: this.demos.Select<ComponentDemoTabData, Widget>( |
|||
(ComponentDemoTabData data) => new Tab(text: data.tabName)) |
|||
.ToList() |
|||
) |
|||
), |
|||
body: new TabBarView( |
|||
children: this.demos.Select<ComponentDemoTabData, Widget>((ComponentDemoTabData demo) => { |
|||
return new SafeArea( |
|||
top: false, |
|||
bottom: false, |
|||
child: new Column( |
|||
children: new List<Widget> { |
|||
new Padding( |
|||
padding: EdgeInsets.all(16.0f), |
|||
child: new Text(demo.description, |
|||
style: Theme.of(context).textTheme.subhead |
|||
) |
|||
), |
|||
new Expanded(child: demo.demoWidget) |
|||
} |
|||
) |
|||
); |
|||
}).ToList() |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
|
|||
class FullScreenCodeDialog : StatefulWidget { |
|||
public FullScreenCodeDialog(Key key = null, string exampleCodeTag = null) : base(key: key) { |
|||
this.exampleCodeTag = exampleCodeTag; |
|||
} |
|||
|
|||
public readonly string exampleCodeTag; |
|||
|
|||
public override State createState() { |
|||
return new FullScreenCodeDialogState(); |
|||
} |
|||
} |
|||
|
|||
class FullScreenCodeDialogState : State<FullScreenCodeDialog> { |
|||
public FullScreenCodeDialogState() { |
|||
} |
|||
|
|||
string _exampleCode; |
|||
|
|||
public override void didChangeDependencies() { |
|||
base.didChangeDependencies(); |
|||
string code = new ExampleCodeParser().getExampleCode(this.widget.exampleCodeTag, DefaultAssetBundle.of(this.context)); |
|||
if (this.mounted) { |
|||
this.setState(() => { this._exampleCode = code; }); |
|||
} |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
SyntaxHighlighterStyle style = Theme.of(context).brightness == Brightness.dark |
|||
? SyntaxHighlighterStyle.darkThemeStyle() |
|||
: SyntaxHighlighterStyle.lightThemeStyle(); |
|||
|
|||
Widget body; |
|||
if (this._exampleCode == null) { |
|||
body = new Center( |
|||
child: new CircularProgressIndicator() |
|||
); |
|||
} |
|||
else { |
|||
body = new SingleChildScrollView( |
|||
child: new Padding( |
|||
padding: EdgeInsets.all(16.0f), |
|||
child: new RichText( |
|||
text: new TextSpan( |
|||
style: new TextStyle(fontFamily: "monospace", fontSize: 10.0f), |
|||
children: new List<TextSpan> { |
|||
new DartSyntaxHighlighter(style).format(this._exampleCode) |
|||
} |
|||
) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
|
|||
return new Scaffold( |
|||
appBar: new AppBar( |
|||
leading: new IconButton( |
|||
icon: new Icon( |
|||
Icons.clear |
|||
), |
|||
onPressed: () => { Navigator.pop(context); } |
|||
), |
|||
title: new Text("Example code") |
|||
), |
|||
body: body |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 3c8404e1b03d43aba2e91d19f124de5e |
|||
timeCreated: 1552462303 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using RSG; |
|||
using Unity.UIWidgets.foundation; |
|||
using UnityEngine; |
|||
|
|||
namespace UIWidgetsGallery.gallery { |
|||
|
|||
public class ExampleCodeParser { |
|||
const string _kStartTag = "// START "; |
|||
const string _kEndTag = "// END"; |
|||
|
|||
Dictionary<string, string> _exampleCode; |
|||
|
|||
public string getExampleCode(string tag, AssetBundle bundle) { |
|||
if (this._exampleCode == null) |
|||
this._parseExampleCode(bundle); |
|||
return this._exampleCode.getOrDefault(tag); |
|||
} |
|||
|
|||
void _parseExampleCode(AssetBundle bundle) { |
|||
string code = Resources.Load<TextAsset>("example_code.cs")?.text ?? |
|||
"// example_code.cs not found\n"; |
|||
this._exampleCode = new Dictionary<string, string>{}; |
|||
|
|||
List<String> lines = code.Split('\n').ToList(); |
|||
|
|||
List<String> codeBlock = null; |
|||
string codeTag = null; |
|||
|
|||
foreach (string line in lines) { |
|||
if (codeBlock == null) { |
|||
if (line.StartsWith(_kStartTag)) { |
|||
codeBlock = new List<String>(); |
|||
codeTag = line.Substring(_kStartTag.Length).Trim(); |
|||
} else { |
|||
} |
|||
} else { |
|||
if (line.StartsWith(_kEndTag)) { |
|||
this._exampleCode[codeTag] = string.Join("\n", codeBlock); |
|||
codeBlock = null; |
|||
codeTag = null; |
|||
} else { |
|||
codeBlock.Add(line.TrimEnd()); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 57879fd6125746699974c2e0bc8762b8 |
|||
timeCreated: 1552468268 |
|
|||
using System.Collections.Generic; |
|||
using System.Text.RegularExpressions; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.ui; |
|||
using TextStyle = Unity.UIWidgets.painting.TextStyle; |
|||
|
|||
namespace UIWidgetsGallery.gallery { |
|||
public class SyntaxHighlighterStyle { |
|||
public SyntaxHighlighterStyle( |
|||
TextStyle baseStyle = null, |
|||
TextStyle numberStyle = null, |
|||
TextStyle commentStyle = null, |
|||
TextStyle keywordStyle = null, |
|||
TextStyle stringStyle = null, |
|||
TextStyle punctuationStyle = null, |
|||
TextStyle classStyle = null, |
|||
TextStyle constantStyle = null |
|||
) { |
|||
this.baseStyle = baseStyle; |
|||
this.numberStyle = numberStyle; |
|||
this.commentStyle = commentStyle; |
|||
this.keywordStyle = keywordStyle; |
|||
this.stringStyle = stringStyle; |
|||
this.punctuationStyle = punctuationStyle; |
|||
this.classStyle = classStyle; |
|||
this.constantStyle = constantStyle; |
|||
} |
|||
|
|||
public static SyntaxHighlighterStyle lightThemeStyle() { |
|||
return new SyntaxHighlighterStyle( |
|||
baseStyle: new TextStyle(color: new Color(0xFF000000)), |
|||
numberStyle: new TextStyle(color: new Color(0xFF1565C0)), |
|||
commentStyle: new TextStyle(color: new Color(0xFF9E9E9E)), |
|||
keywordStyle: new TextStyle(color: new Color(0xFF9C27B0)), |
|||
stringStyle: new TextStyle(color: new Color(0xFF43A047)), |
|||
punctuationStyle: new TextStyle(color: new Color(0xFF000000)), |
|||
classStyle: new TextStyle(color: new Color(0xFF512DA8)), |
|||
constantStyle: new TextStyle(color: new Color(0xFF795548)) |
|||
); |
|||
} |
|||
|
|||
public static SyntaxHighlighterStyle darkThemeStyle() { |
|||
return new SyntaxHighlighterStyle( |
|||
baseStyle: new TextStyle(color: new Color(0xFFFFFFFF)), |
|||
numberStyle: new TextStyle(color: new Color(0xFF1565C0)), |
|||
commentStyle: new TextStyle(color: new Color(0xFF9E9E9E)), |
|||
keywordStyle: new TextStyle(color: new Color(0xFF80CBC4)), |
|||
stringStyle: new TextStyle(color: new Color(0xFF009688)), |
|||
punctuationStyle: new TextStyle(color: new Color(0xFFFFFFFF)), |
|||
classStyle: new TextStyle(color: new Color(0xFF009688)), |
|||
constantStyle: new TextStyle(color: new Color(0xFF795548)) |
|||
); |
|||
} |
|||
|
|||
public readonly TextStyle baseStyle; |
|||
public readonly TextStyle numberStyle; |
|||
public readonly TextStyle commentStyle; |
|||
public readonly TextStyle keywordStyle; |
|||
public readonly TextStyle stringStyle; |
|||
public readonly TextStyle punctuationStyle; |
|||
public readonly TextStyle classStyle; |
|||
public readonly TextStyle constantStyle; |
|||
} |
|||
|
|||
public abstract class SyntaxHighlighter { |
|||
// ignore: one_member_abstracts
|
|||
public abstract TextSpan format(string src); |
|||
} |
|||
|
|||
public class DartSyntaxHighlighter : SyntaxHighlighter { |
|||
public DartSyntaxHighlighter(SyntaxHighlighterStyle _style = null) { |
|||
this._spans = new List<_HighlightSpan> { }; |
|||
this._style = _style ?? SyntaxHighlighterStyle.darkThemeStyle(); |
|||
} |
|||
|
|||
SyntaxHighlighterStyle _style; |
|||
|
|||
readonly List<string> _keywords = new List<string> { |
|||
"abstract", "as", "assert", "async", "await", "break", "case", "catch", |
|||
"class", "const", "continue", "default", "deferred", "do", "dynamic", "else", |
|||
"enum", "export", "external", "extends", "factory", "false", "final", |
|||
"finally", "for", "get", "if", "implements", "import", "in", "is", "library", |
|||
"new", "null", "operator", "part", "rethrow", "return", "set", "static", |
|||
"super", "switch", "sync", "this", "throw", "true", "try", "typedef", "var", |
|||
"void", "while", "with", "yield" |
|||
}; |
|||
|
|||
readonly List<string> _builtInTypes = new List<string> { |
|||
"int", "double", "num", "bool" |
|||
}; |
|||
|
|||
string _src; |
|||
StringScanner _scanner; |
|||
|
|||
List<_HighlightSpan> _spans; |
|||
|
|||
public override TextSpan format(string src) { |
|||
this._src = src; |
|||
this._scanner = new StringScanner(this._src); |
|||
|
|||
if (this._generateSpans()) { |
|||
List<TextSpan> formattedText = new List<TextSpan> { }; |
|||
int currentPosition = 0; |
|||
|
|||
foreach (_HighlightSpan span in this._spans) { |
|||
if (currentPosition != span.start) { |
|||
formattedText.Add(new TextSpan(text: this._src.Substring(currentPosition, span.start))); |
|||
} |
|||
|
|||
formattedText.Add(new TextSpan(style: span.textStyle(this._style), |
|||
text: span.textForSpan(this._src))); |
|||
|
|||
currentPosition = span.end; |
|||
} |
|||
|
|||
if (currentPosition != this._src.Length) { |
|||
formattedText.Add(new TextSpan(text: this._src.Substring(currentPosition, this._src.Length))); |
|||
} |
|||
|
|||
return new TextSpan(style: this._style.baseStyle, children: formattedText); |
|||
} |
|||
else { |
|||
return new TextSpan(style: this._style.baseStyle, text: src); |
|||
} |
|||
} |
|||
|
|||
bool _generateSpans() { |
|||
int lastLoopPosition = this._scanner.position; |
|||
|
|||
while (!this._scanner.isDone) { |
|||
this._scanner.scan(new Regex(@"\s+")); |
|||
|
|||
// Block comments
|
|||
if (this._scanner.scan(new Regex(@"/\*(.|\n)*\*/"))) { |
|||
this._spans.Add(new _HighlightSpan( |
|||
_HighlightType.comment, |
|||
this._scanner.lastMatch.Index, |
|||
this._scanner.lastMatch.Index + this._scanner.lastMatch.Length |
|||
)); |
|||
continue; |
|||
} |
|||
|
|||
// Line comments
|
|||
if (this._scanner.scan(new Regex(@"//"))) { |
|||
int startComment = this._scanner.lastMatch.Index; |
|||
|
|||
bool eof = false; |
|||
int endComment; |
|||
if (this._scanner.scan(new Regex(@".*\n"))) { |
|||
endComment = this._scanner.lastMatch.Index + this._scanner.lastMatch.Length - 1; |
|||
} |
|||
else { |
|||
eof = true; |
|||
endComment = this._src.Length; |
|||
} |
|||
|
|||
this._spans.Add(new _HighlightSpan( |
|||
_HighlightType.comment, |
|||
startComment, |
|||
endComment |
|||
)); |
|||
|
|||
if (eof) { |
|||
break; |
|||
} |
|||
|
|||
continue; |
|||
} |
|||
|
|||
// Raw r"String"
|
|||
if (this._scanner.scan(new Regex(@"r"".*"""))) { |
|||
this._spans.Add(new _HighlightSpan( |
|||
_HighlightType._string, |
|||
this._scanner.lastMatch.Index, |
|||
this._scanner.lastMatch.Index + this._scanner.lastMatch.Length |
|||
)); |
|||
continue; |
|||
} |
|||
|
|||
// Raw r"String"
|
|||
if (this._scanner.scan(new Regex(@"r"".*"""))) { |
|||
this._spans.Add(new _HighlightSpan( |
|||
_HighlightType._string, |
|||
this._scanner.lastMatch.Index, |
|||
this._scanner.lastMatch.Index + this._scanner.lastMatch.Length |
|||
)); |
|||
continue; |
|||
} |
|||
|
|||
// Multiline """String"""
|
|||
if (this._scanner.scan(new Regex(@"""""""(?:[^""\\]|\\(.|\n))*"""""""))) { |
|||
this._spans.Add(new _HighlightSpan( |
|||
_HighlightType._string, |
|||
this._scanner.lastMatch.Index, |
|||
this._scanner.lastMatch.Index + this._scanner.lastMatch.Length |
|||
)); |
|||
continue; |
|||
} |
|||
|
|||
// Multiline '''String'''
|
|||
if (this._scanner.scan(new Regex(@"'''(?:[^""\\]|\\(.|\n))*'''"))) { |
|||
this._spans.Add(new _HighlightSpan( |
|||
_HighlightType._string, |
|||
this._scanner.lastMatch.Index, |
|||
this._scanner.lastMatch.Index + this._scanner.lastMatch.Length |
|||
)); |
|||
continue; |
|||
} |
|||
|
|||
// "String"
|
|||
if (this._scanner.scan(new Regex(@"""(?:[^""\\]|\\.)*"""))) { |
|||
this._spans.Add(new _HighlightSpan( |
|||
_HighlightType._string, |
|||
this._scanner.lastMatch.Index, |
|||
this._scanner.lastMatch.Index + this._scanner.lastMatch.Length |
|||
)); |
|||
continue; |
|||
} |
|||
|
|||
// "String"
|
|||
if (this._scanner.scan(new Regex(@"""(?:[^""\\]|\\.)*"""))) { |
|||
this._spans.Add(new _HighlightSpan( |
|||
_HighlightType._string, |
|||
this._scanner.lastMatch.Index, |
|||
this._scanner.lastMatch.Index + this._scanner.lastMatch.Length |
|||
)); |
|||
continue; |
|||
} |
|||
|
|||
// Double
|
|||
if (this._scanner.scan(new Regex(@"\d+\.\d+"))) { |
|||
this._spans.Add(new _HighlightSpan( |
|||
_HighlightType.number, |
|||
this._scanner.lastMatch.Index, |
|||
this._scanner.lastMatch.Index + this._scanner.lastMatch.Length |
|||
)); |
|||
continue; |
|||
} |
|||
|
|||
// Integer
|
|||
if (this._scanner.scan(new Regex(@"\d+"))) { |
|||
this._spans.Add(new _HighlightSpan( |
|||
_HighlightType.number, |
|||
this._scanner.lastMatch.Index, |
|||
this._scanner.lastMatch.Index + this._scanner.lastMatch.Length) |
|||
); |
|||
continue; |
|||
} |
|||
|
|||
// Punctuation
|
|||
if (this._scanner.scan(new Regex(@"[\[\]{}().!=<>&\|\?\+\-\*/%\^~;:,]"))) { |
|||
this._spans.Add(new _HighlightSpan( |
|||
_HighlightType.punctuation, |
|||
this._scanner.lastMatch.Index, |
|||
this._scanner.lastMatch.Index + this._scanner.lastMatch.Length |
|||
)); |
|||
continue; |
|||
} |
|||
|
|||
// Meta data
|
|||
if (this._scanner.scan(new Regex(@"@\w+"))) { |
|||
this._spans.Add(new _HighlightSpan( |
|||
_HighlightType.keyword, |
|||
this._scanner.lastMatch.Index, |
|||
this._scanner.lastMatch.Index + this._scanner.lastMatch.Length |
|||
)); |
|||
continue; |
|||
} |
|||
|
|||
// Words
|
|||
if (this._scanner.scan(new Regex(@"\w+"))) { |
|||
_HighlightType? type = null; |
|||
|
|||
string word = this._scanner.lastMatch.Groups[0].Value; |
|||
if (word.StartsWith("_")) { |
|||
word = word.Substring(1); |
|||
} |
|||
|
|||
if (this._keywords.Contains(word)) { |
|||
type = _HighlightType.keyword; |
|||
} |
|||
else if (this._builtInTypes.Contains(word)) { |
|||
type = _HighlightType.keyword; |
|||
} |
|||
else if (this._firstLetterIsUpperCase(word)) { |
|||
type = _HighlightType.klass; |
|||
} |
|||
else if (word.Length >= 2 && word.StartsWith("k") && |
|||
this._firstLetterIsUpperCase(word.Substring(1))) { |
|||
type = _HighlightType.constant; |
|||
} |
|||
|
|||
if (type != null) { |
|||
this._spans.Add(new _HighlightSpan( |
|||
type, |
|||
this._scanner.lastMatch.Index, |
|||
this._scanner.lastMatch.Index + this._scanner.lastMatch.Length |
|||
)); |
|||
} |
|||
} |
|||
|
|||
// Check if this loop did anything
|
|||
if (lastLoopPosition == this._scanner.position) { |
|||
// Failed to parse this file, abort gracefully
|
|||
return false; |
|||
} |
|||
|
|||
lastLoopPosition = this._scanner.position; |
|||
} |
|||
|
|||
this._simplify(); |
|||
return true; |
|||
} |
|||
|
|||
void _simplify() { |
|||
for (int i = this._spans.Count - 2; i >= 0; i -= 1) { |
|||
if (this._spans[i].type == this._spans[i + 1].type && this._spans[i].end == this._spans[i + 1].start) { |
|||
this._spans[i] = new _HighlightSpan( |
|||
this._spans[i].type, |
|||
this._spans[i].start, |
|||
this._spans[i + 1].end |
|||
); |
|||
this._spans.RemoveAt(i + 1); |
|||
} |
|||
} |
|||
} |
|||
|
|||
bool _firstLetterIsUpperCase(string str) { |
|||
if (str.isNotEmpty()) { |
|||
string first = str.Substring(0, 1); |
|||
return first == first.ToUpper(); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
} |
|||
|
|||
enum _HighlightType { |
|||
number, |
|||
comment, |
|||
keyword, |
|||
_string, |
|||
punctuation, |
|||
klass, |
|||
constant |
|||
} |
|||
|
|||
class _HighlightSpan { |
|||
public _HighlightSpan(_HighlightType? type, int start, int end) { |
|||
this.type = type; |
|||
this.start = start; |
|||
this.end = end; |
|||
} |
|||
|
|||
public readonly _HighlightType? type; |
|||
public readonly int start; |
|||
public readonly int end; |
|||
|
|||
public string textForSpan(string src) { |
|||
return src.Substring(this.start, this.end); |
|||
} |
|||
|
|||
public TextStyle textStyle(SyntaxHighlighterStyle style) { |
|||
if (this.type == _HighlightType.number) { |
|||
return style.numberStyle; |
|||
} |
|||
else if (this.type == _HighlightType.comment) { |
|||
return style.commentStyle; |
|||
} |
|||
else if (this.type == _HighlightType.keyword) { |
|||
return style.keywordStyle; |
|||
} |
|||
else if (this.type == _HighlightType._string) { |
|||
return style.stringStyle; |
|||
} |
|||
else if (this.type == _HighlightType.punctuation) { |
|||
return style.punctuationStyle; |
|||
} |
|||
else if (this.type == _HighlightType.klass) { |
|||
return style.classStyle; |
|||
} |
|||
else if (this.type == _HighlightType.constant) { |
|||
return style.constantStyle; |
|||
} |
|||
else { |
|||
return style.baseStyle; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class StringScanner { |
|||
string _source { get; set; } |
|||
public int position { get; set; } |
|||
|
|||
public Match lastMatch { |
|||
get { return this._lastMatch; } |
|||
} |
|||
Match _lastMatch; |
|||
|
|||
public StringScanner(string source) { |
|||
this._source = source; |
|||
this.position = 0; |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return this.isDone ? "" : this._source.Substring(this.position); |
|||
} |
|||
|
|||
public bool isDone { |
|||
get { return this.position >= this._source.Length; } |
|||
} |
|||
|
|||
public bool scan(Regex regex) { |
|||
var match = regex.Match(this.ToString()); |
|||
|
|||
if (match.Success) { |
|||
this.position += match.Length; |
|||
this._lastMatch = match; |
|||
return true; |
|||
} |
|||
else { |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 205d7446dc624493a18d7118ffeec352 |
|||
timeCreated: 1552469338 |
|
|||
|