[gui] update

This commit is contained in:
2019-03-06 17:07:26 +03:00
parent c2ab82b351
commit b0824773c9
46 changed files with 583 additions and 737 deletions

View File

@@ -1,38 +1,50 @@
package demo; package demo;
import haxework.gui.frame.IFrameSwitcher; import haxework.net.JsonLoader;
import demo.popup.ColorPopup;
import haxework.App;
import haxework.gui.frame.FrameSwitcher;
import haxework.gui.IGroupView; import haxework.gui.IGroupView;
import haxework.gui.IView; import haxework.gui.IView;
import haxework.gui.Root;
import haxework.gui.ToggleButtonView; import haxework.gui.ToggleButtonView;
import haxework.gui.VGroupView; import haxework.gui.VGroupView;
import haxework.log.TraceLogger; import haxework.log.TraceLogger;
import haxework.net.manage.ILoaderManager;
import haxework.net.manage.LoaderManager;
import haxework.resources.IResources;
import haxework.resources.Resources;
@:template class Demo extends VGroupView { @:template class DemoView extends VGroupView {
@:view var switcher:FrameSwitcher;
@:provide static var resources:IResources;
@:provide static var manager:ILoaderManager;
public static function main() {
L.push(new TraceLogger());
resources = new Resources();
manager = new LoaderManager();
resources.image.put("logo", HaxeLogo.resolve());
Theme.setColor(0x33aa33);
var demo = new Demo();
demo.switcher.change("list_form");
Root.bind(demo);
Root.instance.onResize.connect(function(rect) trace("resize", rect));
}
@:view var switcher:IFrameSwitcher;
@:view var tabs:IGroupView; @:view var tabs:IGroupView;
private function init():Void {
switcher.change("list_form");
}
private function onFrameSwitch(frame:IView<Dynamic>):Void { private function onFrameSwitch(frame:IView<Dynamic>):Void {
for (view in tabs.views) cast(view, ToggleButtonView).on = view.id == frame.id; for (view in tabs.views) cast(view, ToggleButtonView).on = view.id == frame.id;
} }
private function choiceColor():Void {
new ColorPopup()
.show()
.then(function(color) Theme.setColor(color))
.catchError(function(e) {});
}
}
class Demo extends App {
public static function main() {
L.push(new TraceLogger());
var app = new App();
app.resources.image.put("logo", HaxeLogo.resolve());
Theme.setColor(0x33aa33);
app.start(new DemoView());
new JsonLoader().GET("http://umix.tv/channel/data2/renova.json")
.then(function(data:Array<Model>) {
app.resources.any.put("data", data);
app.resources.any.put("data50", Util.marray(data, 50));
})
.catchError(function(error) trace(error));
}
} }

View File

@@ -33,19 +33,23 @@ views:
+onPress: "$code:switcher.change('data_form')" +onPress: "$code:switcher.change('data_form')"
- id: switcher - id: switcher
$type: haxework.gui.frame.FrameSwitcher $type: haxework.gui.frame.FrameSwitcher
skin: $r:skin:border skin: $r:skin:panel
animateFactory: { $class: haxework.animate.SlideAnimate }
+onSwitch: $this:onFrameSwitch +onSwitch: $this:onFrameSwitch
geometry.size.stretch: true geometry.size.stretch: true
geometry.padding: 5 geometry.padding: 5
views: views:
- id: list_form - id: list_form
$type: demo.form.ListForm $type: demo.form.ListForm
skin: $r:skin:background
geometry.size.stretch: true geometry.size.stretch: true
- id: tail_form - id: tail_form
$type: demo.form.TailForm $type: demo.form.TailForm
skin: $r:skin:background
geometry.size.stretch: true geometry.size.stretch: true
- id: data_form - id: data_form
$type: demo.form.DataForm $type: demo.form.DataForm
skin: $r:skin:background
geometry.size.stretch: true geometry.size.stretch: true
- $type: haxework.gui.HGroupView - $type: haxework.gui.HGroupView
geometry.size.percent.width: 100 geometry.size.percent.width: 100
@@ -55,23 +59,8 @@ views:
- $type: haxework.gui.ButtonView - $type: haxework.gui.ButtonView
geometry.padding: [25, 8] geometry.padding: [25, 8]
skin: $r:skin:button skin: $r:skin:button
text: green text: Color
+onPress: "$code:Theme.setColor(0x33AA33)" +onPress: "$code:choiceColor()"
- $type: haxework.gui.ButtonView
geometry.padding: [25, 8]
skin: $r:skin:button
text: red
+onPress: "$code:Theme.setColor(0xAA3333)"
- $type: haxework.gui.ButtonView
geometry.padding: [25, 8]
skin: $r:skin:button
text: yellow
+onPress: "$code:Theme.setColor(0xFFCC55, 0x555555)"
- $type: haxework.gui.ButtonView
geometry.padding: [25, 8]
skin: $r:skin:button
text: pink
+onPress: "$code:Theme.setColor(0xCC33AA)"
# separator # separator
- $type: haxework.gui.SpriteView - $type: haxework.gui.SpriteView
geometry.size.stretch: true geometry.size.stretch: true

10
demo/src/demo/Model.hx Normal file
View File

@@ -0,0 +1,10 @@
package demo;
typedef Model = {
var id:String;
var created_at:Int;
var maker:String;
var title:String;
var message:String;
var image:{url:String, width:Int, height:Int};
}

View File

