From 61e74a37551e2938aff3bcdce637f05d1dc8a395 Mon Sep 17 00:00:00 2001 From: shmyga Date: Tue, 9 Jul 2019 12:03:38 +0300 Subject: [PATCH] [view] add SelectView --- demo/src/demo/DemoView.yaml | 10 +- demo/src/demo/form/DataForm.yaml | 2 +- demo/src/demo/form/ListForm.yaml | 4 +- demo/src/demo/form/SelectForm.hx | 9 ++ demo/src/demo/form/SelectForm.yaml | 28 ++++ demo/src/demo/form/TailForm.yaml | 2 +- demo/src/demo/popup/ColorPopup.yaml | 6 +- src/main/Meta.hx | 30 ---- src/main/haxework/macro/TemplateMacro.hx | 19 ++- src/main/haxework/view/DataView.hx | 6 + src/main/haxework/view/GroupView.hx | 4 + src/main/haxework/view/IGroupView.hx | 2 + src/main/haxework/view/IView.hx | 3 + src/main/haxework/view/Root.hx | 4 + src/main/haxework/view/SelectView.hx | 146 +++++++++++++++++++ src/main/haxework/view/View.hx | 17 ++- src/main/haxework/view/popup/PopupManager.hx | 10 +- src/main/haxework/view/skin/Skin.hx | 2 + 18 files changed, 247 insertions(+), 57 deletions(-) create mode 100644 demo/src/demo/form/SelectForm.hx create mode 100644 demo/src/demo/form/SelectForm.yaml delete mode 100755 src/main/Meta.hx create mode 100644 src/main/haxework/view/SelectView.hx diff --git a/demo/src/demo/DemoView.yaml b/demo/src/demo/DemoView.yaml index c9c696b..8958d61 100644 --- a/demo/src/demo/DemoView.yaml +++ b/demo/src/demo/DemoView.yaml @@ -13,18 +13,19 @@ views: geometry.padding.left: 5 geometry.margin.bottom: -3 buttonSkinId: tab - +onDataSelect: $code:function(id) switcher.change(id) + +onDataSelect: ~function(id) switcher.change(id) data: - "list" - "tail" - "data" - "test_layout" + - "select" selected: "list" - id: switcher $type: haxework.view.frame.FrameSwitcher skinId: panel animateFactory: { $class: haxework.animate.SlideAnimate } - +onSwitch: $this:onFrameSwitch + +onSwitch: ~onFrameSwitch geometry.size.stretch: true geometry.padding: 5 factory: @@ -32,6 +33,7 @@ views: _tail_: {$class: demo.form.TailForm} _data_: {$class: demo.form.DataForm} _test_layout_: {$class: demo.form.TestLayoutForm} + _select_: {$class: demo.form.SelectForm} - $type: haxework.view.HGroupView geometry.size.percent.width: 100 geometry.padding: 10 @@ -41,7 +43,7 @@ views: geometry.padding: [25, 8] skinId: button text: Color - +onPress: "$code:choiceColor()" + +onPress: ~choiceColor() # separator - $type: haxework.view.SpriteView geometry.size.stretch: true @@ -57,4 +59,4 @@ views: geometry.padding: [25, 8] skinId: button text: Cancel - +onPress: "$code:flash.system.System.exit(0)" + +onPress: ~flash.system.System.exit(0) diff --git a/demo/src/demo/form/DataForm.yaml b/demo/src/demo/form/DataForm.yaml index 66a48de..14cd890 100644 --- a/demo/src/demo/form/DataForm.yaml +++ b/demo/src/demo/form/DataForm.yaml @@ -8,6 +8,6 @@ views: $type: haxework.view.DataView layout: $type: haxework.view.layout.VerticalLayout - factory: $this:factory + factory: ~factory geometry.size.width: 100% data: $r:any:data diff --git a/demo/src/demo/form/ListForm.yaml b/demo/src/demo/form/ListForm.yaml index d93b79b..d010b2c 100644 --- a/demo/src/demo/form/ListForm.yaml +++ b/demo/src/demo/form/ListForm.yaml @@ -2,8 +2,8 @@ views: - id: list $type: haxework.view.list.VListView - +onItemSelect: $this:onItemSelect - factory: $this:factory + +onItemSelect: ~onItemSelect + factory: ~factory geometry.size.stretch: true scroll: $type: haxework.view.list.VScrollBarView diff --git a/demo/src/demo/form/SelectForm.hx b/demo/src/demo/form/SelectForm.hx new file mode 100644 index 0000000..a89b7b3 --- /dev/null +++ b/demo/src/demo/form/SelectForm.hx @@ -0,0 +1,9 @@ +package demo.form; + +import haxework.view.frame.FrameView; + +@:template class SelectForm extends FrameView { + public function new() { + super("select"); + } +} diff --git a/demo/src/demo/form/SelectForm.yaml b/demo/src/demo/form/SelectForm.yaml new file mode 100644 index 0000000..9dd6bf9 --- /dev/null +++ b/demo/src/demo/form/SelectForm.yaml @@ -0,0 +1,28 @@ +--- +geometry.padding: 10 +layout.margin: 5 +views: + - $type: haxework.view.SelectView + layout.margin: 2 + dataView.layout.margin: 1 + labelSkinId: text + data: + - "value 1" + - "value 2" + - "value 3" + - "value 4" + selected: "value 1" + +onSelect: ~function(value) trace('select', value) + + - $type: haxework.view.SelectView.SelectIdView<{id:Int,label:String}, Int> + layout.margin: 2 + dataView.layout.margin: 1 + labelSkinId: text + labelBuilder: ~function(item) return item.label + data: + - {id: 1, label: "item 1", $type: Dynamic} + - {id: 2, label: "item 2", $type: Dynamic} + - {id: 3, label: "item 3", $type: Dynamic} + - {id: 4, label: "item 4", $type: Dynamic} + selectedId: 1 + +onSelect: ~function(value) trace('select', value) diff --git a/demo/src/demo/form/TailForm.yaml b/demo/src/demo/form/TailForm.yaml index d658297..6ad4794 100644 --- a/demo/src/demo/form/TailForm.yaml +++ b/demo/src/demo/form/TailForm.yaml @@ -9,6 +9,6 @@ views: layout: $type: haxework.view.layout.TailLayout margin: 2 - factory: $this:factory + factory: ~factory geometry.size.width: 100% data: $r:any:data diff --git a/demo/src/demo/popup/ColorPopup.yaml b/demo/src/demo/popup/ColorPopup.yaml index 9b5c787..79d637b 100644 --- a/demo/src/demo/popup/ColorPopup.yaml +++ b/demo/src/demo/popup/ColorPopup.yaml @@ -15,14 +15,14 @@ view: $type: haxework.view.layout.TailLayout vAlign: middle margin: 5 - factory: $this:colorViewFactory + factory: ~colorViewFactory data: - 0x33AA33 - 0xAA3333 - 0xFFCC55 # 0x555555 - 0xCC33AA - 0x3333AA - +onDataSelect: $this:close + +onDataSelect: ~close - $type: haxework.view.HGroupView geometry.size.width: 100% layout.hAlign: right @@ -32,4 +32,4 @@ view: geometry.padding: [25, 8] skinId: button text: Cancel - +onPress: $code:reject('cancel') + +onPress: ~reject('cancel') diff --git a/src/main/Meta.hx b/src/main/Meta.hx deleted file mode 100755 index 6b89a8f..0000000 --- a/src/main/Meta.hx +++ /dev/null @@ -1,30 +0,0 @@ -package; - -#if macro -import haxe.macro.Context; -import haxe.macro.Expr; -#end - -class Meta { - - #if macro - private static inline var VERSION:String = "version"; - private static inline var BUILD:String = "build"; - - private static var data:Map = new Map(); - #end - - macro static public function getBuild():ExprOf { - return Context.makeExpr(data.get(BUILD), Context.currentPos()); - } - - macro static public function getVersion():ExprOf { - return Context.makeExpr(data.get(VERSION), Context.currentPos()); - } - - macro static public function set(version:String) { - data.set(BUILD, Date.now().toString()); - data.set(VERSION, version); - return macro {}; - } -} \ No newline at end of file diff --git a/src/main/haxework/macro/TemplateMacro.hx b/src/main/haxework/macro/TemplateMacro.hx index ccf1c16..1d0c253 100644 --- a/src/main/haxework/macro/TemplateMacro.hx +++ b/src/main/haxework/macro/TemplateMacro.hx @@ -64,7 +64,7 @@ class TemplateMacro { private function specialValue(name:String, key:String, a:Array, position:JsonKeyPosition, exprs:Array):Dynamic { return switch (a[0]) { case "asset" | "a": - switch (a[1]) { + switch a[1] { case "image": 'openfl.Assets.getBitmapData("${a[2]}")'; case _: @@ -76,12 +76,8 @@ class TemplateMacro { null; case "translate" | "t": 'new haxework.translate.TranslateString("${a[1]}")'; - case "code": - a[1]; - case "this": - 'this.${a[1]}'; - case "layout": - var template = FileUtil.loadJsonFile(a[1]); + case "template": + var template = FileUtil.loadFile(a[1]); return createValue(name, key, template, position, exprs); case _: Context.error('Unsupported prefix "${a[0]}"', getPosition(position)); @@ -94,7 +90,9 @@ class TemplateMacro { return createValue(null, null, v, position, exprs); }); } else if (Std.is(value, String)) { - if (value.charAt(0) == "@" || value.charAt(0) == "$") { + if (value.charAt(0) == "~" ) { + value.substring(1, value.length); + } else if (value.charAt(0) == "@" || value.charAt(0) == "$") { specialValue(name, key, value.substring(1, value.length).split(":"), position, exprs); } else if (~/(0x|#)[A-Fa-f\d]{6}/.match(value)) { Std.parseInt(StringTools.replace(Std.string(value), "#", "0x")); @@ -134,7 +132,8 @@ class TemplateMacro { private function createElement(name:String, data:Dynamic, exprs:Array):String { if (Reflect.hasField(data, "id")) { var id = Reflect.field(data, "id"); - if (bindings.exists(id)) { + // ToDo: only for view? + if (Std.is(id, String) && bindings.exists(id)) { var bind = bindings.get(id); exprs.push(Context.parse('this.${bind} = ${name}', getPosition())); bindings.remove(id); @@ -149,7 +148,7 @@ class TemplateMacro { switch [key.charAt(0), key.charAt(key.length - 1)] { case ["+", _]: var e:Expr = Context.parse(value, getPosition(position)); - e = switch (e.expr) { + e = switch e.expr { case ECall(_, _): macro function(_) ${e}; case _: e; } diff --git a/src/main/haxework/view/DataView.hx b/src/main/haxework/view/DataView.hx index acb359d..754301b 100644 --- a/src/main/haxework/view/DataView.hx +++ b/src/main/haxework/view/DataView.hx @@ -3,6 +3,8 @@ package haxework.view; import flash.display.DisplayObject; import flash.events.MouseEvent; import haxework.signal.Signal; +import haxework.view.layout.ILayout; +import haxework.view.layout.VerticalLayout; typedef Factory> = Int -> D -> V @@ -16,6 +18,10 @@ class DataView> extends GroupView { private var objectIndexes:Map = new Map(); + public function new(?layout:ILayout) { + super(layout != null ? layout : new VerticalLayout()); + } + private function set_data(value:Array):Array { data = value; if (factory != null) rebuild(); diff --git a/src/main/haxework/view/GroupView.hx b/src/main/haxework/view/GroupView.hx index 938b6b0..636cc90 100755 --- a/src/main/haxework/view/GroupView.hx +++ b/src/main/haxework/view/GroupView.hx @@ -56,6 +56,10 @@ class GroupView extends SpriteView implements IGroupView { return views; } + public function containsView(view:IView):Bool { + return views.indexOf(view) > -1; + } + public function addView(view:IView):IView { views.push(view); if (view.content != null) content.addChild(view.content); diff --git a/src/main/haxework/view/IGroupView.hx b/src/main/haxework/view/IGroupView.hx index 388d024..9b35c53 100755 --- a/src/main/haxework/view/IGroupView.hx +++ b/src/main/haxework/view/IGroupView.hx @@ -9,6 +9,8 @@ interface IGroupView extends IView { public var views(default, set):Array>; public var layout(default, default):ILayout; + public function containsView(view:IView):Bool; + public function addView(view:IView):IView; public function addViewFirst(view:IView):IView; diff --git a/src/main/haxework/view/IView.hx b/src/main/haxework/view/IView.hx index bc18c3d..cf438dd 100755 --- a/src/main/haxework/view/IView.hx +++ b/src/main/haxework/view/IView.hx @@ -1,6 +1,7 @@ package haxework.view; import flash.display.DisplayObject; +import flash.geom.Rectangle; import haxework.view.core.Geometry; import haxework.view.skin.ISkin.SkinSet; @@ -25,6 +26,8 @@ interface IView { public var index(default, set):Int; public var mouseEnabled(default, set):Bool; + public var rect(get, null):Rectangle; + public function update():Void; public function redraw():Void; diff --git a/src/main/haxework/view/Root.hx b/src/main/haxework/view/Root.hx index a9475a2..a5662aa 100755 --- a/src/main/haxework/view/Root.hx +++ b/src/main/haxework/view/Root.hx @@ -1,5 +1,6 @@ package haxework.view; +import haxework.provider.Provider; import flash.display.DisplayObject; import flash.display.StageAlign; import flash.display.StageScaleMode; @@ -27,6 +28,9 @@ class Root { this.view = view; this.autoSize = autoSize; Lib.current.addChild(view.content); + if (Std.is(view, IGroupView)) { + Provider.set(IGroupView, cast view); + } var content:DisplayObject = view.content; if (content.stage == null) { content.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); diff --git a/src/main/haxework/view/SelectView.hx b/src/main/haxework/view/SelectView.hx new file mode 100644 index 0000000..cfe6ea9 --- /dev/null +++ b/src/main/haxework/view/SelectView.hx @@ -0,0 +1,146 @@ +package haxework.view; + +import flash.events.MouseEvent; +import flash.geom.Point; +import haxework.signal.Signal; +import haxework.view.core.Geometry.Position; +import haxework.view.layout.VerticalLayout; +import haxework.view.skin.Skin; +using haxework.utils.StringUtil; + +class SelectIdView extends SelectView { + public var selectedId(get, set):K; + public var idResolver(default, default):D -> K; + + private var _selectedId:K; + + public function new() { + super(); + idResolver = function(item:D):K return Reflect.field(item, "id"); + } + + override private function set_selected(value:D):D { + var result = super.set_selected(value); + _selectedId = idResolver(result); + return result; + } + + private inline function get_selectedId():K { + return _selectedId; + } + + private function set_selectedId(value:K):K { + if (_selectedId != value) { + _selectedId = value; + for (item in data) { + if (idResolver(item) == _selectedId) { + selected = item; + break; + } + } + } + return _selectedId; + } +} + +class SelectView extends GroupView { + + public var currentView(default, null):ButtonView; + public var dataView(default, null):DataView; + + public var labelSkinId(default, set):String; + public var labelBuilder(default, set):D -> String; + public var data(default, set):Array; + public var selected(default, set):D; + public var onSelect(default, null):Signal = new Signal(); + + @:provide private static var root:IGroupView; + + public function new() { + super(new VerticalLayout()); + skin = [Skin.transparent]; + currentView = new ButtonView(); + currentView.onPress.connect(function(_) toggle()); + dataView = new DataView(); + dataView.skin = [Skin.transparent]; + dataView.geometry.position = ABSOLUTE; + dataView.factory = factory; + dataView.onDataSelect.connect(function(value:D):Void { + selected = value; + close(); + }); + views = [currentView]; + labelBuilder = function(value:D):String return Std.string(value).title(); + } + + private function factory(index:Int, value:D):LabelView { + var result = new LabelView(); + result.skinId = labelSkinId; + result.text = labelBuilder(value); + return result; + } + + private function set_labelSkinId(value:String):String { + if (labelSkinId != value) { + labelSkinId = value; + currentView.skinId = labelSkinId; + for (view in dataView.dataViews) { + view.skinId = labelSkinId; + } + } + return labelSkinId; + } + + private function set_labelBuilder(value:D -> String):D -> String { + labelBuilder = value; + for (i in 0...dataView.dataViews.length) { + dataView.dataViews[i].text = labelBuilder(data[i]); + } + return labelBuilder; + } + + private function set_data(value:Array):Array { + data = value; + dataView.data = value; + return data; + } + + private function set_selected(value:D):D { + selected = value; + currentView.text = labelBuilder(selected); + onSelect.emit(selected); + return selected; + } + + public function toggle():Void { + if (root.containsView(dataView)) { + close(); + } else { + open(); + } + } + + public function open():Void { + root.addView(dataView); + content.stage.addEventListener(MouseEvent.MOUSE_DOWN, onStageMouseClick); + } + + public function close():Void { + content.stage.removeEventListener(MouseEvent.MOUSE_DOWN, onStageMouseClick); + root.removeView(dataView); + } + + override public function update():Void { + super.update(); + var rect = currentView.rect; + dataView.geometry.margin.left = rect.left; + dataView.geometry.margin.top = rect.top + rect.height + layout.margin; + } + + private function onStageMouseClick(event:MouseEvent):Void { + var objects = content.stage.getObjectsUnderPoint(new Point(event.stageX, event.stageY)); + if (objects.indexOf(content) == -1 && objects.indexOf(dataView.content) == -1) { + close(); + } + } +} diff --git a/src/main/haxework/view/View.hx b/src/main/haxework/view/View.hx index 74e39b0..50e34a2 100755 --- a/src/main/haxework/view/View.hx +++ b/src/main/haxework/view/View.hx @@ -2,9 +2,10 @@ package haxework.view; import flash.display.DisplayObject; import flash.display.InteractiveObject; +import flash.geom.Rectangle; +import haxework.resources.IResources; import haxework.view.core.Geometry; import haxework.view.skin.ISkin; -import haxework.resources.IResources; class View implements IView { @:provide private var r:IResources; @@ -32,6 +33,8 @@ class View implements IView { public var index(default, set):Int; public var mouseEnabled(default, set):Bool = true; + public var rect(get, null):Rectangle; + public function new(content:C) { id = Type.getClassName(Type.getClass(this)) + counter++; this.content = content; @@ -160,4 +163,16 @@ class View implements IView { } return mouseEnabled; } + + private function get_rect():Rectangle { + var x = this.x; + var y = this.y; + var parent = this.parent; + while (parent != null) { + x += parent.x; + y += parent.y; + parent = parent.parent; + } + return new Rectangle(x, y, width, height); + } } diff --git a/src/main/haxework/view/popup/PopupManager.hx b/src/main/haxework/view/popup/PopupManager.hx index a8962eb..3344931 100755 --- a/src/main/haxework/view/popup/PopupManager.hx +++ b/src/main/haxework/view/popup/PopupManager.hx @@ -1,7 +1,6 @@ package haxework.view.popup; import haxework.animate.IAnimate; -import haxework.view.Root; import haxework.view.IGroupView; typedef P = PopupView; @@ -13,12 +12,14 @@ class PopupManager { private var popups:Array

; + @:provide private static var root:IGroupView; + public function new() { popups = new Array

(); } public function show(popup:P):Void { - cast(Root.instance.view, IGroupView).addView(popup); + root.addView(popup); if (showAnimateFactory != null) { showAnimateFactory(popup).start(null); } @@ -35,9 +36,8 @@ class PopupManager { } public function remove(popup:P):Void { - var container = cast(Root.instance.view, IGroupView); - if (container.views.indexOf(popup) > -1) { - container.removeView(popup); + if (root.containsView(popup)) { + root.removeView(popup); } } diff --git a/src/main/haxework/view/skin/Skin.hx b/src/main/haxework/view/skin/Skin.hx index 80b95d8..c45a45e 100644 --- a/src/main/haxework/view/skin/Skin.hx +++ b/src/main/haxework/view/skin/Skin.hx @@ -7,6 +7,8 @@ import flash.display.BitmapData; class Skin { + public static var transparent(default, never):ISkin = new ColorSkin(0, 0); + public static function size(width:Float, height:Float):ISkin { return new GeometrySkin(new Geometry().setSize(width, height)); }