55 Commits
0.1.0 ... 0.6.1

Author SHA1 Message Date
59058c1b92 [log] fix format 2017-12-20 17:01:17 +03:00
ff1233b28e update 2017-07-11 14:14:59 +03:00
6e7da7c348 BaseLoader: fix load text resource from assets 2017-05-31 17:30:22 +03:00
f32085e053 vertical flag in ProgressSkin 2017-02-06 10:51:35 +03:00
fe5a4a71c4 bitmap_text compile flag 2015-12-01 16:17:43 +03:00
a39b45d090 ordersupplier fix 2015-09-11 11:11:33 +03:00
d4acd11c86 fixes 2015-09-11 10:31:33 +03:00
56d8509f8a change type field to @type 2015-08-05 15:40:36 +03:00
2669e56e06 README.md edited online with Bitbucket 2015-07-18 13:26:41 +00:00
60a7f21a48 added readme 2015-07-18 16:23:43 +03:00
cb348a4740 description update 2015-07-18 12:10:08 +03:00
5f04ad6c57 up version 2015-07-18 12:05:18 +03:00
29b1b05441 view example update 2015-07-18 00:02:21 +03:00
c532dc6e9f remove callback 2015-07-17 23:53:19 +03:00
047db87a25 promise in popup 2015-07-17 21:36:55 +03:00
18808764f9 use promise in loader 2015-07-17 21:27:20 +03:00
61b0078f3f added loader sample 2015-07-14 12:25:17 +03:00
95ab956ea3 move sources to src/main 2015-07-14 12:01:51 +03:00
7f172ab7a0 view builder update 2015-07-13 14:59:40 +03:00
a060118589 view builder update 2015-07-13 14:13:38 +03:00
f53b065d59 view type removed 2015-07-10 19:52:21 +03:00
7fb65137fa ViewBuilder fileName 2015-07-03 12:32:58 +03:00
37846c4a18 sample fix 2015-07-03 11:43:05 +03:00
cd2e80501b int fontSize 2015-07-03 10:41:44 +03:00
6687bc83d1 BitmapUtil added cache 2015-07-03 10:33:04 +03:00
1df0857db3 update 2015-07-02 15:09:21 +03:00
2113d81475 update 2015-07-02 11:12:52 +03:00
b714f60be6 added ViewBuilder 2015-07-01 17:58:37 +03:00
3bbb5e384d [js] fixes 2015-06-30 18:04:33 +03:00
374f540fe5 GuiBuilder => Builder 2015-06-30 17:57:36 +03:00
e2361b66a0 added Locale String 2015-06-30 12:43:07 +03:00
38ceb7eecb added popupmanager & animates 2015-06-30 11:11:10 +03:00
462ee023c3 BitmapTextField fix 2015-06-25 17:15:49 +03:00
78fb9bac50 [callback] added nay method 2015-06-16 16:41:09 +03:00
75ca7b90f0 Added BitmapTextField 2015-06-15 11:41:19 +03:00
19fd6866f1 Resources add int ResMap 2015-06-05 16:58:44 +03:00
7c6bdf98f4 TextView paddings 2015-06-05 12:55:43 +03:00
4d3acce9ea update 2015-06-04 16:57:55 +03:00
25a3fc7bf1 fixes 2015-05-26 12:42:22 +03:00
1643283b5d text view fix 2015-05-25 14:47:47 +03:00
28b94b7470 [js] textview fix 2015-05-22 17:50:36 +03:00
9b80d545c1 update 2015-05-21 17:41:43 +03:00
448e48e803 added animates 2015-05-20 12:27:06 +03:00
9abd0ebf88 [framwswitcher] focus fix 2015-05-14 18:01:31 +03:00
6ca134c3ee abstract enums 2015-05-12 17:15:09 +03:00
256c3e0457 texview fixes 2015-05-07 18:10:26 +03:00
a9886d8cc4 buttonview fix 2015-05-06 18:00:11 +03:00
91d588d622 added style support to GuiBuilder 2015-05-05 12:14:24 +03:00
dd613b463a [ImageView] added imageUrl field 2015-04-29 17:26:02 +03:00
759cb4c0b3 [GuiBuilder] added buildFromAssets method 2015-04-29 15:51:25 +03:00
8a29f1ca46 [GroupView] added insertItem method 2015-04-28 17:52:40 +03:00
5403b13931 Root instance & dispatcher run once 2015-04-28 17:02:20 +03:00
d0fc36c097 [html5] TextView height fix 2015-04-28 00:20:54 +03:00
1baa673f8a fixes for html5 2015-04-27 18:01:10 +03:00
2e6dbb7b38 fixes for html5 2015-04-24 14:24:04 +03:00
136 changed files with 2128 additions and 1069 deletions

5
.gitignore vendored
View File

@@ -1,5 +1,8 @@
/.idea
*.iml *.iml
*.ipr *.ipr
*.iws *.iws
out/ out/
target/ target/
*.zip
pack.sh

62
README.md Executable file
View File

@@ -0,0 +1,62 @@
# haxework
Gui framework for Haxe.
## View
`haxework.gui` provides views classes.
### Example
Build form using `haxework.gui.ViewBuilder`.
form.json:
```json
{
"type":"haxework.gui.VGroupView",
"skin":{"type":"haxework.gui.skin.ColorSkin", "color":"0xffff00"},
"paddings":20,
"layoutMargin":10,
"views":[
{
"id":"view1",
"type":"haxework.gui.SpriteView",
"pWidth":100, "pHeight":100,
"skin":{"type":"haxework.gui.skin.ColorSkin", "color":"0xff0000"}
},
{
"id":"view2",
"type":"haxework.gui.SpriteView",
"pWidth":100, "height":50,
"skin":{"type":"haxework.gui.skin.ColorSkin", "color":"0x00ff00"}
}
]
}
```
```haxe
@:template("form.json")
class FormView extends VGroupView implements ViewBuilder {}
var form = new FormView();
Root.bind(form); // Add form to stage as root view element.
trace(form.view1);
trace(form.view2);
```
## Loader
`haxework.net` provides loaders classes.
### Example
```haxe
new JsonLoader().GET("http://example.com/file.json")
.then(function(data) {
trace("Json Ok: " + data);
})
.catchError(function(error) {
trace("Json Fail: " + error);
});
```

View File

@@ -1,4 +0,0 @@
-main examples.ViewExample
-swf target/ViewExample.swf
-debug
-dce no

View File

@@ -1,32 +0,0 @@
package examples;
import haxework.gui.IGroupView;
import haxework.gui.ButtonView;
import haxework.gui.GuiBuilder;
import haxework.asset.JsonAsset;
import haxework.gui.Root;
import flash.display.Sprite;
@:file("examples/form.json")
class Form extends JsonAsset {}
class ViewExample implements ButtonViewListener {
public static function main() {
new ViewExample();
}
public function new() {
//var form:Dynamic = new Form().value;
var bytes = openfl.Assets.getBytes("examples/form.json");
var form:Dynamic = haxe.Json.parse(bytes.readUTFBytes(bytes.bytesAvailable));
var v:IGroupView<Sprite> = GuiBuilder.build(form, {listener:this});
new Root(v);
var button3:ButtonView = v.findViewById("panel:button3");
trace(button3.id);
}
public function onPress(view:ButtonView):Void {
trace("onPress: " + view.id);
}
}

View File

@@ -1,69 +0,0 @@
{
"type":"haxework.gui.VGroupView",
"layoutHAlign":"~haxework.gui.core.HAlign:CENTER",
"layoutVAlign":"~haxework.gui.core.VAlign:MIDDLE",
"paddings":20,
"layoutMargin":10,
"skin":{"type":"haxework.gui.skin.ColorSkin", "color":"0xff0000"},
"views":[
{
"type":"haxework.gui.View",
"pWidth":100,
"pHeight":100,
"leftMargin":5,
"rightMargin":10,
"skin":{"type":"haxework.gui.skin.ColorSkin", "color":"0x00ff00"}
},
{
"type":"haxework.gui.View",
"vAlign":"~haxework.gui.core.VAlign:BOTTOM",
"width":50,
"height":50,
"leftMargin":5,
"rightMargin":10,
"skin":{"type":"haxework.gui.skin.ColorSkin", "color":"0x0000ff"}
},
{
"id":"panel",
"type":"haxework.gui.HGroupView",
"layoutHAlign":"~haxework.gui.core.HAlign:RIGHT",
"layoutVAlign":"~haxework.gui.core.VAlign:MIDDLE",
"pWidth":100,
"height":30,
"paddings":3,
"layoutMargin":3,
"skin":{"type":"haxework.gui.skin.ColorSkin", "color":"0xffff00"},
"views":[
{
"id":"button1",
"type":"haxework.gui.ButtonView",
"width":100,
"pHeight":100,
"skin":{"type":"haxework.gui.skin.ButtonColorSkin", "color":"0xcc0000"},
"text":"Text1",
"onPress":"#listener"
},
{
"id":"button2",
"type":"haxework.gui.ButtonView",
"contentSize":true,
"skin":{"type":"haxework.gui.skin.ButtonColorSkin", "color":"0x00cc00"},
"text":"Text2",
"fontFamily":"Georgia",
"fontColor":"0xffffff",
"onPress":"#listener"
},
{
"id":"button3",
"type":"haxework.gui.ButtonView",
"contentSize":true,
"skin":{"type":"haxework.gui.skin.ButtonColorSkin", "color":"0x00cccc"},
"text":"Text 3333333333 ddd",
"fontFamily":"Tahoma",
"fontColor":"0xff0000",
"onPress":"#listener"
}
]
}
]
}

View File

@@ -4,8 +4,11 @@
"license": "BSD", "license": "BSD",
"tags": ["flash"], "tags": ["flash"],
"description": "Framework.", "description": "Framework.",
"version": "0.1.0", "version": "0.6.1",
"releasenote": "Update.", "releasenote": "Update.",
"contributors": ["shmyga"], "contributors": ["shmyga"],
"dependencies": {} "classPath": "src/main",
"dependencies": {
"promhx": ""
}
} }

View File

@@ -1,43 +0,0 @@
package haxework.frame;
import flash.display.Sprite;
import haxework.gui.IView;
import haxework.gui.GroupView;
class FrameSwitcher extends GroupView implements IFrameSwitcher<Sprite> {
public var current(default, null):Null<IView<Dynamic>>;
private var frames:Map<String, IView<Dynamic>>;
public function new() {
super();
frames = new Map<String, IView<Dynamic>>();
current = null;
}
public function change(id:String):IView<Dynamic> {
if (current != null) {
if (current.id == id) return current;
var onHideethod:Dynamic = Reflect.field(current, "onHide");
if (onHideethod != null) Reflect.callMethod(current, onHideethod, []);
removeView(current);
}
current = frames.get(id);
addView(current);
var onShowMethod:Dynamic = Reflect.field(current, "onShow");
if (onShowMethod != null) Reflect.callMethod(current, onShowMethod, []);
return current;
}
override public function set_views(value:Array<IView<Dynamic>>):Array<IView<Dynamic>> {
views = [];
if (value.length > 0) {
for (view in value) {
view.pWidth = 100;
view.pHeight = 100;
frames.set(view.id, view);
}
}
return value;
}
}

View File

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

View File