@@ -13,9 +13,7 @@ class Theme {
public static function setColor(color:Int, textColor:Int = 0xffffff):Void { public static function setColor(color:Int, textColor:Int = 0xffffff):Void {
var text:ISkin<Dynamic> = new TextSkin(textColor, 16, "Courirer"); var text:ISkin<Dynamic> = new TextSkin(textColor, 16, "Courirer");
var background:SkinSet = [ var background = Skin.color(0x00000);
Skin.color(0x00000),
];
var button:SkinSet = [ var button:SkinSet = [
Skin.buttonColor(color), Skin.buttonColor(color),
text, text,
@@ -32,18 +30,22 @@ class Theme {
var scroll:SkinSet = [ var scroll:SkinSet = [
ScrollBarSkin.vertical(color, ColorUtils.diff(color, 128)), ScrollBarSkin.vertical(color, ColorUtils.diff(color, 128)),
]; ];
var border:SkinSet = [ var border = Skin.border(ColorUtils.multiply(color, 1.5), 1, 2);
Skin.border(ColorUtils.multiply(color, 1.5), 1, 2), resources.skin.put("text0", [
];
resources.skin.put("text", [
Skin.color(ColorUtils.diff(color, 128)), Skin.color(ColorUtils.diff(color, 128)),
new TextSkin(ColorUtils.diff(color, -128), 16, "Courirer"), new TextSkin(ColorUtils.diff(color, -128), 16, "Courirer"),
]); ]);
resources.skin.put("background", background); resources.skin.put("text1", [
Skin.color(ColorUtils.diff(color, 64)),
new TextSkin(ColorUtils.diff(color, -128), 16, "Courirer"),
]);
resources.skin.put("text", resources.skin.get("text0"));
resources.skin.put("background", [background]);
resources.skin.put("button", button); resources.skin.put("button", button);
resources.skin.put("tab", tab); resources.skin.put("tab", tab);
resources.skin.put("view", view); resources.skin.put("view", view);
resources.skin.put("scroll", scroll); resources.skin.put("scroll", scroll);
resources.skin.put("border", border); resources.skin.put("border", [border]);
resources.skin.put("panel", [background, border]);
} }
} }

View File

@@ -1,31 +1,17 @@
package demo.form; package demo.form;
import haxework.gui.DataView;
import haxework.gui.TextView; import haxework.gui.TextView;
import haxework.gui.VGroupView; import haxework.gui.VGroupView;
import haxework.net.JsonLoader;
import haxework.resources.IResources;
@:template class DataForm extends VGroupView { @:template class DataForm extends VGroupView {
@:view var data:DataView<String>;
@:provide var resources:IResources;
private function init() { private function factory(index:Int, value:Model):TextView {
new JsonLoader().GET("http://umix.tv/channel/data2/renova.json")
.then(function(data:Array<Dynamic>) {
var values = data.map(function(item) return '${item.id}: ${item.message}');
this.data.data = Util.marray(values, 1);
})
.catchError(function(error) trace(error));
}
private function factory(index:Int, value:String):TextView {
var label = new TextView(); var label = new TextView();
label.geometry.size.percent.width = 100; label.geometry.size.percent.width = 100;
label.geometry.margin = 1; label.geometry.margin = 1;
label.geometry.padding = 2; label.geometry.padding = 2;
resources.skin.bind("text", label, "skin"); label.skinId = "text";
label.text = value; label.text = (value.title != null ? '${value.title}\n-\n' : '') + value.message;
return label; return label;
} }
} }

View File

@@ -5,11 +5,12 @@ views:
geometry.size.stretch: true geometry.size.stretch: true
view: view:
id: data id: data
$type: haxework.gui.DataView<String> $type: haxework.gui.DataView<Model>
layout: layout:
$type: haxework.gui.layout.VerticalLayout $type: haxework.gui.layout.VerticalLayout
factory: $this:factory factory: $this:factory
geometry.size.width: 100% geometry.size.width: 100%
data: $r:any:data
scroll: scroll:
$type: haxework.gui.list.VScrollBarView $type: haxework.gui.list.VScrollBarView
skin: $r:skin:scroll skin: $r:skin:scroll

View File

@@ -1,23 +1,18 @@
package demo.form; package demo.form;
import haxework.gui.list.LabelListItem;
import haxework.gui.list.ListView.IListItemView; import haxework.gui.list.ListView.IListItemView;
import haxework.gui.list.VListView; import haxework.gui.list.VListView;
import haxework.gui.VGroupView; import haxework.gui.VGroupView;
import haxework.net.JsonLoader;
@:template class ListForm extends VGroupView { @:template class ListForm extends VGroupView {
@:view public var list(default, null):VListView<String>; @:view public var list(default, null):VListView<Model>;
private function init() { private function factory() {
new JsonLoader().GET("http://umix.tv/channel/data2/renova.json") return new LabelListItem(function(index:Int, value:Model) return '${index}. ${value.id}: ${value.title}');
.then(function(data:Array<Dynamic>) {
var values = data.map(function(item) return '${item.id}: ${item.message}');
list.data = Util.marray(values, 50);
})
.catchError(function(error) trace(error));
} }
private function onItemSelect(item:IListItemView<String>):Void { private function onItemSelect(item:IListItemView<Model>):Void {
trace('onItemSelect: ${item.data}'); trace('onItemSelect: ${item.data.id}');
} }
} }

View File

@@ -1,12 +1,13 @@
--- ---
views: views:
- id: list - id: list
$type: haxework.gui.list.VListView<String> $type: haxework.gui.list.VListView<Model>
+onItemSelect: $this:onItemSelect +onItemSelect: $this:onItemSelect
factory: { $class: haxework.gui.list.LabelListItem } factory: $this:factory
geometry.size.stretch: true geometry.size.stretch: true
scroll: scroll:
$type: haxework.gui.list.VScrollBarView $type: haxework.gui.list.VScrollBarView
skin: $r:skin:scroll skin: $r:skin:scroll
geometry.size.height: 100% geometry.size.height: 100%
geometry.size.width: 10 geometry.size.width: 10
data: $r:any:data50

View File

@@ -1,24 +1,29 @@
package demo.form; package demo.form;
import haxework.gui.DataView;
import haxework.gui.HGroupView; import haxework.gui.HGroupView;
import haxework.gui.ImageView;
import haxework.gui.IView;
import haxework.gui.TextView; import haxework.gui.TextView;
import haxework.resources.IResources; import haxework.gui.utils.DrawUtil.FillType;
@:template class TailForm extends HGroupView { @:template class TailForm extends HGroupView {
@:view public var data:DataView<String>;
@:provide var resources:IResources;
private function init() { private function factory(index:Int, value:Model):IView<Dynamic> {
data.data = [for (i in 0...100) '${i}']; var view:IView<Dynamic>;
} if (value.image != null) {
var imageView = new ImageView();
private function factory(index:Int, value:String):TextView { imageView.skinId = "border";
var view = new TextView(); imageView.fillType = FillType.CONTAIN;
view.geometry.size.fixed.width = 100 + 100 * Math.random(); imageView.imageUrl = value.image.url;
view.geometry.size.fixed.height = 100 + 100 * Math.random(); view = imageView;
resources.skin.bind("view", view, "skin"); } else {
view.text = 'View #${index}'; var textView = new TextView();
textView.skinId = "view";
textView.text = '${value.id}\n${value.maker}';
view = textView;
}
view.geometry.size.fixed.width = 350;
view.geometry.size.fixed.height = 200;
return view; return view;
} }
} }

View File

@@ -4,12 +4,13 @@ views:
geometry.size.stretch: true geometry.size.stretch: true
view: view:
id: data id: data
$type: haxework.gui.DataView<String> $type: haxework.gui.DataView<Model>
layout: layout:
$type: haxework.gui.layout.TailLayout $type: haxework.gui.layout.TailLayout
margin: 2 margin: 2
factory: $this:factory factory: $this:factory
geometry.size.width: 100% geometry.size.width: 100%
data: $r:any:data
scroll: scroll:
$type: haxework.gui.list.VScrollBarView $type: haxework.gui.list.VScrollBarView
skin: $r:skin:scroll skin: $r:skin:scroll

View File

@@ -0,0 +1,15 @@
package demo.popup;
import haxework.gui.ButtonView;
import haxework.gui.popup.PopupView;
import haxework.gui.skin.Skin;
@:template class ColorPopup extends PopupView<Int> {
private function colorViewFactory(index:Int, color:Int) {
var view = new ButtonView();
view.geometry.size.fixed = [48, 48];
view.skin = [Skin.buttonColor(color)];
return view;
}
}

View File

@@ -0,0 +1,35 @@
---
view:
$type: haxework.gui.VGroupView
geometry.size.width: 400
geometry.size.height: 200
geometry.padding: 10
geometry.hAlign: center
geometry.vAlign: middle
skinId: panel
views:
- id: colors
$type: haxework.gui.DataView
geometry.size.stretch: true
layout:
$type: haxework.gui.layout.TailLayout
vAlign: middle
margin: 5
factory: $this:colorViewFactory
data:
- 0x33AA33
- 0xAA3333
- 0xFFCC55 # 0x555555
- 0xCC33AA
- 0x3333AA
+onDataSelect: $this:close
- $type: haxework.gui.HGroupView
geometry.size.width: 100%
layout.hAlign: right
layout.margin: 10
views:
- $type: haxework.gui.ButtonView
geometry.padding: [25, 8]
skinId: button
text: Cancel
+onPress: $code:reject('cancel')

35
src/main/haxework/App.hx Normal file
View File

@@ -0,0 +1,35 @@
package haxework;
import haxework.gui.Root;
import haxework.gui.IView;
import flash.Lib;
import haxework.animate.Animate;
import haxework.animate.FadeAnimate;
import haxework.animate.UnFadeAnimate;
import haxework.gui.popup.PopupManager;
import haxework.net.manage.ILoaderManager;
import haxework.net.manage.LoaderManager;
import haxework.resources.IResources;
import haxework.resources.Resources;
class App {
@:provide var app:App;
@:provide var resources:IResources;
@:provide var loaderManager:ILoaderManager;
@:provide var popupManager:PopupManager;
public function new() {
resources = new Resources();
loaderManager = new LoaderManager();
popupManager = new PopupManager();
popupManager.showAnimateFactory = UnFadeAnimate;
popupManager.closeAnimateFactory = FadeAnimate;
app = this;
}
public function start(view:IView<Dynamic>) {
Animate.bind(Lib.current.stage);
Root.bind(view);
}
}

View File

@@ -4,50 +4,51 @@ import flash.events.Event;
import flash.display.Stage; import flash.display.Stage;
class Animate implements IAnimate { class Animate implements IAnimate {
public static var defaultDuraion = 300;
private static var running:Array<IAnimate> = new Array<IAnimate>(); private static var running:Array<IAnimate> = new Array<IAnimate>();
public static function bind(stage:Stage):Void { public static function bind(stage:Stage):Void {
stage.addEventListener(Event.ENTER_FRAME, function(_) { stage.addEventListener(Event.ENTER_FRAME, function(_) {
Animate.updateAll(); Animate.updateAll();
}); });
}
public static function updateAll():Void {
if (running.length > 0) {
var time = Date.now().getTime();
for (animate in running) animate.update(time);
} }
}
private var callback:Animate -> Void; public static function updateAll():Void {
private var duration:Int; if (running.length > 0) {
private var startTime:Float; var time = Date.now().getTime();
private var progress:Float; for (animate in running) animate.update(time);
}
public function new(duration:Int) {
this.duration = duration;
}
public function start(callback:IAnimate -> Void, ?custom:Bool = false):Void {
startTime = Date.now().getTime();
this.callback = callback;
if (!custom) running.push(this);
update(startTime);
}
private function update(time:Float):Void {
progress = (time - startTime) / duration;
if (progress >= 1) {
running.remove(this);
if (callback != null) {
callback(this);
callback = null;
}
} }
}
public function cancel():Void { private var callback:Animate -> Void;
if (!Math.isNaN(startTime)) update(startTime + duration); private var duration:Int;
} private var startTime:Float;
private var progress:Float;
public function new(duration:Int) {
this.duration = duration > -1 ? duration : defaultDuraion;
}
public function start(callback:IAnimate -> Void, custom:Bool = false):Void {
startTime = Date.now().getTime();
this.callback = callback;
if (!custom) running.push(this);
update(startTime);
}
private function update(time:Float):Void {
progress = (time - startTime) / duration;
if (progress >= 1) {
running.remove(this);
if (callback != null) {
callback(this);
callback = null;
}
}
}
public function cancel():Void {
if (!Math.isNaN(startTime)) update(startTime + duration);
}
} }

View File

@@ -1,63 +1,62 @@
package haxework.animate; package haxework.animate;
import flash.display.DisplayObjectContainer;
import haxework.animate.IAnimate;
import flash.display.Sprite; import flash.display.Sprite;
import haxework.gui.IView;
import haxework.animate.Animate; import haxework.animate.Animate;
import haxework.animate.IAnimate;
import haxework.gui.IView;
class CircleMaskAnimate extends Animate { class CircleMaskAnimate extends Animate {
private var view:IView; private var view:IView<Dynamic>;
private var mask:Sprite; private var mask:Sprite;
private var cyrcle:Sprite; private var cyrcle:Sprite;
private var size:Float; private var size:Float;
public function new(view:IView, ?duration:Int = 1000) { public function new(view:IView<Dynamic>, duration:Int = -1) {
super(duration); super(duration);
this.view = view; this.view = view;
this.mask = new Sprite(); this.mask = new Sprite();
this.cyrcle = new Sprite(); this.cyrcle = new Sprite();
} }
override public function start(callback:IAnimate -> Void, ?custom:Bool = false):Void { override public function start(callback:IAnimate -> Void, custom:Bool = false):Void {
var width = view.parent.width; var width = view.parent.width;
var height = view.parent.height; var height = view.parent.height;
size = Math.sqrt(width * width + height * height); size = Math.sqrt(width * width + height * height);
//size = Math.max(width, height); //size = Math.max(width, height);
cyrcle.x = mask.x = -(size - width) / 2 - size; cyrcle.x = mask.x = -(size - width) / 2 - size;
cyrcle.y = mask.y = -(size - height) / 2 - size; cyrcle.y = mask.y = -(size - height) / 2 - size;
redraw(size, size); redraw(size, size);
view.parent.container.addChild(mask); view.parent.container.addChild(mask);
view.content.mask = mask; view.content.mask = mask;
view.parent.container.addChild(cyrcle); view.parent.container.addChild(cyrcle);
super.start(callback, custom); super.start(callback, custom);
} }
private function redraw(size:Float, r:Float):Void { private function redraw(size:Float, r:Float):Void {
mask.graphics.clear(); mask.graphics.clear();
mask.graphics.beginFill(0xffffff); mask.graphics.beginFill(0xffffff);
mask.graphics.drawCircle(size + size / 2, size + size / 2, r / 2); mask.graphics.drawCircle(size + size / 2, size + size / 2, r / 2);
mask.graphics.endFill(); mask.graphics.endFill();
cyrcle.graphics.clear(); cyrcle.graphics.clear();
cyrcle.graphics.lineStyle(8, 0xffffff); cyrcle.graphics.lineStyle(4, 0xffffff);
cyrcle.graphics.drawCircle(size + size / 2, size + size / 2, r / 2); cyrcle.graphics.drawCircle(size + size / 2, size + size / 2, r / 2);
cyrcle.graphics.lineStyle(); cyrcle.graphics.lineStyle();
} }
override private function update(time:Float):Void { override private function update(time:Float):Void {
super.update(time); super.update(time);
redraw(size, size * progress); redraw(size, size * progress);
if (progress >= 1 && view.content.parent != null) { if (progress >= 1 && view.content.parent != null) {
if (view.content.parent.contains(mask)) view.content.parent.removeChild(mask); if (view.content.parent.contains(mask)) view.content.parent.removeChild(mask);
view.content.mask = null; view.content.mask = null;
if (view.content.parent.contains(cyrcle)) view.parent.container.removeChild(cyrcle); if (view.content.parent.contains(cyrcle)) view.parent.container.removeChild(cyrcle);
}
} }
}
} }

View File

@@ -1,29 +1,29 @@
package haxework.animate; package haxework.animate;
import flash.display.DisplayObject;
import haxework.animate.IAnimate; import haxework.animate.IAnimate;
import flash.display.Sprite;
import haxework.gui.IView; import haxework.gui.IView;
import haxework.animate.Animate; import haxework.animate.Animate;
class FadeAnimate extends Animate { class FadeAnimate extends Animate {
private var view:IView; private var view:IView<DisplayObject>;
public function new(view:IView, ?duration = 500) { public function new(view:IView<DisplayObject>, duration:Int = -1) {
super(duration); super(duration);
this.view = view; this.view = view;
} }
override public function start(callback:IAnimate -> Void, ?custom:Bool = false):Void { override public function start(callback:IAnimate -> Void, custom:Bool = false):Void {
view.content.alpha = 1.0; view.content.alpha = 1.0;
super.start(callback, custom); super.start(callback, custom);
} }
override private function update(time:Float):Void { override private function update(time:Float):Void {
super.update(time); super.update(time);
view.content.alpha = 1 - (progress * 1.0); view.content.alpha = 1 - (progress * 1.0);
if (progress >= 1) { if (progress >= 1) {
view.content.alpha = 0.0; view.content.alpha = 0.0;
}
} }
}
} }

View File

@@ -2,8 +2,9 @@ package haxework.animate;
interface IAnimate { interface IAnimate {
public function start(callback:IAnimate->Void, ?custom:Bool = false):Void; public function start(callback:IAnimate -> Void, custom:Bool = false):Void;
public function cancel():Void;
private function update(time:Float):Void; public function cancel():Void;
private function update(time:Float):Void;
} }

View File

@@ -0,0 +1,24 @@
package haxework.animate;
import flash.display.DisplayObject;
import haxework.gui.IView;
class SlideAnimate extends Animate {
private var view:IView<DisplayObject>;
public function new(view:IView<DisplayObject>, duration:Int = -1) {
super(duration);
this.view = view;
}
override public function start(callback:IAnimate -> Void, custom:Bool = false):Void {
view.content.x = view.x - this.view.width + this.view.width / progress;
super.start(callback, custom);
}
override private function update(time:Float):Void {
super.update(time);
view.content.x = view.x - this.view.width + this.view.width / Math.min(1, progress);
}
}

View File

@@ -1,28 +1,28 @@
package haxework.animate; package haxework.animate;
import flash.display.Sprite; import flash.display.DisplayObject;
import haxework.gui.IView; import haxework.gui.IView;
import haxework.animate.Animate; import haxework.animate.Animate;
class UnFadeAnimate extends Animate { class UnFadeAnimate extends Animate {
private var view:IView; private var view:IView<DisplayObject>;
public function new(view:IView, ?duration = 500) { public function new(view:IView<DisplayObject>, duration:Int = -1) {
super(duration); super(duration);
this.view = view; this.view = view;
} }
override public function start(callback:IAnimate -> Void, ?custom:Bool = false):Void { override public function start(callback:IAnimate -> Void, custom:Bool = false):Void {
view.content.alpha = 0.0; view.content.alpha = 0.0;
super.start(callback, custom); super.start(callback, custom);
} }
override private function update(time:Float):Void { override private function update(time:Float):Void {
super.update(time); super.update(time);
view.content.alpha = progress * 1.0; view.content.alpha = progress * 1.0;
if (progress >= 1) { if (progress >= 1) {
view.content.alpha = 1.0; view.content.alpha = 1.0;
}
} }
}
} }

View File

@@ -1,5 +0,0 @@
package haxework.core;
interface IDisposable {
public function dispose():Void;
}

View File

@@ -1,133 +0,0 @@
package haxework.core;
typedef Tuple2#if!H<T1, T2>#end = {
var first(default, null):T1;
var second(default, null):T2;
}
typedef Tuple3#if!H<T1, T2, T3>#end = {> Tuple2<T1, T2>,
var third(default, null):T3;
}
typedef Tuple4#if!H<T1, T2, T3, T4>#end = {> Tuple3<T1, T2, T3>,
var fourth(default, null):T4;
}
typedef Tuple5#if!H<T1, T2, T3, T4, T5>#end = {> Tuple4<T1, T2, T3, T4>,
var fifth(default, null):T5;
}
class Tuple {
public static function five<T1, T2, T3, T4, T5>(first:T1, second:T2, third:T3, fourth:T4, fifth:T5):Tuple5<T1, T2, T3, T4, T5> {
return new InternalTuple5(first, second, third, fourth, fifth);
}
public static function four<T1, T2, T3, T4>(first:T1, second:T2, third:T3, fourth:T4):Tuple4<T1, T2, T3, T4> {
return new InternalTuple4(first, second, third, fourth);
}
public static function three<T1, T2, T3>(first:T1, second:T2, third:T3):Tuple3<T1, T2, T3> {
return new InternalTuple3(first, second, third);
}
public static function two<T1, T2>(first:T1, second:T2):Tuple2<T1, T2> {
return new InternalTuple2(first, second);
}
public static inline function asTuple2<T1, T2, T3>(tuple:Tuple3<T1, T2, T3>):Tuple2<T1, T2>
return tuple;
public static inline function asTuple3<T1, T2, T3, T4>(tuple:Tuple4<T1, T2, T3, T4>):Tuple3<T1, T2, T3>
return tuple;
public static inline function asTuple4<T1, T2, T3, T4, T5>(tuple:Tuple5<T1, T2, T3, T4, T5>):Tuple4<T1, T2, T3, T4>
return tuple;
}
private class InternalTuple2<T1, T2> {
public var first(default, null):T1;
public var second(default, null):T2;
/**
* Creates a new tuple.
* @param first The first value.
* @param second The second value.
*/
public function new(first:T1, second:T2) {
this.first = first;
this.second = second;
}
public function toString():String {
return "(" + first + ", " + second + ")";
}
}
private class InternalTuple3<T1, T2, T3> extends InternalTuple2<T1, T2> {
public var third(default, null):T3;
/**
* Creates a new tuple.
* @param first The first value.
* @param second The second value.
* @param third The third value.
*/
public function new(first:T1, second:T2, third:T3) {
super(first, second);
this.third = third;
}
public override function toString():String {
return "("
+ first + ", "
+ second + ", "
+ third + ")";
}
}
private class InternalTuple4<T1, T2, T3, T4> extends InternalTuple3<T1, T2, T3> {
public var fourth(default, null):T4;
/**
* Creates a new tuple.
* @param first The first value.
* @param second The second value.
* @param third The third value.
* @param fourth The fourth value.
*/
public function new(first:T1, second:T2, third:T3, fourth:T4) {
super(first, second, third);
this.fourth = fourth;
}
public override function toString():String {
return "("
+ first + ", "
+ second + ", "
+ third + ", "
+ fourth + ")";
}
}
private class InternalTuple5<T1, T2, T3, T4, T5> extends InternalTuple4<T1, T2, T3, T4> {
public var fifth(default, null):T5;
/**
* Creates a new tuple.
* @param first The first value.
* @param second The second value.
* @param third The third value.
* @param fourth The fourth value.
* @param fifth The fifth value.
*/
public function new(first:T1, second:T2, third:T3, fourth:T4, fifth:T5) {
super(first, second, third, fourth);
this.fifth = fifth;
}
public override function toString():String {
return "("
+ first + ", "
+ second + ", "
+ third + ", "
+ fourth + ", "
+ fifth + ")";
}
}

