[view] add SelectView

This commit is contained in:
2019-07-09 12:03:38 +03:00
parent 34cb98beb1
commit 61e74a3755
18 changed files with 247 additions and 57 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,9 @@
package demo.form;
import haxework.view.frame.FrameView;
@:template class SelectForm extends FrameView<Dynamic> {
public function new() {
super("select");
}
}

View File

@@ -0,0 +1,28 @@
---
geometry.padding: 10
layout.margin: 5
views:
- $type: haxework.view.SelectView<String>
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)

View File

@@ -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

View File

@@ -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')

View File

@@ -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<String, Dynamic> = new Map<String, Dynamic>();
#end
macro static public function getBuild():ExprOf<String> {
return Context.makeExpr(data.get(BUILD), Context.currentPos());
}
macro static public function getVersion():ExprOf<String> {
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 {};
}
}

View File

@@ -64,7 +64,7 @@ class TemplateMacro {
private function specialValue(name:String, key:String, a:Array<String>, position:JsonKeyPosition, exprs:Array<Expr>):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<Expr>):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;
}

View File

@@ -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<D, V:IView<Dynamic>> = Int -> D -> V
@@ -16,6 +18,10 @@ class DataView<D, V:IView<Dynamic>> extends GroupView {
private var objectIndexes:Map<DisplayObject, Int> = new Map();
public function new(?layout:ILayout) {
super(layout != null ? layout : new VerticalLayout());
}
private function set_data(value:Array<D>):Array<D> {
data = value;
if (factory != null) rebuild();

View File

@@ -56,6 +56,10 @@ class GroupView extends SpriteView implements IGroupView {
return views;
}
public function containsView(view:IView<Dynamic>):Bool {
return views.indexOf(view) > -1;
}
public function addView(view:IView<Dynamic>):IView<Dynamic> {
views.push(view);
if (view.content != null) content.addChild(view.content);

View File

@@ -9,6 +9,8 @@ interface IGroupView extends IView<Dynamic> {
public var views(default, set):Array<IView<Dynamic>>;
public var layout(default, default):ILayout;
public function containsView(view:IView<Dynamic>):Bool;
public function addView(view:IView<Dynamic>):IView<Dynamic>;
public function addViewFirst(view:IView<Dynamic>):IView<Dynamic>;

View File

@@ -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<C:DisplayObject> {
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;

View File

@@ -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);

View File

@@ -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<D, K> extends SelectView<D> {
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<D> extends GroupView {
public var currentView(default, null):ButtonView;
public var dataView(default, null):DataView<D, LabelView>;
public var labelSkinId(default, set):String;
public var labelBuilder(default, set):D -> String;
public var data(default, set):Array<D>;
public var selected(default, set):D;
public var onSelect(default, null):Signal<D> = 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<D>):Array<D> {
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();
}
}
}

View File

@@ -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<C:DisplayObject> implements IView<C> {
@:provide private var r:IResources;
@@ -32,6 +33,8 @@ class View<C:DisplayObject> implements IView<C> {
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<C:DisplayObject> implements IView<C> {
}
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);
}
}

View File

@@ -1,7 +1,6 @@
package haxework.view.popup;
import haxework.animate.IAnimate;
import haxework.view.Root;
import haxework.view.IGroupView;
typedef P = PopupView<Dynamic>;
@@ -13,12 +12,14 @@ class PopupManager {
private var popups:Array<P>;
@:provide private static var root:IGroupView;
public function new() {
popups = new Array<P>();
}
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);
}
}

View File

@@ -7,6 +7,8 @@ import flash.display.BitmapData;
class Skin {
public static var transparent(default, never):ISkin<SpriteView> = new ColorSkin(0, 0);
public static function size(width:Float, height:Float):ISkin<Dynamic> {
return new GeometrySkin(new Geometry().setSize(width, height));
}