Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7b7819fe6e | |||
| 2428ed20e0 | |||
| bc3d6e4458 | |||
| d217727d94 | |||
| c889ca04da | |||
| 39ca4b3d9b | |||
| f81ab02e67 | |||
| 284593e82c | |||
| a311dc1c19 | |||
| 07c228121c | |||
| a6ff04fd1b | |||
| a768e75cec | |||
| 7a5b32b251 | |||
| 74ed2d4425 | |||
| fcbac5587e | |||
| 78f4ae3a03 | |||
| b18b9d2d30 | |||
| c88a2c810f | |||
| a253aeaed4 | |||
| 3478963a6f | |||
| 5989da3fe4 | |||
| 32309389e5 | |||
| 3d54a2489b | |||
| 7a68604cad | |||
| f31b1ce506 | |||
| f186b08e9f |
@@ -1,7 +1,8 @@
|
||||
-cp src
|
||||
-cp ../src/main
|
||||
#-cp ../src/main
|
||||
-lib yaml
|
||||
-lib promhx
|
||||
-lib haxework
|
||||
--macro haxework.parser.Parser.auto()
|
||||
-debug
|
||||
-D native_trace
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
<source path="src"/>
|
||||
<assets path="src" rename="image" include="*.png"/>
|
||||
|
||||
<haxelib name="lime" version="7.3.0"/>
|
||||
<haxelib name="openfl" version="8.9.0"/>
|
||||
<haxelib name="hxcpp" version="4.0.8"/>
|
||||
<haxelib name="promhx" version="1.1.0"/>
|
||||
<haxelib name="yaml" version="1.3.0"/>
|
||||
<haxelib name="lime" version=""/>
|
||||
<haxelib name="openfl" version=""/>
|
||||
<haxelib name="hxcpp" version=""/>
|
||||
<!--<haxelib name="promhx" version=""/>-->
|
||||
<haxelib name="haxework" version="git"/>
|
||||
|
||||
<haxeflag name="--macro" value="haxework.parser.Parser.auto()"/>
|
||||
<!--<haxeflag name="--macro" value="haxework.parser.Parser.auto()"/>-->
|
||||
<haxeflag name="--macro" value="CompilationOption.set('build','xxx')"/>
|
||||
|
||||
<window fps="30"/>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
SDK_PATH=~/sdk
|
||||
echo "`pwd`/target" > ~/.macromedia/Flash_Player/#Security/FlashPlayerTrust/haxework_demo.cfg
|
||||
. /opt/sdk/neko/2.2.0/activate
|
||||
. /opt/sdk/haxe/3.4.7/activate
|
||||
haxe build.hxml && flashplayerdebugger target/demo.swf &
|
||||
. ${SDK_PATH}/neko/2.2.0/activate
|
||||
. ${SDK_PATH}/haxe/4.0.5/activate
|
||||
haxe build.hxml && ${SDK_PATH}/flashplayer/32/flashplayerdebugger target/demo.swf &
|
||||
tail -f ~/.macromedia/Flash_Player/Logs/flashlog.txt
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
SDK_PATH=~/sdk
|
||||
echo "`pwd`/target/flash/bin" > ~/.macromedia/Flash_Player/#Security/FlashPlayerTrust/haxework_demo.cfg
|
||||
. /opt/sdk/neko/2.2.0/activate
|
||||
. /opt/sdk/haxe/3.4.7/activate
|
||||
haxelib run openfl test flash
|
||||
. ${SDK_PATH}/neko/2.2.0/activate
|
||||
. ${SDK_PATH}/haxe/4.0.5/activate
|
||||
#haxelib run openfl test flash
|
||||
haxelib run openfl test html5
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package demo;
|
||||
|
||||
import demo.storage.TestStorage;
|
||||
import haxework.resources.IResources;
|
||||
import haxework.provider.Provider;
|
||||
import demo.dispatch.DemoDispatcher;
|
||||
import demo.popup.ColorPopup;
|
||||
import demo.popup.FontPopup;
|
||||
@@ -15,7 +18,8 @@ import haxework.view.group.VGroupView;
|
||||
@:view var switcher:FrameSwitcher;
|
||||
@:view var tabs:ButtonGroup<String>;
|
||||
|
||||
private function init():Void {
|
||||
public function new():Void {
|
||||
super();
|
||||
switcher.change("list");
|
||||
}
|
||||
|
||||
@@ -42,13 +46,19 @@ import haxework.view.group.VGroupView;
|
||||
|
||||
class Demo extends App implements DemoListener {
|
||||
|
||||
@:provide static var resources:IResources;
|
||||
@:provide static var storage:TestStorage;
|
||||
|
||||
public static function main() {
|
||||
L.push(new TraceLogger());
|
||||
|
||||
var app = new Demo(new AppTheme());
|
||||
app.resources.image.put("logo", HaxeLogo.resolve());
|
||||
resources.image.put("logo", HaxeLogo.resolve());
|
||||
var app = new Demo(new AppTheme(), resources.image.get("logo"));
|
||||
app.start(new DemoView());
|
||||
|
||||
trace(storage);
|
||||
storage.write("test", "value");
|
||||
|
||||
var dispatcher = new DemoDispatcher();
|
||||
dispatcher.connect(app);
|
||||
dispatcher.test1Signal.emit();
|
||||
@@ -63,8 +73,8 @@ class Demo extends App implements DemoListener {
|
||||
|
||||
new JsonLoader().GET("https://embed.tvbit.co/channel/data2/renova.json")
|
||||
.then(function(data:Array<Model>) {
|
||||
app.resources.any.put("data", data);
|
||||
app.resources.any.put("data50", Util.marray(data, 50));
|
||||
resources.any.put("data", data);
|
||||
resources.any.put("data50", Util.marray(data, 50));
|
||||
})
|
||||
.catchError(function(error) trace(error));
|
||||
}
|
||||
|
||||
@@ -9,6 +9,6 @@ interface DemoListener {
|
||||
public function onTest4(app:App):Void;
|
||||
}
|
||||
|
||||
@:yield @:dispatcher(DemoListener) class DemoDispatcher {
|
||||
@:dispatcher(DemoListener) class DemoDispatcher {
|
||||
public function new() {}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,6 @@ import haxework.view.SpriteView;
|
||||
|
||||
public function new() {
|
||||
super("test_layout");
|
||||
}
|
||||
|
||||
public function init():Void {
|
||||
resize();
|
||||
content.addEventListener(MouseEvent.CLICK, function(_) {
|
||||
resize();
|
||||
|
||||
@@ -23,7 +23,8 @@ class FontLabelView extends LabelListItem<ThemeFont> {
|
||||
|
||||
@:view var fonts:ListView<ThemeFont>;
|
||||
|
||||
private function init():Void {
|
||||
public function new():Void {
|
||||
super();
|
||||
var values:Array<ThemeFont> = Font.enumerateFonts(true).map(function(font:Font) {
|
||||
return {
|
||||
name: font.fontName,
|
||||
|
||||
10
demo/src/demo/storage/TestStorage.hx
Normal file
10
demo/src/demo/storage/TestStorage.hx
Normal file
@@ -0,0 +1,10 @@
|
||||
package demo.storage;
|
||||
|
||||
import haxework.storage.SharedObjectStorage;
|
||||
|
||||
@:provide class TestStorage extends SharedObjectStorage {
|
||||
|
||||
public function new() {
|
||||
super("test");
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
"template"
|
||||
],
|
||||
"description": "View framework.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.3.0",
|
||||
"releasenote": "Update.",
|
||||
"contributors": [
|
||||
"shmyga"
|
||||
@@ -16,6 +16,6 @@
|
||||
"classPath": "src/main",
|
||||
"dependencies": {
|
||||
"promhx": "1.1.0",
|
||||
"yaml": "1.3.0"
|
||||
"yaml": "2.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package haxework;
|
||||
|
||||
import flash.display.BitmapData;
|
||||
import flash.Lib;
|
||||
import haxework.animate.Animate;
|
||||
import haxework.animate.FadeAnimate;
|
||||
import haxework.animate.UnFadeAnimate;
|
||||
import haxework.net.manage.ILoaderManager;
|
||||
import haxework.net.manage.LoaderManager;
|
||||
import haxework.resources.IResources;
|
||||
import haxework.resources.Resources;
|
||||
import haxework.view.IView;
|
||||
import haxework.view.popup.PopupManager;
|
||||
import haxework.view.Root;
|
||||
@@ -17,15 +14,15 @@ class App {
|
||||
|
||||
@:provide var app:App;
|
||||
@:provide var theme:ITheme;
|
||||
@:provide var resources:IResources;
|
||||
@:provide var loaderManager:ILoaderManager;
|
||||
@:provide var popupManager:PopupManager;
|
||||
|
||||
public function new(?theme:ITheme) {
|
||||
public function new(?theme:ITheme, ?icon:BitmapData) {
|
||||
this.theme = theme;
|
||||
resources = new Resources();
|
||||
loaderManager = new LoaderManager();
|
||||
popupManager = new PopupManager();
|
||||
#if linux
|
||||
if (icon != null) {
|
||||
haxework.app.LinuxIcon.value = icon;
|
||||
}
|
||||
#end
|
||||
popupManager.showAnimateFactory = function(v) return new UnFadeAnimate(v);
|
||||
popupManager.closeAnimateFactory = function(v) return new FadeAnimate(v);
|
||||
app = this;
|
||||
|
||||
29
src/main/haxework/app/LinuxIcon.hx
Normal file
29
src/main/haxework/app/LinuxIcon.hx
Normal file
@@ -0,0 +1,29 @@
|
||||
package haxework.app;
|
||||
|
||||
import flash.display.BitmapData;
|
||||
import flash.filters.ColorMatrixFilter;
|
||||
import flash.geom.Point;
|
||||
import flash.Lib;
|
||||
|
||||
class LinuxIcon {
|
||||
|
||||
public static var value(default, set):BitmapData;
|
||||
|
||||
private static function set_value(value:BitmapData):BitmapData {
|
||||
LinuxIcon.value = value;
|
||||
Lib.current.stage.window.setIcon(prepareIcon(value).image);
|
||||
return LinuxIcon.value;
|
||||
}
|
||||
|
||||
private static function prepareIcon(bitmap:BitmapData):BitmapData {
|
||||
var matrix:Array<Float> = [];
|
||||
matrix = matrix.concat([0, 0, 1, 0, 0]);
|
||||
matrix = matrix.concat([0, 1, 0, 0, 0]);
|
||||
matrix = matrix.concat([1, 0, 0, 0, 0]);
|
||||
matrix = matrix.concat([0, 0, 0, 1, 0]);
|
||||
var cmf:ColorMatrixFilter = new ColorMatrixFilter(matrix);
|
||||
var bitmap:BitmapData = bitmap.clone();
|
||||
bitmap.applyFilter(bitmap, bitmap.rect, new Point(0, 0), cmf);
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,25 @@ abstract Color(Int) {
|
||||
}
|
||||
|
||||
@:from static public inline function fromString(value:String):Color {
|
||||
return new Color(Std.parseInt('0x${value.split('#').pop()}'));
|
||||
return new Color(switch value {
|
||||
case "white": 0xFFFFFF;
|
||||
case "silver": 0xC0C0C0;
|
||||
case "gray": 0x808080;
|
||||
case "black": 0x000000;
|
||||
case "red": 0xFF0000;
|
||||
case "maroon": 0x800000;
|
||||
case "yellow": 0xFFFF00;
|
||||
case "olive": 0x808000;
|
||||
case "lime": 0x00FF00;
|
||||
case "green": 0x008000;
|
||||
case "aqua": 0x00FFFF;
|
||||
case "teal": 0x008080;
|
||||
case "blue": 0x0000FF;
|
||||
case "navy": 0x000080;
|
||||
case "fuchsia": 0xFF00FF;
|
||||
case "purple": 0x800080;
|
||||
case x: Std.parseInt('0x${x.split('#').pop()}');
|
||||
});
|
||||
}
|
||||
|
||||
@:to public inline function toString():String {
|
||||
|
||||
35
src/main/haxework/geom/IntPoint.hx
Normal file
35
src/main/haxework/geom/IntPoint.hx
Normal file
@@ -0,0 +1,35 @@
|
||||
package haxework.geom;
|
||||
|
||||
abstract IntPoint(Array<Int>) {
|
||||
public var x(get, set):Int;
|
||||
public var y(get, set):Int;
|
||||
|
||||
public function new(x:Int, y:Int) {
|
||||
this = [x, y];
|
||||
}
|
||||
|
||||
private inline function get_x() return this[0];
|
||||
|
||||
private inline function set_x(value) return this[0] = value;
|
||||
|
||||
private inline function get_y() return this[1];
|
||||
|
||||
private inline function set_y(value) return this[1] = value;
|
||||
|
||||
public function clone():IntPoint {
|
||||
return new IntPoint(x, y);
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return 'IntPoint{x=$x,y=$y}';
|
||||
}
|
||||
|
||||
@:to inline public function toInt():Int {
|
||||
return (x << 16) + y;
|
||||
}
|
||||
|
||||
@:to inline public function toPoint():Point {
|
||||
return new Point(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
40
src/main/haxework/geom/Point.hx
Normal file
40
src/main/haxework/geom/Point.hx
Normal file
@@ -0,0 +1,40 @@
|
||||
package haxework.geom;
|
||||
|
||||
import flash.geom.Point as FlashPoint;
|
||||
|
||||
abstract Point(Array<Float>) {
|
||||
public var x(get, set):Float;
|
||||
public var y(get, set):Float;
|
||||
|
||||
public function new(x:Float, y:Float) {
|
||||
this = [x, y];
|
||||
}
|
||||
|
||||
private inline function get_x() return this[0];
|
||||
|
||||
private inline function set_x(value) return this[0] = value;
|
||||
|
||||
private inline function get_y() return this[1];
|
||||
|
||||
private inline function set_y(value) return this[1] = value;
|
||||
|
||||
public function add(point:Point):Point {
|
||||
return new Point(x + point.x, y + point.y);
|
||||
}
|
||||
|
||||
public function subtract(point:Point):Point {
|
||||
return new Point(x - point.x, y - point.y);
|
||||
}
|
||||
|
||||
public function clone():Point {
|
||||
return new Point(x, y);
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return 'Point{x=$x,y=$y}';
|
||||
}
|
||||
|
||||
@:from public static function fromFlashPoint(value:FlashPoint):Point {
|
||||
return new Point(value.x, value.y);
|
||||
}
|
||||
}
|
||||
102
src/main/haxework/geom/Rectangle.hx
Normal file
102
src/main/haxework/geom/Rectangle.hx
Normal file
@@ -0,0 +1,102 @@
|
||||
package haxework.geom;
|
||||
|
||||
abstract Rectangle(Array<Float>) {
|
||||
public var x(get, set):Float;
|
||||
public var y(get, set):Float;
|
||||
public var width(get, set):Float;
|
||||
public var height(get, set):Float;
|
||||
public var center(get, set):Point;
|
||||
public var size(get, set):Point;
|
||||
public var left(get, never):Float;
|
||||
public var right(get, never):Float;
|
||||
public var top(get, never):Float;
|
||||
public var bottom(get, never):Float;
|
||||
public var position(get, set):Point;
|
||||
|
||||
public function new(x:Float = 0, y:Float = 0, width:Float = 0, height:Float = 0) {
|
||||
this = [x, y, width, height];
|
||||
}
|
||||
|
||||
private inline function get_x() return this[0];
|
||||
|
||||
private inline function set_x(value) return this[0] = value;
|
||||
|
||||
private inline function get_y() return this[1];
|
||||
|
||||
private inline function set_y(value) return this[1] = value;
|
||||
|
||||
private inline function get_width() return this[2];
|
||||
|
||||
private inline function set_width(value) return this[2] = value;
|
||||
|
||||
private inline function get_height() return this[3];
|
||||
|
||||
private inline function set_height(value) return this[3] = value;
|
||||
|
||||
private function get_center():Point {
|
||||
return new Point(x + width / 2, y + height / 2);
|
||||
}
|
||||
|
||||
private function set_center(value:Point):Point {
|
||||
x = value.x - width / 2;
|
||||
y = value.y - height / 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
private function get_size():Point {
|
||||
return new Point(width, height);
|
||||
}
|
||||
|
||||
private function set_size(value:Point):Point {
|
||||
width = value.x;
|
||||
height = value.y;
|
||||
return value;
|
||||
}
|
||||
|
||||
public function contain(point:Point):Bool {
|
||||
return point.x >= left && point.y >= top && point.x <= right && point.y <= bottom;
|
||||
}
|
||||
|
||||
public function intersection(rect:Rectangle):Bool {
|
||||
return !(
|
||||
rect.left > right ||
|
||||
rect.right < left ||
|
||||
rect.top > bottom ||
|
||||
rect.bottom < top
|
||||
);
|
||||
}
|
||||
|
||||
public function clone():Rectangle {
|
||||
return new Rectangle(x, y, width, height);
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return 'Rectangle{x=$x,y=$y,width=$width,height=$height}';
|
||||
}
|
||||
|
||||
private function get_left():Float {
|
||||
return x;
|
||||
}
|
||||
|
||||
private function get_right():Float {
|
||||
return x + width;
|
||||
}
|
||||
|
||||
private function get_top():Float {
|
||||
return y;
|
||||
}
|
||||
|
||||
private function get_bottom():Float {
|
||||
return y + height;
|
||||
}
|
||||
|
||||
private function get_position():Point {
|
||||
return new Point(x, y);
|
||||
}
|
||||
|
||||
private function set_position(position:Point):Point {
|
||||
x = position.x;
|
||||
y = position.y;
|
||||
return position;
|
||||
}
|
||||
}
|
||||
15
src/main/haxework/log/AndroidLog.hx
Normal file
15
src/main/haxework/log/AndroidLog.hx
Normal file
@@ -0,0 +1,15 @@
|
||||
package haxework.log;
|
||||
|
||||
import cpp.VarArg;
|
||||
import haxe.extern.Rest;
|
||||
import cpp.ConstCharStar;
|
||||
|
||||
@:include("android/log.h")
|
||||
extern class AndroidLog {
|
||||
|
||||
@:native("__android_log_print")
|
||||
public static function print(prio:Int, tag:ConstCharStar, fmt:ConstCharStar, rest:Rest<VarArg>):Void;
|
||||
|
||||
@:native("__android_log_write")
|
||||
public static function write(prio:Int, tag:ConstCharStar, message:ConstCharStar):Void;
|
||||
}
|
||||
@@ -12,11 +12,11 @@ class LoggerUtil {
|
||||
|
||||
public static function printStackItem(item:StackItem):String {
|
||||
return switch item {
|
||||
case StackItem.CFunction: 'CFunction';
|
||||
case StackItem.Module(m): m;
|
||||
case StackItem.FilePos(s, file, line): '${file}:${line}';
|
||||
case StackItem.Method(classname, method): '${classname}::${method}}';
|
||||
case StackItem.LocalFunction(v): 'LocalFunction(${v})';
|
||||
case CFunction: 'CFunction';
|
||||
case Module(m): m;
|
||||
case FilePos(s, file, line): '${file}:${line}';
|
||||
case Method(classname, method): '${classname}::${method}}';
|
||||
case LocalFunction(v): 'LocalFunction(${v})';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,11 @@ class TraceLogger extends BaseLogger {
|
||||
$print("\n");
|
||||
}
|
||||
#elseif js
|
||||
untyped js.Boot.__trace(v, infos);
|
||||
if (js.Syntax.typeof(untyped console) != "undefined" && (untyped console).log != null)
|
||||
(untyped console).log(v);
|
||||
//untyped js.Boot.__trace(v, infos);
|
||||
#elseif android
|
||||
haxework.log.AndroidLog.write(3, "", ConstCharStar.fromString(Std.string(v)));
|
||||
#elseif (php && php7)
|
||||
php.Boot.trace(v);
|
||||
#elseif php
|
||||
|
||||
20
src/main/haxework/macro/ClassProvideMacro.hx
Normal file
20
src/main/haxework/macro/ClassProvideMacro.hx
Normal file
@@ -0,0 +1,20 @@
|
||||
package haxework.macro;
|
||||
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type;
|
||||
|
||||
class ClassProvideMacro extends ClassTypeMacro {
|
||||
|
||||
public static var bundle(default, null):Array<{key: ClassType, value: ClassType}> = [];
|
||||
|
||||
public function new() {
|
||||
super(":provide");
|
||||
}
|
||||
|
||||
override public function apply(classType:ClassType, fields:Array<Field>):Array<Field> {
|
||||
var meta = MacroUtil.getClassMeta(classType, metaName);
|
||||
var valueType = meta.params.length == 0 ? classType : MacroUtil.getExprClassType(meta.params[0]);
|
||||
bundle.push({key: classType, value: valueType});
|
||||
return super.apply(classType, fields);
|
||||
}
|
||||
}
|
||||
21
src/main/haxework/macro/ClassTypeMacro.hx
Normal file
21
src/main/haxework/macro/ClassTypeMacro.hx
Normal file
@@ -0,0 +1,21 @@
|
||||
package haxework.macro;
|
||||
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type;
|
||||
|
||||
class ClassTypeMacro {
|
||||
|
||||
public var metaName(default, null):String;
|
||||
|
||||
public function new(metaName:String) {
|
||||
this.metaName = metaName;
|
||||
}
|
||||
|
||||
public function has(classType:ClassType):Bool {
|
||||
return classType.meta.has(metaName);
|
||||
}
|
||||
|
||||
public function apply(classType:ClassType, fields:Array<Field>):Array<Field> {
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
@@ -6,20 +6,10 @@ import haxe.macro.ExprTools;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type;
|
||||
|
||||
class DispatcherMacro {
|
||||
class DispatcherMacro extends ClassTypeMacro {
|
||||
|
||||
private static inline var metaName:String = ':dispatcher';
|
||||
|
||||
public static function has(classType:ClassType):Bool {
|
||||
return classType.meta.has(metaName);
|
||||
}
|
||||
|
||||
private var classType:ClassType;
|
||||
private var fields:Array<Field>;
|
||||
|
||||
public function new(classType:ClassType, fields:Array<Field>) {
|
||||
this.classType = classType;
|
||||
this.fields = fields;
|
||||
public function new() {
|
||||
super(":dispatcher");
|
||||
}
|
||||
|
||||
private static inline function signalName(fieldName:String):String {
|
||||
@@ -30,13 +20,10 @@ class DispatcherMacro {
|
||||
}
|
||||
}
|
||||
|
||||
public function apply():Array<Field> {
|
||||
override public function apply(classType:ClassType, fields:Array<Field>):Array<Field> {
|
||||
var result:Array<Field> = fields.slice(0);
|
||||
var typeName = ExprTools.toString(classType.meta.extract(metaName)[0].params[0]);
|
||||
var type:ClassType = switch Context.getType(typeName) {
|
||||
case TInst(t, _): t.get();
|
||||
case _: null;
|
||||
}
|
||||
var type:ClassType = MacroUtil.getExprClassType(classType.meta.extract(metaName)[0].params[0]);
|
||||
var fields = type.fields.get();
|
||||
for (field in fields) {
|
||||
var argsTypes:Array<Type> = switch field.type {
|
||||
|
||||
21
src/main/haxework/macro/FieldMacro.hx
Normal file
21
src/main/haxework/macro/FieldMacro.hx
Normal file
@@ -0,0 +1,21 @@
|
||||
package haxework.macro;
|
||||
|
||||
import haxe.macro.Expr;
|
||||
|
||||
using haxework.macro.MacroUtil;
|
||||
|
||||
class FieldMacro {
|
||||
public var metaName(default, null):String;
|
||||
|
||||
public function new(metaName:String) {
|
||||
this.metaName = metaName;
|
||||
}
|
||||
|
||||
public function has(field:Field):Bool {
|
||||
return field.getFieldMeta(metaName) != null;
|
||||
}
|
||||
|
||||
public function apply(field:Field):Array<Field> {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package haxework.macro;
|
||||
|
||||
import haxe.macro.Type.ClassType;
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.ExprTools;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type;
|
||||
|
||||
class Util {
|
||||
class MacroUtil {
|
||||
|
||||
public static function getMetaParams(meta:MetadataEntry):Array<String> {
|
||||
return meta.params.map(function(param:Expr) return switch param.expr {
|
||||
@@ -17,15 +19,21 @@ class Util {
|
||||
}
|
||||
|
||||
public static function getClassMeta(classType:ClassType, metaName:String):Null<MetadataEntry> {
|
||||
for (md in classType.meta.get()) if (md.name == metaName) {
|
||||
return md;
|
||||
for (meta in classType.meta.get()) {
|
||||
if (meta.name == metaName) {
|
||||
return meta;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getFieldMeta(field:Field, metaName:String):Null<MetadataEntry> {
|
||||
for (md in field.meta) if (md.name == metaName) {
|
||||
return md;
|
||||
if (field.meta != null) {
|
||||
for (meta in field.meta) {
|
||||
if (meta.name == metaName) {
|
||||
return meta;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -48,4 +56,29 @@ class Util {
|
||||
public static function getField(fields:Array<Field>, name:String):Null<Field> {
|
||||
return Lambda.find(fields, function(field:Field):Bool return field.name == name);
|
||||
}
|
||||
|
||||
public static function getExprClassType(expr:Expr):Null<ClassType> {
|
||||
var typeName = ExprTools.toString(expr);
|
||||
return switch Context.getType(typeName) {
|
||||
case TInst(t, _): t.get();
|
||||
case _: null;
|
||||
}
|
||||
}
|
||||
|
||||
public static function upgradeField(field:Field, expr:Expr, position:Int = 0):Field {
|
||||
switch field.kind {
|
||||
case FFun(f):
|
||||
var fieldExpr = f.expr;
|
||||
switch fieldExpr.expr {
|
||||
case EBlock(exprs):
|
||||
exprs.insert(position, expr);
|
||||
fieldExpr = macro $b{exprs};
|
||||
case _:
|
||||
fieldExpr = macro $b{[fieldExpr, expr]}
|
||||
}
|
||||
f.expr = fieldExpr;
|
||||
case _:
|
||||
}
|
||||
return field;
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ class PositionYamlParser {
|
||||
}
|
||||
|
||||
private function parseAll():Void {
|
||||
parseBlock(result);
|
||||
//parseBlock(result);
|
||||
}
|
||||
|
||||
private function parseBlock(result:DynamicAccess<Dynamic>):Void {
|
||||
|
||||
@@ -3,25 +3,16 @@ package haxework.macro;
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
|
||||
using haxework.macro.Util;
|
||||
using haxework.macro.MacroUtil;
|
||||
|
||||
class ProvideMacro {
|
||||
class ProvideMacro extends FieldMacro {
|
||||
|
||||
private static var metaName = ":provide";
|
||||
|
||||
public static function has(field:Field):Bool {
|
||||
return field.getFieldMeta(metaName) != null;
|
||||
public function new() {
|
||||
super(":provide");
|
||||
}
|
||||
|
||||
private var field:Field;
|
||||
private var meta:MetadataEntry;
|
||||
|
||||
public function new(field:Field) {
|
||||
this.field = field;
|
||||
this.meta = field.getFieldMeta(metaName);
|
||||
}
|
||||
|
||||
public function apply():Array<Field> {
|
||||
override public function apply(field:Field):Array<Field> {
|
||||
var meta:MetadataEntry = field.getFieldMeta(metaName);
|
||||
var result:Array<Field> = [];
|
||||
var type:ComplexType = switch field.kind {
|
||||
case FVar(t): t;
|
||||
@@ -31,14 +22,9 @@ class ProvideMacro {
|
||||
case TPath(p): p.name;
|
||||
default: null;
|
||||
}
|
||||
var provideType:String = meta.params.length == 0 ? null : Util.getExprString(meta.params[0].expr);
|
||||
var provideType:String = meta.params.length == 0 ? null : MacroUtil.getExprString(meta.params[0].expr);
|
||||
var isStatic = Lambda.exists(field.access, function(a: Access) return a == AStatic);
|
||||
result.push({
|
||||
name: field.name,
|
||||
access: isStatic ? [APublic, AStatic] : [APublic],
|
||||
pos: field.pos,
|
||||
kind: FProp('get', 'set', type),
|
||||
});
|
||||
field.kind = FProp('get', 'set', type);
|
||||
var access = [APrivate, AInline];
|
||||
if (isStatic) access.push(AStatic);
|
||||
var args = [name];
|
||||
@@ -49,7 +35,7 @@ class ProvideMacro {
|
||||
pos: field.pos,
|
||||
kind: FFun({
|
||||
args: [],
|
||||
expr: Context.parse('return haxework.provider.Provider.get(${args.join(',')})', field.pos),
|
||||
expr: Context.parse('return haxework.provider.Provider.instance.get(${args.join(',')})', field.pos),
|
||||
params: [],
|
||||
ret: type,
|
||||
})
|
||||
@@ -61,7 +47,7 @@ class ProvideMacro {
|
||||
pos: field.pos,
|
||||
kind: FFun({
|
||||
args: [{name: 'value', type: type}],
|
||||
expr: Context.parse('{haxework.provider.Provider.set(${args.join(',')}); return value;}', field.pos),
|
||||
expr: Context.parse('{haxework.provider.Provider.instance.set(${args.join(',')}); return value;}', field.pos),
|
||||
params: [],
|
||||
ret: type,
|
||||
})
|
||||
|
||||
@@ -1,22 +1,10 @@
|
||||
package haxework.macro;
|
||||
|
||||
import haxe.macro.Expr;
|
||||
using haxework.macro.MacroUtil;
|
||||
|
||||
using haxework.macro.Util;
|
||||
class ResourceMacro extends FieldMacro {
|
||||
|
||||
class ResourceMacro {
|
||||
public static function has(field:Field):Bool {
|
||||
return field.getFieldMeta(":resource") != null;
|
||||
}
|
||||
|
||||
private var field:Field;
|
||||
|
||||
public function new(field:Field) {
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
public function apply():Array<Field> {
|
||||
var result:Array<Field> = [];
|
||||
return result;
|
||||
public function new() {
|
||||
super(":resource");
|
||||
}
|
||||
}
|
||||
|
||||
43
src/main/haxework/macro/SingletonMacro.hx
Normal file
43
src/main/haxework/macro/SingletonMacro.hx
Normal file
@@ -0,0 +1,43 @@
|
||||
package haxework.macro;
|
||||
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type;
|
||||
|
||||
class SingletonMacro extends ClassTypeMacro {
|
||||
|
||||
public function new() {
|
||||
super(":singleton");
|
||||
}
|
||||
|
||||
|
||||
override public function apply(classType:ClassType, fields:Array<Field>):Array<Field> {
|
||||
var result:Array<Field> = fields.slice(0);
|
||||
var classTypePath:TypePath = {
|
||||
pack: classType.pack,
|
||||
name: classType.name,
|
||||
};
|
||||
var type:ComplexType = TPath(classTypePath);
|
||||
result.push({
|
||||
name: 'instance',
|
||||
access: [APublic, AStatic],
|
||||
pos: Context.currentPos(),
|
||||
kind: FProp('get', 'null', type),
|
||||
});
|
||||
var typeStr = classType.name;
|
||||
result.push({
|
||||
name: 'get_instance',
|
||||
access: [APrivate, AStatic],
|
||||
pos: Context.currentPos(),
|
||||
kind: FFun({
|
||||
args: [],
|
||||
ret: type,
|
||||
expr: macro $b{[
|
||||
macro if (instance == null) instance = new $classTypePath(),
|
||||
macro return instance
|
||||
]},
|
||||
}),
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import haxe.macro.Expr;
|
||||
import haxe.macro.Type;
|
||||
|
||||
using haxe.macro.ComplexTypeTools;
|
||||
using haxework.macro.Util;
|
||||
using haxework.macro.MacroUtil;
|
||||
using haxe.macro.MacroStringTools;
|
||||
|
||||
typedef TProperty<T> = {
|
||||
@@ -13,21 +13,10 @@ typedef TProperty<T> = {
|
||||
var defaultValue: T;
|
||||
}
|
||||
|
||||
class StyleMacro {
|
||||
private static inline var metaName:String = ':style';
|
||||
class StyleMacro extends ClassTypeMacro {
|
||||
|
||||
public static function has(classType:ClassType):Bool {
|
||||
return classType.getClassMeta(metaName) != null;
|
||||
}
|
||||
|
||||
private var classType:ClassType;
|
||||
private var fields:Array<Field>;
|
||||
private var overrideStyle:Bool;
|
||||
|
||||
public function new(classType:ClassType, fields:Array<Field>) {
|
||||
this.classType = classType;
|
||||
this.fields = fields;
|
||||
this.overrideStyle = classType.getClassMeta(":style").params.length > 0;
|
||||
public function new() {
|
||||
super(":style");
|
||||
}
|
||||
|
||||
private static function processPropertyField(field:Field):Array<Field> {
|
||||
@@ -173,11 +162,11 @@ class StyleMacro {
|
||||
}
|
||||
for (field in properties) {
|
||||
var propertyName = 'theme_${field.name}';
|
||||
expr.push(macro $i{propertyName} = haxework.provider.Provider.get(haxework.view.theme.ITheme).resolve((styleKey!=null?(styleKey+"."):"")+$v{field.name}, style));
|
||||
expr.push(macro $i{propertyName} = haxework.provider.Provider.instance.get(haxework.view.theme.ITheme).resolve((styleKey!=null?(styleKey+"."):"")+$v{field.name}, style));
|
||||
}
|
||||
for (field in styleds) {
|
||||
var propertyName = '${field.name}';
|
||||
expr.push(macro $i{propertyName} = haxework.provider.Provider.get(haxework.view.theme.ITheme).resolve((styleKey!=null?(styleKey+"."):"")+$v{field.name}, style));
|
||||
expr.push(macro $i{propertyName} = haxework.provider.Provider.instance.get(haxework.view.theme.ITheme).resolve((styleKey!=null?(styleKey+"."):"")+$v{field.name}, style));
|
||||
}
|
||||
if (hasOnStyle) {
|
||||
expr.push(macro onStyle());
|
||||
@@ -201,14 +190,15 @@ class StyleMacro {
|
||||
return result;
|
||||
}
|
||||
|
||||
public function apply():Array<Field> {
|
||||
override public function apply(classType:ClassType, fields:Array<Field>):Array<Field> {
|
||||
var overrideStyle = classType.getClassMeta(metaName).params.length > 0;
|
||||
var result:Array<Field> = fields.slice(0);
|
||||
var styleds:Array<Field> = [];
|
||||
var properties:Array<Field> = [];
|
||||
var newFields:Array<Field> = [];
|
||||
var hasOnStyle:Bool = fields.getField("onStyle") != null;
|
||||
for (field in fields) if (field.meta != null) {
|
||||
var meta = field.getFieldMeta(":style");
|
||||
var meta = field.getFieldMeta(metaName);
|
||||
if (meta != null) {
|
||||
if (meta.params.length > 0) {
|
||||
newFields = newFields.concat(processPropertyField(field));
|
||||
|
||||
@@ -1,45 +1,23 @@
|
||||
package haxework.macro;
|
||||
|
||||
import Lambda;
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type;
|
||||
import haxework.macro.PositionJsonParser;
|
||||
import Lambda;
|
||||
|
||||
using haxework.macro.Util;
|
||||
using haxework.macro.MacroUtil;
|
||||
|
||||
class TemplateMacro {
|
||||
class TemplateMacro extends ClassTypeMacro {
|
||||
|
||||
private static inline var metaName:String = ':template';
|
||||
|
||||
public static function has(classType:ClassType):Bool {
|
||||
return classType.getClassMeta(metaName) != null;
|
||||
}
|
||||
|
||||
private var classType:ClassType;
|
||||
private var fields:Array<Field>;
|
||||
private var bindings:Map<String, String>;
|
||||
|
||||
private var meta:MetadataEntry;
|
||||
private var templateFile:String;
|
||||
private var template:Dynamic;
|
||||
private var i:Int;
|
||||
|
||||
|
||||
public function new(classType:ClassType, fields:Array<Field>) {
|
||||
this.classType = classType;
|
||||
this.meta = classType.getClassMeta(metaName);
|
||||
this.fields = fields;
|
||||
var params = Util.getMetaParams(meta);
|
||||
var filePath = params[0];
|
||||
if (filePath == null) {
|
||||
filePath = classType.pack.join("/") + "/" + classType.name + ".yaml";
|
||||
public function new() {
|
||||
super(":template");
|
||||
}
|
||||
templateFile = Context.resolvePath(filePath);
|
||||
template = FileUtil.loadFile(templateFile);
|
||||
bindings = findViewsBindings(fields);
|
||||
}
|
||||
|
||||
|
||||
private static function getSpecField(object:Dynamic, field:String):Dynamic {
|
||||
if (Reflect.hasField(object, "@" + field)) {
|
||||
@@ -68,7 +46,7 @@ class TemplateMacro {
|
||||
a[2];
|
||||
}
|
||||
case "resource" | "r":
|
||||
var bindExpr = 'haxework.provider.Provider.get(haxework.resources.IResources).${a[1]}.bind("${a[2]}", ${name}, "${key}")';
|
||||
var bindExpr = 'haxework.provider.Provider.instance.get(haxework.resources.IResources).${a[1]}.bind("${a[2]}", ${name}, "${key}")';
|
||||
exprs.push(Context.parse(bindExpr, getPosition(position)));
|
||||
null;
|
||||
case "translate" | "t":
|
||||
@@ -176,57 +154,57 @@ class TemplateMacro {
|
||||
}
|
||||
}
|
||||
|
||||
private function buildConstructor(init:Bool, constructor:Field = null):Field {
|
||||
var contstrExprs = [];
|
||||
if (constructor != null) {
|
||||
switch constructor.kind {
|
||||
case FFun(f): contstrExprs.push(f.expr);
|
||||
case _:
|
||||
}
|
||||
} else {
|
||||
contstrExprs.push(macro super());
|
||||
}
|
||||
contstrExprs.push(macro build());
|
||||
if (init) contstrExprs.push(macro init());
|
||||
|
||||
return {
|
||||
private function upgradeConstructor(constructor:Field = null):Field {
|
||||
if (constructor == null) {
|
||||
constructor = {
|
||||
name: "new",
|
||||
access: [Access.APublic],
|
||||
pos: getPosition(),
|
||||
kind: FieldType.FFun({
|
||||
args: [],
|
||||
expr: macro $b{contstrExprs},
|
||||
expr: macro super(),
|
||||
params: [],
|
||||
ret: null
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
MacroUtil.upgradeField(constructor, macro build(), 1);
|
||||
return constructor;
|
||||
}
|
||||
|
||||
private static function findViewsBindings(fields:Array<Field>):Map<String, String> {
|
||||
var result:Map<String, String> = new Map();
|
||||
for (field in fields) if (field.meta != null) {
|
||||
for (meta in field.meta) {
|
||||
if (meta.name == ':view') {
|
||||
var viewId:String = meta.params.length == 0 ? field.name : Util.getExprString(meta.params[0].expr);
|
||||
for (field in fields) {
|
||||
var viewMeta = field.getFieldMeta(":view");
|
||||
if (viewMeta != null) {
|
||||
var viewId:String = viewMeta.params.length == 0 ? field.name : MacroUtil.getExprString(viewMeta.params[0].expr);
|
||||
result.set(viewId, field.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public function apply():Array<Field> {
|
||||
override public function apply(classType:ClassType, fields:Array<Field>):Array<Field> {
|
||||
i = 0;
|
||||
var meta = classType.getClassMeta(metaName);
|
||||
var params = MacroUtil.getMetaParams(meta);
|
||||
var filePath = params[0];
|
||||
if (filePath == null) {
|
||||
filePath = classType.pack.join("/") + "/" + classType.name + ".yaml";
|
||||
}
|
||||
// ToDo: template builder
|
||||
templateFile = Context.resolvePath(filePath);
|
||||
template = FileUtil.loadFile(templateFile);
|
||||
bindings = findViewsBindings(fields);
|
||||
var result:Array<Field> = fields.slice(0);
|
||||
var exprs:Array<Expr> = [];
|
||||
var init = Lambda.exists(result, function(f) return f.name == "init");
|
||||
createElement("this", template, exprs);
|
||||
result.push(buildBuild(exprs));
|
||||
var constructor = Lambda.find(result, function(f) return f.name == "new");
|
||||
if (constructor != null) {
|
||||
result.remove(constructor);
|
||||
}
|
||||
result.push(buildConstructor(init, constructor));
|
||||
result.push(upgradeConstructor(constructor));
|
||||
if (Lambda.count(bindings) > 0) {
|
||||
var keys = Lambda.map({iterator: bindings.keys}, function(k) return '"${k}"').join(",");
|
||||
Context.error('Invalid @:view bindings: $keys', getPosition());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package haxework.net.manage;
|
||||
|
||||
interface ILoaderManager {
|
||||
@:provide(LoaderManager) interface ILoaderManager {
|
||||
public var actives(default, null):Array<ILoader<Dynamic>>;
|
||||
public var queue(default, null):Array<ILoader<Dynamic>>;
|
||||
public var limit(default, default):Int;
|
||||
|
||||
@@ -1,17 +1,34 @@
|
||||
package haxework.parser;
|
||||
|
||||
import haxework.macro.StyleMacro;
|
||||
import haxe.macro.TypeTools;
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type;
|
||||
import haxe.macro.TypeTools;
|
||||
import haxework.macro.ClassProvideMacro;
|
||||
import haxework.macro.ClassTypeMacro;
|
||||
import haxework.macro.DispatcherMacro;
|
||||
import haxework.macro.FieldMacro;
|
||||
import haxework.macro.ProvideMacro;
|
||||
import haxework.macro.ResourceMacro;
|
||||
import haxework.macro.SingletonMacro;
|
||||
import haxework.macro.StyleMacro;
|
||||
import haxework.macro.TemplateMacro;
|
||||
|
||||
class Parser {
|
||||
|
||||
private static var classTypeMacros:Array<ClassTypeMacro> = [
|
||||
new ClassProvideMacro(),
|
||||
new TemplateMacro(),
|
||||
new DispatcherMacro(),
|
||||
new StyleMacro(),
|
||||
new SingletonMacro(),
|
||||
];
|
||||
|
||||
private static var fieldMacros:Array<FieldMacro> = [
|
||||
new ProvideMacro(),
|
||||
new ResourceMacro(),
|
||||
];
|
||||
|
||||
private static var processed:Map<String, Bool> = new Map();
|
||||
|
||||
private static function auto():Void {
|
||||
@@ -29,39 +46,25 @@ class Parser {
|
||||
var modify:Bool = false;
|
||||
var fields:Array<Field> = Context.getBuildFields();
|
||||
var result:Array<Field> = [];
|
||||
var appends:Array<Field> = [];
|
||||
// process fields meta
|
||||
for (field in fields) {
|
||||
if (ProvideMacro.has(field)) {
|
||||
modify = true;
|
||||
var provide = new ProvideMacro(field);
|
||||
result = result.concat(provide.apply());
|
||||
} else if (ResourceMacro.has(field)) {
|
||||
modify = true;
|
||||
var resource = new ResourceMacro(field);
|
||||
result = result.concat(resource.apply());
|
||||
} else {
|
||||
result.push(field);
|
||||
for (item in fieldMacros) {
|
||||
if (item.has(field)) {
|
||||
modify = true;
|
||||
result = result.concat(item.apply(field));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (modify) {
|
||||
fields = result;
|
||||
}
|
||||
// process class meta
|
||||
if (TemplateMacro.has(ct)) {
|
||||
for (item in classTypeMacros) {
|
||||
if (item.has(ct)) {
|
||||
modify = true;
|
||||
var template = new TemplateMacro(ct, fields);
|
||||
fields = template.apply();
|
||||
fields = item.apply(ct, fields);
|
||||
}
|
||||
if (DispatcherMacro.has(ct)) {
|
||||
modify = true;
|
||||
var dispatcher = new DispatcherMacro(ct, fields);
|
||||
fields = dispatcher.apply();
|
||||
}
|
||||
if (StyleMacro.has(ct)) {
|
||||
modify = true;
|
||||
var style = new StyleMacro(ct, fields);
|
||||
fields = style.apply();
|
||||
}
|
||||
processed.set(localName, true);
|
||||
modify ? fields : null;
|
||||
|
||||
@@ -15,7 +15,7 @@ abstract KeyType<T>(String) {
|
||||
}
|
||||
}
|
||||
|
||||
class Provider {
|
||||
@:singleton class Provider {
|
||||
|
||||
private static function key<T>(i:KeyType<T>, ?type:Dynamic):String {
|
||||
var result:String = Std.string(i);
|
||||
@@ -23,22 +23,40 @@ class Provider {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static var factories:Map<String, Class<Dynamic>> = new Map();
|
||||
private static var args:Map<String, Array<Dynamic>> = new Map();
|
||||
private static var instances:Map<String, Dynamic> = new Map();
|
||||
public var factories:Map<String, Class<Dynamic>>;
|
||||
private var args:Map<String, Array<Dynamic>>;
|
||||
private var instances:Map<String, Dynamic>;
|
||||
|
||||
public static function setFactory<T>(i:KeyType<T>, clazz:Class<T>, ?type:Dynamic, ?args:Array<Dynamic>):Void {
|
||||
var key = key(i, type);
|
||||
factories.set(key, clazz);
|
||||
if (args != null) Provider.args.set(key, args);
|
||||
public function new() {
|
||||
factories = new Map();
|
||||
args = new Map();
|
||||
instances = new Map();
|
||||
resolveDefaultFactories();
|
||||
}
|
||||
|
||||
public static function set<T>(i:KeyType<T>, instance:T, ?type:Dynamic):Void {
|
||||
macro static function resolveDefaultFactories() {
|
||||
var result = [];
|
||||
for (item in haxework.macro.ClassProvideMacro.bundle) {
|
||||
// ToDo: ClassType to Expr?
|
||||
var k = haxe.macro.Context.parse(haxe.macro.MacroStringTools.toDotPath(item.key.pack, item.key.name), haxe.macro.Context.currentPos());
|
||||
var v = haxe.macro.Context.parse(haxe.macro.MacroStringTools.toDotPath(item.value.pack, item.value.name), haxe.macro.Context.currentPos());
|
||||
result.push(macro setFactory(${k}, ${v}));
|
||||
}
|
||||
return macro $b{result};
|
||||
}
|
||||
|
||||
public function setFactory<T>(i:KeyType<T>, clazz:Class<T>, ?type:Dynamic, ?args:Array<Dynamic>):Void {
|
||||
var key = key(i, type);
|
||||
factories.set(key, clazz);
|
||||
if (args != null) this.args.set(key, args);
|
||||
}
|
||||
|
||||
public function set<T>(i:KeyType<T>, instance:T, ?type:Dynamic):Void {
|
||||
var key = key(i, type);
|
||||
instances.set(key, instance);
|
||||
}
|
||||
|
||||
public static function get<T>(i:KeyType<T>, ?type:Dynamic):T {
|
||||
public function get<T>(i:KeyType<T>, ?type:Dynamic):T {
|
||||
var key = key(i, type);
|
||||
if (instances.exists(key)) {
|
||||
return instances.get(key);
|
||||
@@ -47,12 +65,11 @@ class Provider {
|
||||
instances.set(key, instance);
|
||||
return instance;
|
||||
} else {
|
||||
return null;
|
||||
//throw 'Factory for "${key}" not found';
|
||||
throw 'Factory for "${key}" not found';
|
||||
}
|
||||
}
|
||||
|
||||
public static function build<T>(i:Class<T>, ?type:Dynamic):T {
|
||||
public function build<T>(i:Class<T>, ?type:Dynamic):T {
|
||||
var key = key(i, type);
|
||||
if (factories.exists(key)) {
|
||||
var instance:T = Type.createInstance(factories.get(key), args.exists(key) ? args.get(key) : []);
|
||||
@@ -62,7 +79,7 @@ class Provider {
|
||||
}
|
||||
}
|
||||
|
||||
public static function setProperty<T>(i:Class<T>, field:String, value:Dynamic, ?type:Dynamic):Void {
|
||||
public function setProperty<T>(i:Class<T>, field:String, value:Dynamic, ?type:Dynamic):Void {
|
||||
var o:Dynamic = get(i, type);
|
||||
if (o != null && Reflect.hasField(o, field)) {
|
||||
Reflect.setProperty(o, field, value);
|
||||
|
||||
@@ -2,9 +2,9 @@ package haxework.resources;
|
||||
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.MovieClip;
|
||||
import haxework.resources.Resources.ResMap;
|
||||
import haxework.resources.Resources;
|
||||
|
||||
interface IResources {
|
||||
@:provide(Resources) interface IResources {
|
||||
public var image(default, null):ResMap<BitmapData>;
|
||||
public var color(default, null):ResMap<Int>;
|
||||
public var movie(default, null):ResMap<MovieClip>;
|
||||
|
||||
@@ -30,7 +30,7 @@ class Root {
|
||||
this.autoSize = autoSize;
|
||||
Lib.current.addChild(view.content);
|
||||
if (Std.is(view, IGroupView)) {
|
||||
Provider.set(IGroupView, cast view);
|
||||
Provider.instance.set(IGroupView, cast view);
|
||||
}
|
||||
var content:DisplayObject = view.content;
|
||||
if (content.stage == null) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package haxework.view;
|
||||
|
||||
import haxework.view.form.InputView;
|
||||
import flash.Lib;
|
||||
import flash.display.Stage;
|
||||
import flash.display.DisplayObject;
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.geom.Rectangle;
|
||||
@@ -40,6 +41,12 @@ import haxework.view.theme.ITheme;
|
||||
|
||||
public var rect(get, null):Rectangle;
|
||||
|
||||
private var stage(get, null):Stage;
|
||||
|
||||
private function get_stage():Stage {
|
||||
return Lib.current.stage;
|
||||
}
|
||||
|
||||
public function new(content:C) {
|
||||
id = Type.getClassName(Type.getClass(this)) + counter++;
|
||||
size = new SizeSet();
|
||||
|
||||
@@ -9,6 +9,10 @@ import haxework.view.layout.VerticalLayout;
|
||||
|
||||
typedef Factory<D, V:IView<Dynamic>> = Int -> D -> V
|
||||
|
||||
class ActionDataView<D, V:IView<Dynamic>, A> extends DataView<D, V> {
|
||||
public var onDataAction(default, null):Signal2<D, A> = new Signal2();
|
||||
}
|
||||
|
||||
class DataView<D, V:IView<Dynamic>> extends GroupView {
|
||||
|
||||
public var data(default, set):Array<D>;
|
||||
|
||||
@@ -18,6 +18,7 @@ class ButtonView extends LabelView {
|
||||
public var disabled(default, set):Bool;
|
||||
public var state(get, null):ButtonState;
|
||||
public var onPress(default, null):Signal<ButtonView>;
|
||||
public var propagation(default, default):Bool;
|
||||
|
||||
private var overed:Bool;
|
||||
private var downed:Bool;
|
||||
@@ -26,6 +27,7 @@ class ButtonView extends LabelView {
|
||||
super();
|
||||
skin = new ButtonColorSkin();
|
||||
style = "button";
|
||||
propagation = true;
|
||||
overed = false;
|
||||
downed = false;
|
||||
state = ButtonState.UP;
|
||||
@@ -47,7 +49,7 @@ class ButtonView extends LabelView {
|
||||
|
||||
private function onMouseClick(event:MouseEvent):Void {
|
||||
#if js if (downed) { #end
|
||||
//event.stopImmediatePropagation();
|
||||
if (!propagation) event.stopImmediatePropagation();
|
||||
if (!disabled) onPress.emit(this);
|
||||
#if js } #end
|
||||
}
|
||||
|
||||
@@ -17,11 +17,13 @@ class FrameSwitcher extends GroupView {
|
||||
public var animateFactory(default, default):Class<IAnimate>;
|
||||
|
||||
private var animate:IAnimate;
|
||||
private var history:Array<{id:String, data:Dynamic}>;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
factory = new Map();
|
||||
frames = new Map();
|
||||
history = [];
|
||||
current = null;
|
||||
}
|
||||
|
||||
@@ -55,29 +57,33 @@ class FrameSwitcher extends GroupView {
|
||||
if (current == null) {
|
||||
throw 'frame "$id" not found';
|
||||
}
|
||||
addView(current);
|
||||
toUpdate();
|
||||
update();
|
||||
//ToDo:
|
||||
if (content.stage != null) {
|
||||
content.stage.focus = current.content;
|
||||
}
|
||||
current.onShow(data);
|
||||
if (animate != null) {
|
||||
animate.cancel();
|
||||
}
|
||||
animate = buildAnimate(current);
|
||||
if (animate != null && prev != null) {
|
||||
animate.start(function(_) {
|
||||
removePrev(prev);
|
||||
});
|
||||
animate.start(function(_) removePrev(prev));
|
||||
} else {
|
||||
removePrev(prev);
|
||||
}
|
||||
addView(current);
|
||||
toUpdate();
|
||||
update();
|
||||
focus(current);
|
||||
current.onShow(data);
|
||||
history.push({id:current.frameId, data:data});
|
||||
onSwitch.emit(current);
|
||||
return cast current;
|
||||
}
|
||||
|
||||
public function back():Void {
|
||||
if (history.length > 1) {
|
||||
history.pop();
|
||||
var item = history.pop();
|
||||
change(item.id, item.data);
|
||||
}
|
||||
}
|
||||
|
||||
private function removePrev(prev:Null<FrameView<Dynamic>>):Void {
|
||||
if (prev != null) {
|
||||
prev.onHide();
|
||||
|
||||
@@ -67,7 +67,7 @@ class OverflowControl {
|
||||
}
|
||||
|
||||
@:style(true) class GroupView extends SpriteView implements IGroupView {
|
||||
public var container(null, null):DisplayObjectContainer;
|
||||
public var container(default, null):DisplayObjectContainer;
|
||||
|
||||
public var views(default, set):Array<IView<Dynamic>>;
|
||||
@:style public var layout(default, default):ILayout;
|
||||
@@ -79,6 +79,7 @@ class OverflowControl {
|
||||
private var _mask:Sprite;
|
||||
private var scrollX(get, null):HScrollBarView;
|
||||
private var scrollY(get, null):VScrollBarView;
|
||||
private var maskEnable(default, set):Bool;
|
||||
|
||||
public var overflowControlX(default, null):OverflowControl;
|
||||
public var overflowControlY(default, null):OverflowControl;
|
||||
@@ -88,8 +89,6 @@ class OverflowControl {
|
||||
container = new Sprite();
|
||||
content.addChild(container);
|
||||
_mask = new Sprite();
|
||||
content.addChild(_mask);
|
||||
container.mask = _mask;
|
||||
this.layout = layout != null ? layout : new DefaultLayout();
|
||||
this.overflow = overflow != null ? overflow : new Overflow();
|
||||
views = [];
|
||||
@@ -101,6 +100,21 @@ class OverflowControl {
|
||||
content.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
|
||||
}
|
||||
|
||||
private function set_maskEnable(value:Bool):Bool {
|
||||
if (maskEnable != value) {
|
||||
maskEnable = value;
|
||||
if (maskEnable) {
|
||||
content.addChild(_mask);
|
||||
container.mask = _mask;
|
||||
} else {
|
||||
content.removeChild(_mask);
|
||||
container.mask = null;
|
||||
}
|
||||
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private function onMouseWheelEvent(event:MouseEvent):Void {
|
||||
if (overflowY > 1) {
|
||||
#if flash event.preventDefault(); #end
|
||||
@@ -130,8 +144,8 @@ class OverflowControl {
|
||||
|
||||
private function onTouchEnd(event:TouchEvent):Void {
|
||||
event.preventDefault();
|
||||
content.stage.removeEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
|
||||
content.stage.removeEventListener(TouchEvent.TOUCH_END, onTouchEnd);
|
||||
stage.removeEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
|
||||
stage.removeEventListener(TouchEvent.TOUCH_END, onTouchEnd);
|
||||
}
|
||||
|
||||
private function get_scrollX():HScrollBarView {
|
||||
@@ -157,10 +171,12 @@ class OverflowControl {
|
||||
}
|
||||
|
||||
public function set_overflowX(value:Float):Float {
|
||||
maskEnable = value > 1;
|
||||
return overflowX = overflowControlX.overflow = value;
|
||||
}
|
||||
|
||||
public function set_overflowY(value:Float):Float {
|
||||
maskEnable = value > 1;
|
||||
return overflowY = overflowControlY.overflow = value;
|
||||
}
|
||||
|
||||
@@ -177,7 +193,9 @@ class OverflowControl {
|
||||
overflowControlY.size = height;
|
||||
_mask.graphics.clear();
|
||||
_mask.graphics.beginFill(0, 1);
|
||||
if (!Math.isNaN(width) && !Math.isNaN(height) && width > 0 && height > 0) {
|
||||
_mask.graphics.drawRect(0, 0, width, height);
|
||||
}
|
||||
_mask.graphics.endFill();
|
||||
}
|
||||
|
||||
@@ -235,6 +253,12 @@ class OverflowControl {
|
||||
}
|
||||
}
|
||||
|
||||
public function focus(?view:IView<Dynamic>):Void {
|
||||
if (container.stage != null) {
|
||||
container.stage.focus = view != null ? view.content : content;
|
||||
}
|
||||
}
|
||||
|
||||
override private function get_rect():Rectangle {
|
||||
var result = super.get_rect();
|
||||
result.x += overflowControlX.offset;
|
||||
|
||||
@@ -11,7 +11,7 @@ interface IGroupView extends IView<Dynamic> {
|
||||
public var overflowX(default, set):Float;
|
||||
public var overflowY(default, set):Float;
|
||||
|
||||
public var container(null, null):DisplayObjectContainer;
|
||||
public var container(default, null):DisplayObjectContainer;
|
||||
public var views(default, set):Array<IView<Dynamic>>;
|
||||
|
||||
public function containsView(view:IView<Dynamic>):Bool;
|
||||
@@ -25,4 +25,6 @@ interface IGroupView extends IView<Dynamic> {
|
||||
public function removeView(view:IView<Dynamic>):IView<Dynamic>;
|
||||
|
||||
public function removeAllViews():Void;
|
||||
|
||||
public function focus(?view:IView<Dynamic>):Void;
|
||||
}
|
||||
|
||||
@@ -35,16 +35,18 @@ class DefaultLayout extends Layout {
|
||||
},
|
||||
"group"
|
||||
);
|
||||
switch group.overflow.x {
|
||||
var ox = switch group.overflow.x {
|
||||
case SCROLL:
|
||||
group.overflowX = width / (group.width - group.geometry.padding.horizontal);
|
||||
case _:
|
||||
width / (group.width - group.geometry.padding.horizontal);
|
||||
case _: 1;
|
||||
}
|
||||
switch group.overflow.y {
|
||||
group.overflowX = ox;
|
||||
var oy = switch group.overflow.y {
|
||||
case SCROLL:
|
||||
group.overflowY = height / (group.height - group.geometry.padding.vertical);
|
||||
case _:
|
||||
height / (group.height - group.geometry.padding.vertical);
|
||||
case _: 1;
|
||||
}
|
||||
group.overflowY = oy;
|
||||
}
|
||||
|
||||
private function filterViews(group:IGroupView, views:Array<IView<Dynamic>>):Array<IView<Dynamic>> {
|
||||
|
||||
@@ -11,17 +11,19 @@ typedef Row = {
|
||||
|
||||
class TailLayout extends DefaultLayout {
|
||||
|
||||
public var rowSize:Int = 0;
|
||||
@:style(0) public var rowSize:Null<Int>;
|
||||
@:style(false) public var stretch:Null<Bool>;
|
||||
|
||||
private function placeRow(group:IGroupView, y:Float, row:Row):Void {
|
||||
var x:Float = (group.width - row.width) / 2;
|
||||
for (v in row.views) {
|
||||
v.x = x;
|
||||
v.y = switch group.layout.vAlign {
|
||||
var vy = switch group.layout.vAlign {
|
||||
case TOP | NONE: y;
|
||||
case MIDDLE: y + (row.height - v.height) / 2;
|
||||
case BOTTOM: y + (row.height - v.height);
|
||||
}
|
||||
v.y = vy;
|
||||
x += v.width + margin;
|
||||
}
|
||||
}
|
||||
@@ -40,7 +42,7 @@ class TailLayout extends DefaultLayout {
|
||||
setViewHeight(group, view);
|
||||
if (
|
||||
(rowSize > 0 && row.views.length >= rowSize) ||
|
||||
(/*rowSize == 0 && */row.width + view.width + margin + group.geometry.margin.horizontal > size.width)
|
||||
(/*rowSize == 0 && */row.width + view.width + margin + group.geometry.margin.horizontal > size.width && !stretch)
|
||||
) {
|
||||
row.width -= margin;
|
||||
w = Math.max(w, row.width);
|
||||
|
||||
@@ -180,6 +180,13 @@ class ListView<D> extends GroupView {
|
||||
item.visible = true;
|
||||
item.item_index = index;
|
||||
item.data = filteredData[item.item_index];
|
||||
if (
|
||||
selected != null && selected.indexOf(item.data) > -1 ?
|
||||
item.style.add("selected") :
|
||||
item.style.remove("selected")
|
||||
) {
|
||||
item.style = item.style;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
21
src/main/haxework/view/popup/AlertView.hx
Normal file
21
src/main/haxework/view/popup/AlertView.hx
Normal file
@@ -0,0 +1,21 @@
|
||||
package haxework.view.popup;
|
||||
|
||||
import haxework.view.form.LabelView;
|
||||
import haxework.view.text.TextView;
|
||||
import promhx.Promise;
|
||||
|
||||
@:template class AlertView extends PopupView<Dynamic> {
|
||||
|
||||
@:view var header:LabelView;
|
||||
@:view var message:TextView;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static function alert(message:String):Promise<Dynamic> {
|
||||
var result = new AlertView();
|
||||
result.message.text = message;
|
||||
return result.show();
|
||||
}
|
||||
}
|
||||
31
src/main/haxework/view/popup/AlertView.yaml
Normal file
31
src/main/haxework/view/popup/AlertView.yaml
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
view:
|
||||
$type: haxework.view.group.VGroupView
|
||||
geometry.width: 400
|
||||
geometry.height: 200
|
||||
geometry.padding: 10
|
||||
geometry.hAlign: center
|
||||
geometry.vAlign: middle
|
||||
style: frame
|
||||
views:
|
||||
- $type: haxework.view.group.HGroupView
|
||||
geometry.width: 100%
|
||||
layout.margin: 10
|
||||
views:
|
||||
- id: header
|
||||
$type: haxework.view.form.LabelView
|
||||
- id: message
|
||||
$type: haxework.view.form.LabelView
|
||||
font.align: CENTER
|
||||
layout.hAlign: center
|
||||
layout.vAlign: middle
|
||||
geometry.width: 100%
|
||||
geometry.height: 100%
|
||||
- $type: haxework.view.group.HGroupView
|
||||
geometry.width: 100%
|
||||
layout.hAlign: center
|
||||
layout.margin: 10
|
||||
views:
|
||||
- $type: haxework.view.form.ButtonView
|
||||
text: OK
|
||||
+onPress: ~close('ok')
|
||||
21
src/main/haxework/view/popup/ConfirmView.hx
Normal file
21
src/main/haxework/view/popup/ConfirmView.hx
Normal file
@@ -0,0 +1,21 @@
|
||||
package haxework.view.popup;
|
||||
|
||||
import haxework.view.form.LabelView;
|
||||
import haxework.view.text.TextView;
|
||||
import promhx.Promise;
|
||||
|
||||
@:template class ConfirmView extends PopupView<Bool> {
|
||||
|
||||
@:view var header:LabelView;
|
||||
@:view var message:TextView;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static function confirm(message:String):Promise<Bool> {
|
||||
var result = new ConfirmView();
|
||||
result.message.text = message;
|
||||
return result.show();
|
||||
}
|
||||
}
|
||||
34
src/main/haxework/view/popup/ConfirmView.yaml
Normal file
34
src/main/haxework/view/popup/ConfirmView.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
view:
|
||||
$type: haxework.view.group.VGroupView
|
||||
geometry.width: 400
|
||||
geometry.height: 200
|
||||
geometry.padding: 10
|
||||
geometry.hAlign: center
|
||||
geometry.vAlign: middle
|
||||
style: frame
|
||||
views:
|
||||
- $type: haxework.view.group.HGroupView
|
||||
geometry.width: 100%
|
||||
layout.margin: 10
|
||||
views:
|
||||
- id: header
|
||||
$type: haxework.view.form.LabelView
|
||||
- id: message
|
||||
$type: haxework.view.form.LabelView
|
||||
font.align: CENTER
|
||||
layout.hAlign: center
|
||||
layout.vAlign: middle
|
||||
geometry.width: 100%
|
||||
geometry.height: 100%
|
||||
- $type: haxework.view.group.HGroupView
|
||||
geometry.width: 100%
|
||||
layout.hAlign: center
|
||||
layout.margin: 10
|
||||
views:
|
||||
- $type: haxework.view.form.ButtonView
|
||||
text: Yes
|
||||
+onPress: ~close(true)
|
||||
- $type: haxework.view.form.ButtonView
|
||||
text: No
|
||||
+onPress: ~reject('no')
|
||||
@@ -5,7 +5,7 @@ import haxework.animate.IAnimate;
|
||||
|
||||
typedef P = PopupView<Dynamic>;
|
||||
|
||||
class PopupManager {
|
||||
@:provide class PopupManager {
|
||||
|
||||
public var showAnimateFactory(default, default):IView<Dynamic> -> IAnimate;
|
||||
public var closeAnimateFactory(default, default):IView<Dynamic> -> IAnimate;
|
||||
@@ -38,6 +38,7 @@ class PopupManager {
|
||||
public function remove(popup:P):Void {
|
||||
if (root.containsView(popup)) {
|
||||
root.removeView(popup);
|
||||
root.focus();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,20 +56,22 @@ class PopupView<R> extends GroupView {
|
||||
}
|
||||
|
||||
public function close(result:R):Void {
|
||||
var d = deferred;
|
||||
deferred = null;
|
||||
manager.close(this);
|
||||
onClose();
|
||||
if (deferred != null) {
|
||||
deferred.resolve(result);
|
||||
deferred = null;
|
||||
if (d != null) {
|
||||
d.resolve(result);
|
||||
}
|
||||
}
|
||||
|
||||
public function reject(reason:Dynamic):Void {
|
||||
manager.close(this);
|
||||
if (deferred != null) {
|
||||
//deferred.throwError(reason);
|
||||
deferred.resolve(null);
|
||||
var d = deferred;
|
||||
deferred = null;
|
||||
manager.close(this);
|
||||
if (d != null) {
|
||||
//d.throwError(reason);
|
||||
d.resolve(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,10 @@ using haxework.color.ColorUtil;
|
||||
|
||||
@:style(0xffffff) public var color(default, default):Null<Color>;
|
||||
@:style(null) public var borderColor(default, default):Null<Color>;
|
||||
public var round(default, default):Float;
|
||||
@:style(15) public var round(default, default):Null<Float>;
|
||||
private var colors:Map<ButtonState, Int>;
|
||||
|
||||
public function new(?color:Color, ?borderColor:Color, round:Float = 15) {
|
||||
public function new(?color:Color, ?borderColor:Color, ?round:Float) {
|
||||
this.color = color;
|
||||
this.borderColor = borderColor;
|
||||
this.round = round;
|
||||
|
||||
@@ -6,10 +6,12 @@ import flash.display.Graphics;
|
||||
|
||||
@:style public var border(default, default):Border;
|
||||
@:style public var background(default, default):Background;
|
||||
@:style(null) public var round(default, default):Null<Float>;
|
||||
|
||||
public function new(?background:Background, ?border:Border) {
|
||||
public function new(?background:Background, ?border:Border, ?round:Float) {
|
||||
this.background = background != null ? background : new Background();
|
||||
this.border = border != null ? border : new Border();
|
||||
this.round = round;
|
||||
}
|
||||
|
||||
public function draw(view:SpriteView):Void {
|
||||
@@ -24,7 +26,11 @@ import flash.display.Graphics;
|
||||
graphics.beginFill(0, 0);
|
||||
}
|
||||
var o = border.color != null ? border.thickness / 2 : 0;
|
||||
if (round != null) {
|
||||
graphics.drawRoundRect(o, o, view.width - o * 2, view.height - o * 2, round, round);
|
||||
} else {
|
||||
graphics.drawRect(o, o, view.width - o * 2, view.height - o * 2);
|
||||
}
|
||||
graphics.lineStyle();
|
||||
graphics.endFill();
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ import haxework.view.list.ScrollBarView;
|
||||
graphics.drawRect(0, 0, view.width, view.height);
|
||||
graphics.beginFill(foreColor);
|
||||
graphics.lineStyle();
|
||||
if (!Math.isNaN(position) && !Math.isNaN(size)) {
|
||||
graphics.drawRect(0, position, view.width, size);
|
||||
}
|
||||
graphics.endFill();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,27 @@ abstract StyleId(Array<String>) {
|
||||
this = value != null ? value : [];
|
||||
}
|
||||
|
||||
public function add(value:String):Bool {
|
||||
if (this.indexOf(value) == -1) {
|
||||
this.push(value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public inline function remove(value:String):Bool {
|
||||
return this.remove(value);
|
||||
}
|
||||
|
||||
public function match(value:StyleId):Bool {
|
||||
for (v in value.toArray()) {
|
||||
if (this.indexOf(v) == -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@:to public inline function toArray():Array<String> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package haxework.view.theme;
|
||||
|
||||
import haxework.view.geometry.VAlign;
|
||||
import haxework.view.geometry.HAlign;
|
||||
import flash.text.Font;
|
||||
import flash.text.FontType;
|
||||
import haxework.color.Color;
|
||||
import haxework.signal.Signal;
|
||||
import haxework.view.geometry.Box;
|
||||
import haxework.view.geometry.HAlign;
|
||||
import haxework.view.geometry.SizeValue;
|
||||
import haxework.view.geometry.VAlign;
|
||||
import haxework.view.skin.TabColorSkin;
|
||||
import haxework.view.theme.ITheme;
|
||||
|
||||
@@ -25,19 +25,68 @@ class Style {
|
||||
}
|
||||
}
|
||||
|
||||
class StyleBundle {
|
||||
|
||||
private var data:Map<String, Map<String, Dynamic>>;
|
||||
private var parentMap:Map<String, String>;
|
||||
|
||||
public function new() {
|
||||
data = new Map();
|
||||
parentMap = new Map();
|
||||
}
|
||||
|
||||
public function register(style:Style):Void {
|
||||
for (key in style.data.keys()) {
|
||||
if (!data.exists(key)) {
|
||||
data.set(key, new Map());
|
||||
}
|
||||
data.get(key).set(style.id, style.data.get(key));
|
||||
}
|
||||
if (style.parent != null) {
|
||||
parentMap.set(style.id, style.parent);
|
||||
}
|
||||
}
|
||||
|
||||
public function get(key:String, id:StyleId):Null<Dynamic> {
|
||||
var result = null;
|
||||
if (data.exists(key)) {
|
||||
var bundle:Map<String, Dynamic> = data.get(key);
|
||||
var length = 0;
|
||||
for (key in bundle.keys()) {
|
||||
if (id.match(key) && key.length > length) {
|
||||
result = bundle.get(key);
|
||||
length = key.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result == null) {
|
||||
if (parentMap.exists(id)) {
|
||||
var parentId:StyleId = parentMap.get(id);
|
||||
for (pId in parentId.toArray()) {
|
||||
result = get(key, pId);
|
||||
if (result != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class Theme implements ITheme {
|
||||
public var font(default, set):ThemeFont;
|
||||
public var fontSize(default, set):ThemeFontSize;
|
||||
public var colors(default, set):ThemeColors;
|
||||
public var updateSignal(default, null):Signal0;
|
||||
|
||||
private var data:Map<String, Style>;
|
||||
private var cache:Map<String, Dynamic>;
|
||||
private var bundle:StyleBundle;
|
||||
|
||||
public function new(?font:ThemeFont, ?colors:ThemeColors, ?fontSize:ThemeFontSize) {
|
||||
updateSignal = new Signal0();
|
||||
data = new Map();
|
||||
cache = new Map();
|
||||
bundle = new StyleBundle();
|
||||
this.font = font;
|
||||
this.colors = colors;
|
||||
this.fontSize = fontSize;
|
||||
@@ -79,7 +128,7 @@ class Theme implements ITheme {
|
||||
}
|
||||
|
||||
private function register(style:Style):Void {
|
||||
data.set(style.id, style);
|
||||
bundle.register(style);
|
||||
}
|
||||
|
||||
private function reload():Void {
|
||||
@@ -104,6 +153,12 @@ class Theme implements ITheme {
|
||||
register(new Style("text1", [
|
||||
"skin.background.color" => colors.light.diff(16),
|
||||
], ["text"]));
|
||||
register(new Style("text0.selected", [
|
||||
"font.color" => colors.active,
|
||||
], ["text0"]));
|
||||
register(new Style("text1.selected", [
|
||||
"font.color" => colors.active,
|
||||
], ["text1"]));
|
||||
register(new Style("label", [
|
||||
"geometry.padding" => Box.fromArray([8, 2]),
|
||||
], ["text"]));
|
||||
@@ -142,20 +197,8 @@ class Theme implements ITheme {
|
||||
]));
|
||||
}
|
||||
|
||||
private function _resolve<T>(key:String, style:Style):Null<T> {
|
||||
if (style == null) {
|
||||
return null;
|
||||
} else if (style.data.exists(key)) {
|
||||
return style.data.get(key);
|
||||
} else if (style.parent != null) {
|
||||
for (s in style.parent.toArray()) {
|
||||
var result = _resolve(key, data.get(s));
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
private function _resolve<T>(key:String, style:StyleId):Null<T> {
|
||||
return bundle.get(key, style);
|
||||
}
|
||||
|
||||
public function resolve<T>(key:String, style:StyleId):T {
|
||||
@@ -165,7 +208,7 @@ class Theme implements ITheme {
|
||||
if (cache.exists(k)) {
|
||||
result = cache.get(k);
|
||||
} else {
|
||||
result = _resolve(key, data.get(style));
|
||||
result = _resolve(key, style);
|
||||
cache.set(k, result);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user