@@ -1,175 +0,0 @@
package haxework.gui;
//ToDo:
import flash.errors.Error;
import openfl.Assets;
import flash.errors.TypeError;
import flash.errors.ArgumentError;
import haxework.resources.IResources;
import haxework.provider.Provider;
import haxework.gui.View;
import haxework.gui.SpriteView;
import haxework.gui.MovieView;
import haxework.gui.GroupView;
import haxework.gui.HGroupView;
import haxework.gui.VGroupView;
import haxework.gui.TextView;
import haxework.gui.InputView;
import haxework.gui.LabelView;
import haxework.gui.ButtonView;
import haxework.gui.ToggleButtonView;
import haxework.gui.ProgressView;
import haxework.gui.AnimateView;
import haxework.gui.skin.ColorSkin;
import haxework.gui.skin.BitmapSkin;
import haxework.gui.skin.ButtonColorSkin;
import haxework.gui.skin.ButtonBitmapSkin;
import haxework.gui.skin.ProgressSkin;
import haxework.frame.FrameSwitcher;
class GuiBuilder {
public static function build(data:Dynamic, ?links:Dynamic):Dynamic {
return new GuiB(data, links, data._includes).build();
}
public static function fill(object:Dynamic, data:Dynamic, ?links:Dynamic):Void {
new GuiF(object, data, links, data._includes).fill();
}
}
class GuiB {
private var data:Dynamic;
private var links:Dynamic;
private var includes:Dynamic;
public function new(data:Dynamic, ?links:Dynamic, ?includes:Dynamic) {
this.data = data;
this.links = links;
this.includes = includes;
}
public function build():Dynamic {
if (Reflect.hasField(data, "type")) {
var type:String = data.type;
//Reflect.deleteField(data, "type");
if (type.charAt(0) == "~") return Type.resolveClass(type.substr(1));
var object:Dynamic = instance(type);
new GuiF(object, data, links, includes).fill();
var initMethod:Dynamic = Reflect.field(object, "init");
if (initMethod != null) Reflect.callMethod(object, initMethod, []);
return object;
} else if (Std.is(data, String)) {
return GuiF.convertString(data, links);
} else {
new GuiF(data, data, links, includes).fill();
return data;
}
}
private static function instance(type:String):Dynamic {
var clazz:Class<Dynamic> = Type.resolveClass(type);
if (clazz == null) throw new TypeError("Class \"" + type + "\" not found");
var instance:Dynamic = Type.createInstance(clazz, []);
return instance;
}
}
class GuiF {
private var object:Dynamic;
private var data:Dynamic;
private var links:Dynamic;
private var includes:Dynamic;
public function new(object:Dynamic, data:Dynamic, ?links:Dynamic, ?includes:Dynamic) {
this.object = object;
this.data = data;
this.links = links;
this.includes = includes;
}
public static function convertString(value:Dynamic, ?links:Dynamic):Dynamic {
var s:String = cast(value, String);
var c:String = s.charAt(0);
if (c == "#") {
value = Reflect.field(links, s.substr(1));
} else if (c == "~") {
var a:Array<String> = s.substr(1).split(":");
var e:Enum<Dynamic> = Type.resolveEnum(a[0]);
value = Type.createEnum(e, a[1]);
} else if (c == "@") {
if (s.charAt(1) == "~") {
var a:Array<String> = s.substr(2).split(":");
value = Assets.getBitmapData(a[1]);
} else {
var a:Array<String> = s.substr(1).split(":");
value = Reflect.field(Provider.get(IResources), a[0]).get(a[1]);
}
} else if (~/0x[A-Fa-f\d]{6}/.match(value)) {
value = Std.parseInt(value);
}
return value;
}
public function fill() {
var fields:Array<String> = Reflect.fields(data);
for (field in fields) {
if (field == "type") continue;
if (field == "_includes") continue;
var value:Dynamic = Reflect.field(data, field);
if (field == "_include") {
var data:Dynamic = includes == null ? null : Reflect.field(includes, value);
if (data != null) {
new GuiF(object, data, links).fill();
}
continue;
}
if (Std.is(value, Array)) {
var a:Array<Dynamic> = [];
for (o in cast(value, Array<Dynamic>)) a.push(new GuiB(o, links, includes).build());
value = a;
} else if (Std.is(value, String)) {
var s:String = cast(value, String);
var c:String = s.charAt(0);
if (c == "#") {
value = Reflect.field(links, s.substr(1));
} else if (c == "~") {
var a:Array<String> = s.substr(1).split(":");
var e:Enum<Dynamic> = Type.resolveEnum(a[0]);
value = Type.createEnum(e, a[1]);
} else if (c == "@") {
if (s.charAt(1) == "~") {
var a:Array<String> = s.substr(2).split(":");
switch (a[0]) {
case "image": Reflect.setProperty(object, field, Assets.getBitmapData(a[1]));
}
} else {
var a:Array<String> = s.substr(1).split(":");
//value = Reflect.field(Provider.get(IResources), a[0]).get(a[1]);
Reflect.field(Provider.get(IResources), a[0]).bind(a[1], object, field);
}
continue;
} else if (~/0x[A-Fa-f\d]{6}/.match(value)) {
value = Std.parseInt(value);
}
} else if (Std.is(value, Float)) {
} else if (Std.is(value, Bool)) {
} else {
var o:Dynamic = new GuiB(value, links, includes).build();
new GuiF(o, value, links).fill();
value = o;
}
try {
Reflect.setProperty(object, field, value);
} catch(error:Dynamic) {
L.e("GuiBuilder", "", error);
}
}
}
}

View File

@@ -1,29 +0,0 @@
package haxework.gui;
import haxework.gui.IView.Content;
import haxework.gui.core.HAlign;
import haxework.gui.core.VAlign;
import haxework.gui.layout.ILayout;
interface IGroupView<C:Content> extends IView<C> {
public var views(default, null):Array<IView<Dynamic>>;
public var layout(default, default):ILayout;
public var layoutVAlign(default, set):VAlign;
public var layoutHAlign(default, set):HAlign;
public var layoutMargin(default, set):Float;
public var leftPadding(default, set):Float;
public var rightPadding(default, set):Float;
public var topPadding(default, set):Float;
public var bottomPadding(default, set):Float;
public var paddings(null, set):Float;
public function addView(view:IView<Dynamic>):IView<Dynamic>;
public function addViewFirst(view:IView<Dynamic>):IView<Dynamic>;
public function removeView(view:IView<Dynamic>):IView<Dynamic>;
public function removeAllViews():Void;
public function removeViewById(id:String):IView<Dynamic>;
public function findViewById<V:IView<Dynamic>>(id:String, ?clazz:Class<V>):Null<V>;
}

View File

@@ -1,24 +0,0 @@
package haxework.gui;
import haxework.gui.utils.DrawUtil.FillType;
import haxework.gui.skin.BitmapSkin;
import haxework.gui.skin.ButtonBitmapSkin;
import flash.display.BitmapData;
class ImageView extends SpriteView {
public var image(default, set):BitmapData;
public function new() {
super();
}
private function set_image(value:BitmapData):BitmapData {
if (image != value) {
image = value;
skin = untyped new BitmapSkin(image, FillType.CONTAIN);
invalidate();
}
return image;
}
}

View File

@@ -1,19 +0,0 @@
package haxework.gui;
import flash.display.Graphics;
import flash.display.Sprite;
class SpriteView extends View<Sprite> {
public function new() {
super(new Sprite());
}
/*override public function update():Void {
super.update();
var g:Graphics = content.graphics;
g.lineStyle(1, 0x00ff00);
g.drawRect(0, 0, width, height);
g.lineStyle();
}*/
}

View File

@@ -1,195 +0,0 @@
package haxework.gui;
import flash.geom.Point;
import flash.text.TextFieldAutoSize;
import haxework.gui.core.HAlign;
import haxework.gui.core.VAlign;
import flash.text.TextFormatAlign;
import haxework.gui.skin.ISize;
import flash.text.TextFormat;
import flash.display.Sprite;
import flash.text.TextField;
class TextView extends SpriteView implements ITextView<Sprite, TextField> {
public var textField(default, null):TextField;
public var text(get, set):String;
private var _text:String;
public var align(default, set):TextFormatAlign;
public var fontFamily(default, set):String;
public var fontEmbed(default, set):Bool;
public var fontColor(default, set):Int;
public var fontSize(default, set):Float;
public var layoutHAlign(default, set):HAlign;
public var layoutVAlign(default, set):VAlign;
public var fill(default, set):Bool = true;
public var paddings(default, set):Float = 0.0;
private var textFormat:TextFormat;
public function new() {
super();
layoutHAlign = HAlign.NONE;
layoutVAlign = VAlign.NONE;
textField = buildTextField();
textField.width = 1;
textField.height = #if html5 25 #else 1 #end;
textField.wordWrap = true;
textFormat = textField.defaultTextFormat;
textFormat.font = "Arial";
textFormat.size = 16;
content.addChild(textField);
}
private function buildTextField():TextField {
return new TextField();
}
private function set_paddings(value:Float):Float {
if (paddings != value) {
paddings = value;
invalidate();
}
return paddings;
}
private function set_fill(value:Bool):Bool {
if (fill != value) {
fill = value;
invalidate();
}
return fill;
}
private function set_layoutHAlign(value:HAlign):HAlign {
if (layoutHAlign != value) {
layoutHAlign = value;
invalidate();
}
return layoutHAlign;
}
private function set_layoutVAlign(value:VAlign):VAlign {
if (layoutVAlign != value) {
layoutVAlign = value;
invalidate();
}
return layoutVAlign;
}
private function get_text():String {
return textField.text;
}
private function set_text(value:String):String {
if (_text != value) {
_text = value;
invalidate();
}
return _text;
}
private function set_align(value:TextFormatAlign):TextFormatAlign {
if (align != value) {
align = value;
#if (flash || html5)
textFormat.align = value;
#else
textFormat.align = Std.string(value);
#end
invalidate();
}
return align;
}
private function set_fontFamily(value:String):String {
if (fontFamily != value) {
fontFamily = value;
textFormat.font = fontFamily;
invalidate();
}
return fontFamily;
}
private function set_fontEmbed(value:Bool):Bool {
if (fontEmbed != value) {
fontEmbed = value;
invalidate();
}
return fontEmbed;
}
private function set_fontColor(value:Int):Int {
if (fontColor != value) {
fontColor = value;
textFormat.color = fontColor;
invalidate();
}
return fontColor;
}
private function set_fontSize(value:Float):Float {
if (fontSize != value) {
fontSize = value;
textFormat.size = fontSize;
invalidate();
}
return fontSize;
}
private function currentText():String {
return _text;
}
override public function update():Void {
textField.embedFonts = fontEmbed;
textField.defaultTextFormat = textFormat;
textField.autoSize = fill ? TextFieldAutoSize.NONE : TextFieldAutoSize.LEFT;
var t:String = currentText();
if (t != null) textField.text = t;
if (contentSize && !Std.is(skin, ISize)) {
width = textField.width + paddings * 2;
height = textField.height + paddings * 2;
textField.x = paddings;
textField.y = paddings;
} else {
placeTextField(textField);
}
//ToDo:
var t:Point = content.localToGlobal(new Point(textField.x, textField.y));
t.x = Math.round(t.x);
t.y = Math.round(t.y);
t = content.globalToLocal(t);
textField.x = t.x;
textField.y = t.y;
super.update();
}
private function placeTextField(textField:TextField):Void {
if (fill) {
textField.width = width - paddings * 2;
textField.height = height - paddings * 2;
textField.x = paddings;
textField.y = paddings;
} else {
textField.x = switch (layoutHAlign) {
case HAlign.NONE: 0;
case HAlign.LEFT: paddings;
case HAlign.CENTER: (width - textField.width) / 2;
case HAlign.RIGHT: width - textField.width - paddings;
}
textField.y = switch (layoutVAlign) {
case VAlign.NONE: 0;
case VAlign.TOP: paddings;
case VAlign.MIDDLE: (height - textField.height) / 2;
case VAlign.BOTTOM: height - textField.height - paddings;
}
}
}
override private function set_mouseEnabled(value:Bool):Bool {
textField.mouseEnabled = value;
return super.set_mouseEnabled(value);
}
}

View File

@@ -1,8 +0,0 @@
package haxework.gui.core;
@:fakeEnum(String) enum HAlign {
NONE;
LEFT;
CENTER;
RIGHT;
}

View File

@@ -1,8 +0,0 @@
package haxework.gui.core;
@:fakeEnum(String) enum VAlign {
NONE;
TOP;
MIDDLE;
BOTTOM;
}

View File

@@ -1,5 +0,0 @@
package haxework.gui.layout;
interface ILayout {
public function place(group:IGroupView<Dynamic>, views:Array<IView<Dynamic>>):Void;
}

View File

@@ -1,51 +0,0 @@
package haxework.net;
import haxework.net.callback.Callback;
import haxework.net.callback.ICallback;
import flash.events.Event;
import flash.net.URLLoader;
class BatchLoader<T> {
public var factory:Class<ILoader<T>>;
public function new(factory:Class<ILoader<T>>) {
this.factory = factory;
}
public function GET(urls:Array<String>):ICallback<Array<T>> {
var callbacks:Array<ICallback<T>> = urls.map(function(url:String):ICallback<T> {
var loader:ILoader<T> = Type.createInstance(factory, []);
return loader.GET(url);
});
return new BatchCallback(callbacks);
}
}
class BatchCallback<T> extends Callback<Array<T>> {
private var data:Array<T>;
private var counter:Int;
public function new(callbacks:Array<ICallback<T>>) {
super();
data = new Array<T>();
counter = callbacks.length;
for (i in 0...callbacks.length) {
register(callbacks[i], i);
}
}
private function register(callback:ICallback<T>, index:Int):Void {
callback
.success(function(d:T):Void {
data[index] = d;
if (--counter == 0) callSuccess(data);
})
.fail(function(error:Dynamic):Void {
L.e("BatchLoader", "", error);
if (--counter == 0) callSuccess(data);
});
}
}

View File

@@ -1,16 +0,0 @@
package haxework.net.callback;
class AutoCallback {
public static function success<T>(?value:T):ICallback<T> {
var callback:ICallback<T> = new Callback<T>();
callback.callSuccessAsync(value);
return callback;
}
public static function fail<T>(error:Dynamic):ICallback<T> {
var callback:ICallback<T> = new Callback<T>();
callback.callFailAsync(error);
return callback;
}
}

View File

