Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a6f7841e1 | |||
| 4a7403022b | |||
| 163e6d68c3 | |||
| f396c86a23 | |||
| e5f8d7834a | |||
| a4ca9a924c | |||
| 88b4459023 | |||
| ccfa8c05f8 | |||
| 4017df4d00 | |||
| fe60e78b74 | |||
| 279baa1113 | |||
| 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
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@ out/
|
|||||||
target/
|
target/
|
||||||
*.zip
|
*.zip
|
||||||
pack.sh
|
pack.sh
|
||||||
|
.vscode/
|
||||||
|
|||||||
55
README.md
55
README.md
@@ -1,43 +1,42 @@
|
|||||||
# haxework
|
# HaxeWork
|
||||||
|
|
||||||
Gui framework for Haxe.
|
HaXe framework.
|
||||||
|
|
||||||
## View
|
## View
|
||||||
|
|
||||||
`haxework.gui` provides views classes.
|
`hw.view` provides views classes.
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
Build form using macro @:template.
|
Build form using macro @:template.
|
||||||
|
|
||||||
form.json:
|
form.yaml:
|
||||||
|
|
||||||
```json
|
```yaml
|
||||||
{
|
---
|
||||||
"$type": "haxework.gui.VGroupView",
|
skin:
|
||||||
"skin": [{"$type": "haxework.gui.skin.ColorSkin", "color": "0xffff00"}],
|
- $type: hw.gui.skin.ColorSkin
|
||||||
"geometry.padding": 20,
|
color: 0xffff00
|
||||||
"layout.margin": 10,
|
geometry.padding: 20
|
||||||
"views":[
|
layout.margin: 10
|
||||||
{
|
views:
|
||||||
"id": "view1",
|
- id: view1
|
||||||
"type":"haxework.gui.SpriteView",
|
type: hw.view.SpriteView
|
||||||
"geometry.size.stretch": true,
|
geometry.size.stretch: true
|
||||||
"skin":[{"$type":"haxework.gui.skin.ColorSkin", "color": "0xff0000"}]
|
skin:
|
||||||
},
|
- $type: hw.view.skin.ColorSkin
|
||||||
{
|
color: 0xff0000
|
||||||
"id": "view2",
|
- id: view2
|
||||||
"type": "haxework.gui.SpriteView",
|
type: hw.view.SpriteView
|
||||||
"geometry.size.width": "100%",
|
geometry.size.width: 100%
|
||||||
"geometry.size.height": 50,
|
geometry.size.height: 50
|
||||||
"skin": [{"$type":"haxework.gui.skin.ColorSkin", "color": "0x00ff00"}]
|
skin:
|
||||||
}
|
- "$type": hw.view.skin.ColorSkin
|
||||||
]
|
color: 0x00ff00
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```haxe
|
```haxe
|
||||||
@:template("form.json")
|
@:template("form.yaml")
|
||||||
class FormView extends VGroupView {
|
class FormView extends VGroupView {
|
||||||
@:view public var view1:SpriteView;
|
@:view public var view1:SpriteView;
|
||||||
@:view("view2") public var anyVarName:SpriteView;
|
@:view("view2") public var anyVarName:SpriteView;
|
||||||
@@ -51,7 +50,7 @@ trace(form.anyVarName);
|
|||||||
|
|
||||||
## Loader
|
## Loader
|
||||||
|
|
||||||
`haxework.net` provides loaders classes.
|
`hw.net` provides loaders classes.
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
|
|||||||
1
build.hxml
Normal file
1
build.hxml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-p src/main
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
-cp src
|
-cp src
|
||||||
-cp ../src/main
|
#-cp ../src/main
|
||||||
-lib yaml
|
-lib yaml
|
||||||
-lib promhx
|
-lib promhx
|
||||||
--macro haxework.parser.Parser.auto()
|
-lib haxework
|
||||||
|
--macro hw.parser.Parser.auto()
|
||||||
-debug
|
-debug
|
||||||
-D native_trace
|
-D native_trace
|
||||||
#-D dev_layout
|
#-D dev_layout
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<project>
|
<project>
|
||||||
<meta title="Demo" package="haxework.demo" version="1.0.0" company="MegaLoMania"/>
|
<meta title="Demo" package="hw.demo" version="1.0.0" company="MegaLoMania"/>
|
||||||
<app main="demo.Demo" path="target" file="demo"/>
|
<app main="demo.Demo" path="target" file="demo"/>
|
||||||
<icon path="src/haxe-logo.png"/>
|
<icon path="src/haxe-logo.png"/>
|
||||||
|
|
||||||
@@ -8,13 +8,13 @@
|
|||||||
<source path="src"/>
|
<source path="src"/>
|
||||||
<assets path="src" rename="image" include="*.png"/>
|
<assets path="src" rename="image" include="*.png"/>
|
||||||
|
|
||||||
<haxelib name="lime" version="7.3.0"/>
|
<haxelib name="lime" version=""/>
|
||||||
<haxelib name="openfl" version="8.9.0"/>
|
<haxelib name="openfl" version=""/>
|
||||||
<haxelib name="hxcpp" version="4.0.8"/>
|
<haxelib name="hxcpp" version=""/>
|
||||||
<haxelib name="promhx" version="1.1.0"/>
|
<!--<haxelib name="promhx" version=""/>-->
|
||||||
<haxelib name="yaml" version="1.3.0"/>
|
<haxelib name="haxework" version="git"/>
|
||||||
|
|
||||||
<haxeflag name="--macro" value="haxework.parser.Parser.auto()"/>
|
<!--<haxeflag name="--macro" value="hw.parser.Parser.auto()"/>-->
|
||||||
<haxeflag name="--macro" value="CompilationOption.set('build','xxx')"/>
|
<haxeflag name="--macro" value="CompilationOption.set('build','xxx')"/>
|
||||||
|
|
||||||
<window fps="30"/>
|
<window fps="30"/>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
SDK_PATH=~/sdk
|
||||||
echo "`pwd`/target" > ~/.macromedia/Flash_Player/#Security/FlashPlayerTrust/haxework_demo.cfg
|
echo "`pwd`/target" > ~/.macromedia/Flash_Player/#Security/FlashPlayerTrust/haxework_demo.cfg
|
||||||
. /opt/sdk/neko/2.2.0/activate
|
. ${SDK_PATH}/neko/2.2.0/activate
|
||||||
. /opt/sdk/haxe/3.4.7/activate
|
. ${SDK_PATH}/haxe/4.0.5/activate
|
||||||
haxe build.hxml && flashplayerdebugger target/demo.swf &
|
haxe build.hxml && ${SDK_PATH}/flashplayer/32/flashplayerdebugger target/demo.swf &
|
||||||
tail -f ~/.macromedia/Flash_Player/Logs/flashlog.txt
|
tail -f ~/.macromedia/Flash_Player/Logs/flashlog.txt
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
SDK_PATH=~/sdk
|
||||||
echo "`pwd`/target/flash/bin" > ~/.macromedia/Flash_Player/#Security/FlashPlayerTrust/haxework_demo.cfg
|
echo "`pwd`/target/flash/bin" > ~/.macromedia/Flash_Player/#Security/FlashPlayerTrust/haxework_demo.cfg
|
||||||
. /opt/sdk/neko/2.2.0/activate
|
. ${SDK_PATH}/neko/2.2.0/activate
|
||||||
. /opt/sdk/haxe/3.4.7/activate
|
. ${SDK_PATH}/haxe/4.0.5/activate
|
||||||
haxelib run openfl test flash
|
#haxelib run openfl test flash
|
||||||
|
haxelib run openfl test html5
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package demo;
|
package demo;
|
||||||
|
|
||||||
import haxework.view.geometry.Box;
|
import hw.view.geometry.Box;
|
||||||
import haxework.color.Color;
|
import hw.color.Color;
|
||||||
import haxework.view.theme.Theme;
|
import hw.view.theme.Theme;
|
||||||
|
|
||||||
using haxework.color.ColorUtil;
|
using hw.color.ColorUtil;
|
||||||
|
|
||||||
class AppTheme extends Theme {
|
class AppTheme extends Theme {
|
||||||
|
|
||||||
|
|||||||
@@ -3,19 +3,22 @@ package demo;
|
|||||||
import demo.dispatch.DemoDispatcher;
|
import demo.dispatch.DemoDispatcher;
|
||||||
import demo.popup.ColorPopup;
|
import demo.popup.ColorPopup;
|
||||||
import demo.popup.FontPopup;
|
import demo.popup.FontPopup;
|
||||||
import haxework.App;
|
import demo.storage.TestStorage;
|
||||||
import haxework.log.TraceLogger;
|
import hw.app.App;
|
||||||
import haxework.net.JsonLoader;
|
import hw.log.TraceLogger;
|
||||||
import haxework.view.data.ButtonGroup;
|
import hw.net.JsonLoader;
|
||||||
import haxework.view.frame.FrameSwitcher;
|
import hw.resources.IResources;
|
||||||
import haxework.view.frame.FrameView;
|
import hw.view.data.ButtonGroup;
|
||||||
import haxework.view.group.VGroupView;
|
import hw.view.frame.FrameSwitcher;
|
||||||
|
import hw.view.frame.FrameView;
|
||||||
|
import hw.view.group.VGroupView;
|
||||||
|
|
||||||
@:template class DemoView extends VGroupView {
|
@:template class DemoView extends VGroupView {
|
||||||
@:view var switcher:FrameSwitcher;
|
@:view var switcher:FrameSwitcher;
|
||||||
@:view var tabs:ButtonGroup<String>;
|
@:view var tabs:ButtonGroup<String>;
|
||||||
|
|
||||||
private function init():Void {
|
public function new():Void {
|
||||||
|
super();
|
||||||
switcher.change("list");
|
switcher.change("list");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,12 +45,18 @@ import haxework.view.group.VGroupView;
|
|||||||
|
|
||||||
class Demo extends App implements DemoListener {
|
class Demo extends App implements DemoListener {
|
||||||
|
|
||||||
|
@:provide static var storage:TestStorage;
|
||||||
|
|
||||||
public static function main() {
|
public static function main() {
|
||||||
L.push(new TraceLogger());
|
L.push(new TraceLogger());
|
||||||
|
|
||||||
var app = new Demo(new AppTheme());
|
App.resources.image.put("logo", HaxeLogo.resolve());
|
||||||
app.resources.image.put("logo", HaxeLogo.resolve());
|
var app = new Demo();
|
||||||
app.start(new DemoView());
|
app.theme = new AppTheme();
|
||||||
|
app.icon = App.resources.image.get("logo");
|
||||||
|
app.view = new DemoView();
|
||||||
|
trace(storage);
|
||||||
|
storage.write("test", "value");
|
||||||
|
|
||||||
var dispatcher = new DemoDispatcher();
|
var dispatcher = new DemoDispatcher();
|
||||||
dispatcher.connect(app);
|
dispatcher.connect(app);
|
||||||
@@ -63,8 +72,8 @@ class Demo extends App implements DemoListener {
|
|||||||
|
|
||||||
new JsonLoader().GET("https://embed.tvbit.co/channel/data2/renova.json")
|
new JsonLoader().GET("https://embed.tvbit.co/channel/data2/renova.json")
|
||||||
.then(function(data:Array<Model>) {
|
.then(function(data:Array<Model>) {
|
||||||
app.resources.any.put("data", data);
|
App.resources.any.put("data", data);
|
||||||
app.resources.any.put("data50", Util.marray(data, 50));
|
App.resources.any.put("data50", Util.marray(data, 50));
|
||||||
})
|
})
|
||||||
.catchError(function(error) trace(error));
|
.catchError(function(error) trace(error));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
---
|
---
|
||||||
style: background
|
style: background
|
||||||
views:
|
views:
|
||||||
- $type: haxework.view.ImageView
|
- $type: hw.view.ImageView
|
||||||
geometry.padding: 10
|
geometry.padding: 10
|
||||||
image: $r:image:logo
|
image: $r:image:logo
|
||||||
- id: tabs
|
- id: tabs
|
||||||
$type: haxework.view.data.ButtonGroup<String>
|
$type: hw.view.data.ButtonGroup<String>
|
||||||
layout.margin: 5
|
layout.margin: 5
|
||||||
layout.hAlign: left
|
layout.hAlign: left
|
||||||
geometry.width: 100%
|
geometry.width: 100%
|
||||||
@@ -20,8 +20,8 @@ views:
|
|||||||
- "test_layout"
|
- "test_layout"
|
||||||
- "select"
|
- "select"
|
||||||
- id: switcher
|
- id: switcher
|
||||||
$type: haxework.view.frame.FrameSwitcher
|
$type: hw.view.frame.FrameSwitcher
|
||||||
animateFactory: { $class: haxework.animate.SlideAnimate }
|
animateFactory: { $class: hw.animate.SlideAnimate }
|
||||||
+onSwitch: ~onFrameSwitch
|
+onSwitch: ~onFrameSwitch
|
||||||
geometry.stretch: true
|
geometry.stretch: true
|
||||||
geometry.padding: 5
|
geometry.padding: 5
|
||||||
@@ -31,24 +31,24 @@ views:
|
|||||||
_data_: {$class: demo.form.DataForm}
|
_data_: {$class: demo.form.DataForm}
|
||||||
_test_layout_: {$class: demo.form.TestLayoutForm}
|
_test_layout_: {$class: demo.form.TestLayoutForm}
|
||||||
_select_: {$class: demo.form.SelectForm}
|
_select_: {$class: demo.form.SelectForm}
|
||||||
- $type: haxework.view.group.HGroupView
|
- $type: hw.view.group.HGroupView
|
||||||
geometry.width: 100%
|
geometry.width: 100%
|
||||||
geometry.padding: 10
|
geometry.padding: 10
|
||||||
layout.margin: 10
|
layout.margin: 10
|
||||||
views:
|
views:
|
||||||
- $type: haxework.view.form.ButtonView
|
- $type: hw.view.form.ButtonView
|
||||||
text: Color
|
text: Color
|
||||||
+onPress: ~choiceColor()
|
+onPress: ~choiceColor()
|
||||||
- $type: haxework.view.form.ButtonView
|
- $type: hw.view.form.ButtonView
|
||||||
text: Font
|
text: Font
|
||||||
+onPress: ~choiceFont()
|
+onPress: ~choiceFont()
|
||||||
# separator
|
# separator
|
||||||
- $type: haxework.view.SpriteView
|
- $type: hw.view.SpriteView
|
||||||
geometry.stretch: true
|
geometry.stretch: true
|
||||||
- $type: haxework.view.form.ButtonView
|
- $type: hw.view.form.ButtonView
|
||||||
text: OK
|
text: OK
|
||||||
- $type: haxework.view.form.ButtonView
|
- $type: hw.view.form.ButtonView
|
||||||
text: Apply
|
text: Apply
|
||||||
- $type: haxework.view.form.ButtonView
|
- $type: hw.view.form.ButtonView
|
||||||
text: Cancel
|
text: Cancel
|
||||||
+onPress: ~flash.system.System.exit(0)
|
+onPress: ~flash.system.System.exit(0)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package demo;
|
package demo;
|
||||||
|
|
||||||
import demo.test.TestView;
|
import demo.test.TestView;
|
||||||
import haxework.view.Root;
|
import hw.view.Root;
|
||||||
import haxework.view.SpriteView;
|
import hw.view.SpriteView;
|
||||||
|
|
||||||
class Test {
|
class Test {
|
||||||
public static function main():Void {
|
public static function main():Void {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package demo.dispatch;
|
package demo.dispatch;
|
||||||
|
|
||||||
import haxework.App;
|
import hw.app.App;
|
||||||
|
|
||||||
interface DemoListener {
|
interface DemoListener {
|
||||||
public function onTest1():Void;
|
public function onTest1():Void;
|
||||||
@@ -9,6 +9,6 @@ interface DemoListener {
|
|||||||
public function onTest4(app:App):Void;
|
public function onTest4(app:App):Void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@:yield @:dispatcher(DemoListener) class DemoDispatcher {
|
@:dispatcher(DemoListener) class DemoDispatcher {
|
||||||
public function new() {}
|
public function new() {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package demo.form;
|
package demo.form;
|
||||||
|
|
||||||
import haxework.view.frame.FrameView;
|
import hw.view.frame.FrameView;
|
||||||
import haxework.view.text.TextView;
|
import hw.view.text.TextView;
|
||||||
|
|
||||||
@:template class DataForm extends FrameView<Dynamic> {
|
@:template class DataForm extends FrameView<Dynamic> {
|
||||||
public function new() {
|
public function new() {
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
overflow.y: scroll
|
overflow.y: scroll
|
||||||
views:
|
views:
|
||||||
- id: data
|
- id: data
|
||||||
$type: haxework.view.data.DataView
|
$type: hw.view.data.DataView
|
||||||
layout:
|
layout:
|
||||||
$type: haxework.view.layout.VerticalLayout
|
$type: hw.view.layout.VerticalLayout
|
||||||
factory: ~factory
|
factory: ~factory
|
||||||
geometry.width: 100%
|
geometry.width: 100%
|
||||||
data: $r:any:data
|
data: $r:any:data
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package demo.form;
|
package demo.form;
|
||||||
|
|
||||||
import haxework.view.frame.FrameView;
|
import hw.view.frame.FrameView;
|
||||||
import haxework.view.list.LabelListItem;
|
import hw.view.list.LabelListItem;
|
||||||
import haxework.view.list.ListView.IListItemView;
|
import hw.view.list.ListView.IListItemView;
|
||||||
import haxework.view.list.VListView;
|
import hw.view.list.VListView;
|
||||||
|
|
||||||
@:template class ListForm extends FrameView<Dynamic> {
|
@:template class ListForm extends FrameView<Dynamic> {
|
||||||
@:view public var list(default, null):VListView<Model>;
|
@:view public var list(default, null):VListView<Model>;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
views:
|
views:
|
||||||
- id: list
|
- id: list
|
||||||
$type: haxework.view.list.VListView
|
$type: hw.view.list.VListView
|
||||||
+onItemSelect: ~onItemSelect
|
+onItemSelect: ~onItemSelect
|
||||||
factory: ~factory
|
factory: ~factory
|
||||||
geometry.stretch: true
|
geometry.stretch: true
|
||||||
scroll:
|
scroll:
|
||||||
$type: haxework.view.list.VScrollBarView
|
$type: hw.view.list.VScrollBarView
|
||||||
data: $r:any:data50
|
data: $r:any:data50
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package demo.form;
|
package demo.form;
|
||||||
|
|
||||||
import haxework.view.frame.FrameView;
|
import hw.view.frame.FrameView;
|
||||||
|
|
||||||
@:template class SelectForm extends FrameView<Dynamic> {
|
@:template class SelectForm extends FrameView<Dynamic> {
|
||||||
public function new() {
|
public function new() {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
geometry.padding: 10
|
geometry.padding: 10
|
||||||
layout.margin: 5
|
layout.margin: 5
|
||||||
views:
|
views:
|
||||||
- $type: haxework.view.form.SelectView<String>
|
- $type: hw.view.form.SelectView<String>
|
||||||
layout.margin: 2
|
layout.margin: 2
|
||||||
dataView.layout.margin: 1
|
dataView.layout.margin: 1
|
||||||
data:
|
data:
|
||||||
@@ -13,7 +13,7 @@ views:
|
|||||||
selected: "value 1"
|
selected: "value 1"
|
||||||
+onSelect: ~function(value) trace('select', value)
|
+onSelect: ~function(value) trace('select', value)
|
||||||
|
|
||||||
- $type: haxework.view.form.SelectView.SelectIdView<{id:Int,label:String}, Int>
|
- $type: hw.view.form.SelectView.SelectIdView<{id:Int,label:String}, Int>
|
||||||
layout.margin: 2
|
layout.margin: 2
|
||||||
dataView.layout.margin: 1
|
dataView.layout.margin: 1
|
||||||
labelBuilder: |
|
labelBuilder: |
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package demo.form;
|
package demo.form;
|
||||||
|
|
||||||
import haxework.view.frame.FrameView;
|
import hw.view.frame.FrameView;
|
||||||
import haxework.view.ImageView;
|
import hw.view.ImageView;
|
||||||
import haxework.view.IView;
|
import hw.view.IView;
|
||||||
import haxework.view.text.TextView;
|
import hw.view.text.TextView;
|
||||||
import haxework.view.utils.DrawUtil;
|
import hw.view.utils.DrawUtil;
|
||||||
|
|
||||||
@:template class TailForm extends FrameView<Dynamic> {
|
@:template class TailForm extends FrameView<Dynamic> {
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
overflow.y: scroll
|
overflow.y: scroll
|
||||||
views:
|
views:
|
||||||
- id: data
|
- id: data
|
||||||
$type: haxework.view.data.DataView
|
$type: hw.view.data.DataView
|
||||||
geometry.padding: 4
|
geometry.padding: 4
|
||||||
layout:
|
layout:
|
||||||
$type: haxework.view.layout.TailLayout
|
$type: hw.view.layout.TailLayout
|
||||||
margin: 6
|
margin: 6
|
||||||
factory: ~factory
|
factory: ~factory
|
||||||
geometry.width: 100%
|
geometry.width: 100%
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package demo.form;
|
package demo.form;
|
||||||
|
|
||||||
import flash.events.MouseEvent;
|
import flash.events.MouseEvent;
|
||||||
import haxework.view.frame.FrameView;
|
import hw.view.frame.FrameView;
|
||||||
import haxework.view.SpriteView;
|
import hw.view.SpriteView;
|
||||||
|
|
||||||
@:template class TestLayoutForm extends FrameView<Dynamic> {
|
@:template class TestLayoutForm extends FrameView<Dynamic> {
|
||||||
|
|
||||||
@@ -10,9 +10,6 @@ import haxework.view.SpriteView;
|
|||||||
|
|
||||||
public function new() {
|
public function new() {
|
||||||
super("test_layout");
|
super("test_layout");
|
||||||
}
|
|
||||||
|
|
||||||
public function init():Void {
|
|
||||||
resize();
|
resize();
|
||||||
content.addEventListener(MouseEvent.CLICK, function(_) {
|
content.addEventListener(MouseEvent.CLICK, function(_) {
|
||||||
resize();
|
resize();
|
||||||
|
|||||||
@@ -1,52 +1,52 @@
|
|||||||
---
|
---
|
||||||
views:
|
views:
|
||||||
- id: main
|
- id: main
|
||||||
$type: haxework.view.group.VGroupView
|
$type: hw.view.group.VGroupView
|
||||||
geometry.stretch: true
|
geometry.stretch: true
|
||||||
layout.hAlign: center
|
layout.hAlign: center
|
||||||
layout.vAlign: middle
|
layout.vAlign: middle
|
||||||
views:
|
views:
|
||||||
- id: container
|
- id: container
|
||||||
$type: haxework.view.group.VGroupView
|
$type: hw.view.group.VGroupView
|
||||||
layout.margin: 10
|
layout.margin: 10
|
||||||
skin:
|
skin:
|
||||||
$type: [haxework.view.skin.Skin.color, 0xffff00]
|
$type: [hw.view.skin.Skin.color, 0xffff00]
|
||||||
views:
|
views:
|
||||||
- id: top
|
- id: top
|
||||||
$type: haxework.view.group.GroupView
|
$type: hw.view.group.GroupView
|
||||||
layout.hAlign: center
|
layout.hAlign: center
|
||||||
geometry.width: 100%
|
geometry.width: 100%
|
||||||
geometry.height: 20
|
geometry.height: 20
|
||||||
style: test
|
style: test
|
||||||
- id: middle
|
- id: middle
|
||||||
$type: haxework.view.group.HGroupView
|
$type: hw.view.group.HGroupView
|
||||||
layout.margin: 10
|
layout.margin: 10
|
||||||
views:
|
views:
|
||||||
- id: left
|
- id: left
|
||||||
$type: haxework.view.group.GroupView
|
$type: hw.view.group.GroupView
|
||||||
layout.vAlign: middle
|
layout.vAlign: middle
|
||||||
geometry.width: 20
|
geometry.width: 20
|
||||||
geometry.height: 100%
|
geometry.height: 100%
|
||||||
style: test
|
style: test
|
||||||
- id: render
|
- id: render
|
||||||
$type: haxework.view.SpriteView
|
$type: hw.view.SpriteView
|
||||||
#geometry.width: 300
|
#geometry.width: 300
|
||||||
#geometry.height: 200
|
#geometry.height: 200
|
||||||
style: test
|
style: test
|
||||||
- id: right
|
- id: right
|
||||||
$type: haxework.view.group.GroupView
|
$type: hw.view.group.GroupView
|
||||||
layout.vAlign: middle
|
layout.vAlign: middle
|
||||||
geometry.width: 20
|
geometry.width: 20
|
||||||
geometry.height: 100%
|
geometry.height: 100%
|
||||||
style: test
|
style: test
|
||||||
views:
|
views:
|
||||||
- $type: haxework.view.SpriteView
|
- $type: hw.view.SpriteView
|
||||||
geometry.width: 100
|
geometry.width: 100
|
||||||
geometry.height: 100%
|
geometry.height: 100%
|
||||||
skin:
|
skin:
|
||||||
$type: [haxework.view.skin.Skin.color, 0xff0000]
|
$type: [hw.view.skin.Skin.color, 0xff0000]
|
||||||
- id: bottom
|
- id: bottom
|
||||||
$type: haxework.view.group.GroupView
|
$type: hw.view.group.GroupView
|
||||||
layout.hAlign: center
|
layout.hAlign: center
|
||||||
style: test
|
style: test
|
||||||
geometry.width: 100%
|
geometry.width: 100%
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package demo.popup;
|
package demo.popup;
|
||||||
|
|
||||||
import haxework.view.form.ButtonView;
|
import hw.view.form.ButtonView;
|
||||||
import haxework.view.popup.PopupView;
|
import hw.view.popup.PopupView;
|
||||||
import haxework.view.skin.Skin;
|
import hw.view.skin.Skin;
|
||||||
|
|
||||||
@:template class ColorPopup extends PopupView<Null<Int>> {
|
@:template class ColorPopup extends PopupView<Null<Int>> {
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
view:
|
view:
|
||||||
$type: haxework.view.group.VGroupView
|
$type: hw.view.group.VGroupView
|
||||||
geometry.width: 400
|
geometry.width: 400
|
||||||
geometry.height: 200
|
geometry.height: 200
|
||||||
geometry.padding: 10
|
geometry.padding: 10
|
||||||
@@ -9,10 +9,10 @@ view:
|
|||||||
style: frame
|
style: frame
|
||||||
views:
|
views:
|
||||||
- id: colors
|
- id: colors
|
||||||
$type: haxework.view.data.DataView
|
$type: hw.view.data.DataView
|
||||||
geometry.stretch: true
|
geometry.stretch: true
|
||||||
layout:
|
layout:
|
||||||
$type: haxework.view.layout.TailLayout
|
$type: hw.view.layout.TailLayout
|
||||||
vAlign: middle
|
vAlign: middle
|
||||||
margin: 5
|
margin: 5
|
||||||
factory: ~colorViewFactory
|
factory: ~colorViewFactory
|
||||||
@@ -23,11 +23,11 @@ view:
|
|||||||
- 0xCC33AA
|
- 0xCC33AA
|
||||||
- 0x3333AA
|
- 0x3333AA
|
||||||
+onDataSelect: ~close
|
+onDataSelect: ~close
|
||||||
- $type: haxework.view.group.HGroupView
|
- $type: hw.view.group.HGroupView
|
||||||
geometry.width: 100%
|
geometry.width: 100%
|
||||||
layout.hAlign: right
|
layout.hAlign: right
|
||||||
layout.margin: 10
|
layout.margin: 10
|
||||||
views:
|
views:
|
||||||
- $type: haxework.view.form.ButtonView
|
- $type: hw.view.form.ButtonView
|
||||||
text: Cancel
|
text: Cancel
|
||||||
+onPress: ~reject('cancel')
|
+onPress: ~reject('cancel')
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package demo.popup;
|
|||||||
|
|
||||||
import flash.text.Font;
|
import flash.text.Font;
|
||||||
import flash.text.FontType;
|
import flash.text.FontType;
|
||||||
import haxework.view.list.LabelListItem;
|
import hw.view.list.LabelListItem;
|
||||||
import haxework.view.list.ListView;
|
import hw.view.list.ListView;
|
||||||
import haxework.view.popup.PopupView;
|
import hw.view.popup.PopupView;
|
||||||
import haxework.view.theme.ITheme;
|
import hw.view.theme.ITheme;
|
||||||
|
|
||||||
class FontLabelView extends LabelListItem<ThemeFont> {
|
class FontLabelView extends LabelListItem<ThemeFont> {
|
||||||
|
|
||||||
@@ -23,7 +23,8 @@ class FontLabelView extends LabelListItem<ThemeFont> {
|
|||||||
|
|
||||||
@:view var fonts:ListView<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) {
|
var values:Array<ThemeFont> = Font.enumerateFonts(true).map(function(font:Font) {
|
||||||
return {
|
return {
|
||||||
name: font.fontName,
|
name: font.fontName,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
view:
|
view:
|
||||||
$type: haxework.view.group.VGroupView
|
$type: hw.view.group.VGroupView
|
||||||
geometry.width: 400
|
geometry.width: 400
|
||||||
geometry.height: 80%
|
geometry.height: 80%
|
||||||
geometry.padding: 10
|
geometry.padding: 10
|
||||||
@@ -9,17 +9,17 @@ view:
|
|||||||
style: frame
|
style: frame
|
||||||
views:
|
views:
|
||||||
- id: fonts
|
- id: fonts
|
||||||
$type: haxework.view.list.VListView
|
$type: hw.view.list.VListView
|
||||||
geometry.stretch: true
|
geometry.stretch: true
|
||||||
factory: ~fontViewFactory
|
factory: ~fontViewFactory
|
||||||
+onItemSelect: ~function(item) close(item.data)
|
+onItemSelect: ~function(item) close(item.data)
|
||||||
scroll:
|
scroll:
|
||||||
$type: haxework.view.list.VScrollBarView
|
$type: hw.view.list.VScrollBarView
|
||||||
- $type: haxework.view.group.HGroupView
|
- $type: hw.view.group.HGroupView
|
||||||
geometry.width: 100%
|
geometry.width: 100%
|
||||||
geometry.margin.top: 10
|
geometry.margin.top: 10
|
||||||
layout.hAlign: right
|
layout.hAlign: right
|
||||||
views:
|
views:
|
||||||
- $type: haxework.view.form.ButtonView
|
- $type: hw.view.form.ButtonView
|
||||||
text: Cancel
|
text: Cancel
|
||||||
+onPress: ~reject('cancel')
|
+onPress: ~reject('cancel')
|
||||||
|
|||||||
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 hw.storage.SharedObjectStorage;
|
||||||
|
|
||||||
|
@:provide class TestStorage extends SharedObjectStorage {
|
||||||
|
|
||||||
|
public function new() {
|
||||||
|
super("test");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package demo.test;
|
package demo.test;
|
||||||
|
|
||||||
import haxework.view.group.GroupView;
|
import hw.view.group.GroupView;
|
||||||
|
|
||||||
@:template class TestView extends GroupView {
|
@:template class TestView extends GroupView {
|
||||||
|
|
||||||
|
|||||||
@@ -1,61 +1,61 @@
|
|||||||
---
|
---
|
||||||
geometry.padding: 10
|
geometry.padding: 10
|
||||||
views:
|
views:
|
||||||
- $type: haxework.view.group.HGroupView
|
- $type: hw.view.group.HGroupView
|
||||||
geometry.padding: 10
|
geometry.padding: 10
|
||||||
geometry.width: 100%
|
geometry.width: 100%
|
||||||
layout.margin: 10
|
layout.margin: 10
|
||||||
layout.vAlign: middle
|
layout.vAlign: middle
|
||||||
skin:
|
skin:
|
||||||
$type: haxework.view.skin.SpriteSkin
|
$type: hw.view.skin.SpriteSkin
|
||||||
background.color: 0xffff00
|
background.color: 0xffff00
|
||||||
background.alpha: 1
|
background.alpha: 1
|
||||||
views:
|
views:
|
||||||
- $type: haxework.view.SpriteView
|
- $type: hw.view.SpriteView
|
||||||
geometry.width: 100
|
geometry.width: 100
|
||||||
geometry.height: 100
|
geometry.height: 100
|
||||||
skin:
|
skin:
|
||||||
$type: haxework.view.skin.SpriteSkin
|
$type: hw.view.skin.SpriteSkin
|
||||||
background.color: 0xff0000
|
background.color: 0xff0000
|
||||||
background.alpha: 1
|
background.alpha: 1
|
||||||
- $type: haxework.view.group.VGroupView
|
- $type: hw.view.group.VGroupView
|
||||||
geometry.padding: 10
|
geometry.padding: 10
|
||||||
layout.margin: 10
|
layout.margin: 10
|
||||||
skin:
|
skin:
|
||||||
$type: haxework.view.skin.SpriteSkin
|
$type: hw.view.skin.SpriteSkin
|
||||||
background.color: 0x00ffff
|
background.color: 0x00ffff
|
||||||
background.alpha: 1
|
background.alpha: 1
|
||||||
views:
|
views:
|
||||||
- $type: haxework.view.SpriteView
|
- $type: hw.view.SpriteView
|
||||||
geometry.width: 100
|
geometry.width: 100
|
||||||
geometry.height: 100
|
geometry.height: 100
|
||||||
size:
|
size:
|
||||||
_test_: [200, 200]
|
_test_: [200, 200]
|
||||||
skin:
|
skin:
|
||||||
$type: haxework.view.skin.SpriteSkin
|
$type: hw.view.skin.SpriteSkin
|
||||||
background.color: 0xff0000
|
background.color: 0xff0000
|
||||||
background.alpha: 1
|
background.alpha: 1
|
||||||
- $type: haxework.view.SpriteView
|
- $type: hw.view.SpriteView
|
||||||
geometry.width: 100
|
geometry.width: 100
|
||||||
geometry.height: 100
|
geometry.height: 100
|
||||||
skin:
|
skin:
|
||||||
$type: haxework.view.skin.SpriteSkin
|
$type: hw.view.skin.SpriteSkin
|
||||||
background.color: 0xff0000
|
background.color: 0xff0000
|
||||||
background.alpha: 1
|
background.alpha: 1
|
||||||
- $type: haxework.view.text.TextView
|
- $type: hw.view.text.TextView
|
||||||
geometry.padding: 20
|
geometry.padding: 20
|
||||||
text: "Azazaza"
|
text: "Azazaza"
|
||||||
- $type: haxework.view.SpriteView
|
- $type: hw.view.SpriteView
|
||||||
geometry.width: 60%
|
geometry.width: 60%
|
||||||
geometry.height: 100%
|
geometry.height: 100%
|
||||||
skin:
|
skin:
|
||||||
$type: haxework.view.skin.SpriteSkin
|
$type: hw.view.skin.SpriteSkin
|
||||||
background.color: 0xff0000
|
background.color: 0xff0000
|
||||||
background.alpha: 1
|
background.alpha: 1
|
||||||
- $type: haxework.view.SpriteView
|
- $type: hw.view.SpriteView
|
||||||
geometry.width: 40%
|
geometry.width: 40%
|
||||||
geometry.height: 80%
|
geometry.height: 80%
|
||||||
skin:
|
skin:
|
||||||
$type: haxework.view.skin.SpriteSkin
|
$type: hw.view.skin.SpriteSkin
|
||||||
background.color: 0xff0000
|
background.color: 0xff0000
|
||||||
background.alpha: 1
|
background.alpha: 1
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
--macro haxework.parser.Parser.auto()
|
--macro hw.parser.Parser.auto()
|
||||||
|
|||||||
16
haxelib.json
16
haxelib.json
@@ -2,20 +2,16 @@
|
|||||||
"name": "haxework",
|
"name": "haxework",
|
||||||
"url": "https://bitbucket.org/shmyga/haxework",
|
"url": "https://bitbucket.org/shmyga/haxework",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"tags": [
|
"tags": ["view", "layout", "template"],
|
||||||
"view",
|
|
||||||
"layout",
|
|
||||||
"template"
|
|
||||||
],
|
|
||||||
"description": "View framework.",
|
"description": "View framework.",
|
||||||
"version": "1.0.0",
|
"version": "2.1.0",
|
||||||
"releasenote": "Update.",
|
"releasenote": "Update.",
|
||||||
"contributors": [
|
"contributors": ["shmyga"],
|
||||||
"shmyga"
|
|
||||||
],
|
|
||||||
"classPath": "src/main",
|
"classPath": "src/main",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"promhx": "1.1.0",
|
"promhx": "1.1.0",
|
||||||
"yaml": "1.3.0"
|
"protohx": "0.4.6",
|
||||||
|
"haxe-crypto": "0.0.8",
|
||||||
|
"yaml": "2.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package;
|
package;
|
||||||
|
|
||||||
import haxework.log.ILogger;
|
import hw.log.ILogger;
|
||||||
|
|
||||||
class L {
|
class L {
|
||||||
|
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
package haxework;
|
|
||||||
|
|
||||||
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;
|
|
||||||
import haxework.view.theme.ITheme;
|
|
||||||
|
|
||||||
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) {
|
|
||||||
this.theme = theme;
|
|
||||||
resources = new Resources();
|
|
||||||
loaderManager = new LoaderManager();
|
|
||||||
popupManager = new PopupManager();
|
|
||||||
popupManager.showAnimateFactory = function(v) return new UnFadeAnimate(v);
|
|
||||||
popupManager.closeAnimateFactory = function(v) return new FadeAnimate(v);
|
|
||||||
app = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function start(view:IView<Dynamic>) {
|
|
||||||
Animate.bind(Lib.current.stage);
|
|
||||||
Root.bind(view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
package haxework.animate;
|
|
||||||
|
|
||||||
import flash.display.DisplayObject;
|
|
||||||
import flash.display.Stage;
|
|
||||||
import flash.events.Event;
|
|
||||||
import haxework.view.IView;
|
|
||||||
|
|
||||||
class Animate implements IAnimate {
|
|
||||||
public static var defaultDuraion = 300;
|
|
||||||
|
|
||||||
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 view:IView<Dynamic>;
|
|
||||||
private var duration:Int;
|
|
||||||
private var startTime:Float;
|
|
||||||
private var progress:Float;
|
|
||||||
|
|
||||||
private var object(get, null):DisplayObject;
|
|
||||||
|
|
||||||
public function new(view:IView<Dynamic>, duration:Int = -1) {
|
|
||||||
this.view = view;
|
|
||||||
this.duration = duration > -1 ? duration : defaultDuraion;
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline function get_object():DisplayObject {
|
|
||||||
return cast view.content;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package haxework.animate;
|
|
||||||
|
|
||||||
import haxework.animate.Animate;
|
|
||||||
import haxework.animate.IAnimate;
|
|
||||||
|
|
||||||
class FadeAnimate extends Animate {
|
|
||||||
|
|
||||||
override public function start(callback:IAnimate -> Void, custom:Bool = false):Void {
|
|
||||||
object.alpha = 1.0;
|
|
||||||
super.start(callback, custom);
|
|
||||||
}
|
|
||||||
|
|
||||||
override private function update(time:Float):Void {
|
|
||||||
super.update(time);
|
|
||||||
object.alpha = 1 - (progress * 1.0);
|
|
||||||
if (progress >= 1) {
|
|
||||||
object.alpha = 0.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package haxework.animate;
|
|
||||||
|
|
||||||
class SlideAnimate extends Animate {
|
|
||||||
|
|
||||||
override public function start(callback:IAnimate -> Void, custom:Bool = false):Void {
|
|
||||||
object.x = view.x - this.view.width + this.view.width / progress;
|
|
||||||
super.start(callback, custom);
|
|
||||||
}
|
|
||||||
|
|
||||||
override private function update(time:Float):Void {
|
|
||||||
super.update(time);
|
|
||||||
object.x = view.x - this.view.width + this.view.width / Math.min(1, progress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package haxework.animate;
|
|
||||||
|
|
||||||
import haxework.animate.Animate;
|
|
||||||
|
|
||||||
class UnFadeAnimate extends Animate {
|
|
||||||
|
|
||||||
override public function start(callback:IAnimate -> Void, custom:Bool = false):Void {
|
|
||||||
object.alpha = 0.0;
|
|
||||||
super.start(callback, custom);
|
|
||||||
}
|
|
||||||
|
|
||||||
override private function update(time:Float):Void {
|
|
||||||
super.update(time);
|
|
||||||
object.alpha = progress * 1.0;
|
|
||||||
if (progress >= 1) {
|
|
||||||
object.alpha = 1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package haxework.macro;
|
|
||||||
|
|
||||||
import haxe.macro.Expr;
|
|
||||||
|
|
||||||
using haxework.macro.Util;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
package haxework.parser;
|
|
||||||
|
|
||||||
import haxework.macro.StyleMacro;
|
|
||||||
import haxe.macro.TypeTools;
|
|
||||||
import haxe.macro.Context;
|
|
||||||
import haxe.macro.Expr;
|
|
||||||
import haxe.macro.Type;
|
|
||||||
import haxework.macro.DispatcherMacro;
|
|
||||||
import haxework.macro.ProvideMacro;
|
|
||||||
import haxework.macro.ResourceMacro;
|
|
||||||
import haxework.macro.TemplateMacro;
|
|
||||||
|
|
||||||
class Parser {
|
|
||||||
|
|
||||||
private static var processed:Map<String, Bool> = new Map();
|
|
||||||
|
|
||||||
private static function auto():Void {
|
|
||||||
haxe.macro.Compiler.addGlobalMetadata("", "@:build(haxework.parser.Parser.autoRun())", true, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static macro function autoRun():Array<Field> {
|
|
||||||
var localType = Context.getLocalType();
|
|
||||||
return switch localType {
|
|
||||||
case Type.TInst(_.get() => ct, _):
|
|
||||||
var localName = TypeTools.toString(localType);
|
|
||||||
if (processed.exists(localName)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (modify) {
|
|
||||||
fields = result;
|
|
||||||
}
|
|
||||||
// process class meta
|
|
||||||
if (TemplateMacro.has(ct)) {
|
|
||||||
modify = true;
|
|
||||||
var template = new TemplateMacro(ct, fields);
|
|
||||||
fields = template.apply();
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
default: null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
60
src/main/hw/Timer.hx
Normal file
60
src/main/hw/Timer.hx
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package hw;
|
||||||
|
|
||||||
|
#if cpp
|
||||||
|
|
||||||
|
import haxe.Log;
|
||||||
|
import haxe.PosInfos;
|
||||||
|
import cpp.vm.Thread;
|
||||||
|
|
||||||
|
class Timer {
|
||||||
|
|
||||||
|
private var sleep:Float;
|
||||||
|
private var stopped:Bool;
|
||||||
|
|
||||||
|
public function new(time_ms:Int) {
|
||||||
|
this.sleep = time_ms / 1000.0;
|
||||||
|
this.stopped = false;
|
||||||
|
Thread.create(function() {
|
||||||
|
while (!stopped) {
|
||||||
|
Sys.sleep(sleep);
|
||||||
|
try {
|
||||||
|
run();
|
||||||
|
} catch (error:Dynamic) {
|
||||||
|
trace(hw.log.BaseLogger.LoggerUtil.printError(error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stop() {
|
||||||
|
stopped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public dynamic function run() {}
|
||||||
|
|
||||||
|
public static function delay(f:Void -> Void, time_ms:Int) {
|
||||||
|
var t = new Timer(time_ms);
|
||||||
|
t.run = function() {
|
||||||
|
t.stop();
|
||||||
|
f();
|
||||||
|
};
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function measure<T>(f:Void -> T, ?pos:PosInfos):T {
|
||||||
|
var t0 = stamp();
|
||||||
|
var r = f();
|
||||||
|
Log.trace((stamp() - t0) + "s", pos);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static inline function stamp():Float {
|
||||||
|
return Sys.time();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
typedef Timer = haxe.Timer;
|
||||||
|
|
||||||
|
#end
|
||||||
51
src/main/hw/animate/Animate.hx
Normal file
51
src/main/hw/animate/Animate.hx
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package hw.animate;
|
||||||
|
|
||||||
|
import flash.display.DisplayObject;
|
||||||
|
import hw.view.IView;
|
||||||
|
import promhx.Deferred;
|
||||||
|
import promhx.Promise;
|
||||||
|
|
||||||
|
class Animate implements IAnimate {
|
||||||
|
public static var defaultDuraion = 300;
|
||||||
|
|
||||||
|
@:provide private static var runner:AnimateRunner;
|
||||||
|
|
||||||
|
private var view:IView<Dynamic>;
|
||||||
|
private var duration:Int;
|
||||||
|
private var startTime:Float;
|
||||||
|
private var progress:Float;
|
||||||
|
|
||||||
|
private var object(get, null):DisplayObject;
|
||||||
|
private var deferred:Deferred<IAnimate>;
|
||||||
|
|
||||||
|
public function new(view:IView<Dynamic>, duration:Int = -1) {
|
||||||
|
this.view = view;
|
||||||
|
this.duration = duration > -1 ? duration : defaultDuraion;
|
||||||
|
this.startTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline function get_object():DisplayObject {
|
||||||
|
return cast view.content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function start():Promise<IAnimate> {
|
||||||
|
startTime = Date.now().getTime();
|
||||||
|
deferred = new Deferred();
|
||||||
|
runner.push(this);
|
||||||
|
this.update(startTime);
|
||||||
|
return deferred.promise();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(time:Float):Bool {
|
||||||
|
progress = (time - startTime) / duration;
|
||||||
|
if (progress >= 1) {
|
||||||
|
deferred.resolve(this);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cancel():Void {
|
||||||
|
progress = startTime + duration;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/main/hw/animate/AnimateRunner.hx
Normal file
25
src/main/hw/animate/AnimateRunner.hx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package hw.animate;
|
||||||
|
|
||||||
|
import flash.events.Event;
|
||||||
|
import flash.Lib;
|
||||||
|
|
||||||
|
@:provide class AnimateRunner {
|
||||||
|
|
||||||
|
private var animates:Array<IAnimate>;
|
||||||
|
|
||||||
|
public function new() {
|
||||||
|
animates = [];
|
||||||
|
Lib.current.stage.addEventListener(Event.ENTER_FRAME, _ -> update());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function update():Void {
|
||||||
|
if (animates.length > 0) {
|
||||||
|
var time = Date.now().getTime();
|
||||||
|
animates = animates.filter(animate -> animate.update(time));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function push(animate:IAnimate):Void {
|
||||||
|
animates.push(animate);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
package haxework.animate;
|
package hw.animate;
|
||||||
|
|
||||||
import flash.display.DisplayObject;
|
import flash.display.DisplayObject;
|
||||||
import flash.display.Sprite;
|
import flash.display.Sprite;
|
||||||
import haxework.animate.Animate;
|
import hw.animate.Animate;
|
||||||
import haxework.animate.IAnimate;
|
import hw.animate.IAnimate;
|
||||||
import haxework.view.IView;
|
import hw.view.IView;
|
||||||
|
import promhx.Promise;
|
||||||
|
|
||||||
class CircleMaskAnimate extends Animate {
|
class CircleMaskAnimate extends Animate {
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ class CircleMaskAnimate extends Animate {
|
|||||||
this.cyrcle = new Sprite();
|
this.cyrcle = new Sprite();
|
||||||
}
|
}
|
||||||
|
|
||||||
override public function start(callback:IAnimate -> Void, custom:Bool = false):Void {
|
override public function start():Promise<IAnimate> {
|
||||||
var width = view.parent.width;
|
var width = view.parent.width;
|
||||||
var height = view.parent.height;
|
var height = view.parent.height;
|
||||||
size = Math.sqrt(width * width + height * height);
|
size = Math.sqrt(width * width + height * height);
|
||||||
@@ -33,7 +34,7 @@ class CircleMaskAnimate extends Animate {
|
|||||||
view.content.mask = mask;
|
view.content.mask = mask;
|
||||||
view.parent.container.addChild(cyrcle);
|
view.parent.container.addChild(cyrcle);
|
||||||
|
|
||||||
super.start(callback, custom);
|
return super.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function redraw(size:Float, r:Float):Void {
|
private function redraw(size:Float, r:Float):Void {
|
||||||
@@ -48,15 +49,14 @@ class CircleMaskAnimate extends Animate {
|
|||||||
cyrcle.graphics.lineStyle();
|
cyrcle.graphics.lineStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
override private function update(time:Float):Void {
|
override public function update(time:Float):Bool {
|
||||||
super.update(time);
|
var result = super.update(time);
|
||||||
|
|
||||||
redraw(size, size * progress);
|
redraw(size, size * progress);
|
||||||
|
|
||||||
if (progress >= 1 && view.content.parent != null) {
|
if (progress >= 1 && view.content.parent != null) {
|
||||||
if (view.content.parent.contains(mask)) view.content.parent.removeChild(mask);
|
if (view.content.parent.contains(mask)) view.content.parent.removeChild(mask);
|
||||||
view.content.mask = null;
|
view.content.mask = null;
|
||||||
if (view.content.parent.contains(cyrcle)) view.parent.container.removeChild(cyrcle);
|
if (view.content.parent.contains(cyrcle)) view.parent.container.removeChild(cyrcle);
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
22
src/main/hw/animate/FadeAnimate.hx
Executable file
22
src/main/hw/animate/FadeAnimate.hx
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
package hw.animate;
|
||||||
|
|
||||||
|
import hw.animate.Animate;
|
||||||
|
import hw.animate.IAnimate;
|
||||||
|
import promhx.Promise;
|
||||||
|
|
||||||
|
class FadeAnimate extends Animate {
|
||||||
|
|
||||||
|
override public function start():Promise<IAnimate> {
|
||||||
|
object.alpha = 1.0;
|
||||||
|
return super.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function update(time:Float):Bool {
|
||||||
|
var result = super.update(time);
|
||||||
|
object.alpha = 1 - (progress * 1.0);
|
||||||
|
if (progress >= 1) {
|
||||||
|
object.alpha = 0.0;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/main/hw/animate/IAnimate.hx
Normal file
12
src/main/hw/animate/IAnimate.hx
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package hw.animate;
|
||||||
|
|
||||||
|
import promhx.Promise;
|
||||||
|
|
||||||
|
interface IAnimate {
|
||||||
|
|
||||||
|
public function start():Promise<IAnimate>;
|
||||||
|
|
||||||
|
public function cancel():Void;
|
||||||
|
|
||||||
|
public function update(time:Float):Bool;
|
||||||
|
}
|
||||||
17
src/main/hw/animate/SlideAnimate.hx
Normal file
17
src/main/hw/animate/SlideAnimate.hx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package hw.animate;
|
||||||
|
|
||||||
|
import promhx.Promise;
|
||||||
|
|
||||||
|
class SlideAnimate extends Animate {
|
||||||
|
|
||||||
|
override public function start():Promise<IAnimate> {
|
||||||
|
object.x = view.x - this.view.width + this.view.width / progress;
|
||||||
|
return super.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function update(time:Float):Bool {
|
||||||
|
var result = super.update(time);
|
||||||
|
object.x = view.x - this.view.width + this.view.width / Math.min(1, progress);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/main/hw/animate/UnFadeAnimate.hx
Executable file
21
src/main/hw/animate/UnFadeAnimate.hx
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
package hw.animate;
|
||||||
|
|
||||||
|
import hw.animate.Animate;
|
||||||
|
import promhx.Promise;
|
||||||
|
|
||||||
|
class UnFadeAnimate extends Animate {
|
||||||
|
|
||||||
|
override public function start():Promise<IAnimate> {
|
||||||
|
object.alpha = 0.0;
|
||||||
|
return super.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function update(time:Float):Bool {
|
||||||
|
var result = super.update(time);
|
||||||
|
object.alpha = progress * 1.0;
|
||||||
|
if (progress >= 1) {
|
||||||
|
object.alpha = 1.0;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
84
src/main/hw/app/App.hx
Normal file
84
src/main/hw/app/App.hx
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package hw.app;
|
||||||
|
|
||||||
|
import flash.display.BitmapData;
|
||||||
|
import flash.display.StageDisplayState;
|
||||||
|
import flash.events.FullScreenEvent;
|
||||||
|
import flash.Lib;
|
||||||
|
import hw.animate.FadeAnimate;
|
||||||
|
import hw.animate.IAnimate;
|
||||||
|
import hw.animate.UnFadeAnimate;
|
||||||
|
import hw.resources.IResources;
|
||||||
|
import hw.signal.Signal;
|
||||||
|
import hw.view.IView;
|
||||||
|
import hw.view.popup.PopupManager;
|
||||||
|
import hw.view.Root;
|
||||||
|
import hw.view.theme.ITheme;
|
||||||
|
|
||||||
|
class App {
|
||||||
|
|
||||||
|
public var view(default, set):IView<Dynamic>;
|
||||||
|
|
||||||
|
private function set_view(value:IView<Dynamic>):IView<Dynamic> {
|
||||||
|
view = value;
|
||||||
|
Root.bind(view);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
public var icon(default, set):BitmapData;
|
||||||
|
|
||||||
|
private function set_icon(value:BitmapData):BitmapData {
|
||||||
|
icon = value;
|
||||||
|
#if linux
|
||||||
|
if (icon != null) {
|
||||||
|
hw.app.LinuxIcon.value = icon;
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public var fullScreenSupport(get, never):Bool;
|
||||||
|
|
||||||
|
public function get_fullScreenSupport():Bool {
|
||||||
|
return Lib.current.stage.allowsFullScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public var fullScreen(get, set):Bool;
|
||||||
|
|
||||||
|
private function get_fullScreen():Bool {
|
||||||
|
return Lib.current.stage.displayState != StageDisplayState.NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function set_fullScreen(value:Bool):Bool {
|
||||||
|
Lib.current.stage.displayState = value ? StageDisplayState.FULL_SCREEN : StageDisplayState.NORMAL;
|
||||||
|
return get_fullScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
public var fullScreenSignal(default, null):Signal<Bool> = new Signal();
|
||||||
|
|
||||||
|
@:provide static var app:App;
|
||||||
|
@:provide static var resources:IResources;
|
||||||
|
@:provide static var popupManager:PopupManager;
|
||||||
|
|
||||||
|
@:provide public var theme:ITheme;
|
||||||
|
|
||||||
|
public function new() {
|
||||||
|
Lib.current.stage.stageFocusRect = false;
|
||||||
|
Lib.current.stage.addEventListener(FullScreenEvent.FULL_SCREEN, event -> fullScreenSignal.emit(event.fullScreen));
|
||||||
|
|
||||||
|
popupManager.showAnimateFactory = createShowAnimate;
|
||||||
|
popupManager.closeAnimateFactory = createCloseAnimate;
|
||||||
|
|
||||||
|
resources.text.put("app.version", Const.instance.VERSION);
|
||||||
|
resources.text.put("app.name", Const.instance.NAME);
|
||||||
|
|
||||||
|
app = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createShowAnimate(view:IView<Dynamic>):IAnimate {
|
||||||
|
return new UnFadeAnimate(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createCloseAnimate(view:IView<Dynamic>):IAnimate {
|
||||||
|
return new FadeAnimate(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/main/hw/app/Const.hx
Executable file
22
src/main/hw/app/Const.hx
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
package hw.app;
|
||||||
|
|
||||||
|
import flash.Lib;
|
||||||
|
import flash.system.Capabilities;
|
||||||
|
|
||||||
|
@:singleton class Const {
|
||||||
|
public var FPS(default, null):Int;
|
||||||
|
public var BUILD(default, null):String;
|
||||||
|
public var VERSION(default, null):String;
|
||||||
|
public var NAME(default, null):String;
|
||||||
|
public var DEBUG(default, null):Bool;
|
||||||
|
|
||||||
|
public function new():Void {
|
||||||
|
BUILD = CompilationOption.get("build");
|
||||||
|
#if lime
|
||||||
|
FPS = Std.parseInt(Lib.current.stage.application.meta.get("fps"));
|
||||||
|
VERSION = Lib.current.stage.application.meta.get("version");
|
||||||
|
NAME = Lib.current.stage.application.meta.get("name");
|
||||||
|
#end
|
||||||
|
DEBUG = Capabilities.isDebugger;
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/main/hw/app/LinuxIcon.hx
Normal file
29
src/main/hw/app/LinuxIcon.hx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package hw.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.color;
|
package hw.color;
|
||||||
|
|
||||||
abstract Color(Int) {
|
abstract Color(Int) {
|
||||||
public var alpha(get, never):Int;
|
public var alpha(get, never):Int;
|
||||||
@@ -44,7 +44,25 @@ abstract Color(Int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@:from static public inline function fromString(value:String):Color {
|
@: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 {
|
@:to public inline function toString():String {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.color;
|
package hw.color;
|
||||||
|
|
||||||
class ColorUtil {
|
class ColorUtil {
|
||||||
|
|
||||||
52
src/main/hw/connect/BaseConnection.hx
Executable file
52
src/main/hw/connect/BaseConnection.hx
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
package hw.connect;
|
||||||
|
|
||||||
|
import haxe.io.Bytes;
|
||||||
|
import hw.connect.IConnection;
|
||||||
|
import hw.signal.Signal;
|
||||||
|
import promhx.Deferred;
|
||||||
|
import promhx.Promise;
|
||||||
|
import protohx.Message;
|
||||||
|
|
||||||
|
class BaseConnection<O:Message, I:Message> implements IConnection<O, I> {
|
||||||
|
public var handler(default, null):Signal<ConnectionEvent>;
|
||||||
|
public var sendHandler(default, null):Signal<O>;
|
||||||
|
public var receiveHandler(default, null):Signal<I>;
|
||||||
|
public var connected(default, null):Bool;
|
||||||
|
public var queue(default, null):PacketQueue<I>;
|
||||||
|
|
||||||
|
private var connectDeferred:Deferred<IConnection<O, I>>;
|
||||||
|
|
||||||
|
public function new(inputFactory:Class<I>) {
|
||||||
|
queue = new PacketQueue<I>(inputFactory);
|
||||||
|
handler = new Signal<ConnectionEvent>();
|
||||||
|
sendHandler = new Signal<O>();
|
||||||
|
receiveHandler = new Signal<I>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function connect():Promise<IConnection<O, I>> {
|
||||||
|
throw "Not implemented";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function disconnect():Void {
|
||||||
|
throw "Not implemented";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pushData(bytes:Bytes):Void {
|
||||||
|
#if proto_debug L.d('Proto', 'pushData: ${bytes.length}'); #end
|
||||||
|
queue.addBytes(bytes);
|
||||||
|
while (queue.hasMsg()) {
|
||||||
|
var packet:I = queue.popMsg();
|
||||||
|
receive(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send(packet:O):Void {
|
||||||
|
#if proto_debug L.d('Proto', 'send: ${packet}'); #end
|
||||||
|
sendHandler.emit(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function receive(packet:I):Void {
|
||||||
|
#if proto_debug L.d('Proto', 'receive: ${packet}'); #end
|
||||||
|
receiveHandler.emit(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/main/hw/connect/ConnectionFactory.hx
Normal file
16
src/main/hw/connect/ConnectionFactory.hx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package hw.connect;
|
||||||
|
|
||||||
|
import protohx.Message;
|
||||||
|
|
||||||
|
class ConnectionFactory {
|
||||||
|
|
||||||
|
public static function buildClientConnection<O:Message, I:Message>(host: String, port:Int, inputFactory:Class<I>):IConnection<O, I> {
|
||||||
|
#if flash
|
||||||
|
return new hw.connect.flash.FlashConnection<O, I>(host, port, inputFactory);
|
||||||
|
#elseif html5
|
||||||
|
return new hw.connect.js.JsConnection<O, I>(host, port + (hw.connect.js.JsConnection.isSecured() ? 1 : 0), inputFactory);
|
||||||
|
#else
|
||||||
|
return new hw.connect.desktop.DesktopConnection<O, I>(host, port, inputFactory);
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/main/hw/connect/IConnection.hx
Executable file
24
src/main/hw/connect/IConnection.hx
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
package hw.connect;
|
||||||
|
|
||||||
|
import haxe.io.Bytes;
|
||||||
|
import hw.signal.Signal;
|
||||||
|
import promhx.Promise;
|
||||||
|
import protohx.Message;
|
||||||
|
|
||||||
|
enum ConnectionEvent {
|
||||||
|
CONNECTED;
|
||||||
|
DISCONNECTED;
|
||||||
|
ERROR(error:Dynamic);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IConnection<O:Message, I:Message> {
|
||||||
|
public var connected(default, null):Bool;
|
||||||
|
public var handler(default, null):Signal<ConnectionEvent>;
|
||||||
|
public var sendHandler(default, null):Signal<O>;
|
||||||
|
public var receiveHandler(default, null):Signal<I>;
|
||||||
|
|
||||||
|
public function connect():Promise<IConnection<O, I>>;
|
||||||
|
public function disconnect():Void;
|
||||||
|
public function send(packet:O):Void;
|
||||||
|
public function pushData(bytes:Bytes):Void;
|
||||||
|
}
|
||||||
70
src/main/hw/connect/PacketQueue.hx
Executable file
70
src/main/hw/connect/PacketQueue.hx
Executable file
@@ -0,0 +1,70 @@
|
|||||||
|
package hw.connect;
|
||||||
|
|
||||||
|
import haxe.io.Bytes;
|
||||||
|
import haxe.io.BytesBuffer;
|
||||||
|
import haxe.io.BytesInput;
|
||||||
|
import protohx.Message;
|
||||||
|
|
||||||
|
class PacketQueue<P:Message> {
|
||||||
|
|
||||||
|
public var packetClass(default, null):Class<P>;
|
||||||
|
|
||||||
|
private var buffer:BytesBuffer;
|
||||||
|
private var msgs:List<P>;
|
||||||
|
|
||||||
|
public function new(packetClass:Class<P>) {
|
||||||
|
this.packetClass = packetClass;
|
||||||
|
msgs = new List<P>();
|
||||||
|
buffer = new BytesBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function hasMsg():Bool {
|
||||||
|
return !msgs.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function popMsg():P {
|
||||||
|
return msgs.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function addMsg(msg:P):Void {
|
||||||
|
msgs.add(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function readPackage():Null<P> {
|
||||||
|
var bytes = buffer.getBytes();
|
||||||
|
var input = new BytesInput(bytes);
|
||||||
|
input.bigEndian = false;
|
||||||
|
if (input.length > 1) {
|
||||||
|
var packetSize = input.readUInt16();
|
||||||
|
if (input.length >= packetSize + 2) {
|
||||||
|
var packet:P = Type.createInstance(packetClass, []);
|
||||||
|
try {
|
||||||
|
packet.mergeFrom(input.read(packetSize));
|
||||||
|
buffer = new BytesBuffer();
|
||||||
|
buffer.add(input.read(input.length - (packetSize + 2)));
|
||||||
|
return packet;
|
||||||
|
} catch (error:Dynamic) {
|
||||||
|
L.w("PacketQueue", "readPackage ", error);
|
||||||
|
buffer = new BytesBuffer();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer = new BytesBuffer();
|
||||||
|
buffer.add(bytes);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addBytes(bytes:Bytes):Void {
|
||||||
|
buffer.add(bytes);
|
||||||
|
var packet = readPackage();
|
||||||
|
while (packet != null) {
|
||||||
|
msgs.add(packet);
|
||||||
|
packet = readPackage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clean():Void {
|
||||||
|
buffer = new BytesBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/main/hw/connect/PacketUtil.hx
Normal file
29
src/main/hw/connect/PacketUtil.hx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package hw.connect;
|
||||||
|
|
||||||
|
import haxe.io.Bytes;
|
||||||
|
import haxe.io.BytesOutput;
|
||||||
|
import protohx.Message;
|
||||||
|
|
||||||
|
class PacketUtil {
|
||||||
|
|
||||||
|
public static function fromBytes<P:Message>(bytes:Bytes, factory:Class<P>):P {
|
||||||
|
var packet:P = Type.createInstance(factory, []);
|
||||||
|
packet.mergeFrom(bytes);
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function toBytes<P:Message>(packet:P):Bytes {
|
||||||
|
var out = new BytesOutput();
|
||||||
|
packet.writeTo(out);
|
||||||
|
return out.getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function toBytesWithSize<P:Message>(packet:P):Bytes {
|
||||||
|
var out = new BytesOutput();
|
||||||
|
out.writeUInt16(0);
|
||||||
|
packet.writeTo(out);
|
||||||
|
var bytes = out.getBytes();
|
||||||
|
bytes.setUInt16(0, bytes.length - 2);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
76
src/main/hw/connect/desktop/DesktopConnection.hx
Normal file
76
src/main/hw/connect/desktop/DesktopConnection.hx
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
package hw.connect.desktop;
|
||||||
|
|
||||||
|
import cpp.vm.Thread;
|
||||||
|
import haxe.Timer;
|
||||||
|
import hw.connect.IConnection;
|
||||||
|
import promhx.Deferred;
|
||||||
|
import promhx.Promise;
|
||||||
|
import protohx.Message;
|
||||||
|
import sys.net.Host;
|
||||||
|
import sys.net.Socket;
|
||||||
|
|
||||||
|
class DesktopConnection<O:Message, I:Message> extends BaseConnection<O, I> {
|
||||||
|
|
||||||
|
private var host:String;
|
||||||
|
private var port:Int;
|
||||||
|
private var socket:Socket;
|
||||||
|
private var reader:Thread;
|
||||||
|
|
||||||
|
public function new(host:String, port:Int, inputFactory:Class<I>) {
|
||||||
|
super(inputFactory);
|
||||||
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
connected = false;
|
||||||
|
socket = new Socket();
|
||||||
|
socket.setFastSend(true);
|
||||||
|
socket.output.bigEndian = false;
|
||||||
|
socket.input.bigEndian = false;
|
||||||
|
sendHandler.connect(_send);
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function connect():Promise<IConnection<O, I>> {
|
||||||
|
connectDeferred = new Deferred();
|
||||||
|
try {
|
||||||
|
if (connected) {
|
||||||
|
connectDeferred.resolve(this);
|
||||||
|
} else {
|
||||||
|
socket.connect(new Host(host), port);
|
||||||
|
connected = true;
|
||||||
|
reader = Thread.create(_read);
|
||||||
|
connectDeferred.resolve(this);
|
||||||
|
handler.emit(ConnectionEvent.CONNECTED);
|
||||||
|
}
|
||||||
|
} catch (error:Dynamic) {
|
||||||
|
handler.emit(ConnectionEvent.ERROR(error));
|
||||||
|
Timer.delay(function() connectDeferred.throwError(error), 1);
|
||||||
|
}
|
||||||
|
return connectDeferred.promise();
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function disconnect():Void {
|
||||||
|
socket.close();
|
||||||
|
connected = false;
|
||||||
|
handler.emit(DISCONNECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _read():Void {
|
||||||
|
try {
|
||||||
|
while (connected) {
|
||||||
|
socket.waitForRead();
|
||||||
|
var size = socket.input.readUInt16();
|
||||||
|
var data = socket.input.read(size);
|
||||||
|
var packet:I = PacketUtil.fromBytes(data, queue.packetClass);
|
||||||
|
receiveHandler.emit(packet);
|
||||||
|
}
|
||||||
|
} catch (error:Dynamic) {
|
||||||
|
handler.emit(ERROR(error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _send(packet:O):Void {
|
||||||
|
var bytes = PacketUtil.toBytes(packet);
|
||||||
|
socket.output.writeUInt16(bytes.length);
|
||||||
|
socket.output.write(bytes);
|
||||||
|
socket.output.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/main/hw/connect/fake/FakeConnection.hx
Normal file
18
src/main/hw/connect/fake/FakeConnection.hx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package hw.connect.fake;
|
||||||
|
|
||||||
|
import hw.connect.IConnection;
|
||||||
|
import promhx.Promise;
|
||||||
|
import protohx.Message;
|
||||||
|
|
||||||
|
class FakeConnection<O:Message, I:Message> extends BaseConnection<O, I> {
|
||||||
|
|
||||||
|
override public function connect():Promise<IConnection<O, I>> {
|
||||||
|
handler.emit(ConnectionEvent.CONNECTED);
|
||||||
|
var promise:Promise<IConnection<O, I>> = cast Promise.promise(this);
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function disconnect():Void {
|
||||||
|
handler.emit(ConnectionEvent.DISCONNECTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
89
src/main/hw/connect/flash/FlashConnection.hx
Executable file
89
src/main/hw/connect/flash/FlashConnection.hx
Executable file
@@ -0,0 +1,89 @@
|
|||||||
|
package hw.connect.flash;
|
||||||
|
|
||||||
|
import flash.events.ErrorEvent;
|
||||||
|
import flash.events.Event;
|
||||||
|
import flash.events.IOErrorEvent;
|
||||||
|
import flash.events.ProgressEvent;
|
||||||
|
import flash.events.SecurityErrorEvent;
|
||||||
|
import flash.net.Socket;
|
||||||
|
import flash.utils.Endian;
|
||||||
|
import haxe.io.Bytes;
|
||||||
|
import promhx.Deferred;
|
||||||
|
import promhx.Promise;
|
||||||
|
import protohx.Message;
|
||||||
|
import hw.connect.IConnection;
|
||||||
|
|
||||||
|
class FlashConnection<O:Message, I:Message> extends BaseConnection<O, I> {
|
||||||
|
|
||||||
|
private var host:String;
|
||||||
|
private var port:Int;
|
||||||
|
private var socket:Socket;
|
||||||
|
|
||||||
|
public function new(host:String, port:Int, inputFactory:Class<I>) {
|
||||||
|
super(inputFactory);
|
||||||
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
connected = false;
|
||||||
|
socket = new Socket();
|
||||||
|
socket.addEventListener(IOErrorEvent.IO_ERROR, onError);
|
||||||
|
socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
|
||||||
|
socket.addEventListener(Event.CLOSE, onClose);
|
||||||
|
socket.addEventListener(Event.CONNECT, onConnect);
|
||||||
|
socket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
|
||||||
|
socket.endian = Endian.LITTLE_ENDIAN;
|
||||||
|
sendHandler.connect(_send);
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function connect():Promise<IConnection<O, I>> {
|
||||||
|
socket.connect(host, port);
|
||||||
|
connectDeferred = new Deferred();
|
||||||
|
return connectDeferred.promise();
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function disconnect():Void {
|
||||||
|
if (socket.connected) {
|
||||||
|
socket.close();
|
||||||
|
connected = false;
|
||||||
|
handler.emit(ConnectionEvent.DISCONNECTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onError(event:ErrorEvent):Void {
|
||||||
|
socket.close();
|
||||||
|
connected = false;
|
||||||
|
handler.emit(ConnectionEvent.ERROR(event));
|
||||||
|
if (connectDeferred != null) {
|
||||||
|
connectDeferred.throwError(event);
|
||||||
|
connectDeferred = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onConnect(_):Void {
|
||||||
|
connected = true;
|
||||||
|
handler.emit(ConnectionEvent.CONNECTED);
|
||||||
|
if (connectDeferred != null) {
|
||||||
|
connectDeferred.resolve(this);
|
||||||
|
connectDeferred = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onClose(_):Void {
|
||||||
|
socket.close();
|
||||||
|
connected = false;
|
||||||
|
handler.emit(ConnectionEvent.DISCONNECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onSocketData(_):Void {
|
||||||
|
var data = new flash.utils.ByteArray();
|
||||||
|
socket.readBytes(data);
|
||||||
|
var bytes = Bytes.ofData(data);
|
||||||
|
pushData(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _send(packet:O):Void {
|
||||||
|
var bytes = PacketUtil.toBytes(packet);
|
||||||
|
socket.writeShort(bytes.length);
|
||||||
|
socket.writeBytes(bytes.getData());
|
||||||
|
socket.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
87
src/main/hw/connect/js/JsConnection.hx
Normal file
87
src/main/hw/connect/js/JsConnection.hx
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package hw.connect.js;
|
||||||
|
|
||||||
|
import haxe.io.Bytes;
|
||||||
|
import hw.connect.IConnection;
|
||||||
|
import js.Browser;
|
||||||
|
import js.html.BinaryType;
|
||||||
|
import js.html.WebSocket;
|
||||||
|
import promhx.Deferred;
|
||||||
|
import promhx.Promise;
|
||||||
|
import protohx.Message;
|
||||||
|
|
||||||
|
class JsConnection<O:Message, I:Message> extends BaseConnection<O, I> {
|
||||||
|
|
||||||
|
private var host:String;
|
||||||
|
private var port:Int;
|
||||||
|
private var socket:WebSocket;
|
||||||
|
|
||||||
|
public function new(host:String, port:Int, inputFactory:Class<I>) {
|
||||||
|
super(inputFactory);
|
||||||
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isSecured():Bool {
|
||||||
|
return Browser.location.protocol == "https:";
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildSocket(host:String, port:Int):WebSocket {
|
||||||
|
var protocol = isSecured() ? "wss:" : "ws:";
|
||||||
|
return new WebSocket('$protocol//$host:$port');
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function connect():Promise<IConnection<O, I>> {
|
||||||
|
var self = this;
|
||||||
|
connectDeferred = new Deferred();
|
||||||
|
try {
|
||||||
|
socket = buildSocket(host, port);
|
||||||
|
socket.binaryType = BinaryType.ARRAYBUFFER;
|
||||||
|
socket.onopen = this.onConnect;
|
||||||
|
socket.onclose = this.onClose;
|
||||||
|
socket.onerror = this.onError;
|
||||||
|
socket.onmessage = this.onSocketData;
|
||||||
|
} catch (error:Dynamic) {
|
||||||
|
connectDeferred.throwError(error);
|
||||||
|
}
|
||||||
|
return connectDeferred.promise();
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function disconnect():Void {
|
||||||
|
socket.close(1000);
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onError(event:Dynamic):Void {
|
||||||
|
socket.close(1000);
|
||||||
|
connected = false;
|
||||||
|
handler.emit(ConnectionEvent.ERROR(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onConnect(_):Void {
|
||||||
|
connected = true;
|
||||||
|
handler.emit(ConnectionEvent.CONNECTED);
|
||||||
|
connectDeferred.resolve(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onClose(_):Void {
|
||||||
|
socket.close();
|
||||||
|
connected = false;
|
||||||
|
handler.emit(ConnectionEvent.DISCONNECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onSocketData(event:Dynamic):Void {
|
||||||
|
var bytes = Bytes.ofData(event.data);
|
||||||
|
pushData(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function send(packet:O):Void {
|
||||||
|
if (connected) {
|
||||||
|
super.send(packet);
|
||||||
|
var bytes = PacketUtil.toBytesWithSize(packet);
|
||||||
|
socket.send(bytes.getData());
|
||||||
|
} else {
|
||||||
|
L.w("Connection", "closed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
57
src/main/hw/connect/server/ServerConnection.hx
Executable file
57
src/main/hw/connect/server/ServerConnection.hx
Executable file
@@ -0,0 +1,57 @@
|
|||||||
|
package hw.connect.server;
|
||||||
|
|
||||||
|
import hw.Timer;
|
||||||
|
import protohx.Message;
|
||||||
|
import sys.net.Socket;
|
||||||
|
|
||||||
|
class ServerConnection<O:Message, I:Message> extends BaseConnection<O, I> {
|
||||||
|
|
||||||
|
public var socket(default, null):Socket;
|
||||||
|
|
||||||
|
private var sendQueue:Array<O>;
|
||||||
|
private var timer:Timer;
|
||||||
|
|
||||||
|
public function new(socket:Socket, i:Class<I>) {
|
||||||
|
super(i);
|
||||||
|
this.socket = socket;
|
||||||
|
socket.setFastSend(true);
|
||||||
|
socket.output.bigEndian = false;
|
||||||
|
socket.input.bigEndian = false;
|
||||||
|
sendHandler.connect(pushPacket);
|
||||||
|
sendQueue = [];
|
||||||
|
timer = new Timer(1);
|
||||||
|
timer.run = sendRun;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sendPacket(packet:O):Void {
|
||||||
|
try {
|
||||||
|
var bytes = PacketUtil.toBytes(packet);
|
||||||
|
socket.output.writeUInt16(bytes.length);
|
||||||
|
socket.output.write(bytes);
|
||||||
|
socket.output.flush();
|
||||||
|
} catch (error:Dynamic) {
|
||||||
|
L.e('Proto', 'Error send packet: ${packet}', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sendRun():Void {
|
||||||
|
if (sendQueue.length > 0) {
|
||||||
|
for (packet in sendQueue) {
|
||||||
|
sendPacket(packet);
|
||||||
|
}
|
||||||
|
sendQueue = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function pushPacket(packet:O):Void {
|
||||||
|
sendQueue.push(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function disconnect():Void {
|
||||||
|
if (timer != null) {
|
||||||
|
timer.stop();
|
||||||
|
timer = null;
|
||||||
|
}
|
||||||
|
super.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
155
src/main/hw/connect/server/ServerWSConnection.hx
Normal file
155
src/main/hw/connect/server/ServerWSConnection.hx
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
package hw.connect.server;
|
||||||
|
|
||||||
|
import com.hurlant.crypto.hash.SHA1;
|
||||||
|
import com.hurlant.util.Base64;
|
||||||
|
import haxe.io.Bytes;
|
||||||
|
import haxe.io.BytesBuffer;
|
||||||
|
import protohx.Message;
|
||||||
|
import sys.net.Socket;
|
||||||
|
|
||||||
|
class ServerWSConnection<O:Message, I:Message> extends ServerConnection<O, I> {
|
||||||
|
|
||||||
|
private var opened:Bool;
|
||||||
|
private var buffer:Bytes;
|
||||||
|
|
||||||
|
public function new(socket:Socket, i:Class<I>) {
|
||||||
|
super(socket, i);
|
||||||
|
opened = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
override private function sendPacket(packet:O):Void {
|
||||||
|
var bytes = PacketUtil.toBytesWithSize(packet);
|
||||||
|
writeData(bytes, socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function pushData(bytes:Bytes):Void {
|
||||||
|
if (!opened) {
|
||||||
|
var str:String = bytes.getString(0, bytes.length);
|
||||||
|
if (StringTools.startsWith(str, "GET")) {
|
||||||
|
var r = ~/Sec-WebSocket-Key:\s*([A-z0-9=+\/]+)/;
|
||||||
|
r.match(str);
|
||||||
|
opened = true;
|
||||||
|
sendServerHandShake(socket, r.matched(1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var data = parseData(bytes);
|
||||||
|
if (data != null) {
|
||||||
|
super.pushData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sendServerHandShake(socket:sys.net.Socket, inpKey:String) {
|
||||||
|
var magicKey = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||||
|
var value:String = StringTools.trim(inpKey) + magicKey;
|
||||||
|
var hash = new SHA1().hash(Bytes.ofString(value));
|
||||||
|
var outKey = Base64.encodeByteArray(hash);
|
||||||
|
var s = "HTTP/1.1 101 Switching Protocols\r\n"
|
||||||
|
+ "Upgrade: websocket\r\n"
|
||||||
|
+ "Connection: Upgrade\r\n"
|
||||||
|
+ "Sec-WebSocket-Accept: " + outKey + "\r\n"
|
||||||
|
+ "\r\n";
|
||||||
|
socket.output.writeString(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function writeData(data:Bytes, socket:sys.net.Socket, isServer = true):Void {
|
||||||
|
socket.output.writeByte(130);
|
||||||
|
|
||||||
|
var len = 0;
|
||||||
|
if (data.length < 126) len = data.length;
|
||||||
|
else if (data.length < 65536) len = 126;
|
||||||
|
else len = 127;
|
||||||
|
|
||||||
|
socket.output.writeByte(len | (!isServer ? 0x80 : 0x00));
|
||||||
|
|
||||||
|
if (data.length >= 126) {
|
||||||
|
if (data.length < 65536) {
|
||||||
|
socket.output.writeByte((data.length >> 8) & 0xFF);
|
||||||
|
socket.output.writeByte(data.length & 0xFF);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
socket.output.writeByte((data.length >> 24) & 0xFF);
|
||||||
|
socket.output.writeByte((data.length >> 16) & 0xFF);
|
||||||
|
socket.output.writeByte((data.length >> 8) & 0xFF);
|
||||||
|
socket.output.writeByte(data.length & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isServer) {
|
||||||
|
socket.output.writeBytes(data, 0, data.length);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var mask = [ Std.random(256), Std.random(256), Std.random(256), Std.random(256) ];
|
||||||
|
socket.output.writeByte(mask[0]);
|
||||||
|
socket.output.writeByte(mask[1]);
|
||||||
|
socket.output.writeByte(mask[2]);
|
||||||
|
socket.output.writeByte(mask[3]);
|
||||||
|
var maskedData = new BytesBuffer();
|
||||||
|
for (i in 0...data.length) {
|
||||||
|
maskedData.addByte(data.get(i) ^ mask[i % 4]);
|
||||||
|
}
|
||||||
|
socket.output.writeBytes(maskedData.getBytes(), 0, maskedData.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseData(bytes:Bytes):Bytes {
|
||||||
|
var p = 0;
|
||||||
|
var opcode = bytes.get(p++);
|
||||||
|
|
||||||
|
if (opcode == 0x00) {
|
||||||
|
var data = new BytesBuffer();
|
||||||
|
var b:Int;
|
||||||
|
while ((b = bytes.get(p++)) != 0xFF) {
|
||||||
|
data.addByte(b);
|
||||||
|
}
|
||||||
|
return data.getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 130 = binary data
|
||||||
|
if (opcode == 130) {
|
||||||
|
var len = bytes.get(p++);
|
||||||
|
|
||||||
|
// mask
|
||||||
|
if (len & 0x80 != 0) {
|
||||||
|
len &= 0x7F;
|
||||||
|
|
||||||
|
if (len == 126) {
|
||||||
|
var b2 = bytes.get(p++);
|
||||||
|
var b3 = bytes.get(p++);
|
||||||
|
len = (b2 << 8) + b3;
|
||||||
|
}
|
||||||
|
else if (len == 127) {
|
||||||
|
var b2 = bytes.get(p++);
|
||||||
|
var b3 = bytes.get(p++);
|
||||||
|
var b4 = bytes.get(p++);
|
||||||
|
var b5 = bytes.get(p++);
|
||||||
|
len = (b2 << 24) + (b3 << 16) + (b4 << 8) + b5;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mask = [];
|
||||||
|
mask.push(bytes.get(p++));
|
||||||
|
mask.push(bytes.get(p++));
|
||||||
|
mask.push(bytes.get(p++));
|
||||||
|
mask.push(bytes.get(p++));
|
||||||
|
|
||||||
|
var data = new BytesBuffer();
|
||||||
|
for (i in 0...len) {
|
||||||
|
data.addByte(bytes.get(p++) ^ mask[i % 4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.getBytes();
|
||||||
|
} else {
|
||||||
|
throw "Expected masked data.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opcode == 136) {
|
||||||
|
//socket.close();
|
||||||
|
opened = false;
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
throw "Unsupported websocket opcode: " + opcode;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/main/hw/connect/session/ISession.hx
Normal file
9
src/main/hw/connect/session/ISession.hx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package hw.connect.session;
|
||||||
|
|
||||||
|
import haxe.io.Bytes;
|
||||||
|
|
||||||
|
interface ISession {
|
||||||
|
public var id(default, null):Int;
|
||||||
|
public function pushData(bytes:Bytes):Void;
|
||||||
|
public function disconnect():Void;
|
||||||
|
}
|
||||||
71
src/main/hw/connect/session/ProtoSession.hx
Normal file
71
src/main/hw/connect/session/ProtoSession.hx
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package hw.connect.session;
|
||||||
|
|
||||||
|
import haxe.io.Bytes;
|
||||||
|
import hw.connect.server.ServerConnection;
|
||||||
|
import hw.connect.server.ServerWSConnection;
|
||||||
|
import protohx.Message;
|
||||||
|
import sys.net.Socket;
|
||||||
|
|
||||||
|
class ProtoSession<O:Message, I:Message> implements ISession {
|
||||||
|
private static inline var TAG = "Session";
|
||||||
|
|
||||||
|
private static var POLICY_FILE:String = [
|
||||||
|
"<?xml version=\"1.0\"?>",
|
||||||
|
"<!DOCTYPE cross-domain-policy SYSTEM \"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\">",
|
||||||
|
"<cross-domain-policy>",
|
||||||
|
"<site-control permitted-cross-domain-policies=\"master-only\"/>",
|
||||||
|
"<allow-access-from domain=\"*\" to-ports=\"*\"/>",
|
||||||
|
"</cross-domain-policy>"
|
||||||
|
].join("\n");
|
||||||
|
|
||||||
|
private static var idCounter:Int = 0;
|
||||||
|
|
||||||
|
public var id(default, null):Int;
|
||||||
|
public var connection(default, null):IConnection<O, I>;
|
||||||
|
private var socket:Socket;
|
||||||
|
private var request:Class<I>;
|
||||||
|
|
||||||
|
public function new(socket:Socket, request:Class<I>) {
|
||||||
|
this.id = ++idCounter;
|
||||||
|
this.socket = socket;
|
||||||
|
this.request = request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildConnection(bytes:Bytes):IConnection<O, I> {
|
||||||
|
var str:String = bytes.getString(0, bytes.length);
|
||||||
|
if (str == "<policy-file-request/>" + String.fromCharCode(0)) {
|
||||||
|
L.d(TAG, "policy-file-request");
|
||||||
|
socket.output.writeString(POLICY_FILE + String.fromCharCode(0));
|
||||||
|
socket.output.flush();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (StringTools.startsWith(str, "GET")) {
|
||||||
|
connection = new ServerWSConnection<O, I>(socket, request);
|
||||||
|
} else {
|
||||||
|
connection = new ServerConnection<O, I>(socket, request);
|
||||||
|
}
|
||||||
|
connection.receiveHandler.connect(onRequest);
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send(packet:O):Void {
|
||||||
|
connection.send(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pushData(bytes:Bytes):Void {
|
||||||
|
if (connection == null) {
|
||||||
|
connection = buildConnection(bytes);
|
||||||
|
}
|
||||||
|
if (connection != null) {
|
||||||
|
connection.pushData(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function disconnect():Void {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onRequest(request:I):Void {
|
||||||
|
L.d(TAG, 'onRequest: ${request}');
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/main/hw/geom/IntPoint.hx
Normal file
35
src/main/hw/geom/IntPoint.hx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package hw.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
34
src/main/hw/geom/Point.hx
Normal file
34
src/main/hw/geom/Point.hx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package hw.geom;
|
||||||
|
|
||||||
|
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}';
|
||||||
|
}
|
||||||
|
}
|
||||||
102
src/main/hw/geom/Rectangle.hx
Normal file
102
src/main/hw/geom/Rectangle.hx
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package hw.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/hw/log/AndroidLog.hx
Normal file
15
src/main/hw/log/AndroidLog.hx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package hw.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;
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package haxework.log;
|
package hw.log;
|
||||||
|
|
||||||
import haxework.log.ILogger.LogLevel;
|
import hw.log.ILogger.LogLevel;
|
||||||
import haxe.CallStack;
|
import haxe.CallStack;
|
||||||
|
|
||||||
|
|
||||||
@@ -12,16 +12,25 @@ class LoggerUtil {
|
|||||||
|
|
||||||
public static function printStackItem(item:StackItem):String {
|
public static function printStackItem(item:StackItem):String {
|
||||||
return switch item {
|
return switch item {
|
||||||
case StackItem.CFunction: 'CFunction';
|
case CFunction: 'CFunction';
|
||||||
case StackItem.Module(m): m;
|
case Module(m): m;
|
||||||
case StackItem.FilePos(s, file, line): '${file}:${line}';
|
case FilePos(s, file, line): '${file}:${line}';
|
||||||
case StackItem.Method(classname, method): '${classname}::${method}}';
|
case Method(classname, method): '${classname}::${method}}';
|
||||||
case StackItem.LocalFunction(v): 'LocalFunction(${v})';
|
case LocalFunction(v): 'LocalFunction(${v})';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getErrorStack(error:Dynamic):String {
|
||||||
|
#if flash
|
||||||
|
if (Std.is(error, flash.errors.Error)) {
|
||||||
|
return cast(error, flash.errors.Error).getStackTrace();
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
return CallStack.exceptionStack().map(printStackItem).join('\n\t');
|
||||||
|
}
|
||||||
|
|
||||||
public static function printError(error:Dynamic):String {
|
public static function printError(error:Dynamic):String {
|
||||||
return error == null ? '' : Std.string('${error}\n\t${CallStack.exceptionStack().map(printStackItem).join('\n\t')}');
|
return error == null ? '' : Std.string('${error}\n\t${getErrorStack(error)}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.log;
|
package hw.log;
|
||||||
|
|
||||||
enum LogLevel {
|
enum LogLevel {
|
||||||
DEBUG; INFO; WARNING; ERROR;
|
DEBUG; INFO; WARNING; ERROR;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package haxework.log;
|
package hw.log;
|
||||||
|
|
||||||
import haxework.log.ILogger.LogLevel;
|
import hw.log.ILogger.LogLevel;
|
||||||
import flash.external.ExternalInterface;
|
import flash.external.ExternalInterface;
|
||||||
import haxework.log.BaseLogger;
|
import hw.log.BaseLogger;
|
||||||
|
|
||||||
|
|
||||||
class JSLogger extends BaseLogger {
|
class JSLogger extends BaseLogger {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package haxework.log;
|
package hw.log;
|
||||||
|
|
||||||
import haxework.log.BaseLogger;
|
import hw.log.BaseLogger;
|
||||||
|
|
||||||
#if js
|
#if js
|
||||||
class SocketLogger extends BaseLogger {}
|
class SocketLogger extends BaseLogger {}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.log;
|
package hw.log;
|
||||||
|
|
||||||
import flash.text.TextField;
|
import flash.text.TextField;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.log;
|
package hw.log;
|
||||||
|
|
||||||
import haxe.PosInfos;
|
import haxe.PosInfos;
|
||||||
#if cpp
|
#if cpp
|
||||||
@@ -27,13 +27,17 @@ class TraceLogger extends BaseLogger {
|
|||||||
$print("\n");
|
$print("\n");
|
||||||
}
|
}
|
||||||
#elseif js
|
#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
|
||||||
|
hw.log.AndroidLog.write(3, "", ConstCharStar.fromString(Std.string(v)));
|
||||||
#elseif (php && php7)
|
#elseif (php && php7)
|
||||||
php.Boot.trace(v);
|
php.Boot.trace(v);
|
||||||
#elseif php
|
#elseif php
|
||||||
untyped __call__('_hx_trace', v);
|
untyped __call__('_hx_trace', v);
|
||||||
#elseif cpp
|
#elseif cpp
|
||||||
Stdio.printf(ConstCharStar.fromString(Std.string(v)));
|
Stdio.printf(ConstCharStar.fromString(Std.string(v)+'\n'));
|
||||||
//untyped __trace(v, null);
|
//untyped __trace(v, null);
|
||||||
#elseif cs
|
#elseif cs
|
||||||
cs.system.Console.WriteLine(v);
|
cs.system.Console.WriteLine(v);
|
||||||
20
src/main/hw/macro/ClassProvideMacro.hx
Normal file
20
src/main/hw/macro/ClassProvideMacro.hx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package hw.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/hw/macro/ClassTypeMacro.hx
Normal file
21
src/main/hw/macro/ClassTypeMacro.hx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package hw.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.macro;
|
package hw.macro;
|
||||||
|
|
||||||
import haxe.macro.TypeTools;
|
import haxe.macro.TypeTools;
|
||||||
import haxe.macro.Context;
|
import haxe.macro.Context;
|
||||||
@@ -6,20 +6,10 @@ import haxe.macro.ExprTools;
|
|||||||
import haxe.macro.Expr;
|
import haxe.macro.Expr;
|
||||||
import haxe.macro.Type;
|
import haxe.macro.Type;
|
||||||
|
|
||||||
class DispatcherMacro {
|
class DispatcherMacro extends ClassTypeMacro {
|
||||||
|
|
||||||
private static inline var metaName:String = ':dispatcher';
|
public function new() {
|
||||||
|
super(":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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static inline function signalName(fieldName:String):String {
|
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 result:Array<Field> = fields.slice(0);
|
||||||
var typeName = ExprTools.toString(classType.meta.extract(metaName)[0].params[0]);
|
var typeName = ExprTools.toString(classType.meta.extract(metaName)[0].params[0]);
|
||||||
var type:ClassType = switch Context.getType(typeName) {
|
var type:ClassType = MacroUtil.getExprClassType(classType.meta.extract(metaName)[0].params[0]);
|
||||||
case TInst(t, _): t.get();
|
|
||||||
case _: null;
|
|
||||||
}
|
|
||||||
var fields = type.fields.get();
|
var fields = type.fields.get();
|
||||||
for (field in fields) {
|
for (field in fields) {
|
||||||
var argsTypes:Array<Type> = switch field.type {
|
var argsTypes:Array<Type> = switch field.type {
|
||||||
@@ -45,7 +32,7 @@ class DispatcherMacro {
|
|||||||
}
|
}
|
||||||
var signal = 'Signal${argsTypes.length}';
|
var signal = 'Signal${argsTypes.length}';
|
||||||
var type = TPath({
|
var type = TPath({
|
||||||
pack: ['haxework', 'signal'],
|
pack: ['hw', 'signal'],
|
||||||
name: 'Signal',
|
name: 'Signal',
|
||||||
sub: signal,
|
sub: signal,
|
||||||
params: argsTypes.map(function(t) return TPType(TypeTools.toComplexType(t))),
|
params: argsTypes.map(function(t) return TPType(TypeTools.toComplexType(t))),
|
||||||
@@ -54,7 +41,7 @@ class DispatcherMacro {
|
|||||||
name: signalName(field.name),
|
name: signalName(field.name),
|
||||||
access: [APublic],
|
access: [APublic],
|
||||||
pos: Context.currentPos(),
|
pos: Context.currentPos(),
|
||||||
kind: FProp('default', 'null', type, Context.parse('new haxework.signal.Signal.${signal}()', Context.currentPos())),
|
kind: FProp('default', 'null', type, Context.parse('new hw.signal.Signal.${signal}()', Context.currentPos())),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
result.push({
|
result.push({
|
||||||
21
src/main/hw/macro/FieldMacro.hx
Normal file
21
src/main/hw/macro/FieldMacro.hx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package hw.macro;
|
||||||
|
|
||||||
|
import haxe.macro.Expr;
|
||||||
|
|
||||||
|
using hw.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,4 +1,4 @@
|
|||||||
package haxework.macro;
|
package hw.macro;
|
||||||
|
|
||||||
import yaml.YamlException;
|
import yaml.YamlException;
|
||||||
import yaml.Parser;
|
import yaml.Parser;
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
package haxework.macro;
|
package hw.macro;
|
||||||
|
|
||||||
import haxe.macro.Type.ClassType;
|
import haxe.macro.Context;
|
||||||
|
import haxe.macro.ExprTools;
|
||||||
import haxe.macro.Expr;
|
import haxe.macro.Expr;
|
||||||
|
import haxe.macro.Type;
|
||||||
|
|
||||||
class Util {
|
class MacroUtil {
|
||||||
|
|
||||||
public static function getMetaParams(meta:MetadataEntry):Array<String> {
|
public static function getMetaParams(meta:MetadataEntry):Array<String> {
|
||||||
return meta.params.map(function(param:Expr) return switch param.expr {
|
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> {
|
public static function getClassMeta(classType:ClassType, metaName:String):Null<MetadataEntry> {
|
||||||
for (md in classType.meta.get()) if (md.name == metaName) {
|
for (meta in classType.meta.get()) {
|
||||||
return md;
|
if (meta.name == metaName) {
|
||||||
|
return meta;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getFieldMeta(field:Field, metaName:String):Null<MetadataEntry> {
|
public static function getFieldMeta(field:Field, metaName:String):Null<MetadataEntry> {
|
||||||
for (md in field.meta) if (md.name == metaName) {
|
if (field.meta != null) {
|
||||||
return md;
|
for (meta in field.meta) {
|
||||||
|
if (meta.name == metaName) {
|
||||||
|
return meta;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -48,4 +56,29 @@ class Util {
|
|||||||
public static function getField(fields:Array<Field>, name:String):Null<Field> {
|
public static function getField(fields:Array<Field>, name:String):Null<Field> {
|
||||||
return Lambda.find(fields, function(field:Field):Bool return field.name == name);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.macro;
|
package hw.macro;
|
||||||
|
|
||||||
typedef JsonKeyPosition = {
|
typedef JsonKeyPosition = {
|
||||||
var min:Int;
|
var min:Int;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.macro;
|
package hw.macro;
|
||||||
|
|
||||||
import haxe.DynamicAccess;
|
import haxe.DynamicAccess;
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ class PositionYamlParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function parseAll():Void {
|
private function parseAll():Void {
|
||||||
parseBlock(result);
|
//parseBlock(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parseBlock(result:DynamicAccess<Dynamic>):Void {
|
private function parseBlock(result:DynamicAccess<Dynamic>):Void {
|
||||||
@@ -1,27 +1,18 @@
|
|||||||
package haxework.macro;
|
package hw.macro;
|
||||||
|
|
||||||
import haxe.macro.Context;
|
import haxe.macro.Context;
|
||||||
import haxe.macro.Expr;
|
import haxe.macro.Expr;
|
||||||
|
|
||||||
using haxework.macro.Util;
|
using hw.macro.MacroUtil;
|
||||||
|
|
||||||
class ProvideMacro {
|
class ProvideMacro extends FieldMacro {
|
||||||
|
|
||||||
private static var metaName = ":provide";
|
public function new() {
|
||||||
|
super(":provide");
|
||||||
public static function has(field:Field):Bool {
|
|
||||||
return field.getFieldMeta(metaName) != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var field:Field;
|
override public function apply(field:Field):Array<Field> {
|
||||||
private var meta:MetadataEntry;
|
var meta:MetadataEntry = field.getFieldMeta(metaName);
|
||||||
|
|
||||||
public function new(field:Field) {
|
|
||||||
this.field = field;
|
|
||||||
this.meta = field.getFieldMeta(metaName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function apply():Array<Field> {
|
|
||||||
var result:Array<Field> = [];
|
var result:Array<Field> = [];
|
||||||
var type:ComplexType = switch field.kind {
|
var type:ComplexType = switch field.kind {
|
||||||
case FVar(t): t;
|
case FVar(t): t;
|
||||||
@@ -31,14 +22,9 @@ class ProvideMacro {
|
|||||||
case TPath(p): p.name;
|
case TPath(p): p.name;
|
||||||
default: null;
|
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);
|
var isStatic = Lambda.exists(field.access, function(a: Access) return a == AStatic);
|
||||||
result.push({
|
field.kind = FProp('get', 'set', type);
|
||||||
name: field.name,
|
|
||||||
access: isStatic ? [APublic, AStatic] : [APublic],
|
|
||||||
pos: field.pos,
|
|
||||||
kind: FProp('get', 'set', type),
|
|
||||||
});
|
|
||||||
var access = [APrivate, AInline];
|
var access = [APrivate, AInline];
|
||||||
if (isStatic) access.push(AStatic);
|
if (isStatic) access.push(AStatic);
|
||||||
var args = [name];
|
var args = [name];
|
||||||
@@ -49,7 +35,7 @@ class ProvideMacro {
|
|||||||
pos: field.pos,
|
pos: field.pos,
|
||||||
kind: FFun({
|
kind: FFun({
|
||||||
args: [],
|
args: [],
|
||||||
expr: Context.parse('return haxework.provider.Provider.get(${args.join(',')})', field.pos),
|
expr: Context.parse('return hw.provider.Provider.instance.get(${args.join(',')})', field.pos),
|
||||||
params: [],
|
params: [],
|
||||||
ret: type,
|
ret: type,
|
||||||
})
|
})
|
||||||
@@ -61,7 +47,7 @@ class ProvideMacro {
|
|||||||
pos: field.pos,
|
pos: field.pos,
|
||||||
kind: FFun({
|
kind: FFun({
|
||||||
args: [{name: 'value', type: type}],
|
args: [{name: 'value', type: type}],
|
||||||
expr: Context.parse('{haxework.provider.Provider.set(${args.join(',')}); return value;}', field.pos),
|
expr: Context.parse('{hw.provider.Provider.instance.set(${args.join(',')}); return value;}', field.pos),
|
||||||
params: [],
|
params: [],
|
||||||
ret: type,
|
ret: type,
|
||||||
})
|
})
|
||||||
10
src/main/hw/macro/ResourceMacro.hx
Normal file
10
src/main/hw/macro/ResourceMacro.hx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package hw.macro;
|
||||||
|
|
||||||
|
using hw.macro.MacroUtil;
|
||||||
|
|
||||||
|
class ResourceMacro extends FieldMacro {
|
||||||
|
|
||||||
|
public function new() {
|
||||||
|
super(":resource");
|
||||||
|
}
|
||||||
|
}
|
||||||
43
src/main/hw/macro/SingletonMacro.hx
Normal file
43
src/main/hw/macro/SingletonMacro.hx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package hw.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package haxework.macro;
|
package hw.macro;
|
||||||
|
|
||||||
import haxe.macro.Context;
|
import haxe.macro.Context;
|
||||||
import haxe.macro.Expr;
|
import haxe.macro.Expr;
|
||||||
import haxe.macro.Type;
|
import haxe.macro.Type;
|
||||||
|
|
||||||
using haxe.macro.ComplexTypeTools;
|
using haxe.macro.ComplexTypeTools;
|
||||||
using haxework.macro.Util;
|
using hw.macro.MacroUtil;
|
||||||
using haxe.macro.MacroStringTools;
|
using haxe.macro.MacroStringTools;
|
||||||
|
|
||||||
typedef TProperty<T> = {
|
typedef TProperty<T> = {
|
||||||
@@ -13,21 +13,10 @@ typedef TProperty<T> = {
|
|||||||
var defaultValue: T;
|
var defaultValue: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
class StyleMacro {
|
class StyleMacro extends ClassTypeMacro {
|
||||||
private static inline var metaName:String = ':style';
|
|
||||||
|
|
||||||
public static function has(classType:ClassType):Bool {
|
public function new() {
|
||||||
return classType.getClassMeta(metaName) != null;
|
super(":style");
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function processPropertyField(field:Field):Array<Field> {
|
private static function processPropertyField(field:Field):Array<Field> {
|
||||||
@@ -154,7 +143,7 @@ class StyleMacro {
|
|||||||
|
|
||||||
private static function buildStyleField(properties:Array<Field>, styleds:Array<Field>, hasOnStyle:Bool, overrideField:Bool):Array<Field> {
|
private static function buildStyleField(properties:Array<Field>, styleds:Array<Field>, hasOnStyle:Bool, overrideField:Bool):Array<Field> {
|
||||||
var result:Array<Field> = [];
|
var result:Array<Field> = [];
|
||||||
var type:ComplexType = "haxework.view.theme.StyleId".toComplex();
|
var type:ComplexType = "hw.view.theme.StyleId".toComplex();
|
||||||
if (!overrideField) {
|
if (!overrideField) {
|
||||||
result.push({
|
result.push({
|
||||||
name: "style",
|
name: "style",
|
||||||
@@ -173,11 +162,11 @@ class StyleMacro {
|
|||||||
}
|
}
|
||||||
for (field in properties) {
|
for (field in properties) {
|
||||||
var propertyName = 'theme_${field.name}';
|
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} = hw.provider.Provider.instance.get(hw.view.theme.ITheme).resolve((styleKey!=null?(styleKey+"."):"")+$v{field.name}, style));
|
||||||
}
|
}
|
||||||
for (field in styleds) {
|
for (field in styleds) {
|
||||||
var propertyName = '${field.name}';
|
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} = hw.provider.Provider.instance.get(hw.view.theme.ITheme).resolve((styleKey!=null?(styleKey+"."):"")+$v{field.name}, style));
|
||||||
}
|
}
|
||||||
if (hasOnStyle) {
|
if (hasOnStyle) {
|
||||||
expr.push(macro onStyle());
|
expr.push(macro onStyle());
|
||||||
@@ -201,14 +190,15 @@ class StyleMacro {
|
|||||||
return result;
|
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 result:Array<Field> = fields.slice(0);
|
||||||
var styleds:Array<Field> = [];
|
var styleds:Array<Field> = [];
|
||||||
var properties:Array<Field> = [];
|
var properties:Array<Field> = [];
|
||||||
var newFields:Array<Field> = [];
|
var newFields:Array<Field> = [];
|
||||||
var hasOnStyle:Bool = fields.getField("onStyle") != null;
|
var hasOnStyle:Bool = fields.getField("onStyle") != null;
|
||||||
for (field in fields) if (field.meta != null) {
|
for (field in fields) if (field.meta != null) {
|
||||||
var meta = field.getFieldMeta(":style");
|
var meta = field.getFieldMeta(metaName);
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
if (meta.params.length > 0) {
|
if (meta.params.length > 0) {
|
||||||
newFields = newFields.concat(processPropertyField(field));
|
newFields = newFields.concat(processPropertyField(field));
|
||||||
@@ -1,46 +1,24 @@
|
|||||||
package haxework.macro;
|
package hw.macro;
|
||||||
|
|
||||||
import Lambda;
|
|
||||||
import haxe.macro.Context;
|
import haxe.macro.Context;
|
||||||
import haxe.macro.Expr;
|
import haxe.macro.Expr;
|
||||||
import haxe.macro.Type;
|
import haxe.macro.Type;
|
||||||
import haxework.macro.PositionJsonParser;
|
import hw.macro.PositionJsonParser;
|
||||||
|
import Lambda;
|
||||||
|
|
||||||
using haxework.macro.Util;
|
using hw.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 bindings:Map<String, String>;
|
||||||
|
|
||||||
private var meta:MetadataEntry;
|
|
||||||
private var templateFile:String;
|
private var templateFile:String;
|
||||||
private var template:Dynamic;
|
private var template:Dynamic;
|
||||||
private var i:Int;
|
private var i:Int;
|
||||||
|
|
||||||
|
public function new() {
|
||||||
public function new(classType:ClassType, fields:Array<Field>) {
|
super(":template");
|
||||||
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";
|
|
||||||
}
|
|
||||||
templateFile = Context.resolvePath(filePath);
|
|
||||||
template = FileUtil.loadFile(templateFile);
|
|
||||||
bindings = findViewsBindings(fields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static function getSpecField(object:Dynamic, field:String):Dynamic {
|
private static function getSpecField(object:Dynamic, field:String):Dynamic {
|
||||||
if (Reflect.hasField(object, "@" + field)) {
|
if (Reflect.hasField(object, "@" + field)) {
|
||||||
return Reflect.field(object, "@" + field);
|
return Reflect.field(object, "@" + field);
|
||||||
@@ -68,11 +46,11 @@ class TemplateMacro {
|
|||||||
a[2];
|
a[2];
|
||||||
}
|
}
|
||||||
case "resource" | "r":
|
case "resource" | "r":
|
||||||
var bindExpr = 'haxework.provider.Provider.get(haxework.resources.IResources).${a[1]}.bind("${a[2]}", ${name}, "${key}")';
|
var bindExpr = 'hw.provider.Provider.instance.get(hw.resources.IResources).${a[1]}.bind("${a[2]}", ${name}, "${key}")';
|
||||||
exprs.push(Context.parse(bindExpr, getPosition(position)));
|
exprs.push(Context.parse(bindExpr, getPosition(position)));
|
||||||
null;
|
null;
|
||||||
case "translate" | "t":
|
case "translate" | "t":
|
||||||
'new haxework.translate.TranslateString("${a[1]}")';
|
'new hw.translate.TranslateString("${a[1]}")';
|
||||||
case "template":
|
case "template":
|
||||||
var template = FileUtil.loadFile(a[1]);
|
var template = FileUtil.loadFile(a[1]);
|
||||||
return createValue(name, key, template, position, exprs);
|
return createValue(name, key, template, position, exprs);
|
||||||
@@ -149,7 +127,7 @@ class TemplateMacro {
|
|||||||
case ECall(_, _): macro function(_) ${e};
|
case ECall(_, _): macro function(_) ${e};
|
||||||
case _: e;
|
case _: e;
|
||||||
}
|
}
|
||||||
exprs.push(macro $p{[name, key.substr(1)]}.connect(${e}));
|
exprs.push(macro $p{[name].concat(key.substr(1).split("."))}.connect(${e}));
|
||||||
case ["_", "_"]:
|
case ["_", "_"]:
|
||||||
//exprs.push(Context.parse('${name}["${key.substr(1, key.length - 2)}"] = ${value}', getPosition(position)));
|
//exprs.push(Context.parse('${name}["${key.substr(1, key.length - 2)}"] = ${value}', getPosition(position)));
|
||||||
exprs.push(Context.parse('${name}.set("${key.substr(1, key.length - 2)}", ${value})', getPosition(position)));
|
exprs.push(Context.parse('${name}.set("${key.substr(1, key.length - 2)}", ${value})', getPosition(position)));
|
||||||
@@ -176,57 +154,57 @@ class TemplateMacro {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildConstructor(init:Bool, constructor:Field = null):Field {
|
private function upgradeConstructor(constructor:Field = null):Field {
|
||||||
var contstrExprs = [];
|
if (constructor == null) {
|
||||||
if (constructor != null) {
|
constructor = {
|
||||||
switch constructor.kind {
|
name: "new",
|
||||||
case FFun(f): contstrExprs.push(f.expr);
|
access: [Access.APublic],
|
||||||
case _:
|
pos: getPosition(),
|
||||||
|
kind: FieldType.FFun({
|
||||||
|
args: [],
|
||||||
|
expr: macro super(),
|
||||||
|
params: [],
|
||||||
|
ret: null
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
contstrExprs.push(macro super());
|
|
||||||
}
|
}
|
||||||
contstrExprs.push(macro build());
|
MacroUtil.upgradeField(constructor, macro build(), 1);
|
||||||
if (init) contstrExprs.push(macro init());
|
return constructor;
|
||||||
|
|
||||||
return {
|
|
||||||
name: "new",
|
|
||||||
access: [Access.APublic],
|
|
||||||
pos: getPosition(),
|
|
||||||
kind: FieldType.FFun({
|
|
||||||
args: [],
|
|
||||||
expr: macro $b{contstrExprs},
|
|
||||||
params: [],
|
|
||||||
ret: null
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function findViewsBindings(fields:Array<Field>):Map<String, String> {
|
private static function findViewsBindings(fields:Array<Field>):Map<String, String> {
|
||||||
var result:Map<String, String> = new Map();
|
var result:Map<String, String> = new Map();
|
||||||
for (field in fields) if (field.meta != null) {
|
for (field in fields) {
|
||||||
for (meta in field.meta) {
|
var viewMeta = field.getFieldMeta(":view");
|
||||||
if (meta.name == ':view') {
|
if (viewMeta != null) {
|
||||||
var viewId:String = meta.params.length == 0 ? field.name : Util.getExprString(meta.params[0].expr);
|
var viewId:String = viewMeta.params.length == 0 ? field.name : MacroUtil.getExprString(viewMeta.params[0].expr);
|
||||||
result.set(viewId, field.name);
|
result.set(viewId, field.name);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function apply():Array<Field> {
|
override public function apply(classType:ClassType, fields:Array<Field>):Array<Field> {
|
||||||
i = 0;
|
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 result:Array<Field> = fields.slice(0);
|
||||||
var exprs:Array<Expr> = [];
|
var exprs:Array<Expr> = [];
|
||||||
var init = Lambda.exists(result, function(f) return f.name == "init");
|
|
||||||
createElement("this", template, exprs);
|
createElement("this", template, exprs);
|
||||||
result.push(buildBuild(exprs));
|
result.push(buildBuild(exprs));
|
||||||
var constructor = Lambda.find(result, function(f) return f.name == "new");
|
var constructor = Lambda.find(result, function(f) return f.name == "new");
|
||||||
if (constructor != null) {
|
if (constructor != null) {
|
||||||
result.remove(constructor);
|
result.remove(constructor);
|
||||||
}
|
}
|
||||||
result.push(buildConstructor(init, constructor));
|
result.push(upgradeConstructor(constructor));
|
||||||
if (Lambda.count(bindings) > 0) {
|
if (Lambda.count(bindings) > 0) {
|
||||||
var keys = Lambda.map({iterator: bindings.keys}, function(k) return '"${k}"').join(",");
|
var keys = Lambda.map({iterator: bindings.keys}, function(k) return '"${k}"').join(",");
|
||||||
Context.error('Invalid @:view bindings: $keys', getPosition());
|
Context.error('Invalid @:view bindings: $keys', getPosition());
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package haxework.net;
|
package hw.net;
|
||||||
|
|
||||||
import promhx.Deferred;
|
import promhx.Deferred;
|
||||||
import promhx.Promise;
|
import promhx.Promise;
|
||||||
import haxe.Timer;
|
import haxe.Timer;
|
||||||
import flash.net.URLRequestMethod;
|
import flash.net.URLRequestMethod;
|
||||||
import flash.events.ProgressEvent;
|
import flash.events.ProgressEvent;
|
||||||
import haxework.net.manage.ILoaderManager;
|
import hw.net.manage.ILoaderManager;
|
||||||
import flash.utils.ByteArray;
|
import flash.utils.ByteArray;
|
||||||
import flash.events.Event;
|
import flash.events.Event;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.net;
|
package hw.net;
|
||||||
|
|
||||||
import flash.events.ProgressEvent;
|
import flash.events.ProgressEvent;
|
||||||
import flash.system.Security;
|
import flash.system.Security;
|
||||||
@@ -6,7 +6,7 @@ import flash.system.SecurityDomain;
|
|||||||
import flash.system.ApplicationDomain;
|
import flash.system.ApplicationDomain;
|
||||||
import flash.system.LoaderContext;
|
import flash.system.LoaderContext;
|
||||||
import flash.utils.ByteArray;
|
import flash.utils.ByteArray;
|
||||||
import haxework.net.BaseLoader;
|
import hw.net.BaseLoader;
|
||||||
import flash.events.SecurityErrorEvent;
|
import flash.events.SecurityErrorEvent;
|
||||||
import flash.events.IOErrorEvent;
|
import flash.events.IOErrorEvent;
|
||||||
import flash.events.Event;
|
import flash.events.Event;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.net;
|
package hw.net;
|
||||||
|
|
||||||
import flash.events.ErrorEvent;
|
import flash.events.ErrorEvent;
|
||||||
import haxe.Timer;
|
import haxe.Timer;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.net;
|
package hw.net;
|
||||||
|
|
||||||
import promhx.Promise;
|
import promhx.Promise;
|
||||||
import promhx.Deferred;
|
import promhx.Deferred;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.net;
|
package hw.net;
|
||||||
|
|
||||||
import flash.net.URLLoaderDataFormat;
|
import flash.net.URLLoaderDataFormat;
|
||||||
import flash.utils.ByteArray;
|
import flash.utils.ByteArray;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.net;
|
package hw.net;
|
||||||
|
|
||||||
import flash.system.Security;
|
import flash.system.Security;
|
||||||
import flash.utils.ByteArray;
|
import flash.utils.ByteArray;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.net;
|
package hw.net;
|
||||||
|
|
||||||
import promhx.Promise;
|
import promhx.Promise;
|
||||||
import flash.utils.ByteArray;
|
import flash.utils.ByteArray;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.net;
|
package hw.net;
|
||||||
|
|
||||||
import flash.display.LoaderInfo;
|
import flash.display.LoaderInfo;
|
||||||
import flash.display.Loader;
|
import flash.display.Loader;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.net;
|
package hw.net;
|
||||||
|
|
||||||
import flash.utils.ByteArray;
|
import flash.utils.ByteArray;
|
||||||
import flash.events.Event;
|
import flash.events.Event;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.net;
|
package hw.net;
|
||||||
|
|
||||||
import flash.display.MovieClip;
|
import flash.display.MovieClip;
|
||||||
import flash.display.LoaderInfo;
|
import flash.display.LoaderInfo;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package haxework.net;
|
package hw.net;
|
||||||
|
|
||||||
import flash.net.URLLoader;
|
import flash.net.URLLoader;
|
||||||
import flash.events.Event;
|
import flash.events.Event;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user