View File

@@ -1,57 +0,0 @@
package haxework.gui;
import haxe.Timer;
import flash.display.Bitmap;
import flash.display.BitmapData;
import haxework.gui.SpriteView;
class AnimateView extends SpriteView {
private var bitmap:Bitmap;
public var frames(default, set):Array<BitmapData>;
public var interval(default, set):Int;
private var frame:Int;
public function new() {
super();
bitmap = new Bitmap();
frames = [];
frame = 0;
interval = 200;
content.addChild(bitmap);
changeFrame();
}
private function set_frames(value:Array<BitmapData>):Array<BitmapData> {
if (frames != value) {
frames = value;
frame = 0;
changeFrame(true);
}
return frames;
}
private function set_interval(value:Int):Int {
if (interval != value) {
interval = value;
}
return interval;
}
private function changeFrame(?forse:Bool = false):Void {
frame = ++frame % frames.length;
bitmap.bitmapData = frames[frame];
update();
if (!forse) Timer.delay(function() changeFrame(false), interval);
}
override public function update():Void {
if (contentSize && bitmap.bitmapData != null) {
width = bitmap.bitmapData.width;
height = bitmap.bitmapData.height;
}
super.update();
bitmap.x = (width - bitmap.width) / 2;
bitmap.y = (height - bitmap.height) / 2;
}
}