@@ -1,67 +0,0 @@
package haxework.net.callback;
import haxe.Timer;
class Callback<T> implements ICallback<T> {
public static function build<T>():ICallback<T> {
return new Callback<T>();
}
private var _success:Null<T -> Void>;
private var _fail:Null<Dynamic -> Void>;
public function new() {}
public function success(f:T -> Void):ICallback<T> {
_success = f;
return this;
}
public function fail(f:Dynamic -> Void):ICallback<T> {
_fail = f;
return this;
}
public function callSuccess(data:T):Void {
try {
if (_success != null) _success(data);
} catch (error:Dynamic) {
callFail(error);
}
dispose();
}
public function callSuccessAsync(data:T):Void {
Timer.delay(function():Void {
callSuccess(data);
}, 1);
}
public function callFail(error:Dynamic):Void {
try {
if (_fail != null) _fail(error);
} catch (error:Dynamic) {
L.d("Callback", "", error);
}
dispose();
}
public function callFailAsync(error:Dynamic):Void {
Timer.delay(function():Void {
callFail(error);
}, 1);
}
public function glue(callback:ICallback<T>):ICallback<T> {
this._success = callback.callSuccess;
this._fail = callback.callFail;
//callback.dispose(); //ToDo:
return this;
}
public function dispose():Void {
_success = null;
_fail = null;
}
}

View File

@@ -1,14 +0,0 @@
package haxework.net.callback;
import haxework.core.IDisposable;
interface ICallback<T> extends IDisposable {
public function success(f:T -> Void):ICallback<T>;
public function fail(f:Dynamic -> Void):ICallback<T>;
public function callSuccess(data:T):Void;
public function callSuccessAsync(data:T):Void;
public function callFail(error:Dynamic):Void;
public function callFailAsync(error:Dynamic):Void;
public function glue(callback:ICallback<T>):ICallback<T>;
}

View File

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

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<project>
<meta title="ViewExample" package="haxework.examples" version="1.0.0" company="MegaLoMania"/>
<app path="target" file="ViewExample" main="examples.ViewExample"/>
<window width="800" height="600" if="desktop"/>
<window width="0" height="0" if="html5"/>
<source path="."/>
<haxelib name="openfl"/>
<assets path="examples" include="*"/>
</project>

View File

@@ -0,0 +1,4 @@
-cp src
-lib haxework
-main ViewExample.hx
-swf target/ViewExample.swf

View File

@@ -0,0 +1,29 @@
package;
import haxework.gui.ViewBuilder;
import haxework.gui.VGroupView;
import haxework.gui.ButtonView;
import haxework.gui.Root;
@:template("form.json")
class FormView extends VGroupView implements ViewBuilder {}
class ViewExample {
public static function main() {
new ViewExample();
}
public function new() {
var form = new FormView({listener:this});
Root.bind(form);
trace(form.panel);
trace(form.button1);
trace(form.button2);
trace(form.button3);
}
public function onPress(view:ButtonView):Void {
trace("onPress: " + view.id);
}
}

66
samples/01-view/src/form.json Executable file
View File

@@ -0,0 +1,66 @@
{
"@type":"haxework.gui.VGroupView",
"paddings":20,
"layoutMargin":10,
"skin":{"@type":"haxework.gui.skin.ColorSkin", "color":"0xff0000"},
"views":[
{
"@type":"haxework.gui.SpriteView",
"pWidth":100,
"pHeight":100,
"leftMargin":5,
"rightMargin":10,
"skin":{"@type":"haxework.gui.skin.ColorSkin", "color":"0x00ff00"}
},
{
"@type":"haxework.gui.SpriteView",
"vAlign":"BOTTOM",
"width":50,
"height":50,
"leftMargin":5,
"rightMargin":10,
"skin":{"@type":"haxework.gui.skin.ColorSkin", "color":"0x0000ff"}
},
{
"id":"panel",
"@type":"haxework.gui.HGroupView",
"layoutHAlign":"RIGHT",
"pWidth":100,
"height":30,
"paddings":3,
"layoutMargin":3,
"skin":{"@type":"haxework.gui.skin.ColorSkin", "color":"0xffff00"},
"views":[
{
"id":"button1",
"@type":"haxework.gui.ButtonView",
"width":100,
"pHeight":100,
"skin":{"@type":"haxework.gui.skin.ButtonColorSkin", "color":"0xcc0000"},
"text":"Text1",
"onPress":"@link:listener"
},
{
"id":"button2",
"@type":"haxework.gui.ButtonView",
"contentSize":true,
"skin":{"@type":"haxework.gui.skin.ButtonColorSkin", "color":"0x00cc00"},
"text":"Text2",
"fontFamily":"Georgia",
"fontColor":"0xffffff",
"onPress":"@link:listener"
},
{
"id":"button3",
"@type":"haxework.gui.ButtonView",
"contentSize":true,
"skin":{"@type":"haxework.gui.skin.ButtonColorSkin", "color":"0x00cccc"},
"text":"Text 3333333333 ddd",
"fontFamily":"Tahoma",
"fontColor":"0xff0000",
"onPress":"@link:listener"
}
]
}
]
}

6
samples/02-loader/build.hxml Executable file
View File

@@ -0,0 +1,6 @@
-cp src
-lib promhx
-lib haxework
-main LoaderExample.hx
-swf-version 10.1
-swf target/LoaderExample.swf

View File

@@ -0,0 +1,43 @@
package;
import flash.display.Bitmap;
import flash.Lib;
import flash.display.BitmapData;
import haxework.net.ImageLoader;
import haxework.net.JsonLoader;
typedef ChannelItem = {
var id:String;
var maker:String;
var title:String;
var message:String;
}
class LoaderExample {
public static function main() {
// Json
trace("Json Request");
new JsonLoader().GET("http://umix.tv/channel/data2/renova.json")
.then(function(channel:Array<ChannelItem>) {
trace("Json Ok: " + channel.length);
for (item in channel) {
trace(item.id + ": " + item.message);
}
})
.catchError(function(error) {
trace(error);
});
// Image
trace("Image Request");
new ImageLoader().GET("http://umix.tv/channel/block/renova/1")
.then(function(image:BitmapData) {
trace("Image Ok: " + image.width + "x" + image.height);
Lib.current.addChild(new Bitmap(image));
})
.catchError(function(error) {
trace(error);
});
}
}

View File

View File

@@ -0,0 +1,53 @@
package haxework.animate;
import openfl.events.Event;
import flash.display.Stage;
class Animate implements IAnimate {
private static var running:Array<IAnimate> = new Array<IAnimate>();
public static function bind(stage:Stage):Void {
stage.addEventListener(Event.ENTER_FRAME, function(_) {
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;
private var duration:Int;
private var startTime:Float;
private var progress:Float;
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 {
if (!Math.isNaN(startTime)) update(startTime + duration);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -10,8 +10,8 @@ class Dispatcher<L:{}> implements IDispatcher<L> {
listeners = new ObjectMap<L, Bool>(); listeners = new ObjectMap<L, Bool>();
} }
public function addListener(listener:L):Void { public function addListener(listener:L, once:Bool = false):Void {
listeners.set(listener, true); listeners.set(listener, once);
} }
public function removeListener(listener:L):Bool { public function removeListener(listener:L):Bool {
@@ -25,6 +25,12 @@ class Dispatcher<L:{}> implements IDispatcher<L> {
public function dispatch(caller:L->Void):Void { public function dispatch(caller:L->Void):Void {
var i:Iterator<L> = listeners.keys(); var i:Iterator<L> = listeners.keys();
while (i.hasNext()) caller(i.next()); var r:Array<L> = [];
while (i.hasNext()) {
var l = i.next();
caller(l);
if (listeners.get(l)) r.push(l);
};
for (l in r) listeners.remove(l);
} }
} }

View File

@@ -6,7 +6,7 @@ interface IDispatcher<L:{}> {
private var listeners(null, null):ObjectMap<L, Bool>; private var listeners(null, null):ObjectMap<L, Bool>;
public function addListener(listener:L):Void; public function addListener(listener:L, once:Bool = false):Void;
public function removeListener(listener:L):Bool; public function removeListener(listener:L):Bool;
public function removeAllListeners():Void; public function removeAllListeners():Void;
public function dispatch(caller:L->Void):Void; public function dispatch(caller:L->Void):Void;

View File

@@ -18,7 +18,7 @@ class AnimateView extends SpriteView {
frames = []; frames = [];
frame = 0; frame = 0;
interval = 200; interval = 200;
content.addChild(bitmap); contentAsSprite.addChild(bitmap);
changeFrame(); changeFrame();
} }

View File

@@ -26,9 +26,13 @@ class ButtonView extends LabelView {
downed = false; downed = false;
state = ButtonState.UP; state = ButtonState.UP;
dispatcher = new Dispatcher<ButtonViewListener<Dynamic>>(); dispatcher = new Dispatcher<ButtonViewListener<Dynamic>>();
content.buttonMode = true; contentAsSprite.buttonMode = true;
content.mouseChildren = false; contentAsSprite.mouseChildren = false;
#if js
content.addEventListener(MouseEvent.MOUSE_UP, onMouseClick);
#else
content.addEventListener(MouseEvent.CLICK, onMouseClick); content.addEventListener(MouseEvent.CLICK, onMouseClick);
#end
#if !mobile #if !mobile
content.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); content.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
content.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut); content.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
@@ -38,8 +42,10 @@ class ButtonView extends LabelView {
} }
private function onMouseClick(event:MouseEvent):Void { private function onMouseClick(event:MouseEvent):Void {
event.stopImmediatePropagation(); #if js if (downed) { #end
if (!disabled) dispatcher.dispatch(pressCaller); event.stopImmediatePropagation();
if (!disabled) dispatcher.dispatch(pressCaller);
#if js } #end
} }
private function onMouseOver(event:MouseEvent):Void { private function onMouseOver(event:MouseEvent):Void {
@@ -54,14 +60,18 @@ class ButtonView extends LabelView {
private function onMouseDown(event:MouseEvent):Void { private function onMouseDown(event:MouseEvent):Void {
downed = true; downed = true;
content.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); if (content.stage != null) {
invalidate(); content.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
invalidate();
}
} }
private function onMouseUp(event:MouseEvent):Void { private function onMouseUp(event:MouseEvent):Void {
downed = false; downed = false;
content.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp); if (content.stage != null) {
invalidate(); content.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
invalidate();
}
} }
private function pressCaller(listener:ButtonViewListener<Dynamic>):Void { private function pressCaller(listener:ButtonViewListener<Dynamic>):Void {
@@ -71,7 +81,7 @@ class ButtonView extends LabelView {
private function set_disabled(value:Bool):Bool { private function set_disabled(value:Bool):Bool {
if (disabled != value) { if (disabled != value) {
disabled = value; disabled = value;
content.buttonMode = !disabled; contentAsSprite.buttonMode = !disabled;
invalidate(); invalidate();
} }
return disabled; return disabled;
@@ -93,6 +103,7 @@ class ButtonView extends LabelView {
public function dispose():Void { public function dispose():Void {
dispatcher.removeAllListeners(); dispatcher.removeAllListeners();
content.removeEventListener(MouseEvent.CLICK, onMouseClick); content.removeEventListener(MouseEvent.CLICK, onMouseClick);
content.removeEventListener(MouseEvent.MOUSE_UP, onMouseClick);
content.removeEventListener(MouseEvent.MOUSE_OVER, onMouseOver); content.removeEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
content.removeEventListener(MouseEvent.MOUSE_OUT, onMouseOut); content.removeEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
content.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); content.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);

View File

@@ -1,14 +1,16 @@
package haxework.gui; package haxework.gui;
import flash.display.DisplayObjectContainer;
import haxework.gui.core.VAlign; import haxework.gui.core.VAlign;
import haxework.gui.core.HAlign; import haxework.gui.core.HAlign;
import haxework.gui.layout.DefaultLayout; import haxework.gui.layout.DefaultLayout;
import haxework.gui.layout.ILayout; import haxework.gui.layout.ILayout;
import flash.display.Sprite; import flash.display.Sprite;
class GroupView extends SpriteView implements IGroupView<Sprite> { class GroupView extends SpriteView implements IGroupView {
public var container(get, null):DisplayObjectContainer;
public var views(default, set):Array<IView<Dynamic>>; public var views(default, set):Array<IView>;
public var layout(default, default):ILayout; public var layout(default, default):ILayout;
public var layoutVAlign(default, set):VAlign; public var layoutVAlign(default, set):VAlign;
@@ -21,7 +23,7 @@ class GroupView extends SpriteView implements IGroupView<Sprite> {
public var bottomPadding(default, set):Float; public var bottomPadding(default, set):Float;
public var paddings(null, set):Float; public var paddings(null, set):Float;
private var viewsById:Map<String, IView<Dynamic>>; private var viewsById:Map<String, IView>;
public function new(?layout:ILayout) { public function new(?layout:ILayout) {
super(); super();
@@ -31,7 +33,11 @@ class GroupView extends SpriteView implements IGroupView<Sprite> {
layoutHAlign = HAlign.CENTER; layoutHAlign = HAlign.CENTER;
layoutVAlign = VAlign.MIDDLE; layoutVAlign = VAlign.MIDDLE;
views = []; views = [];
viewsById = new Map<String, IView<Sprite>>(); viewsById = new Map<String, IView>();
}
inline private function get_container():DisplayObjectContainer {
return contentAsSprite;
} }
override public function update():Void { override public function update():Void {
@@ -39,52 +45,63 @@ class GroupView extends SpriteView implements IGroupView<Sprite> {
for (view in views) { for (view in views) {
view.update(); view.update();
if (view.index > -1) { if (view.index > -1) {
content.setChildIndex(view.content, view.index); contentAsSprite.setChildIndex(view.content, view.index);
} }
} }
super.update(); super.update();
} }
public function set_views(value:Array<IView<Dynamic>>):Array<IView<Dynamic>> { public function set_views(value:Array<IView>):Array<IView> {
removeAllViews();
if (views == null) views = []; if (views == null) views = [];
for (view in value) addView(view); for (view in value) addView(view);
return views; return views;
} }
public function addView(view:IView<Dynamic>):IView<Dynamic> { public function addView(view:IView):IView {
views.push(view); views.push(view);
viewsById.set(view.id, view); viewsById.set(view.id, view);
if (view.content != null) content.addChild(view.content); if (view.content != null) contentAsSprite.addChild(view.content);
view.parent = this; view.parent = this;
invalidate(); invalidate();
return view; return view;
} }
public function addViewFirst(view:IView<Dynamic>):IView<Dynamic> { public function insertView(view:IView, index:Int):IView {
if (index < 0) index = views.length + index;
views.insert(index, view);
viewsById.set(view.id, view);
if (view.content != null) contentAsSprite.addChild(view.content);
view.parent = this;
invalidate();
return view;
}
public function addViewFirst(view:IView):IView {
views.unshift(view); views.unshift(view);
viewsById.set(view.id, view); viewsById.set(view.id, view);
content.addChild(view.content); contentAsSprite.addChild(view.content);
view.parent = this; view.parent = this;
invalidate(); invalidate();
return view; return view;
} }
public function removeView(view:IView<Dynamic>):IView<Dynamic> { public function removeView(view:IView):IView {
view.parent = null; view.parent = null;
viewsById.remove(view.id); viewsById.remove(view.id);
views.remove(view); views.remove(view);
if (view.content != null) content.removeChild(view.content); if (view.content != null) contentAsSprite.removeChild(view.content);
invalidate(); invalidate();
return view; return view;
} }
public function removeAllViews():Void { public function removeAllViews():Void {
while (views.length > 0) { if (views != null) while (views.length > 0) {
removeView(views[0]); removeView(views[0]);
} }
} }
public function removeViewById(id:String):IView<Dynamic> { public function removeViewById(id:String):IView {
if (viewsById.exists(id)) { if (viewsById.exists(id)) {
return removeView(viewsById.get(id)); return removeView(viewsById.get(id));
} else { } else {
@@ -92,7 +109,7 @@ class GroupView extends SpriteView implements IGroupView<Sprite> {
} }
} }
public function findViewById<V:IView<Dynamic>>(id:String, ?clazz:Class<V>):Null<V> { public function findViewById<V:IView>(id:String, ?clazz:Class<V>):Null<V> {
var idd:Array<String> = id.split(":"); var idd:Array<String> = id.split(":");
if (idd.length > 1) { if (idd.length > 1) {
var id0 = idd.shift(); var id0 = idd.shift();

View File

@@ -0,0 +1,9 @@
package haxework.gui;
interface HasPaddings {
public var leftPadding(default, set):Float;
public var rightPadding(default, set):Float;
public var topPadding(default, set):Float;
public var bottomPadding(default, set):Float;
public var paddings(null, set):Float;
}

View File

@@ -0,0 +1,26 @@
package haxework.gui;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import haxework.gui.core.HAlign;
import haxework.gui.core.VAlign;
import haxework.gui.layout.ILayout;
interface IGroupView extends IView extends HasPaddings {
public var container(get, null):DisplayObjectContainer;
public var views(default, set):Array<IView>;
public var layout(default, default):ILayout;
public var layoutVAlign(default, set):VAlign;
public var layoutHAlign(default, set):HAlign;
public var layoutMargin(default, set):Float;
public function addView(view:IView):IView;
public function addViewFirst(view:IView):IView;
public function insertView(view:IView, index:Int):IView;
public function removeView(view:IView):IView;
public function removeAllViews():Void;
public function removeViewById(id:String):IView;
public function findViewById<V:IView>(id:String, ?clazz:Class<V>):Null<V>;
}

View File

@@ -1,15 +1,17 @@
package haxework.gui; package haxework.gui;
import flash.text.TextField;
import haxework.gui.IView.Content; import haxework.gui.IView.Content;
import flash.text.TextFormatAlign; import flash.text.TextFormatAlign;
interface ITextView<C:Content, T> extends IView<C> { interface ITextView extends IView extends HasPaddings {
public var textField(default, null):T; public var textField(default, null):TextField;
public var text(get, set):String; public var text(get, set):String;
public var align(default, set):TextFormatAlign; public var align(default, set):TextFormatAlign;
//ToDo: font properties to object //ToDo: font properties to object
public var fontFamily(default, set):String; public var fontFamily(default, set):String;
public var fontEmbed(default, set):Bool; public var fontEmbed(default, set):Bool;
public var fontColor(default, set):Int; public var fontColor(default, set):Int;
public var fontSize(default, set):Float; public var fontSize(default, set):Int;
public var fontBold(default, set):Bool;
} }

View File

@@ -1,25 +1,12 @@
package haxework.gui; package haxework.gui;
import flash.display.DisplayObject;
import haxework.gui.core.VAlign; import haxework.gui.core.VAlign;
import haxework.gui.core.HAlign; import haxework.gui.core.HAlign;
import haxework.gui.skin.ISkin; import haxework.gui.skin.ISkin;
import haxework.gui.core.SizeType; import haxework.gui.core.SizeType;
typedef Content = { interface IView {
#if flash
var x(default,default):Float;
var y(default,default):Float;
var visible(default,default):Bool;
@:optional var mouseEnabled(default,default):Bool;
#else
var x(get,set):Float;
var y(get,set):Float;
var visible(get,set):Bool;
@:optional var mouseEnabled(default,default):Bool;
#end
}
interface IView<C:Content> {
public var id(default, default):String; public var id(default, default):String;
public var x(default, set):Float; public var x(default, set):Float;
@@ -50,10 +37,10 @@ interface IView<C:Content> {
public var bottomMargin(default, set):Float; public var bottomMargin(default, set):Float;
public var margins(null, set):Float; public var margins(null, set):Float;
public var content(default, null):C; public var content(default, null):DisplayObject;
public var skin(default, set):ISkin<C, IView<C>>; public var skin(default, set):ISkin<Dynamic>;
public var parent(default, null):Null<IGroupView<Dynamic>>; public var parent(default, null):Null<IGroupView>;
public var inLayout(default, set):Bool; public var inLayout(default, set):Bool;
public var visible(default, set):Bool; public var visible(default, set):Bool;

View File

@@ -0,0 +1,39 @@
package haxework.gui;
import haxework.net.ImageLoader;
import haxework.gui.utils.DrawUtil.FillType;
import haxework.gui.skin.BitmapSkin;
import haxework.gui.skin.ButtonBitmapSkin;
import flash.display.BitmapData;
class ImageView extends SpriteView {
public var image(default, set):BitmapData;
public var imageUrl(default, set):String;
public function new(?image:BitmapData) {
super();
if (image != null) {
this.image = image;
}
}
private function set_image(value:BitmapData):BitmapData {
if (image != value) {
image = value;
skin = cast new BitmapSkin(image, FillType.CONTAIN);
invalidate();
}
return image;
}
private function set_imageUrl(value:String):String {
if (imageUrl != value) {
imageUrl = value;
new ImageLoader().GET(imageUrl).then(function(data) {
image = data;
});
}
return imageUrl;
}
}

View File

@@ -14,14 +14,14 @@ class InputTextField extends TextField {
public function new() { public function new() {
super(); super();
#if flash //#if flash
type = TextFieldType.INPUT; type = TextFieldType.INPUT;
#elseif html5 //#elseif js
addEventListener(MouseEvent.CLICK, onMouseClick); //addEventListener(MouseEvent.CLICK, onMouseClick);
#end //#end
} }
#if html5 #if js
private function onMouseClick(event:MouseEvent):Void { private function onMouseClick(event:MouseEvent):Void {
focused = true; focused = true;
border = true; border = true;

View File

@@ -1,5 +1,6 @@
package haxework.gui; package haxework.gui;
import flash.text.TextFormatAlign;
import haxework.dispath.Dispatcher; import haxework.dispath.Dispatcher;
import haxework.dispath.IDispatcher; import haxework.dispath.IDispatcher;
import flash.events.Event; import flash.events.Event;
@@ -28,7 +29,8 @@ class InputView extends TextView implements IDisposable {
textField.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); textField.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
hintTextField = buildHintTextField(); hintTextField = buildHintTextField();
content.addChild(hintTextField); contentAsSprite.addChild(hintTextField);
textFormat.align = TextFormatAlign.LEFT;
} }
override private function buildTextField():TextField { override private function buildTextField():TextField {

View File

@@ -11,6 +11,7 @@ class LabelView extends TextView {
fill = false; fill = false;
textField.selectable = false; textField.selectable = false;
textField.wordWrap = false; textField.wordWrap = false;
textField.multiline = true;
layoutHAlign = HAlign.CENTER; layoutHAlign = HAlign.CENTER;
layoutVAlign = VAlign.MIDDLE; layoutVAlign = VAlign.MIDDLE;
} }

View File

@@ -4,7 +4,7 @@ import haxework.net.SwfLoader;
import flash.display.MovieClip; import flash.display.MovieClip;
//ToDo: sprite wrapper? //ToDo: sprite wrapper?
class MovieView extends View<MovieClip> { class MovieView extends View {
public var movie(get, set):MovieClip; public var movie(get, set):MovieClip;
public var movieUrl(default, set):String; public var movieUrl(default, set):String;
@@ -14,28 +14,28 @@ class MovieView extends View<MovieClip> {
} }
private function get_movie():MovieClip { private function get_movie():MovieClip {
return content; return cast content;
} }
private function set_movie(value:MovieClip):MovieClip { private function set_movie(value:MovieClip):MovieClip {
var index:Int = 0; var index:Int = 0;
if (parent != null && content != null) { if (parent != null && content != null) {
index = parent.content.getChildIndex(content); index = parent.container.getChildIndex(content);
parent.content.removeChild(content); parent.container.removeChild(content);
} }
content = value; content = value;
content.visible = visible; content.visible = visible;
if (parent != null) { if (parent != null) {
parent.content.addChildAt(content, index); parent.container.addChildAt(content, index);
} }
invalidate(); invalidate();
return content; return cast content;
} }
private function set_movieUrl(value:String):String { private function set_movieUrl(value:String):String {
movieUrl = value; movieUrl = value;
new SwfLoader().GET(movieUrl) new SwfLoader().GET(movieUrl)
.success(function(data:MovieClip):Void { .then(function(data:MovieClip):Void {
movie = data; movie = data;
}); });
return movieUrl; return movieUrl;

View File

@@ -1,5 +1,6 @@
package haxework.gui; package haxework.gui;
import flash.errors.Error;
import flash.Lib; import flash.Lib;
import flash.display.StageAlign; import flash.display.StageAlign;
import flash.display.StageScaleMode; import flash.display.StageScaleMode;
@@ -9,10 +10,20 @@ import flash.display.Sprite;
class Root { class Root {
private var view:IView<Sprite>; public static function bind(view:IView, autoSize:Bool = true) {
new Root(view, autoSize);
}
public function new(view:IView<Sprite>) { public static var instance(default, null):Root;
public var view(default, null):IView;
public var autoSize(default, default):Bool;
public function new(view:IView, autoSize:Bool = true) {
if (instance != null) throw new Error("Only one instance");
instance = this;
this.view = view; this.view = view;
this.autoSize = autoSize;
Lib.current.addChild(view.content); Lib.current.addChild(view.content);
var content:DisplayObject = view.content; var content:DisplayObject = view.content;
if (content.stage == null) { if (content.stage == null) {
@@ -36,8 +47,13 @@ class Root {
private function onResize(?_):Void { private function onResize(?_):Void {
var content:DisplayObject = view.content; var content:DisplayObject = view.content;
view.width = content.stage.stageWidth; if (autoSize) {
view.height = content.stage.stageHeight; view.width = content.stage.stageWidth;
view.height = content.stage.stageHeight;
} else {
view.x = (content.stage.stageWidth - view.width) / 2;
view.y = (content.stage.stageHeight - view.height) / 2;
}
L.d("Screen", content.stage.stageWidth + "x" + content.stage.stageHeight); L.d("Screen", content.stage.stageWidth + "x" + content.stage.stageHeight);
} }
} }

View File

@@ -0,0 +1,27 @@
package haxework.gui;
import flash.display.Graphics;
import flash.display.Sprite;
class SpriteView extends View {
public var contentAsSprite(get, null):Sprite;
public function new() {
super(new Sprite());
}
inline private function get_contentAsSprite():Sprite {
return cast content;
}
#if dev_layout
override public function update():Void {
super.update();
var g:Graphics = contentAsSprite.graphics;
g.lineStyle(1, 0x00ff00);
g.drawRect(0, 0, width, height);
g.lineStyle();
}
#end
}

288
src/main/haxework/gui/TextView.hx Executable file
View File

@@ -0,0 +1,288 @@
package haxework.gui;
import haxework.text.TextUtil;
import haxework.text.BitmapTextField;
import flash.geom.Point;
import flash.text.TextFieldAutoSize;
import haxework.gui.core.HAlign;
import haxework.gui.core.VAlign;
import flash.text.TextFormatAlign;
import haxework.gui.skin.ISize;
import flash.text.TextFormat;
import flash.display.Sprite;
import flash.text.TextField;
class TextView extends SpriteView implements ITextView {
public var textField(default, null):TextField;
public var text(get, set):String;
private var _text:String;
public var align(default, set):TextFormatAlign;
public var fontFamily(default, set):String;
public var fontEmbed(default, set):Bool;
public var fontColor(default, set):Int;
public var fontSize(default, set):Int;
public var fontBold(default, set):Bool;
public var layoutHAlign(default, set):HAlign;
public var layoutVAlign(default, set):VAlign;
public var fill(default, set):Bool = true;
public var leftPadding(default, set):Float = 0.0;
public var rightPadding(default, set):Float = 0.0;
public var topPadding(default, set):Float = 0.0;
public var bottomPadding(default, set):Float = 0.0;
public var paddings(null, set):Float = 0.0;
public var shadow(default, set):Bool;
public var shadowColor(default, set):Int;
private var textFormat:TextFormat;
private var _textWidth:Float;
private var _textHeight:Float;
public function new() {
super();
layoutHAlign = HAlign.CENTER;
layoutVAlign = VAlign.MIDDLE;
textField = buildTextField();
textField.width = 1;
textField.height = 1;
textField.multiline = true;
textField.wordWrap = true;
#if dev_layout
textField.borderColor = 0xff0000;
textField.border = true;
#end
textFormat = textField.defaultTextFormat;
textFormat.font = "Arial";
textFormat.size = 16;
textFormat.leading = 0;
textFormat.align = TextFormatAlign.CENTER;
contentAsSprite.addChild(textField);
}
private function buildTextField():TextField {
#if bitmap_text
return new BitmapTextField();
#else
return new TextField();
#end
}
private function set_fill(value:Bool):Bool {
if (fill != value) {
fill = value;
invalidate();
}
return fill;
}
private function set_layoutHAlign(value:HAlign):HAlign {
if (layoutHAlign != value) {
layoutHAlign = value;
invalidate();
}
return layoutHAlign;
}
private function set_layoutVAlign(value:VAlign):VAlign {
if (layoutVAlign != value) {
layoutVAlign = value;
invalidate();
}
return layoutVAlign;
}
private function get_text():String {
return textField.text;
}
private function set_text(value:String):String {
if (_text != value) {
_text = value;
invalidate();
}
return _text;
}
private function set_align(value:TextFormatAlign):TextFormatAlign {
if (align != value) {
align = value;
textFormat.align = value;
invalidate();
}
return align;
}
private function set_fontFamily(value:String):String {
if (fontFamily != value) {
fontFamily = value;
textFormat.font = fontFamily;
invalidate();
}
return fontFamily;
}
private function set_fontEmbed(value:Bool):Bool {
if (fontEmbed != value) {
fontEmbed = value;
invalidate();
}
return fontEmbed;
}
private function set_fontColor(value:Int):Int {
if (fontColor != value) {
fontColor = value;
textFormat.color = fontColor;
invalidate();
}
return fontColor;
}
private function set_fontSize(value:Int):Int {
if (fontSize != value) {
fontSize = value;
textFormat.size = fontSize;
invalidate();
}
return fontSize;
}
private function set_fontBold(value:Bool):Bool {
if (fontBold != value) {
fontBold = value;
textFormat.bold = fontBold;
invalidate();
}
return fontBold;
}
private function currentText():String {
return _text;
}
private function updateTextSize():Void {
var size = TextUtil.getSize(textField);
_textWidth = size.x;
_textHeight = size.y;
}
override public function update():Void {
textField.embedFonts = fontEmbed;
textField.defaultTextFormat = textFormat;
textField.autoSize = fill ? TextFieldAutoSize.NONE : TextFieldAutoSize.LEFT;
var t:String = currentText();
if (t != null) textField.text = t;
textField.setTextFormat(textFormat);
updateTextSize();
if (contentSize && !Std.is(skin, ISize)) {
#if html5
var h = _textHeight;
var w = _textWidth;
//if (h > textFormat.size * 1.5) h = h / 2;
textField.height = h;
textField.width = w;
#end
width = textField.width + leftPadding + rightPadding;
height = textField.height + topPadding + bottomPadding;
textField.x = leftPadding;
textField.y = topPadding;
} else {
placeTextField(textField);
}
//ToDo:
//var t:Point = content.localToGlobal(new Point(textField.x, textField.y));
//t.x = Math.round(t.x);
//t.y = Math.round(t.y);
//t = content.globalToLocal(t);
//textField.x = t.x;
//textField.y = t.y;
super.update();
}
private function placeTextField(textField:TextField):Void {
textField.width = width;
textField.height = _textHeight;
textField.x = switch (layoutHAlign) {
case HAlign.NONE: 0;
case HAlign.LEFT: leftPadding;
case HAlign.CENTER: (width - textField.width) / 2 + leftPadding - rightPadding;
case HAlign.RIGHT: width - textField.width - rightPadding;
default: 0;
}
textField.y = switch (layoutVAlign) {
case VAlign.NONE: 0;
case VAlign.TOP: topPadding;
case VAlign.MIDDLE: (height - _textHeight) / 2 + topPadding - bottomPadding;
case VAlign.BOTTOM: height - _textHeight - bottomPadding;
default: 0;
}
}
override private function set_mouseEnabled(value:Bool):Bool {
textField.mouseEnabled = value;
return super.set_mouseEnabled(value);
}
private function set_leftPadding(value:Float):Float {
if (leftPadding != value) {
leftPadding = value;
invalidate();
}
return leftPadding;
}
private function set_rightPadding(value:Float):Float {
if (rightPadding != value) {
rightPadding = value;
invalidate();
}
return rightPadding;
}
private function set_topPadding(value:Float):Float {
if (topPadding != value) {
topPadding = value;
invalidate();
}
return topPadding;
}
private function set_bottomPadding(value:Float):Float {
if (bottomPadding != value) {
bottomPadding = value;
invalidate();
}
return bottomPadding;
}
private function set_paddings(value:Float):Float {
leftPadding = rightPadding = topPadding = bottomPadding = value;
invalidate();
return value;
}
private function set_shadow(value) {
if (Std.is(textField, BitmapTextField)) {
cast(textField, BitmapTextField).shadow = value;
return cast(textField, BitmapTextField).shadow;
} else {
return value;
}
}
private function set_shadowColor(value) {
if (Std.is(textField, BitmapTextField)) {
cast(textField, BitmapTextField).shadowColor = value;
cast(textField, BitmapTextField).shadow = true;
return cast(textField, BitmapTextField).shadowColor;
} else {
return value;
}
}
}

View File

@@ -6,7 +6,7 @@ import haxework.gui.skin.ISkin;
class ToggleButtonView extends ButtonView { class ToggleButtonView extends ButtonView {
public var on(default, set):Bool; public var on(default, set):Bool;
public var onSkin(default, set):ISkin<Sprite, IView<Sprite>>; public var onSkin(default, set):ISkin<Dynamic>;
public var onText(default, set):String; public var onText(default, set):String;
@@ -20,13 +20,13 @@ class ToggleButtonView extends ButtonView {
return on; return on;
} }
private function set_onSkin(value:ISkin<Sprite, IView<Sprite>>):ISkin<Sprite, IView<Sprite>> { private function set_onSkin(value:ISkin<Dynamic>):ISkin<Dynamic> {
onSkin = value; onSkin = value;
invalidate(); invalidate();
return onSkin; return onSkin;
} }
override private function currentSkin():ISkin<Sprite, IView<Sprite>> { override private function currentSkin():ISkin<Dynamic> {
return on ? onSkin : skin; return on ? onSkin : skin;
} }

View File

@@ -1,6 +1,8 @@
package haxework.gui; package haxework.gui;
import haxework.gui.IView.Content; import flash.display.InteractiveObject;
import flash.display.DisplayObject;
import flash.errors.Error;
import haxework.gui.skin.ISize; import haxework.gui.skin.ISize;
import haxework.gui.core.SizeType; import haxework.gui.core.SizeType;
import haxework.gui.core.HAlign; import haxework.gui.core.HAlign;
@@ -12,7 +14,7 @@ import haxework.gui.skin.ISkin;
import flash.display.Sprite; import flash.display.Sprite;
class View<C:Content> implements IView<C> { class View implements IView {
private static var counter:Int = 0; private static var counter:Int = 0;
public static var updater(default, null):Updater = new Updater(); public static var updater(default, null):Updater = new Updater();
@@ -47,17 +49,17 @@ class View<C:Content> implements IView<C> {
public var bottomMargin(default, set):Float; public var bottomMargin(default, set):Float;
public var margins(null, set):Float; public var margins(null, set):Float;
public var content(default, null):C; public var content(default, null):DisplayObject;
public var skin(default, set):ISkin<C, IView<C>>; public var skin(default, set):ISkin<Dynamic>;
public var parent(default, null):Null<IGroupView<Dynamic>>; public var parent(default, null):Null<IGroupView>;
public var inLayout(default, set):Bool; public var inLayout(default, set):Bool;
public var visible(default, set):Bool; public var visible(default, set):Bool;
public var index(default, set):Int; public var index(default, set):Int;
public var mouseEnabled(default, set):Bool = true; public var mouseEnabled(default, set):Bool = true;
public function new(content:C) { public function new(content:DisplayObject) {
id = Type.getClassName(Type.getClass(this)) + counter++; id = Type.getClassName(Type.getClass(this)) + counter++;
this.content = content; this.content = content;
x = 0; x = 0;
@@ -72,7 +74,7 @@ class View<C:Content> implements IView<C> {
index = -1; index = -1;
} }
private function currentSkin():ISkin<C, IView<C>> { private function currentSkin():ISkin<Dynamic> {
return skin; return skin;
} }
@@ -90,7 +92,7 @@ class View<C:Content> implements IView<C> {
content.x = x; content.x = x;
content.y = y; content.y = y;
} }
var skin:ISkin<C, IView<C>> = currentSkin(); var skin:ISkin<Dynamic> = currentSkin();
if (contentSize && skin != null && Std.is(skin, ISize)) { if (contentSize && skin != null && Std.is(skin, ISize)) {
var size:ISize = cast(skin, ISize); var size:ISize = cast(skin, ISize);
if (!Math.isNaN(size.width)) width = size.width; if (!Math.isNaN(size.width)) width = size.width;
@@ -262,7 +264,7 @@ class View<C:Content> implements IView<C> {
return value; return value;
} }
private function set_skin(value:ISkin<C, IView<C>>):ISkin<C, IView<C>> { private function set_skin(value:ISkin<Dynamic>):ISkin<Dynamic> {
skin = value; skin = value;
invalidate(); invalidate();
return skin; return skin;
@@ -295,7 +297,9 @@ class View<C:Content> implements IView<C> {
private function set_mouseEnabled(value:Bool):Bool { private function set_mouseEnabled(value:Bool):Bool {
if (mouseEnabled != value) { if (mouseEnabled != value) {
mouseEnabled = value; mouseEnabled = value;
if (content != null) content.mouseEnabled = mouseEnabled; if (content != null && Std.is(content, InteractiveObject)) {
cast(content, InteractiveObject).mouseEnabled = mouseEnabled;
}
} }
return mouseEnabled; return mouseEnabled;
} }
@@ -305,7 +309,7 @@ class View<C:Content> implements IView<C> {
class Updater { class Updater {
public var stage(null, set):Stage; public var stage(null, set):Stage;
private var invalidated:Array<IView<Dynamic>>; private var invalidated:Array<Dynamic>;
public function new() { public function new() {
invalidated = []; invalidated = [];
@@ -316,11 +320,12 @@ class Updater {
return value; return value;
} }
public function invalidate(view:IView<Dynamic>):Void { public function invalidate(view:IView):Void {
if (Lambda.indexOf(invalidated, view) == -1) invalidated.push(view); if (Lambda.indexOf(invalidated, view) == -1) invalidated.push(view);
} }
public function update(?_):Void { public function update(?_):Void {
var t = Date.now().getTime();
while (invalidated.length > 0) { while (invalidated.length > 0) {
var v = null; var v = null;
try { try {
@@ -330,6 +335,8 @@ class Updater {
L.e("Update", v + "", error); L.e("Update", v + "", error);
} }
} }
t = Date.now().getTime() - t;
if (t > 10) trace("UPDATE(" + t + ")");
} }
} }

View File

@@ -0,0 +1,14 @@
package haxework.gui;
import haxework.gui.build.Builder;
@:remove @:autoBuild(haxework.gui.ViewBuilderImpl.build())
extern interface ViewBuilder {}
class ViewBuilderImpl {
#if macro
public static function build() {
return new Builder().build();
}
#end
}

View File

@@ -0,0 +1,193 @@
package haxework.gui.build;
#if macro
import haxe.macro.Context;
import haxework.gui.build.PositionJsonParser;
import haxe.macro.Expr;
import haxe.macro.Expr.Field;
class Builder {
private var templateFile:String;
private var templateKey:String;
private var styleFile:String;
private var template:Dynamic;
private var fields:Array<Field>;
private var exprs:Array<Expr>;
private var style:Dynamic;
private var i:Int;
public function new() {
var templateMeta = BuilderUtil.getMeta(":template");
var templatePath = templateMeta[0].split("@");
templateFile = Context.resolvePath(templatePath[0]);
templateKey = templatePath[1];
template = BuilderUtil.loadJsonFile(templateFile);
if (templateKey != null) template = Reflect.field(template, templateKey);
if (templateMeta[1] != null) {
styleFile = Context.resolvePath(templateMeta[1]);
style = BuilderUtil.loadJsonFile(styleFile);
}
fields = Context.getBuildFields();
exprs = [];
i = 0;
}
private function getPosition(?position:JsonKeyPosition):Position {
var min = position == null ? 1 : position.min + 32; // :-(
var max = position == null ? 1 : position.max + 32;
var file = position == null || position.file == null ? templateFile : position.file;
return Context.makePosition({min:min, max:max, file:file});
}
private function specialValue(name:String, key:String, a:Array<String>, position:JsonKeyPosition):Dynamic {
return switch (a[0]) {
case "asset":
switch (a[1]) {
case "image":
"openfl.Assets.getBitmapData(\"" + a[2] + "\")";
case _:
a[2];
}
case "res":
var res = "haxework.provider.Provider.get(haxework.resources.IResources)." + a[1];
var bindExpr = res + ".bind(\"" + a[2] + "\", " + name + ", \"" + key + "\")";
exprs.push(Context.parse(bindExpr, getPosition(position)));
//res + ".get(\"" + a[2] + "\")";
null;
case "locale":
"new haxework.locale.LString(\"" + a[1] + "\")";
case "class":
a[1];
case "layout":
var template = BuilderUtil.loadJsonFile(a[1]);
return getValue(name, key, template, position);
case "link":
"(links == null) ? untyped this : Reflect.field(links, \"" + a[1] + "\")";
case _:
Context.error("Unsupported prefix \"" + a[0] + "\"", getPosition(position));
}
}
private function getValue(name:String, key:String, value:Dynamic, position:JsonKeyPosition):Dynamic {
return if (Std.is(value, Array)) {
value.map(function(v) {
return getValue(null, null, v, position);
});
} else if (Std.is(value, String)) {
if (value.charAt(0) == "@") {
specialValue(name, key, value.substring(1, value.length).split(":"), position);
} else if (~/(0x|#)[A-Fa-f\d]{6}/.match(value)) {
Std.parseInt(StringTools.replace(Std.string(value), "#", "0x"));
} else {
"\"" + value + "\"";
}
} else if (Std.is(value, Float) || (Std.is(value, Bool))) {
value;
} else if (value != null) {
if (Reflect.hasField(value, "@type")) {
var n = "a" + i++;
var type = Reflect.field(value, "@type");
if (type == "Dynamic") {
//ToDo:
exprs.push(Context.parse("var " + n + " = cast {}", getPosition(position)));
} else {
exprs.push(Context.parse("var " + n + " = new " + type + "()", getPosition(position)));
}
createElement(value, n);
n;
} else {
Context.error("Need @type field", getPosition(position));
null;
}
} else {
value;
}
}
private function createElement(template:Dynamic, name:String):String {
if (Reflect.hasField(template, "@style")) {
var s = Reflect.field(style, Reflect.field(template, "@style"));
for (key in Reflect.fields(s)) {
if (key.charAt(0) != "$" && !Reflect.hasField(template, key)) {
Reflect.setField(template, key, Reflect.field(s, key));
Reflect.setField(template, "$" + key, Reflect.field(s, "$" + key));
}
}
}
if (Reflect.hasField(template, "id")) {
var id = Reflect.field(template, "id");
var type = Reflect.field(template, "@type");
var expr = Context.parse("var a:" + type, getPosition());
var complexType = switch (expr.expr) {
case EVars(vars): vars[0].type;
case _: null;
}
fields.push({
name: id,
access: [APublic],
pos: getPosition(),
kind: FProp("default", "null", complexType)
});
exprs.push(Context.parse("this." + id + " = " + name, getPosition()));
}
for (key in Reflect.fields(template)) {
if (key.charAt(0) == "$" || key.charAt(0) == "@") continue;
var position = Reflect.field(template, "$" + key);
var value = getValue(name, key, Reflect.field(template, key), position);
if (value != null) {
exprs.push(Context.parse(name + "." + key + " = " + value, getPosition(position)));
}
}
return name;
}
public function build():Array<Field> {
createElement(template, "this");
var init = false;
for (f in fields) if (f.name == "init") {
init = true;
break;
}
fields.push({
name: "build",
access: [APublic],
pos: getPosition(),
kind: FFun({
args: [{name:"links", type:TPath({name:"Dynamic", pack:[], params:[]}), opt:true, value:null}],
expr: macro $b{exprs},
params: [],
ret: null
})
});
var contstrExprs = [];
contstrExprs.push(macro super());
contstrExprs.push(macro build(links));
if (init) contstrExprs.push(macro init());
fields.push({
name: "new",
access: [APublic],
pos: getPosition(),
kind: FFun({
args: [{name:"links", type:TPath({name:"Dynamic", pack:[], params:[]}), opt:true, value:null}],
expr: macro $b{contstrExprs},
params: [],
ret: null
})
});
return fields;
}
}
#end

View File

@@ -0,0 +1,36 @@
package haxework.gui.build;
#if macro
import haxe.macro.Context;
import haxe.macro.Expr.Constant;
import haxe.macro.Expr.ExprDef;
class BuilderUtil {
public static function loadJsonFile(path:String) {
Context.registerModuleDependency(Context.getLocalModule(), path);
var content = sys.io.File.getContent(path);
var json = null;
try {
json = PositionJsonParser.parse(content, path);
} catch(error:Dynamic) {
Context.error(error, Context.makePosition({min:0, max:0, file:path}));
}
Context.parse(content, Context.makePosition({min:0, max:0, file:path}));
return json;
}
public static function getMeta(key:String):Array<String> {
var c = Context.getLocalClass().get();
for (meta in c.meta.get()) {
if (meta.name == key) {
return meta.params.map(function(param) return switch(param.expr) {
case ExprDef.EConst(Constant.CString(value)): value;
case _: null;
});
}
}
return [];
}
}
#end

View File

@@ -0,0 +1,237 @@
package haxework.gui.build;
typedef JsonKeyPosition = {
var min:Int;
var max:Int;
var file:String;
}
class PositionJsonParser {
static public inline function parse(str : String, file : String) : Dynamic {
return new PositionJsonParser(str, file).parseRec();
}
var str : String;
var pos : Int;
var file : String;
function new( str : String, file:String ) {
this.str = str;
this.pos = 0;
this.file = file;
}
function getKeyPosition():JsonKeyPosition {
return {
min: pos,
max: pos,
file: file
}
}
function parseRec() : Dynamic {
while( true ) {
var c = nextChar();
switch( c ) {
case ' '.code, '\r'.code, '\n'.code, '\t'.code:
// loop
case '{'.code:
var obj = {}, field = null, comma : Null<Bool> = null;
var position = null;
while( true ) {
var c = nextChar();
switch( c ) {
case ' '.code, '\r'.code, '\n'.code, '\t'.code:
// loop
case '}'.code:
if( field != null || comma == false )
invalidChar();
return obj;
case ':'.code:
if( field == null )
invalidChar();
Reflect.setField(obj,field,parseRec());
Reflect.setField(obj,"$" + field,position);
field = null;
comma = true;
case ','.code:
if( comma ) comma = false else invalidChar();
case '"'.code:
if( comma ) invalidChar();
position = getKeyPosition();
field = parseString();
default:
invalidChar();
}
}
case '['.code:
var arr = [], comma : Null<Bool> = null;
while( true ) {
var c = nextChar();
switch( c ) {
case ' '.code, '\r'.code, '\n'.code, '\t'.code:
// loop
case ']'.code:
if( comma == false ) invalidChar();
return arr;
case ','.code:
if( comma ) comma = false else invalidChar();
default:
if( comma ) invalidChar();
pos--;
arr.push(parseRec());
comma = true;
}
}
case 't'.code:
var save = pos;
if( nextChar() != 'r'.code || nextChar() != 'u'.code || nextChar() != 'e'.code ) {
pos = save;
invalidChar();
}
return true;
case 'f'.code:
var save = pos;
if( nextChar() != 'a'.code || nextChar() != 'l'.code || nextChar() != 's'.code || nextChar() != 'e'.code ) {
pos = save;
invalidChar();
}
return false;
case 'n'.code:
var save = pos;
if( nextChar() != 'u'.code || nextChar() != 'l'.code || nextChar() != 'l'.code ) {
pos = save;
invalidChar();
}
return null;
case '"'.code:
return parseString();
case '0'.code, '1'.code,'2'.code,'3'.code,'4'.code,'5'.code,'6'.code,'7'.code,'8'.code,'9'.code,'-'.code:
return parseNumber(c);
default:
invalidChar();
}
}
}
function parseString() {
var start = pos;
var buf = null;
while( true ) {
var c = nextChar();
if( c == '"'.code )
break;
if( c == '\\'.code ) {
if (buf == null) {
buf = new StringBuf();
}
buf.addSub(str,start, pos - start - 1);
c = nextChar();
switch( c ) {
case "r".code: buf.addChar("\r".code);
case "n".code: buf.addChar("\n".code);
case "t".code: buf.addChar("\t".code);
case "b".code: buf.addChar(8);
case "f".code: buf.addChar(12);
case "/".code, '\\'.code, '"'.code: buf.addChar(c);
case 'u'.code:
var uc = Std.parseInt("0x" + str.substr(pos, 4));
pos += 4;
#if (neko || php || cpp)
if( uc <= 0x7F )
buf.addChar(uc);
else if( uc <= 0x7FF ) {
buf.addChar(0xC0 | (uc >> 6));
buf.addChar(0x80 | (uc & 63));
} else if( uc <= 0xFFFF ) {
buf.addChar(0xE0 | (uc >> 12));
buf.addChar(0x80 | ((uc >> 6) & 63));
buf.addChar(0x80 | (uc & 63));
} else {
buf.addChar(0xF0 | (uc >> 18));
buf.addChar(0x80 | ((uc >> 12) & 63));
buf.addChar(0x80 | ((uc >> 6) & 63));
buf.addChar(0x80 | (uc & 63));
}
#else
buf.addChar(uc);
#end
default:
throw "Invalid escape sequence \\" + String.fromCharCode(c) + " at position " + (pos - 1);
}
start = pos;
}
#if (neko || php || cpp)
// ensure utf8 chars are not cut
else if( c >= 0x80 ) {
pos++;
if( c >= 0xFC ) pos += 4;
else if( c >= 0xF8 ) pos += 3;
else if( c >= 0xF0 ) pos += 2;
else if( c >= 0xE0 ) pos++;
}
#end
else if( StringTools.isEof(c) )
throw "Unclosed string";
}
if (buf == null) {
return str.substr(start, pos - start - 1);
}
else {
buf.addSub(str,start, pos - start - 1);
return buf.toString();
}
}
inline function parseNumber( c : Int ) : Dynamic {
var start = pos - 1;
var minus = c == '-'.code, digit = !minus, zero = c == '0'.code;
var point = false, e = false, pm = false, end = false;
while( true ) {
c = nextChar();
switch( c ) {
case '0'.code :
if (zero && !point) invalidNumber(start);
if (minus) {
minus = false; zero = true;
}
digit = true;
case '1'.code,'2'.code,'3'.code,'4'.code,'5'.code,'6'.code,'7'.code,'8'.code,'9'.code :
if (zero && !point) invalidNumber(start);
if (minus) minus = false;
digit = true; zero = false;
case '.'.code :
if (minus || point) invalidNumber(start);
digit = false; point = true;
case 'e'.code, 'E'.code :
if (minus || zero || e) invalidNumber(start);
digit = false; e = true;
case '+'.code, '-'.code :
if (!e || pm) invalidNumber(start);
digit = false; pm = true;
default :
if (!digit) invalidNumber(start);
pos--;
end = true;
}
if (end) break;
}
var f = Std.parseFloat(str.substr(start, pos - start));
var i = Std.int(f);
return if( i == f ) i else f;
}
inline function nextChar() {
return StringTools.fastCodeAt(str,pos++);
}
function invalidChar() {
pos--; // rewind
throw "Invalid char "+StringTools.fastCodeAt(str,pos)+" at position "+pos;
}
function invalidNumber( start : Int ) {
throw "Invalid number at position "+start+": " + str.substr(start, pos - start);
}
}

View File

@@ -0,0 +1,8 @@
package haxework.gui.core;
@:enum abstract HAlign(String) from String to String {
var NONE = "NONE";
var LEFT = "LEFT";
var CENTER = "CENTER";
var RIGHT = "RIGHT";
}

View File

@@ -0,0 +1,8 @@
package haxework.gui.core;
@:enum abstract VAlign(String) from String to String {
var NONE = "NONE";
var TOP = "TOP";
var MIDDLE = "MIDDLE";
var BOTTOM = "BOTTOM";
}

View File

@@ -0,0 +1,72 @@
package haxework.gui.frame;
import haxework.animate.IAnimate;
import flash.display.Sprite;
import haxework.gui.IView;
import haxework.gui.GroupView;
class FrameSwitcher extends GroupView implements IFrameSwitcher {
public var current(default, null):Null<IView>;
private var frames:Map<String, IView>;
public var animateFactory(default, default):Class<IAnimate>;
private var animate:IAnimate;
public function new() {
super();
frames = new Map<String, IView>();
current = null;
}
private function buildAnimate(view:IView):Null<IAnimate> {
if (animateFactory != null) {
return Type.createInstance(animateFactory, [view]);
}
return null;
}
public function change(id:String):IView {
var prev = null;
if (current != null) {
if (current.id == id) return current;
prev = current;
}
current = frames.get(id);
addView(current);
//ToDo:
if (content.stage != null) content.stage.focus = cast(current, SpriteView).contentAsSprite;
var onShowMethod:Dynamic = Reflect.field(current, "onShow");
if (onShowMethod != null) Reflect.callMethod(current, onShowMethod, []);
if (animate != null) animate.cancel();
animate = buildAnimate(current);
if (animate != null && prev != null) {
animate.start(function(_) {
removePrev(prev);
});
} else {
removePrev(prev);
}
return current;
}
private function removePrev(prev:Null<IView>):Void {
if (prev != null) {
var onHideMethod:Dynamic = Reflect.field(prev, "onHide");
if (onHideMethod != null) Reflect.callMethod(prev, onHideMethod, []);
removeView(prev);
}
}
override public function set_views(value:Array<IView>):Array<IView> {
views = [];
if (value.length > 0) {
for (view in value) {
view.pWidth = 100;
view.pHeight = 100;
frames.set(view.id, view);
}
}
return value;
}
}

View File

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

View File

@@ -10,7 +10,7 @@ class DefaultLayout implements ILayout {
} }
public function place(group:IGroupView<Dynamic>, views:Array<IView<Dynamic>>):Void { public function place(group:IGroupView, views:Array<IView>):Void {
for (view in views) { for (view in views) {
setViewWidth(group, view); setViewWidth(group, view);
setViewHeight(group, view); setViewHeight(group, view);
@@ -19,8 +19,8 @@ class DefaultLayout implements ILayout {
} }
} }
private function filterViews(group:IGroupView<Dynamic>, views:Array<IView<Dynamic>>):Array<IView<Dynamic>> { private function filterViews(group:IGroupView, views:Array<IView>):Array<IView> {
return Lambda.array(Lambda.filter(views, function(view:IView<Dynamic>):Bool { return Lambda.array(Lambda.filter(views, function(view:IView):Bool {
return if (view.inLayout) { return if (view.inLayout) {
true; true;
} else { } else {
@@ -33,7 +33,7 @@ class DefaultLayout implements ILayout {
})); }));
} }
private function setViewWidth(group:IGroupView<Dynamic>, view:IView<Dynamic>):Void { private function setViewWidth(group:IGroupView, view:IView):Void {
if (view.widthType == SizeType.PERCENT) { if (view.widthType == SizeType.PERCENT) {
view.w = view.pWidth / 100 * (group.width - view.leftMargin - view.rightMargin - group.leftPadding - group.rightPadding); view.w = view.pWidth / 100 * (group.width - view.leftMargin - view.rightMargin - group.leftPadding - group.rightPadding);
} else if (group.contentSize && group.width < view.width) { } else if (group.contentSize && group.width < view.width) {
@@ -41,7 +41,7 @@ class DefaultLayout implements ILayout {
} }
} }
private function setViewHeight(group:IGroupView<Dynamic>, view:IView<Dynamic>):Void { private function setViewHeight(group:IGroupView, view:IView):Void {
if (view.heightType == SizeType.PERCENT) { if (view.heightType == SizeType.PERCENT) {
view.h = view.pHeight / 100 * (group.height - view.topMargin - view.bottomMargin - group.topPadding - group.bottomPadding); view.h = view.pHeight / 100 * (group.height - view.topMargin - view.bottomMargin - group.topPadding - group.bottomPadding);
} else if (group.contentSize && group.height < view.height) { } else if (group.contentSize && group.height < view.height) {
@@ -49,7 +49,7 @@ class DefaultLayout implements ILayout {
} }
} }
private function placeViewHorizontal(group:IGroupView<Dynamic>, view:IView<Dynamic>):Void { private function placeViewHorizontal(group:IGroupView, view:IView):Void {
var align:HAlign = view.hAlign; var align:HAlign = view.hAlign;
if (align == HAlign.NONE) align = group.layoutHAlign; if (align == HAlign.NONE) align = group.layoutHAlign;
switch (align) { switch (align) {
@@ -63,7 +63,7 @@ class DefaultLayout implements ILayout {
} }
} }
private function placeViewVertical(group:IGroupView<Dynamic>, view:IView<Dynamic>):Void { private function placeViewVertical(group:IGroupView, view:IView):Void {
var align:VAlign = view.vAlign; var align:VAlign = view.vAlign;
if (align == VAlign.NONE) align = group.layoutVAlign; if (align == VAlign.NONE) align = group.layoutVAlign;
switch (align) { switch (align) {

View File

@@ -10,7 +10,7 @@ class HorizontalLayout extends DefaultLayout {
super(); super();
} }
override public function place(group:IGroupView<Dynamic>, views:Array<IView<Dynamic>>):Void { override public function place(group:IGroupView, views:Array<IView>):Void {
views = filterViews(group, views); views = filterViews(group, views);
var fixedSize:Float = group.layoutMargin * (views.length - 1); var fixedSize:Float = group.layoutMargin * (views.length - 1);
@@ -45,6 +45,7 @@ class HorizontalLayout extends DefaultLayout {
case HAlign.LEFT: x = group.leftPadding; case HAlign.LEFT: x = group.leftPadding;
case HAlign.CENTER: x = (group.width - fixedSize) / 2 + group.leftPadding - group.rightPadding; case HAlign.CENTER: x = (group.width - fixedSize) / 2 + group.leftPadding - group.rightPadding;
case HAlign.RIGHT: x = group.width - fixedSize - group.rightPadding; case HAlign.RIGHT: x = group.width - fixedSize - group.rightPadding;
case _:
} }
for (view in views) { for (view in views) {

View File

@@ -0,0 +1,5 @@
package haxework.gui.layout;
interface ILayout {
public function place(group:IGroupView, views:Array<IView>):Void;
}

View File

@@ -9,7 +9,7 @@ class VerticalLayout extends DefaultLayout {
super(); super();
} }
override public function place(group:IGroupView<Dynamic>, views:Array<IView<Dynamic>>):Void { override public function place(group:IGroupView, views:Array<IView>):Void {
views = filterViews(group, views); views = filterViews(group, views);
var fixedSize:Float = group.layoutMargin * (views.length - 1); var fixedSize:Float = group.layoutMargin * (views.length - 1);
@@ -44,6 +44,7 @@ class VerticalLayout extends DefaultLayout {
case VAlign.TOP: y = group.topPadding; case VAlign.TOP: y = group.topPadding;
case VAlign.MIDDLE: y = (group.height - fixedSize) / 2 + group.topPadding - group.bottomPadding; case VAlign.MIDDLE: y = (group.height - fixedSize) / 2 + group.topPadding - group.bottomPadding;
case VAlign.BOTTOM: y = group.height - fixedSize - group.bottomPadding; case VAlign.BOTTOM: y = group.height - fixedSize - group.bottomPadding;
case _:
} }
for (view in views) { for (view in views) {

View File

@@ -11,20 +11,19 @@ class HListView<D> extends ListView<D> {
public function new() { public function new() {
super(new HorizontalLayout(), new VerticalLayout()); super(new HorizontalLayout(), new VerticalLayout());
container.layoutHAlign = HAlign.LEFT; box.layoutHAlign = HAlign.LEFT;
container.layoutVAlign = VAlign.MIDDLE; box.layoutVAlign = VAlign.MIDDLE;
} }
override private function recalcSize(item:IListItemView<D>):Void { override private function recalcSize(item:IListItemView<D>):Void {
var view:IView<Dynamic> = item; itemSize = item.width + item.leftMargin + item.rightMargin + box.layoutMargin;
itemSize = view.width + view.leftMargin + view.rightMargin + container.layoutMargin; size = Math.ceil(Math.max(0, box.width / itemSize)) + 2;
size = Math.ceil(Math.max(0, container.width / itemSize)) + 2; sizeDiff = size - ((box.width - box.layoutMargin - 1) / itemSize);
sizeDiff = size - ((container.width - container.layoutMargin - 1) / itemSize);
} }
override private function set_offsetDiff(value:Float):Float { override private function set_offsetDiff(value:Float):Float {
container.leftPadding = -value * itemSize; box.leftPadding = -value * itemSize;
mask.leftMargin = -container.leftPadding; mask.leftMargin = -box.leftPadding;
return super.set_offsetDiff(value); return super.set_offsetDiff(value);
} }

View File

@@ -4,7 +4,7 @@ import haxework.gui.skin.ISkin;
import flash.display.Sprite; import flash.display.Sprite;
import flash.display.Graphics; import flash.display.Graphics;
class HScrollSkin implements ISkin<Sprite, ScrollView> { class HScrollSkin implements ISkin<ScrollView> {
public var foreColor(default, default):Int; public var foreColor(default, default):Int;
public var backColor(default, default):Int; public var backColor(default, default):Int;
@@ -15,7 +15,7 @@ class HScrollSkin implements ISkin<Sprite, ScrollView> {
} }
public function draw(view:ScrollView):Void { public function draw(view:ScrollView):Void {
var graphics:Graphics = view.content.graphics; var graphics:Graphics = view.contentAsSprite.graphics;
graphics.clear(); graphics.clear();
graphics.beginFill(backColor); graphics.beginFill(backColor);
graphics.drawRect(0, 0, view.width, view.height); graphics.drawRect(0, 0, view.width, view.height);

View File

@@ -35,7 +35,7 @@ class ListView<D> extends GroupView implements ScrollListener {
public var selected(default, set):Array<D>; public var selected(default, set):Array<D>;
private var main:GroupView; private var main:GroupView;
private var container:GroupView; private var box:GroupView;
private var mask:SpriteView; private var mask:SpriteView;
private var itemSize:Float; private var itemSize:Float;
@@ -50,17 +50,17 @@ class ListView<D> extends GroupView implements ScrollListener {
main.pWidth = 100; main.pWidth = 100;
main.pHeight = 100; main.pHeight = 100;
addView(main); addView(main);
container = new GroupView(layout); box = new GroupView(layout);
container.pWidth = 100; box.pWidth = 100;
container.pHeight = 100; box.pHeight = 100;
main.addView(container); main.addView(box);
mask = new SpriteView(); mask = new SpriteView();
mask.pWidth = 100; mask.pWidth = 100;
mask.pHeight = 100; mask.pHeight = 100;
mask.inLayout = false; mask.inLayout = false;
mask.skin = new ColorSkin(0xffffff); mask.skin = new ColorSkin(0xffffff);
container.content.mask = mask.content; box.content.mask = mask.content;
container.addView(mask); box.addView(mask);
dispatcher = new Dispatcher<ListViewListener<D>>(); dispatcher = new Dispatcher<ListViewListener<D>>();
itemSize = 0; itemSize = 0;
offset = 0; offset = 0;
@@ -202,14 +202,14 @@ class ListView<D> extends GroupView implements ScrollListener {
var item:IListItemView<D> = Type.createInstance(factory, []); var item:IListItemView<D> = Type.createInstance(factory, []);
items.push(item); items.push(item);
setClickListener(item); setClickListener(item);
container.addView(item); box.addView(item);
} }
} else if (diff < 0) { } else if (diff < 0) {
for (i in 0...-diff) { for (i in 0...-diff) {
var item:IListItemView<D> = items.pop(); var item:IListItemView<D> = items.pop();
item.content.removeEventListener(MouseEvent.CLICK, itemsListeners.get(item)); item.content.removeEventListener(MouseEvent.CLICK, itemsListeners.get(item));
itemsListeners.remove(item); itemsListeners.remove(item);
container.removeView(item); box.removeView(item);
} }
} }
} }
@@ -232,11 +232,11 @@ class ListView<D> extends GroupView implements ScrollListener {
} }
override private function set_layoutMargin(value:Float):Float { override private function set_layoutMargin(value:Float):Float {
return container.layoutMargin = value; return box.layoutMargin = value;
} }
} }
interface IListItemView<D> extends IView<Sprite> { interface IListItemView<D> extends IView {
public var item_index(default, default):Int; public var item_index(default, default):Int;
public var data(default, set):D; public var data(default, set):D;
} }

View File

@@ -17,7 +17,7 @@ class ScrollView extends SpriteView {
public function new() { public function new() {
super(); super();
content.buttonMode = true; contentAsSprite.buttonMode = true;
position = 0; position = 0;
ratio = 1; ratio = 1;
dispatcher = new Dispatcher<ScrollListener>(); dispatcher = new Dispatcher<ScrollListener>();

View File

@@ -11,20 +11,19 @@ class VListView<D> extends ListView<D> {
public function new() { public function new() {
super(new VerticalLayout(), new HorizontalLayout()); super(new VerticalLayout(), new HorizontalLayout());
container.layoutHAlign = HAlign.CENTER; box.layoutHAlign = HAlign.CENTER;
container.layoutVAlign = VAlign.TOP; box.layoutVAlign = VAlign.TOP;
} }
override private function recalcSize(item:IListItemView<D>):Void { override private function recalcSize(item:IListItemView<D>):Void {
var view:IView<Dynamic> = item; itemSize = item.height + item.topMargin + item.bottomMargin + box.layoutMargin;
itemSize = view.height + view.topMargin + view.bottomMargin + container.layoutMargin; size = Math.ceil(Math.max(0, box.height / itemSize)) + 2;
size = Math.ceil(Math.max(0, container.height / itemSize)) + 2; sizeDiff = size - ((box.height - box.layoutMargin - 1) / itemSize);
sizeDiff = size - ((container.height - container.layoutMargin - 1) / itemSize);
} }
override private function set_offsetDiff(value:Float):Float { override private function set_offsetDiff(value:Float):Float {
container.topPadding = -value * itemSize; box.topPadding = -value * itemSize;
mask.topMargin = -container.topPadding; mask.topMargin = -box.topPadding;
return super.set_offsetDiff(value); return super.set_offsetDiff(value);
} }

View File

@@ -4,7 +4,7 @@ import haxework.gui.skin.ISkin;
import flash.display.Sprite; import flash.display.Sprite;
import flash.display.Graphics; import flash.display.Graphics;
class VScrollSkin implements ISkin<Sprite, ScrollView> { class VScrollSkin implements ISkin<ScrollView> {
public var foreColor(default, default):Int; public var foreColor(default, default):Int;
public var backColor(default, default):Int; public var backColor(default, default):Int;
@@ -15,7 +15,7 @@ class VScrollSkin implements ISkin<Sprite, ScrollView> {
} }
public function draw(view:ScrollView):Void { public function draw(view:ScrollView):Void {
var graphics:Graphics = view.content.graphics; var graphics:Graphics = view.contentAsSprite.graphics;
graphics.clear(); graphics.clear();
graphics.beginFill(backColor); graphics.beginFill(backColor);
graphics.drawRect(0, 0, view.width, view.height); graphics.drawRect(0, 0, view.width, view.height);

View File

@@ -0,0 +1,47 @@
package haxework.gui.popup;
import haxework.animate.IAnimate;
import haxework.gui.Root;
import haxework.gui.IGroupView;
class PopupManager {
public var showAnimateFactory(default, default):Class<IAnimate>;
public var closeAnimateFactory(default, default):Class<IAnimate>;
private var popups:Array<PopupView<Dynamic>>;
public function new() {
popups = new Array<PopupView<Dynamic>>();
}
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 {
popups.remove(popup);
if (closeAnimateFactory != null) {
Type.createInstance(closeAnimateFactory, [popup]).start(function(_) {
cast(Root.instance.view, IGroupView).removeView(popup);
popup.onClose();
});
} else {
cast(Root.instance.view, IGroupView).removeView(popup);
popup.onClose();
}
}
public function closeTop():Bool {
if (popups.length > 0) {
close(popups[popups.length - 1]);
return true;
}
return false;
}
}

View File

@@ -0,0 +1,56 @@
package haxework.gui.popup;
import promhx.Deferred;
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;
class PopupView<V:IView> extends GroupView {
private var buttonId:String;
private var contentView:V;
private var deferred:Deferred<String>;
public function new(contentViewFactory:Class<V>) {
super();
pWidth = 100;
pHeight = 100;
inLayout = false;
skin = new ColorSkin(0x000000, 0.6);
this.contentView = Type.createInstance(contentViewFactory, [{listener:this}]);
addView(contentView);
}
public function onPress(button:ButtonView) {
this.buttonId = button.id;
close();
}
public function show():Deferred<String> {
Provider.get(PopupManager).show(this);
deferred = new Deferred<String>();
return deferred;
}
public function close():Void {
Provider.get(PopupManager).close(this);
}
public function onShow():Void {
buttonId = "close";
}
public function onClose():Void {
if (deferred != null) {
deferred.resolve(buttonId);
deferred = null;
}
}
}

View File

@@ -9,7 +9,7 @@ import haxework.gui.ButtonView.ButtonState;
import flash.display.Graphics; import flash.display.Graphics;
import flash.display.Sprite; import flash.display.Sprite;
class BitmapSkin implements ISkin<Sprite, SpriteView> implements ISize { class BitmapSkin implements ISkin<SpriteView> implements ISize {
public var width(default, null):Float; public var width(default, null):Float;
public var height(default, null):Float; public var height(default, null):Float;
@@ -37,7 +37,7 @@ class BitmapSkin implements ISkin<Sprite, SpriteView> implements ISize {
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.contentAsSprite.graphics, image, new Rectangle(0, 0, view.width, view.height), fillType, color);
} }
} }

View File

@@ -9,7 +9,7 @@ import haxework.gui.ButtonView.ButtonState;
import flash.display.Graphics; import flash.display.Graphics;
import flash.display.Sprite; import flash.display.Sprite;
class ButtonBitmapSkin implements ISkin<Sprite, ButtonView> implements ISize { class ButtonBitmapSkin implements ISkin<ButtonView> implements ISize {
public var width(default, null):Float; public var width(default, null):Float;
public var height(default, null):Float; public var height(default, null):Float;
@@ -20,6 +20,7 @@ class ButtonBitmapSkin implements ISkin<Sprite, ButtonView> implements ISize {
public var upImage(null, set):BitmapData; public var upImage(null, set):BitmapData;
public var overImage(null, set):BitmapData; public var overImage(null, set):BitmapData;
public var downImage(null, set):BitmapData; public var downImage(null, set):BitmapData;
public var disableImage(null, default):BitmapData;
private var images:Map<ButtonState, BitmapData>; private var images:Map<ButtonState, BitmapData>;
private var disable:BitmapData; private var disable:BitmapData;
@@ -62,8 +63,8 @@ class ButtonBitmapSkin implements ISkin<Sprite, ButtonView> implements ISize {
public function draw(view:ButtonView):Void { public function draw(view:ButtonView):Void {
if (images == null) return; if (images == null) return;
var image:BitmapData = view.disabled ? disable : images.get(view.state); var image:BitmapData = view.disabled ? disableImage == null ? disable : disableImage : images.get(view.state);
DrawUtil.draw(view.content.graphics, image, new Rectangle(0, 0, view.width, view.height), fillType, color); DrawUtil.draw(view.contentAsSprite.graphics, image, new Rectangle(0, 0, view.width, view.height), fillType, color);
} }
} }

View File

@@ -5,7 +5,7 @@ import haxework.gui.ButtonView.ButtonState;
import flash.display.Graphics; import flash.display.Graphics;
import flash.display.Sprite; import flash.display.Sprite;
class ButtonColorSkin implements ISkin<Sprite, ButtonView> { class ButtonColorSkin implements ISkin<ButtonView> {
public var color(default, set_color):Int; public var color(default, set_color):Int;
public var alpha(default, default):Float; public var alpha(default, default):Float;
@@ -28,7 +28,7 @@ class ButtonColorSkin implements ISkin<Sprite, ButtonView> {
public function draw(view:ButtonView):Void { public function draw(view:ButtonView):Void {
var color:Int = selectColor(view); var color:Int = selectColor(view);
var graphics:Graphics = view.content.graphics; var graphics:Graphics = view.contentAsSprite.graphics;
graphics.clear(); graphics.clear();
graphics.beginFill(color, alpha); graphics.beginFill(color, alpha);
graphics.drawRect(0, 0, view.width, view.height); graphics.drawRect(0, 0, view.width, view.height);

View File

@@ -3,7 +3,7 @@ package haxework.gui.skin;
import flash.display.Graphics; import flash.display.Graphics;
import flash.display.Sprite; import flash.display.Sprite;
class ColorSkin implements ISkin<Sprite, IView<Sprite>> { class ColorSkin implements ISkin<SpriteView> {
public var color(default, default):Int; public var color(default, default):Int;
public var alpha(default, default):Float; public var alpha(default, default):Float;
@@ -13,8 +13,8 @@ class ColorSkin implements ISkin<Sprite, IView<Sprite>> {
this.alpha = alpha; this.alpha = alpha;
} }
public function draw(view:IView<Sprite>):Void { public function draw(view:SpriteView):Void {
var graphics:Graphics = view.content.graphics; var graphics:Graphics = view.contentAsSprite.graphics;
graphics.clear(); graphics.clear();
graphics.beginFill(color, alpha); graphics.beginFill(color, alpha);
graphics.drawRect(0, 0, view.width, view.height); graphics.drawRect(0, 0, view.width, view.height);

View File

@@ -3,11 +3,11 @@ package haxework.gui.skin;
import flash.display.Graphics; import flash.display.Graphics;
import flash.display.Sprite; import flash.display.Sprite;
class FakeSkin implements ISkin<Sprite, IView<Sprite>> { class FakeSkin implements ISkin<IView> {
public function new() {} public function new() {}
public function draw(view:IView<Sprite>):Void { public function draw(view:IView):Void {
/*var g:Graphics = view.content.graphics; /*var g:Graphics = view.content.graphics;
g.clear(); g.clear();
g.lineStyle(1, 0x00ff00); g.lineStyle(1, 0x00ff00);

View File

@@ -2,6 +2,6 @@ package haxework.gui.skin;
import haxework.gui.IView.Content; import haxework.gui.IView.Content;
interface ISkin<C:Content, V:IView<C>> { interface ISkin<V:IView> {
public function draw(view:V):Void; public function draw(view:V):Void;
} }

View File

@@ -4,20 +4,25 @@ import flash.display.Graphics;
import flash.display.Sprite; import flash.display.Sprite;
import haxework.gui.skin.ISkin; import haxework.gui.skin.ISkin;
class ProgressSkin implements ISkin<Sprite, ProgressView> { class ProgressSkin implements ISkin<ProgressView> {
public var foreColor:Int; public var foreColor:Int;
public var backColor:Int; public var backColor:Int;
public var vertical:Bool;
public function new() {} public function new() {}
public function draw(view:ProgressView):Void { public function draw(view:ProgressView):Void {
var graphics:Graphics = view.content.graphics; var graphics:Graphics = view.contentAsSprite.graphics;
graphics.clear(); graphics.clear();
graphics.beginFill(backColor); graphics.beginFill(backColor);
graphics.drawRect(0, 0, view.width, view.height); graphics.drawRect(0, 0, view.width, view.height);
graphics.beginFill(foreColor); graphics.beginFill(foreColor);
graphics.drawRect(0, 0, view.width * (view.max > 0 ? view.value / view.max : 0), view.height); if (vertical) {
graphics.drawRect(0, view.height - view.height * (view.max > 0 ? view.value / view.max : 0), view.width, view.height);
} else {
graphics.drawRect(0, 0, view.width * (view.max > 0 ? view.value / view.max : 0), view.height);
}
graphics.endFill(); graphics.endFill();
} }
} }

View File

@@ -7,14 +7,31 @@ 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 function fromCache(image:BitmapData, key:String):Null<BitmapData> {
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 {
if (!cache.exists(image)) cache.set(image, new Map<String, BitmapData>());
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);
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);
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);
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]);
@@ -23,6 +40,7 @@ class BitmapUtil {
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);
return out; return out;
} }
} }

View File

@@ -8,19 +8,20 @@ import flash.geom.Rectangle;
import flash.display.BitmapData; import flash.display.BitmapData;
import flash.display.Graphics; import flash.display.Graphics;
@:fakeEnum(String) enum FillType { @:enum abstract FillType(String) from String to String {
NONE; var NONE = "NONE";
DEFAULT; var DEFAULT = "DEFAULT";
COVER; var COVER = "COVER";
CONTAIN; var CONTAIN = "CONTAIN";
REPEAT; var REPEAT = "REPEAT";
STRETCH; var STRETCH = "STRETCH";
NINEPATH; var NINEPATH = "NINEPATH";
} }
class DrawUtil { class DrawUtil {
public static function draw(graphics:Graphics, image:BitmapData, rect:Rectangle, ?fillType:FillType = null, ?color:Int = -1, ?clear:Bool = true):Void { public static function draw(graphics:Graphics, image:BitmapData, rect:Rectangle, ?fillType:FillType = null, ?color:Int = -1, ?clear:Bool = true):Void {
if (image == null) return;
if (fillType == null) fillType = FillType.DEFAULT; if (fillType == null) fillType = FillType.DEFAULT;
if (clear) graphics.clear(); if (clear) graphics.clear();
if (color > -1) { if (color > -1) {

Some files were not shown because too many files have changed in this diff Show More