View File

@@ -4,10 +4,12 @@ import flash.display.DisplayObject;
import flash.events.MouseEvent; import flash.events.MouseEvent;
import haxework.signal.Signal; import haxework.signal.Signal;
typedef Factory<D> = Int -> D -> IView<Dynamic>
class DataView<D> extends GroupView { class DataView<D> extends GroupView {
public var data(default, set):Array<D>; public var data(default, set):Array<D>;
public var factory(default, default):Int -> D -> IView<Dynamic>; public var factory(default, set):Factory<D>;
public var onItemSelect(default, null):Signal3<Int, D, IView<Dynamic>> = new Signal3(); public var onItemSelect(default, null):Signal3<Int, D, IView<Dynamic>> = new Signal3();
public var onDataSelect(default, null):Signal<D> = new Signal(); public var onDataSelect(default, null):Signal<D> = new Signal();
@@ -15,10 +17,16 @@ class DataView<D> extends GroupView {
private function set_data(value:Array<D>):Array<D> { private function set_data(value:Array<D>):Array<D> {
data = value; data = value;
rebuild(); if (factory != null) rebuild();
return data; return data;
} }
private function set_factory(value:Factory<D>):Factory<D> {
factory = value;
if (data != null) rebuild();
return factory;
}
private function rebuild():Void { private function rebuild():Void {
for (view in views) { for (view in views) {
view.content.removeEventListener(MouseEvent.CLICK, onItemClick); view.content.removeEventListener(MouseEvent.CLICK, onItemClick);

View File

@@ -17,6 +17,7 @@ interface IView<C:DisplayObject> {
public var content(default, null):C; public var content(default, null):C;
public var skin(default, set):SkinSet; public var skin(default, set):SkinSet;
public var skinId(null, set):String;
public var parent(default, null):Null<IGroupView>; public var parent(default, null):Null<IGroupView>;

View File

@@ -2,6 +2,7 @@ package haxework.gui;
import flash.display.BitmapData; import flash.display.BitmapData;
import haxework.gui.skin.BitmapSkin; import haxework.gui.skin.BitmapSkin;
import haxework.gui.skin.ISkin;
import haxework.gui.utils.DrawUtil.FillType; import haxework.gui.utils.DrawUtil.FillType;
import haxework.net.ImageLoader; import haxework.net.ImageLoader;
@@ -9,22 +10,29 @@ class ImageView extends SpriteView {
public var image(default, set):BitmapData; public var image(default, set):BitmapData;
public var imageUrl(default, set):String; public var imageUrl(default, set):String;
public var fillType(default, set):FillType;
public function new(?image:BitmapData) { private var bitmapSkin:BitmapSkin = new BitmapSkin();
public function new(image:BitmapData = null) {
super(); super();
fillType = FillType.DEFAULT;
if (image != null) { if (image != null) {
this.image = image; this.image = image;
} }
} }
override private function set_skin(value:SkinSet):SkinSet {
value = value.slice(0);
value.unshift(bitmapSkin);
return super.set_skin(value);
}
private function set_image(value:BitmapData):BitmapData { private function set_image(value:BitmapData):BitmapData {
if (image != value) { if (image != value) {
image = value; image = value;
skin = [new BitmapSkin(image, FillType.DEFAULT)]; bitmapSkin.image = value;
//geometry.size.content.width = value.width; toRedraw();
//geometry.size.content.height = value.height;
//toUpdate();
//toRedraw();
} }
return image; return image;
} }
@@ -34,8 +42,15 @@ class ImageView extends SpriteView {
imageUrl = value; imageUrl = value;
new ImageLoader().GET(imageUrl).then(function(data) { new ImageLoader().GET(imageUrl).then(function(data) {
image = data; image = data;
}); }).catchError(function(e) L.w("ImageView", "load", e));
} }
return imageUrl; return imageUrl;
} }
private function set_fillType(value:FillType):FillType {
if (fillType != value) {
bitmapSkin.fillType = fillType = value;
}
return fillType;
}
} }

View File

@@ -7,10 +7,9 @@ import flash.errors.Error;
import flash.events.Event; import flash.events.Event;
import flash.geom.Rectangle; import flash.geom.Rectangle;
import flash.Lib; import flash.Lib;
import haxework.core.IDisposable;
import haxework.signal.Signal; import haxework.signal.Signal;
class Root implements IDisposable { class Root {
public static function bind(view:IView<Dynamic>, autoSize:Bool = true) { public static function bind(view:IView<Dynamic>, autoSize:Bool = true) {
new Root(view, autoSize); new Root(view, autoSize);

View File

@@ -144,7 +144,7 @@ class TextView extends SpriteView implements ITextView {
private function updateTextSize():Void { private function updateTextSize():Void {
var size = TextUtil.getSize(textField); var size = TextUtil.getSize(textField);
setContentSize(size.x, size.y); setContentSize(size.x, size.y, "text");
} }
override public function update():Void { override public function update():Void {
@@ -168,7 +168,7 @@ class TextView extends SpriteView implements ITextView {
private function placeTextField(textField:TextField):Void { private function placeTextField(textField:TextField):Void {
textField.width = width; textField.width = width;
textField.height = geometry.size.content.height; textField.height = geometry.size.content.exists("text") ? geometry.size.content.get("text").height : height;
textField.x = switch (layout.hAlign) { textField.x = switch (layout.hAlign) {
case LEFT | NONE: geometry.padding.left; case LEFT | NONE: geometry.padding.left;
@@ -178,8 +178,8 @@ class TextView extends SpriteView implements ITextView {
} }
textField.y = switch (layout.vAlign) { textField.y = switch (layout.vAlign) {
case TOP | NONE: geometry.padding.top; case TOP | NONE: geometry.padding.top;
case MIDDLE: (height - geometry.size.content.height) / 2 + geometry.padding.top - geometry.padding.bottom; case MIDDLE: (height - textField.height) / 2 + geometry.padding.top - geometry.padding.bottom;
case BOTTOM: height - geometry.size.content.height - geometry.padding.bottom; case BOTTOM: height - textField.height - geometry.padding.bottom;
default: 0; default: 0;
} }
} }

View File

@@ -1,12 +1,14 @@
package haxework.gui; package haxework.gui;
import haxework.gui.skin.ISkin.ISizeSkin;
import flash.display.DisplayObject; import flash.display.DisplayObject;
import flash.display.InteractiveObject; import flash.display.InteractiveObject;
import haxework.gui.core.Geometry; import haxework.gui.core.Geometry;
import haxework.gui.skin.ISkin.ISizeSkin;
import haxework.gui.skin.ISkin.SkinSet; import haxework.gui.skin.ISkin.SkinSet;
import haxework.resources.IResources;
class View<C:DisplayObject> implements IView<C> { class View<C:DisplayObject> implements IView<C> {
@:provide private var r:IResources;
private static var counter:Int = 0; private static var counter:Int = 0;
public static var updater(default, null):ViewUpdater = new ViewUpdater(); public static var updater(default, null):ViewUpdater = new ViewUpdater();
@@ -23,6 +25,7 @@ class View<C:DisplayObject> implements IView<C> {
public var content(default, null):C; public var content(default, null):C;
public var skin(default, set):SkinSet; public var skin(default, set):SkinSet;
public var skinId(null, set):String;
public var parent(default, null):Null<IGroupView>; public var parent(default, null):Null<IGroupView>;
@@ -63,22 +66,16 @@ class View<C:DisplayObject> implements IView<C> {
for (skin in this.skin) { for (skin in this.skin) {
if (Std.is(skin, ISizeSkin)) { if (Std.is(skin, ISizeSkin)) {
var sizeSkin:ISizeSkin = cast skin; var sizeSkin:ISizeSkin = cast skin;
setSize(sizeSkin.width, sizeSkin.height); setContentSize(sizeSkin.width, sizeSkin.height, "skin");
} }
skin.draw(this); skin.draw(this);
} }
} }
private function setSize(width:Float, height:Float):Void { private function setContentSize(width:Float, height:Float, type:String="default"):Void {
if (width != geometry.size.fixed.width || height != geometry.size.fixed.height) { var contentSize = geometry.size.content.get(type);
geometry.size.fixed = [width, height]; if (contentSize == null || width != contentSize.width || height != contentSize.height) {
toUpdateParent(); geometry.size.content.set(type, [width, height]);
}
}
private function setContentSize(width:Float, height:Float):Void {
if (width != geometry.size.content.width || height != geometry.size.content.height) {
geometry.size.content = [width, height];
toUpdateParent(); toUpdateParent();
} }
} }
@@ -123,6 +120,11 @@ class View<C:DisplayObject> implements IView<C> {
return this.skin; return this.skin;
} }
private function set_skinId(value:String):String {
r.skin.bind(value, this, "skin");
return value;
}
private function set_visible(value:Bool):Bool { private function set_visible(value:Bool):Bool {
if (visible != value) { if (visible != value) {
visible = value; visible = value;

View File

@@ -29,7 +29,7 @@ abstract ASizeValue(SizeValue) {
} }
class SizeSet { class SizeSet {
public var content(default, default):Size; public var content(default, default):Map<String, Size>;
public var fixed(default, default):Size; public var fixed(default, default):Size;
public var percent(default, default):Size; public var percent(default, default):Size;
public var stretch(null, set):Bool; public var stretch(null, set):Bool;
@@ -38,7 +38,7 @@ class SizeSet {
public var height(null, set):ASizeValue; public var height(null, set):ASizeValue;
public function new() { public function new() {
this.content = []; this.content = new Map();
this.fixed = []; this.fixed = [];
this.percent = []; this.percent = [];
} }
@@ -96,7 +96,9 @@ class Geometry {
} }
var result = size.fixed.width; var result = size.fixed.width;
if (result < 0) { if (result < 0) {
result = size.content.width; for (s in size.content.iterator()) {
result = Math.max(result, s.width);
}
} }
result += padding.horizontal; result += padding.horizontal;
return FIXED(result); return FIXED(result);
@@ -108,7 +110,9 @@ class Geometry {
} }
var result = size.fixed.height; var result = size.fixed.height;
if (result < 0) { if (result < 0) {
result = size.content.height; for (s in size.content.iterator()) {
result = Math.max(result, s.height);
}
} }
result += padding.vertical; result += padding.vertical;
return FIXED(result); return FIXED(result);

View File

@@ -5,7 +5,7 @@ import haxework.animate.IAnimate;
import haxework.gui.IView; import haxework.gui.IView;
import haxework.gui.GroupView; import haxework.gui.GroupView;
class FrameSwitcher extends GroupView implements IFrameSwitcher { class FrameSwitcher extends GroupView {
public var current(default, null):Null<IView<Dynamic>>; public var current(default, null):Null<IView<Dynamic>>;
public var onSwitch:Signal<IView<Dynamic>> = new Signal(); public var onSwitch:Signal<IView<Dynamic>> = new Signal();
@@ -39,6 +39,7 @@ class FrameSwitcher extends GroupView implements IFrameSwitcher {
throw 'frame "$id" not found'; throw 'frame "$id" not found';
} }
addView(current); addView(current);
update();
//ToDo: //ToDo:
if (content.stage != null) content.stage.focus = cast(current, SpriteView).content; if (content.stage != null) content.stage.focus = cast(current, SpriteView).content;
var onShowMethod:Dynamic = Reflect.field(current, "onShow"); var onShowMethod:Dynamic = Reflect.field(current, "onShow");

View File

@@ -1,8 +0,0 @@
package haxework.gui.frame;
import haxework.gui.IView;
interface IFrameSwitcher extends IView<Dynamic> {
public var current(default, null):Null<IView<Dynamic>>;
public function change(id:String):IView<Dynamic>;
}

View File

@@ -29,8 +29,7 @@ class HorizontalLayout extends DefaultLayout {
maxSize = Math.max(maxSize, view.height); maxSize = Math.max(maxSize, view.height);
} }
group.geometry.size.content.height = maxSize; group.geometry.size.content.set("group", [fixedSize, maxSize]);
group.geometry.size.content.width = fixedSize;
leftSize -= fixedSize; leftSize -= fixedSize;
for (view in views) { for (view in views) {

View File

@@ -1,5 +1,6 @@
package haxework.gui.layout; package haxework.gui.layout;
import haxework.gui.core.VAlign;
typedef Row = { typedef Row = {
var width:Float; var width:Float;
var height:Float; var height:Float;
@@ -50,10 +51,18 @@ class TailLayout extends DefaultLayout {
var y:Float = Math.max(group.geometry.padding.top, (group.height - h) / 2); var y:Float = Math.max(group.geometry.padding.top, (group.height - h) / 2);
y = group.geometry.padding.top; y = group.geometry.padding.top;
if (h < group.height) {
y = switch vAlign {
case TOP | NONE: group.geometry.padding.top;
case MIDDLE: (group.height - h) / 2;
case BOTTOM: group.height - h - group.geometry.padding.bottom;
}
}
for (row in rows) { for (row in rows) {
placeRow(group, y, row); placeRow(group, y, row);
y += row.height + margin; y += row.height + margin;
} }
group.geometry.size.content.height = h;
group.geometry.size.content.set("group", [-1, h]);
} }
} }

View File

@@ -25,8 +25,7 @@ class VerticalLayout extends DefaultLayout {
maxSize = Math.max(maxSize, view.width); maxSize = Math.max(maxSize, view.width);
} }
group.geometry.size.content.width = maxSize; group.geometry.size.content.set("group", [maxSize, fixedSize]);
group.geometry.size.content.height = fixedSize;
leftSize -= fixedSize; leftSize -= fixedSize;
for (view in views) { for (view in views) {

View File

@@ -2,24 +2,32 @@ package haxework.gui.list;
import haxework.gui.core.HAlign; import haxework.gui.core.HAlign;
import haxework.gui.list.ListView.IListItemView; import haxework.gui.list.ListView.IListItemView;
import haxework.gui.skin.ColorSkin;
private typedef Formatter<T> = Int -> T -> String;
class LabelListItem<T> extends LabelView implements IListItemView<T> { class LabelListItem<T> extends LabelView implements IListItemView<T> {
public var item_index(default, default):Int; public var item_index(default, default):Int;
public var data(default, set):T; public var data(default, set):T;
public var formatter(default, default):Formatter<T>;
public function new() { private static function defaultFormatter<T>(index:Int, value:T):String {
return Std.string(value);
}
public function new(formatter:Formatter<T> = null) {
super(); super();
this.formatter = formatter == null ? defaultFormatter : formatter;
geometry.size.percent.width = 100; geometry.size.percent.width = 100;
geometry.size.fixed.height = 20; geometry.size.fixed.height = 20;
geometry.padding = 8; geometry.padding = 8;
layout.hAlign = HAlign.LEFT; layout.hAlign = LEFT;
} }
private function set_data(value:T):T { private function set_data(value:T):T {
data = value; data = value;
text = Std.string(value); text = formatter(item_index, value);
skin = item_index % 2 == 1 ? [new ColorSkin(0xdddddd)] : [new ColorSkin(0xcccccc)]; skinId = 'text${item_index % 2}';
return value; return value;
} }
} }

View File

@@ -12,7 +12,7 @@ import haxework.utils.NumberUtil;
class ListView<D> extends GroupView { class ListView<D> extends GroupView {
public var data(default, set):Array<D>; public var data(default, set):Array<D>;
public var factory(null, default):Class<IListItemView<D>>; public var factory(null, default):Void->IListItemView<D>;
public var offset(default, set):Int; public var offset(default, set):Int;
private var offsetDiff(default, set):Float; private var offsetDiff(default, set):Float;
@@ -183,7 +183,7 @@ class ListView<D> extends GroupView {
override public function update():Void { override public function update():Void {
super.update(); super.update();
recalcSize(Type.createInstance(factory, [])); recalcSize(factory());
render(); render();
} }
@@ -195,7 +195,7 @@ class ListView<D> extends GroupView {
var diff:Int = size - items.length; var diff:Int = size - items.length;
if (diff > 0) { if (diff > 0) {
for (i in 0...diff) { for (i in 0...diff) {
var item:IListItemView<D> = Type.createInstance(factory, []); var item:IListItemView<D> = factory();
items.push(item); items.push(item);
setClickListener(item); setClickListener(item);
box.addView(item); box.addView(item);

View File

@@ -4,44 +4,43 @@ import haxework.animate.IAnimate;
import haxework.gui.Root; import haxework.gui.Root;
import haxework.gui.IGroupView; import haxework.gui.IGroupView;
typedef P = PopupView<Dynamic>;
class PopupManager { class PopupManager {
public var showAnimateFactory(default, default):Class<IAnimate>; public var showAnimateFactory(default, default):Class<IAnimate>;
public var closeAnimateFactory(default, default):Class<IAnimate>; public var closeAnimateFactory(default, default):Class<IAnimate>;
private var popups:Array<PopupView<Dynamic>>; private var popups:Array<P>;
public function new() { public function new() {
popups = new Array<PopupView<Dynamic>>(); popups = new Array<P>();
}
public function show(popup:PopupView<Dynamic>):Void {
cast(Root.instance.view, IGroupView).addView(popup);
if (showAnimateFactory != null) {
Type.createInstance(showAnimateFactory, [popup]).start(null);
} }
popups.push(popup);
popup.onShow();
}
public function close(popup:PopupView<Dynamic>):Void { public function show(popup:P):Void {
popups.remove(popup); cast(Root.instance.view, IGroupView).addView(popup);
if (closeAnimateFactory != null) { if (showAnimateFactory != null) {
Type.createInstance(closeAnimateFactory, [popup]).start(function(_) { Type.createInstance(showAnimateFactory, [popup]).start(null);
cast(Root.instance.view, IGroupView).removeView(popup); }
popup.onClose(); popups.push(popup);
});
} else {
cast(Root.instance.view, IGroupView).removeView(popup);
popup.onClose();
} }
}
public function closeTop():Bool { public function close(popup:P):Void {
if (popups.length > 0) { popups.remove(popup);
close(popups[popups.length - 1]); if (closeAnimateFactory != null) {
return true; Type.createInstance(closeAnimateFactory, [popup]).start(function(_) {
cast(Root.instance.view, IGroupView).removeView(popup);
});
} else {
cast(Root.instance.view, IGroupView).removeView(popup);
}
}
public function closeTop():Bool {
if (popups.length > 0) {
close(popups[popups.length - 1]);
return true;
}
return false;
} }
return false;
}
} }

View File

@@ -1,56 +1,49 @@
package haxework.gui.popup; package haxework.gui.popup;
import promhx.Deferred; import haxework.gui.core.Geometry.Position;
import haxe.Timer;
import haxework.provider.Provider;
import haxework.dispath.Dispatcher;
import haxework.dispath.IDispatcher;
import haxework.gui.IGroupView;
import haxework.gui.ButtonView;
import haxework.gui.skin.ColorSkin;
import haxework.gui.GroupView; import haxework.gui.GroupView;
import haxework.gui.skin.Skin;
import promhx.Deferred;
import promhx.Promise;
class PopupView<V:IView> extends GroupView { class PopupView<R> extends GroupView {
@:provide var manager:PopupManager;
private var buttonId:String; public var view(default, set):IView<Dynamic>;
private var contentView:V; private var deferred:Deferred<R>;
private var deferred:Deferred<String>;
public function new(contentViewFactory:Class<V>) { public function new() {
super(); super();
geometry.size.stretch = true;
pWidth = 100; geometry.position = Position.ABSOLUTE;
pHeight = 100; skin = [Skin.color(0x000000, 0.6)];
inLayout = false; }
skin = new ColorSkin(0x000000, 0.6);
private function set_view(value:IView<Dynamic>):IView<Dynamic> {
this.contentView = Type.createInstance(contentViewFactory, [{listener:this}]); this.view = value;
addView(contentView); this.views = [value];
} return this.view;
}
public function onPress(button:ButtonView) {
this.buttonId = button.id; public function show():Promise<R> {
close(); manager.show(this);
} deferred = new Deferred<R>();
return deferred.promise();
public function show():Deferred<String> { }
Provider.get(PopupManager).show(this);
deferred = new Deferred<String>(); public function close(result:R):Void {
return deferred; manager.close(this);
} if (deferred != null) {
deferred.resolve(result);
public function close():Void { deferred = null;
Provider.get(PopupManager).close(this); }
} }
public function onShow():Void { public function reject(reason:Dynamic):Void {
buttonId = "close"; manager.close(this);
} if (deferred != null) {
deferred.throwError(reason);
public function onClose():Void { deferred = null;
if (deferred != null) { }
deferred.resolve(buttonId);
deferred = null;
} }
}
} }

View File

@@ -32,6 +32,6 @@ class BitmapSkin implements ISkin<SpriteView> implements ISizeSkin {
public function draw(view:SpriteView):Void { public function draw(view:SpriteView):Void {
if (image == null) return; if (image == null) return;
DrawUtil.draw(view.content.graphics, image, new Rectangle(0, 0, view.width, view.height), fillType, color); DrawUtil.draw(view.content.graphics, image, new Rectangle(0, 0, view.width, view.height), fillType, color, false);
} }
} }

View File

@@ -14,7 +14,7 @@ class BorderSkin implements ISkin<SpriteView> {
public function draw(view:SpriteView):Void { public function draw(view:SpriteView):Void {
view.content.graphics.lineStyle(tickness, color, alpha, true); view.content.graphics.lineStyle(tickness, color, alpha, true);
view.content.graphics.drawRect(tickness, tickness, view.width - tickness * 2, view.height - tickness * 2); view.content.graphics.drawRect(tickness / 2, tickness / 2, view.width - tickness, view.height - tickness);
view.content.graphics.lineStyle(); view.content.graphics.lineStyle();
} }
} }

View File

@@ -7,40 +7,40 @@ import flash.display.BitmapData;
class BitmapUtil { class BitmapUtil {
private static var cache:Map<BitmapData, Map<String, BitmapData>> = new Map<BitmapData, Map<String, BitmapData>>(); private static var cache:Map<BitmapData, Map<String, BitmapData>> = new Map<BitmapData, Map<String, BitmapData>>();
private static function fromCache(image:BitmapData, key:String):Null<BitmapData> { private static function fromCache(image:BitmapData, key:String):Null<BitmapData> {
return cache.exists(image) && cache.get(image).exists(key) ? cache.get(image).get(key) : null; return cache.exists(image) && cache.get(image).exists(key) ? cache.get(image).get(key) : null;
} }
private static function toCache(image:BitmapData, key:String, value:BitmapData):Void { private static function toCache(image:BitmapData, key:String, value:BitmapData):Void {
if (!cache.exists(image)) cache.set(image, new Map<String, BitmapData>()); if (!cache.exists(image)) cache.set(image, new Map<String, BitmapData>());
cache.get(image).set(key, value); cache.get(image).set(key, value);
} }
public static function multiply(image:BitmapData, m:Float):BitmapData { public static function multiply(image:BitmapData, m:Float):BitmapData {
var result = fromCache(image, "multiply:" + m); var result = fromCache(image, "multiply:" + m);
if (result != null) return result; if (result != null) return result;
var ct:ColorTransform = new ColorTransform(m, m, m, 1.0, 0, 0, 0); var ct:ColorTransform = new ColorTransform(m, m, m, 1.0, 0, 0, 0);
var out:BitmapData = image.clone(); var out:BitmapData = image.clone();
out.colorTransform(out.rect, ct); out.colorTransform(out.rect, ct);
toCache(image, "multiply:" + m, out); toCache(image, "multiply:" + m, out);
return out; return out;
} }
public static function grayscale(image:BitmapData, m:Float):BitmapData { public static function grayscale(image:BitmapData, m:Float):BitmapData {
var result = fromCache(image, "grayscale:" + m); var result = fromCache(image, "grayscale:" + m);
if (result != null) return result; if (result != null) return result;
var matrix:Array<Float> = []; var matrix:Array<Float> = [];
matrix = matrix.concat([m, m, m, 0, 0]); matrix = matrix.concat([m, m, m, 0, 0]);
matrix = matrix.concat([m, m, m, 0, 0]); matrix = matrix.concat([m, m, m, 0, 0]);
matrix = matrix.concat([m, m, m, 0, 0]); matrix = matrix.concat([m, m, m, 0, 0]);
matrix = matrix.concat([0, 0, 0, 1, 0]); matrix = matrix.concat([0, 0, 0, 1, 0]);
var cmf:ColorMatrixFilter = new ColorMatrixFilter(matrix); var cmf:ColorMatrixFilter = new ColorMatrixFilter(matrix);
var out:BitmapData = image.clone(); var out:BitmapData = image.clone();
out.applyFilter(out, out.rect, new Point(0,0), cmf); out.applyFilter(out, out.rect, new Point(0, 0), cmf);
toCache(image, "grayscale:" + m, out); toCache(image, "grayscale:" + m, out);
return out; return out;
} }
} }

View File

@@ -2,30 +2,30 @@ package haxework.gui.utils;
class ColorUtils { class ColorUtils {
public static function multiply(color:Int, m:Float):Int { public static function multiply(color:Int, m:Float):Int {
var rgb:Array<Int> = color2rgb(color); var rgb:Array<Int> = color2rgb(color);
var red:Int = cast Math.min(255, Math.round(rgb[0] * m)); var red:Int = cast Math.min(255, Math.round(rgb[0] * m));
var green:Int = cast Math.min(255, Math.round(rgb[1] * m)); var green:Int = cast Math.min(255, Math.round(rgb[1] * m));
var blue:Int = cast Math.min(255, Math.round(rgb[2] * m)); var blue:Int = cast Math.min(255, Math.round(rgb[2] * m));
return rgb2color(red, green, blue); return rgb2color(red, green, blue);
} }
public static function diff(color:Int, d:Int):Int { public static function diff(color:Int, d:Int):Int {
var rgb:Array<Int> = color2rgb(color); var rgb:Array<Int> = color2rgb(color);
var red:Int = cast Math.max(0, Math.min(255, rgb[0] + d)); var red:Int = cast Math.max(0, Math.min(255, rgb[0] + d));
var green:Int = cast Math.max(0, Math.min(255, rgb[1] + d)); var green:Int = cast Math.max(0, Math.min(255, rgb[1] + d));
var blue:Int = cast Math.max(0, Math.min(255, rgb[2] + d)); var blue:Int = cast Math.max(0, Math.min(255, rgb[2] + d));
return rgb2color(red, green, blue); return rgb2color(red, green, blue);
} }
public static function rgb2color(red:Int, green:Int, blue:Int):Int { public static function rgb2color(red:Int, green:Int, blue:Int):Int {
return (red << 16) + (green << 8) + blue; return (red << 16) + (green << 8) + blue;
} }
public static function color2rgb(color:Int):Array<Int> { public static function color2rgb(color:Int):Array<Int> {
var red:Int = ((color & 0xFF0000) >>> 16); var red:Int = ((color & 0xFF0000) >>> 16);
var green:Int = ((color & 0x00FF00) >> 8); var green:Int = ((color & 0x00FF00) >> 8);
var blue:Int = (color & 0x0000FF); var blue:Int = (color & 0x0000FF);
return [red, green, blue]; return [red, green, blue];
} }
} }

View File

@@ -1,18 +0,0 @@
package haxework.net.order;
import promhx.Promise;
import promhx.Deferred;
typedef Order<T> = {
var id:String;
var data:Null<T>;
var deferred:Deferred<T>;
var clients:Int;
}
interface IOrderSupplier {
public var orders(default, null):Map<String, Order<Dynamic>>;
public function request<T>(url:String, clazz:Class<T>):Promise<T>;
public function release(url:String, force:Bool = false):Void;
}

View File

@@ -1,82 +0,0 @@
package haxework.net.order;
import promhx.Promise;
import promhx.Deferred;
import haxework.net.order.IOrderSupplier.Order;
import flash.display.BitmapData;
class OrderSupplier implements IOrderSupplier {
private static inline var TAG:String = "OrderSupplier";
public var orders(default, null):Map<String, Order<Dynamic>>;
public function new() {
orders = new Map<String, Order<Dynamic>>();
}
public function request<T>(url:String, clazz:Class<T>):Promise<T> {
if (orders.exists(url)) {
var order:Order<T> = orders.get(url);
order.clients++;
//L.d(TAG, "Request(" + order.clients + "): " + url);
return order.deferred.promise();
} else {
var deferred = new Deferred<T>();
var order:Order<T> = {
id:url,
data:null,
deferred:deferred,
clients:1
}
//L.d(TAG, "Request(" + order.clients + "): " + url);
orders.set(url, order);
var loader:ILoader<T> = buildLoader(clazz);
loader.GET(url)
.then(function(data:T):Void {
if (orders.exists(url)) {
var order:Order<T> = orders.get(url);
order.data = data;
order.deferred.resolve(data);
}
})
.catchError(function(error:Dynamic):Void {
if (orders.exists(url)) orders.get(url).deferred.throwError(error);
orders.remove(url);
});
return deferred.promise();
}
}
public function release(url:String, force:Bool = false):Void {
if (orders.exists(url)) {
var order:Order<Dynamic> = orders.get(url);
if (--order.clients <= 0 || force) {
var data:Dynamic = order.data;
if (data != null && Std.is(data, BitmapData)) {
cast(data, BitmapData).dispose();
}
orders.remove(url);
}
L.d(TAG, "Release(" + order.clients + "): " + url);
//log();
}
}
private function buildLoader<T>(clazz:Class<T>):ILoader<T> {
var c:Class<Dynamic> = clazz;
return if (c == BitmapData) {
var loader:ILoader<T> = cast new ImageLoader();
loader.timeout = 7000; //ToDo: hardcode timeout for loading images
loader;
} else {
throw "Unsupported order: " + c;
}
}
private function log():Void {
L.d(TAG, "\n" + Lambda.map(orders, function(order:Order<Dynamic>):String {
return "(" + order.clients + ") " + order.id;
}).join("\n"));
}
}

View File

@@ -1,17 +1,17 @@
package haxework.resources; package haxework.resources;
import haxework.gui.skin.ISkin.SkinSet;
import flash.display.MovieClip;
import haxework.resources.Resources.ResMap;
import flash.display.BitmapData; import flash.display.BitmapData;
import flash.display.MovieClip;
import haxework.gui.skin.ISkin.SkinSet;
import haxework.resources.Resources.ResMap;
interface IResources { interface IResources {
public var image(default, null):ResMap<BitmapData>; public var image(default, null):ResMap<BitmapData>;
public var color(default, null):ResMap<Int>; public var color(default, null):ResMap<Int>;
public var movie(default, null):ResMap<MovieClip>; public var movie(default, null):ResMap<MovieClip>;
public var text(default, null):ResMap<String>; public var text(default, null):ResMap<String>;
public var float(default, null):ResMap<Float>; public var float(default, null):ResMap<Float>;
public var int(default, null):ResMap<Int>; public var int(default, null):ResMap<Int>;
public var any(default, null):ResMap<Dynamic>; public var any(default, null):ResMap<Dynamic>;
public var skin(default, null):ResMap<SkinSet>; public var skin(default, null):ResMap<SkinSet>;
} }

View File

@@ -1,20 +1,19 @@
package haxework.resources; package haxework.resources;
import haxework.gui.skin.ISkin.SkinSet;
import flash.display.BitmapData; import flash.display.BitmapData;
import flash.display.MovieClip; import flash.display.MovieClip;
import haxe.ds.StringMap; import haxe.ds.StringMap;
import haxework.core.Tuple; import haxework.gui.skin.ISkin;
private typedef F = Tuple2<Dynamic, String> private typedef Listener = {object:Dynamic, field:String};
class ResMap<T> extends StringMap<T> { class ResMap<T> extends StringMap<T> {
private var listeners:Map<String, Array<F>>; private var listeners:StringMap<Array<Listener>>;
public function new() { public function new() {
super(); super();
listeners = new Map<String, Array<F>>(); listeners = new StringMap();
} }
public function put(key:String, value:T):Void { public function put(key:String, value:T):Void {
@@ -25,17 +24,18 @@ class ResMap<T> extends StringMap<T> {
} }
public function bind(key:String, object:Dynamic, field:String):Void { public function bind(key:String, object:Dynamic, field:String):Void {
var f:F = Tuple.two(object, field); var listener:Listener = {object:object, field:field};
if (listeners.exists(key)) { if (listeners.exists(key)) {
listeners.get(key).push(f); listeners.set(key, listeners.get(key).filter(function(l) return l.object != object || l.field != field));
listeners.get(key).push(listener);
} else { } else {
listeners.set(key, [f]); listeners.set(key, [listener]);
} }
if (exists(key)) call(f, get(key)); if (exists(key)) call(listener, get(key));
} }
private function call(field:F, value:T):Void { private function call(listener:Listener, value:T):Void {
Reflect.setProperty(field.first, field.second, value); Reflect.setProperty(listener.object, listener.field, value);
} }
public function merge(value:Dynamic<T>):Void { public function merge(value:Dynamic<T>):Void {