37 Commits

Author SHA1 Message Date
0a6f7841e1 feat(view): add display width and height size types 2024-01-09 00:30:59 +03:00
4a7403022b build: update dependencies versions 2023-01-04 11:18:26 +03:00
163e6d68c3 [log] fix error stack on flash platform 2020-09-26 16:21:32 +03:00
f396c86a23 [macro] (template) fix Signal connect macro 2020-09-25 15:15:11 +03:00
e5f8d7834a [connect] rename neko -> server package 2020-03-30 19:02:45 +03:00
a4ca9a924c [connect] web-socket connection fixes 2020-03-30 19:00:02 +03:00
88b4459023 [connect] use haxe-crypto in ws connection 2020-03-28 17:17:40 +03:00
ccfa8c05f8 [connect] fixes 2020-03-27 16:25:40 +03:00
4017df4d00 [connect] add package 2020-03-25 21:02:51 +03:00
fe60e78b74 [animate] update 2020-03-24 23:37:08 +03:00
279baa1113 [hw] rename haxework package to hw 2020-03-24 20:58:54 +03:00
7b7819fe6e [view] fix change in FrameSwitcher 2020-02-28 21:58:49 +03:00
2428ed20e0 [yaml] use yaml 2.0.0 library 2020-02-21 14:10:24 +03:00
bc3d6e4458 [view] add stretch param to TailLayout 2020-02-19 20:52:25 +03:00
d217727d94 [demo] add TestStorage 2020-02-13 22:31:10 +03:00
c889ca04da [yaml] add sources 2020-02-13 17:20:50 +03:00
39ca4b3d9b [style] rework 2020-02-11 22:47:03 +03:00
f81ab02e67 [geom] addd 2020-02-11 22:46:47 +03:00
284593e82c [view] add ConfirmView 2020-02-07 17:02:56 +03:00
a311dc1c19 [view] add AlertView 2020-02-06 17:10:19 +03:00
07c228121c [view] add back method to frame switcher 2020-02-05 23:18:29 +03:00
a6ff04fd1b [macro] TemplateMacro: move init to constructor 2019-11-19 21:53:33 +03:00
a768e75cec [demo] fixes 2019-11-19 17:51:30 +03:00
7a5b32b251 [macro] add ClassProvideMacro 2019-11-18 18:00:55 +03:00
74ed2d4425 [macro] add ClassTypeMacro and FieldMacro 2019-11-15 16:32:57 +03:00
fcbac5587e [view] add focus method 2019-11-14 16:48:51 +03:00
78f4ae3a03 [view] popup close fix 2019-11-10 17:03:24 +03:00
b18b9d2d30 [macro] add SignletonMacro 2019-10-30 22:15:46 +03:00
c88a2c810f [view] fix onTouchEnd in GroupView 2019-09-29 12:26:28 +03:00
a253aeaed4 [view] SpriteSkin: add round param 2019-09-11 21:04:42 +03:00
3478963a6f [view] add ActionDataView 2019-09-11 17:52:30 +03:00
5989da3fe4 [view] ListView: add selected style 2019-09-10 19:48:08 +03:00
32309389e5 Merge branch 'master' of bitbucket.org:shmyga/haxework 2019-09-09 21:46:03 +03:00
3d54a2489b [view] DataView: add onDataAction signal 2019-09-09 21:45:39 +03:00
7a68604cad [log] add AndroidLog 2019-08-23 14:38:27 +03:00
f31b1ce506 [view] GroupView: add maskEnable; Color: fromString improve 2019-07-29 17:57:11 +03:00
f186b08e9f build fixes 2019-07-22 23:25:18 +03:00
188 changed files with 2485 additions and 960 deletions

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@ out/
target/
*.zip
pack.sh
.vscode/

View File

@@ -1,43 +1,42 @@
# haxework
# HaxeWork
Gui framework for Haxe.
HaXe framework.
## View
`haxework.gui` provides views classes.
`hw.view` provides views classes.
### Example
Build form using macro @:template.
form.json:
form.yaml:
```json
{
"$type": "haxework.gui.VGroupView",
"skin": [{"$type": "haxework.gui.skin.ColorSkin", "color": "0xffff00"}],
"geometry.padding": 20,
"layout.margin": 10,
"views":[
{
"id": "view1",
"type":"haxework.gui.SpriteView",
"geometry.size.stretch": true,
"skin":[{"$type":"haxework.gui.skin.ColorSkin", "color": "0xff0000"}]
},
{
"id": "view2",
"type": "haxework.gui.SpriteView",
"geometry.size.width": "100%",
"geometry.size.height": 50,
"skin": [{"$type":"haxework.gui.skin.ColorSkin", "color": "0x00ff00"}]
}
]
}
```yaml
---
skin:
- $type: hw.gui.skin.ColorSkin
color: 0xffff00
geometry.padding: 20
layout.margin: 10
views:
- id: view1
type: hw.view.SpriteView
geometry.size.stretch: true
skin:
- $type: hw.view.skin.ColorSkin
color: 0xff0000
- id: view2
type: hw.view.SpriteView
geometry.size.width: 100%
geometry.size.height: 50
skin:
- "$type": hw.view.skin.ColorSkin
color: 0x00ff00
```
```haxe
@:template("form.json")
@:template("form.yaml")
class FormView extends VGroupView {
@:view public var view1:SpriteView;
@:view("view2") public var anyVarName:SpriteView;
@@ -51,7 +50,7 @@ trace(form.anyVarName);
## Loader
`haxework.net` provides loaders classes.
`hw.net` provides loaders classes.
### Example

1
build.hxml Normal file
View File

@@ -0,0 +1 @@
-p src/main

View File

@@ -1,8 +1,9 @@
-cp src
-cp ../src/main
#-cp ../src/main
-lib yaml
-lib promhx
--macro haxework.parser.Parser.auto()
-lib haxework
--macro hw.parser.Parser.auto()
-debug
-D native_trace
#-D dev_layout

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<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"/>
<icon path="src/haxe-logo.png"/>
@@ -8,13 +8,13 @@
<source path="src"/>
<assets path="src" rename="image" include="*.png"/>
<haxelib name="lime" version="7.3.0"/>
<haxelib name="openfl" version="8.9.0"/>
<haxelib name="hxcpp" version="4.0.8"/>
<haxelib name="promhx" version="1.1.0"/>
<haxelib name="yaml" version="1.3.0"/>
<haxelib name="lime" version=""/>
<haxelib name="openfl" version=""/>
<haxelib name="hxcpp" version=""/>
<!--<haxelib name="promhx" version=""/>-->
<haxelib name="haxework" version="git"/>
<haxeflag name="--macro" value="haxework.parser.Parser.auto()"/>
<!--<haxeflag name="&#45;&#45;macro" value="hw.parser.Parser.auto()"/>-->
<haxeflag name="--macro" value="CompilationOption.set('build','xxx')"/>
<window fps="30"/>

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env bash
SDK_PATH=~/sdk
echo "`pwd`/target" > ~/.macromedia/Flash_Player/#Security/FlashPlayerTrust/haxework_demo.cfg
. /opt/sdk/neko/2.2.0/activate
. /opt/sdk/haxe/3.4.7/activate
haxe build.hxml && flashplayerdebugger target/demo.swf &
. ${SDK_PATH}/neko/2.2.0/activate
. ${SDK_PATH}/haxe/4.0.5/activate
haxe build.hxml && ${SDK_PATH}/flashplayer/32/flashplayerdebugger target/demo.swf &
tail -f ~/.macromedia/Flash_Player/Logs/flashlog.txt

View File

@@ -1,5 +1,7 @@
#!/usr/bin/env bash
SDK_PATH=~/sdk
echo "`pwd`/target/flash/bin" > ~/.macromedia/Flash_Player/#Security/FlashPlayerTrust/haxework_demo.cfg
. /opt/sdk/neko/2.2.0/activate
. /opt/sdk/haxe/3.4.7/activate
haxelib run openfl test flash
. ${SDK_PATH}/neko/2.2.0/activate
. ${SDK_PATH}/haxe/4.0.5/activate
#haxelib run openfl test flash
haxelib run openfl test html5

View File

@@ -1,10 +1,10 @@
package demo;
import haxework.view.geometry.Box;
import haxework.color.Color;
import haxework.view.theme.Theme;
import hw.view.geometry.Box;
import hw.color.Color;
import hw.view.theme.Theme;
using haxework.color.ColorUtil;
using hw.color.ColorUtil;
class AppTheme extends Theme {

View File

@@ -3,19 +3,22 @@ package demo;
import demo.dispatch.DemoDispatcher;
import demo.popup.ColorPopup;
import demo.popup.FontPopup;
import haxework.App;
import haxework.log.TraceLogger;
import haxework.net.JsonLoader;
import haxework.view.data.ButtonGroup;
import haxework.view.frame.FrameSwitcher;
import haxework.view.frame.FrameView;
import haxework.view.group.VGroupView;
import demo.storage.TestStorage;
import hw.app.App;
import hw.log.TraceLogger;
import hw.net.JsonLoader;
import hw.resources.IResources;
import hw.view.data.ButtonGroup;
import hw.view.frame.FrameSwitcher;
import hw.view.frame.FrameView;
import hw.view.group.VGroupView;
@:template class DemoView extends VGroupView {
@:view var switcher:FrameSwitcher;
@:view var tabs:ButtonGroup<String>;
private function init():Void {
public function new():Void {
super();
switcher.change("list");
}
@@ -42,12 +45,18 @@ import haxework.view.group.VGroupView;
class Demo extends App implements DemoListener {
@:provide static var storage:TestStorage;
public static function main() {
L.push(new TraceLogger());
var app = new Demo(new AppTheme());
app.resources.image.put("logo", HaxeLogo.resolve());
app.start(new DemoView());
App.resources.image.put("logo", HaxeLogo.resolve());
var app = new Demo();
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();
dispatcher.connect(app);
@@ -63,8 +72,8 @@ class Demo extends App implements DemoListener {
new JsonLoader().GET("https://embed.tvbit.co/channel/data2/renova.json")
.then(function(data:Array<Model>) {
app.resources.any.put("data", data);
app.resources.any.put("data50", Util.marray(data, 50));
App.resources.any.put("data", data);
App.resources.any.put("data50", Util.marray(data, 50));
})
.catchError(function(error) trace(error));
}

View File

@@ -1,11 +1,11 @@
---
style: background
views:
- $type: haxework.view.ImageView
- $type: hw.view.ImageView
geometry.padding: 10
image: $r:image:logo
- id: tabs
$type: haxework.view.data.ButtonGroup<String>
$type: hw.view.data.ButtonGroup<String>
layout.margin: 5
layout.hAlign: left
geometry.width: 100%
@@ -20,8 +20,8 @@ views:
- "test_layout"
- "select"
- id: switcher
$type: haxework.view.frame.FrameSwitcher
animateFactory: { $class: haxework.animate.SlideAnimate }
$type: hw.view.frame.FrameSwitcher
animateFactory: { $class: hw.animate.SlideAnimate }
+onSwitch: ~onFrameSwitch
geometry.stretch: true
geometry.padding: 5
@@ -31,24 +31,24 @@ views:
_data_: {$class: demo.form.DataForm}
_test_layout_: {$class: demo.form.TestLayoutForm}
_select_: {$class: demo.form.SelectForm}
- $type: haxework.view.group.HGroupView
- $type: hw.view.group.HGroupView
geometry.width: 100%
geometry.padding: 10
layout.margin: 10
views:
- $type: haxework.view.form.ButtonView
- $type: hw.view.form.ButtonView
text: Color
+onPress: ~choiceColor()
- $type: haxework.view.form.ButtonView
- $type: hw.view.form.ButtonView
text: Font
+onPress: ~choiceFont()
# separator
- $type: haxework.view.SpriteView
- $type: hw.view.SpriteView
geometry.stretch: true
- $type: haxework.view.form.ButtonView
- $type: hw.view.form.ButtonView
text: OK
- $type: haxework.view.form.ButtonView
- $type: hw.view.form.ButtonView
text: Apply
- $type: haxework.view.form.ButtonView
- $type: hw.view.form.ButtonView
text: Cancel
+onPress: ~flash.system.System.exit(0)

View File

@@ -1,8 +1,8 @@
package demo;
import demo.test.TestView;
import haxework.view.Root;
import haxework.view.SpriteView;
import hw.view.Root;
import hw.view.SpriteView;
class Test {
public static function main():Void {

View File

@@ -1,6 +1,6 @@
package demo.dispatch;
import haxework.App;
import hw.app.App;
interface DemoListener {
public function onTest1():Void;
@@ -9,6 +9,6 @@ interface DemoListener {
public function onTest4(app:App):Void;
}
@:yield @:dispatcher(DemoListener) class DemoDispatcher {
@:dispatcher(DemoListener) class DemoDispatcher {
public function new() {}
}

View File

@@ -1,7 +1,7 @@
package demo.form;
import haxework.view.frame.FrameView;
import haxework.view.text.TextView;
import hw.view.frame.FrameView;
import hw.view.text.TextView;
@:template class DataForm extends FrameView<Dynamic> {
public function new() {

View File

@@ -2,9 +2,9 @@
overflow.y: scroll
views:
- id: data
$type: haxework.view.data.DataView
$type: hw.view.data.DataView
layout:
$type: haxework.view.layout.VerticalLayout
$type: hw.view.layout.VerticalLayout
factory: ~factory
geometry.width: 100%
data: $r:any:data

View File

@@ -1,9 +1,9 @@
package demo.form;
import haxework.view.frame.FrameView;
import haxework.view.list.LabelListItem;
import haxework.view.list.ListView.IListItemView;
import haxework.view.list.VListView;
import hw.view.frame.FrameView;
import hw.view.list.LabelListItem;
import hw.view.list.ListView.IListItemView;
import hw.view.list.VListView;
@:template class ListForm extends FrameView<Dynamic> {
@:view public var list(default, null):VListView<Model>;

View File

@@ -1,10 +1,10 @@
---
views:
- id: list
$type: haxework.view.list.VListView
$type: hw.view.list.VListView
+onItemSelect: ~onItemSelect
factory: ~factory
geometry.stretch: true
scroll:
$type: haxework.view.list.VScrollBarView
$type: hw.view.list.VScrollBarView
data: $r:any:data50

View File

@@ -1,6 +1,6 @@
package demo.form;
import haxework.view.frame.FrameView;
import hw.view.frame.FrameView;
@:template class SelectForm extends FrameView<Dynamic> {
public function new() {

View File

@@ -2,7 +2,7 @@
geometry.padding: 10
layout.margin: 5
views:
- $type: haxework.view.form.SelectView<String>
- $type: hw.view.form.SelectView<String>
layout.margin: 2
dataView.layout.margin: 1
data:
@@ -13,7 +13,7 @@ views:
selected: "value 1"
+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
dataView.layout.margin: 1
labelBuilder: |

View File

@@ -1,10 +1,10 @@
package demo.form;
import haxework.view.frame.FrameView;
import haxework.view.ImageView;
import haxework.view.IView;
import haxework.view.text.TextView;
import haxework.view.utils.DrawUtil;
import hw.view.frame.FrameView;
import hw.view.ImageView;
import hw.view.IView;
import hw.view.text.TextView;
import hw.view.utils.DrawUtil;
@:template class TailForm extends FrameView<Dynamic> {

View File

@@ -2,10 +2,10 @@
overflow.y: scroll
views:
- id: data
$type: haxework.view.data.DataView
$type: hw.view.data.DataView
geometry.padding: 4
layout:
$type: haxework.view.layout.TailLayout
$type: hw.view.layout.TailLayout
margin: 6
factory: ~factory
geometry.width: 100%

View File

@@ -1,8 +1,8 @@
package demo.form;
import flash.events.MouseEvent;
import haxework.view.frame.FrameView;
import haxework.view.SpriteView;
import hw.view.frame.FrameView;
import hw.view.SpriteView;
@:template class TestLayoutForm extends FrameView<Dynamic> {
@@ -10,9 +10,6 @@ import haxework.view.SpriteView;
public function new() {
super("test_layout");
}
public function init():Void {
resize();
content.addEventListener(MouseEvent.CLICK, function(_) {
resize();

View File

@@ -1,52 +1,52 @@
---
views:
- id: main
$type: haxework.view.group.VGroupView
$type: hw.view.group.VGroupView
geometry.stretch: true
layout.hAlign: center
layout.vAlign: middle
views:
- id: container
$type: haxework.view.group.VGroupView
$type: hw.view.group.VGroupView
layout.margin: 10
skin:
$type: [haxework.view.skin.Skin.color, 0xffff00]
$type: [hw.view.skin.Skin.color, 0xffff00]
views:
- id: top
$type: haxework.view.group.GroupView
$type: hw.view.group.GroupView
layout.hAlign: center
geometry.width: 100%
geometry.height: 20
style: test
- id: middle
$type: haxework.view.group.HGroupView
$type: hw.view.group.HGroupView
layout.margin: 10
views:
- id: left
$type: haxework.view.group.GroupView
$type: hw.view.group.GroupView
layout.vAlign: middle
geometry.width: 20
geometry.height: 100%
style: test
- id: render
$type: haxework.view.SpriteView
$type: hw.view.SpriteView
#geometry.width: 300
#geometry.height: 200
style: test
- id: right
$type: haxework.view.group.GroupView
$type: hw.view.group.GroupView
layout.vAlign: middle
geometry.width: 20
geometry.height: 100%
style: test
views:
- $type: haxework.view.SpriteView
- $type: hw.view.SpriteView
geometry.width: 100
geometry.height: 100%
skin:
$type: [haxework.view.skin.Skin.color, 0xff0000]
$type: [hw.view.skin.Skin.color, 0xff0000]
- id: bottom
$type: haxework.view.group.GroupView
$type: hw.view.group.GroupView
layout.hAlign: center
style: test
geometry.width: 100%

View File

@@ -1,8 +1,8 @@
package demo.popup;
import haxework.view.form.ButtonView;
import haxework.view.popup.PopupView;
import haxework.view.skin.Skin;
import hw.view.form.ButtonView;
import hw.view.popup.PopupView;
import hw.view.skin.Skin;
@:template class ColorPopup extends PopupView<Null<Int>> {

View File

@@ -1,6 +1,6 @@
---
view:
$type: haxework.view.group.VGroupView
$type: hw.view.group.VGroupView
geometry.width: 400
geometry.height: 200
geometry.padding: 10
@@ -9,10 +9,10 @@ view:
style: frame
views:
- id: colors
$type: haxework.view.data.DataView
$type: hw.view.data.DataView
geometry.stretch: true
layout:
$type: haxework.view.layout.TailLayout
$type: hw.view.layout.TailLayout
vAlign: middle
margin: 5
factory: ~colorViewFactory
@@ -23,11 +23,11 @@ view:
- 0xCC33AA
- 0x3333AA
+onDataSelect: ~close
- $type: haxework.view.group.HGroupView
- $type: hw.view.group.HGroupView
geometry.width: 100%
layout.hAlign: right
layout.margin: 10
views:
- $type: haxework.view.form.ButtonView
- $type: hw.view.form.ButtonView
text: Cancel
+onPress: ~reject('cancel')

View File

@@ -2,10 +2,10 @@ package demo.popup;
import flash.text.Font;
import flash.text.FontType;
import haxework.view.list.LabelListItem;
import haxework.view.list.ListView;
import haxework.view.popup.PopupView;
import haxework.view.theme.ITheme;
import hw.view.list.LabelListItem;
import hw.view.list.ListView;
import hw.view.popup.PopupView;
import hw.view.theme.ITheme;
class FontLabelView extends LabelListItem<ThemeFont> {
@@ -23,7 +23,8 @@ class FontLabelView extends LabelListItem<ThemeFont> {
@:view var fonts:ListView<ThemeFont>;
private function init():Void {
public function new():Void {
super();
var values:Array<ThemeFont> = Font.enumerateFonts(true).map(function(font:Font) {
return {
name: font.fontName,

View File

@@ -1,6 +1,6 @@
---
view:
$type: haxework.view.group.VGroupView
$type: hw.view.group.VGroupView
geometry.width: 400
geometry.height: 80%
geometry.padding: 10
@@ -9,17 +9,17 @@ view:
style: frame
views:
- id: fonts
$type: haxework.view.list.VListView
$type: hw.view.list.VListView
geometry.stretch: true
factory: ~fontViewFactory
+onItemSelect: ~function(item) close(item.data)
scroll:
$type: haxework.view.list.VScrollBarView
- $type: haxework.view.group.HGroupView
$type: hw.view.list.VScrollBarView
- $type: hw.view.group.HGroupView
geometry.width: 100%
geometry.margin.top: 10
layout.hAlign: right
views:
- $type: haxework.view.form.ButtonView
- $type: hw.view.form.ButtonView
text: Cancel
+onPress: ~reject('cancel')

View File

@@ -0,0 +1,10 @@
package demo.storage;
import hw.storage.SharedObjectStorage;
@:provide class TestStorage extends SharedObjectStorage {
public function new() {
super("test");
}
}

View File

@@ -1,6 +1,6 @@
package demo.test;
import haxework.view.group.GroupView;
import hw.view.group.GroupView;
@:template class TestView extends GroupView {

View File

@@ -1,61 +1,61 @@
---
geometry.padding: 10
views:
- $type: haxework.view.group.HGroupView
- $type: hw.view.group.HGroupView
geometry.padding: 10
geometry.width: 100%
layout.margin: 10
layout.vAlign: middle
skin:
$type: haxework.view.skin.SpriteSkin
$type: hw.view.skin.SpriteSkin
background.color: 0xffff00
background.alpha: 1
views:
- $type: haxework.view.SpriteView
- $type: hw.view.SpriteView
geometry.width: 100
geometry.height: 100
skin:
$type: haxework.view.skin.SpriteSkin
$type: hw.view.skin.SpriteSkin
background.color: 0xff0000
background.alpha: 1
- $type: haxework.view.group.VGroupView
- $type: hw.view.group.VGroupView
geometry.padding: 10
layout.margin: 10
skin:
$type: haxework.view.skin.SpriteSkin
$type: hw.view.skin.SpriteSkin
background.color: 0x00ffff
background.alpha: 1
views:
- $type: haxework.view.SpriteView
- $type: hw.view.SpriteView
geometry.width: 100
geometry.height: 100
size:
_test_: [200, 200]
skin:
$type: haxework.view.skin.SpriteSkin
$type: hw.view.skin.SpriteSkin
background.color: 0xff0000
background.alpha: 1
- $type: haxework.view.SpriteView
- $type: hw.view.SpriteView
geometry.width: 100
geometry.height: 100
skin:
$type: haxework.view.skin.SpriteSkin
$type: hw.view.skin.SpriteSkin
background.color: 0xff0000
background.alpha: 1
- $type: haxework.view.text.TextView
- $type: hw.view.text.TextView
geometry.padding: 20
text: "Azazaza"
- $type: haxework.view.SpriteView
- $type: hw.view.SpriteView
geometry.width: 60%
geometry.height: 100%
skin:
$type: haxework.view.skin.SpriteSkin
$type: hw.view.skin.SpriteSkin
background.color: 0xff0000
background.alpha: 1
- $type: haxework.view.SpriteView
- $type: hw.view.SpriteView
geometry.width: 40%
geometry.height: 80%
skin:
$type: haxework.view.skin.SpriteSkin
$type: hw.view.skin.SpriteSkin
background.color: 0xff0000
background.alpha: 1

View File

@@ -1 +1 @@
--macro haxework.parser.Parser.auto()
--macro hw.parser.Parser.auto()

View File

@@ -2,20 +2,16 @@
"name": "haxework",
"url": "https://bitbucket.org/shmyga/haxework",
"license": "MIT",
"tags": [
"view",
"layout",
"template"
],
"tags": ["view", "layout", "template"],
"description": "View framework.",
"version": "1.0.0",
"version": "2.1.0",
"releasenote": "Update.",
"contributors": [
"shmyga"
],
"contributors": ["shmyga"],
"classPath": "src/main",
"dependencies": {
"promhx": "1.1.0",
"yaml": "1.3.0"
"protohx": "0.4.6",
"haxe-crypto": "0.0.8",
"yaml": "2.0.1"
}
}

View File

@@ -1,6 +1,6 @@
package;
import haxework.log.ILogger;
import hw.log.ILogger;
class L {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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;
}
}

View 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);
}
}

View File

@@ -1,10 +1,11 @@
package haxework.animate;
package hw.animate;
import flash.display.DisplayObject;
import flash.display.Sprite;
import haxework.animate.Animate;
import haxework.animate.IAnimate;
import haxework.view.IView;
import hw.animate.Animate;
import hw.animate.IAnimate;
import hw.view.IView;
import promhx.Promise;
class CircleMaskAnimate extends Animate {
@@ -19,7 +20,7 @@ class CircleMaskAnimate extends Animate {
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 height = view.parent.height;
size = Math.sqrt(width * width + height * height);
@@ -33,7 +34,7 @@ class CircleMaskAnimate extends Animate {
view.content.mask = mask;
view.parent.container.addChild(cyrcle);
super.start(callback, custom);
return super.start();
}
private function redraw(size:Float, r:Float):Void {
@@ -48,15 +49,14 @@ class CircleMaskAnimate extends Animate {
cyrcle.graphics.lineStyle();
}
override private function update(time:Float):Void {
super.update(time);
override public function update(time:Float):Bool {
var result = super.update(time);
redraw(size, size * progress);
if (progress >= 1 && view.content.parent != null) {
if (view.content.parent.contains(mask)) view.content.parent.removeChild(mask);
view.content.mask = null;
if (view.content.parent.contains(cyrcle)) view.parent.container.removeChild(cyrcle);
}
return result;
}
}

View 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;
}
}

View 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;
}

View 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;
}
}

View 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
View 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
View 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;
}
}

View 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;
}
}

View File

@@ -1,4 +1,4 @@
package haxework.color;
package hw.color;
abstract Color(Int) {
public var alpha(get, never):Int;
@@ -44,7 +44,25 @@ abstract Color(Int) {
}
@:from static public inline function fromString(value:String):Color {
return new Color(Std.parseInt('0x${value.split('#').pop()}'));
return new Color(switch value {
case "white": 0xFFFFFF;
case "silver": 0xC0C0C0;
case "gray": 0x808080;
case "black": 0x000000;
case "red": 0xFF0000;
case "maroon": 0x800000;
case "yellow": 0xFFFF00;
case "olive": 0x808000;
case "lime": 0x00FF00;
case "green": 0x008000;
case "aqua": 0x00FFFF;
case "teal": 0x008080;
case "blue": 0x0000FF;
case "navy": 0x000080;
case "fuchsia": 0xFF00FF;
case "purple": 0x800080;
case x: Std.parseInt('0x${x.split('#').pop()}');
});
}
@:to public inline function toString():String {

View File

@@ -1,4 +1,4 @@
package haxework.color;
package hw.color;
class ColorUtil {

View 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);
}
}

View 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
}
}

View 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;
}

View 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();
}
}

View 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;
}
}

View 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();
}
}

View 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);
}
}

View 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();
}
}

View 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");
}
}
}

View 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();
}
}

View 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;
}
}

View 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;
}

View 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}');
}
}

View 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
View 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}';
}
}

View 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;
}
}

View 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;
}

View File

@@ -1,6 +1,6 @@
package haxework.log;
package hw.log;
import haxework.log.ILogger.LogLevel;
import hw.log.ILogger.LogLevel;
import haxe.CallStack;
@@ -12,16 +12,25 @@ class LoggerUtil {
public static function printStackItem(item:StackItem):String {
return switch item {
case StackItem.CFunction: 'CFunction';
case StackItem.Module(m): m;
case StackItem.FilePos(s, file, line): '${file}:${line}';
case StackItem.Method(classname, method): '${classname}::${method}}';
case StackItem.LocalFunction(v): 'LocalFunction(${v})';
case CFunction: 'CFunction';
case Module(m): m;
case FilePos(s, file, line): '${file}:${line}';
case Method(classname, method): '${classname}::${method}}';
case LocalFunction(v): 'LocalFunction(${v})';
}
}
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 {
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)}');
}
}

View File

@@ -1,4 +1,4 @@
package haxework.log;
package hw.log;
enum LogLevel {
DEBUG; INFO; WARNING; ERROR;

View File

@@ -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 haxework.log.BaseLogger;
import hw.log.BaseLogger;
class JSLogger extends BaseLogger {

View File

@@ -1,6 +1,6 @@
package haxework.log;
package hw.log;
import haxework.log.BaseLogger;
import hw.log.BaseLogger;
#if js
class SocketLogger extends BaseLogger {}

View File

@@ -1,4 +1,4 @@
package haxework.log;
package hw.log;
import flash.text.TextField;

View File

@@ -1,4 +1,4 @@
package haxework.log;
package hw.log;
import haxe.PosInfos;
#if cpp
@@ -27,13 +27,17 @@ class TraceLogger extends BaseLogger {
$print("\n");
}
#elseif js
untyped js.Boot.__trace(v, infos);
if (js.Syntax.typeof(untyped console) != "undefined" && (untyped console).log != null)
(untyped console).log(v);
//untyped js.Boot.__trace(v, infos);
#elseif android
hw.log.AndroidLog.write(3, "", ConstCharStar.fromString(Std.string(v)));
#elseif (php && php7)
php.Boot.trace(v);
#elseif php
untyped __call__('_hx_trace', v);
#elseif cpp
Stdio.printf(ConstCharStar.fromString(Std.string(v)));
Stdio.printf(ConstCharStar.fromString(Std.string(v)+'\n'));
//untyped __trace(v, null);
#elseif cs
cs.system.Console.WriteLine(v);

View 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);
}
}

View 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;
}
}

View File

@@ -1,4 +1,4 @@
package haxework.macro;
package hw.macro;
import haxe.macro.TypeTools;
import haxe.macro.Context;
@@ -6,20 +6,10 @@ import haxe.macro.ExprTools;
import haxe.macro.Expr;
import haxe.macro.Type;
class DispatcherMacro {
class DispatcherMacro extends ClassTypeMacro {
private static inline var metaName:String = ':dispatcher';
public static function has(classType:ClassType):Bool {
return classType.meta.has(metaName);
}
private var classType:ClassType;
private var fields:Array<Field>;
public function new(classType:ClassType, fields:Array<Field>) {
this.classType = classType;
this.fields = fields;
public function new() {
super(":dispatcher");
}
private static inline function signalName(fieldName:String):String {
@@ -30,13 +20,10 @@ class DispatcherMacro {
}
}
public function apply():Array<Field> {
override public function apply(classType:ClassType, fields:Array<Field>):Array<Field> {
var result:Array<Field> = fields.slice(0);
var typeName = ExprTools.toString(classType.meta.extract(metaName)[0].params[0]);
var type:ClassType = switch Context.getType(typeName) {
case TInst(t, _): t.get();
case _: null;
}
var type:ClassType = MacroUtil.getExprClassType(classType.meta.extract(metaName)[0].params[0]);
var fields = type.fields.get();
for (field in fields) {
var argsTypes:Array<Type> = switch field.type {
@@ -45,7 +32,7 @@ class DispatcherMacro {
}
var signal = 'Signal${argsTypes.length}';
var type = TPath({
pack: ['haxework', 'signal'],
pack: ['hw', 'signal'],
name: 'Signal',
sub: signal,
params: argsTypes.map(function(t) return TPType(TypeTools.toComplexType(t))),
@@ -54,7 +41,7 @@ class DispatcherMacro {
name: signalName(field.name),
access: [APublic],
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({

View 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 [];
}
}

View File

@@ -1,4 +1,4 @@
package haxework.macro;
package hw.macro;
import yaml.YamlException;
import yaml.Parser;

View File

@@ -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.Type;
class Util {
class MacroUtil {
public static function getMetaParams(meta:MetadataEntry):Array<String> {
return meta.params.map(function(param:Expr) return switch param.expr {
@@ -17,15 +19,21 @@ class Util {
}
public static function getClassMeta(classType:ClassType, metaName:String):Null<MetadataEntry> {
for (md in classType.meta.get()) if (md.name == metaName) {
return md;
for (meta in classType.meta.get()) {
if (meta.name == metaName) {
return meta;
}
}
return null;
}
public static function getFieldMeta(field:Field, metaName:String):Null<MetadataEntry> {
for (md in field.meta) if (md.name == metaName) {
return md;
if (field.meta != null) {
for (meta in field.meta) {
if (meta.name == metaName) {
return meta;
}
}
}
return null;
}
@@ -48,4 +56,29 @@ class Util {
public static function getField(fields:Array<Field>, name:String):Null<Field> {
return Lambda.find(fields, function(field:Field):Bool return field.name == name);
}
public static function getExprClassType(expr:Expr):Null<ClassType> {
var typeName = ExprTools.toString(expr);
return switch Context.getType(typeName) {
case TInst(t, _): t.get();
case _: null;
}
}
public static function upgradeField(field:Field, expr:Expr, position:Int = 0):Field {
switch field.kind {
case FFun(f):
var fieldExpr = f.expr;
switch fieldExpr.expr {
case EBlock(exprs):
exprs.insert(position, expr);
fieldExpr = macro $b{exprs};
case _:
fieldExpr = macro $b{[fieldExpr, expr]}
}
f.expr = fieldExpr;
case _:
}
return field;
}
}

View File

@@ -1,4 +1,4 @@
package haxework.macro;
package hw.macro;
typedef JsonKeyPosition = {
var min:Int;

View File

@@ -1,4 +1,4 @@
package haxework.macro;
package hw.macro;
import haxe.DynamicAccess;
@@ -17,7 +17,7 @@ class PositionYamlParser {
}
private function parseAll():Void {
parseBlock(result);
//parseBlock(result);
}
private function parseBlock(result:DynamicAccess<Dynamic>):Void {

View File

@@ -1,27 +1,18 @@
package haxework.macro;
package hw.macro;
import haxe.macro.Context;
import haxe.macro.Expr;
using haxework.macro.Util;
using hw.macro.MacroUtil;
class ProvideMacro {
class ProvideMacro extends FieldMacro {
private static var metaName = ":provide";
public static function has(field:Field):Bool {
return field.getFieldMeta(metaName) != null;
public function new() {
super(":provide");
}
private var field:Field;
private var meta:MetadataEntry;
public function new(field:Field) {
this.field = field;
this.meta = field.getFieldMeta(metaName);
}
public function apply():Array<Field> {
override public function apply(field:Field):Array<Field> {
var meta:MetadataEntry = field.getFieldMeta(metaName);
var result:Array<Field> = [];
var type:ComplexType = switch field.kind {
case FVar(t): t;
@@ -31,14 +22,9 @@ class ProvideMacro {
case TPath(p): p.name;
default: null;
}
var provideType:String = meta.params.length == 0 ? null : Util.getExprString(meta.params[0].expr);
var provideType:String = meta.params.length == 0 ? null : MacroUtil.getExprString(meta.params[0].expr);
var isStatic = Lambda.exists(field.access, function(a: Access) return a == AStatic);
result.push({
name: field.name,
access: isStatic ? [APublic, AStatic] : [APublic],
pos: field.pos,
kind: FProp('get', 'set', type),
});
field.kind = FProp('get', 'set', type);
var access = [APrivate, AInline];
if (isStatic) access.push(AStatic);
var args = [name];
@@ -49,7 +35,7 @@ class ProvideMacro {
pos: field.pos,
kind: FFun({
args: [],
expr: Context.parse('return haxework.provider.Provider.get(${args.join(',')})', field.pos),
expr: Context.parse('return hw.provider.Provider.instance.get(${args.join(',')})', field.pos),
params: [],
ret: type,
})
@@ -61,7 +47,7 @@ class ProvideMacro {
pos: field.pos,
kind: FFun({
args: [{name: 'value', type: type}],
expr: Context.parse('{haxework.provider.Provider.set(${args.join(',')}); return value;}', field.pos),
expr: Context.parse('{hw.provider.Provider.instance.set(${args.join(',')}); return value;}', field.pos),
params: [],
ret: type,
})

View File

@@ -0,0 +1,10 @@
package hw.macro;
using hw.macro.MacroUtil;
class ResourceMacro extends FieldMacro {
public function new() {
super(":resource");
}
}

View 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;
}
}

View File

@@ -1,11 +1,11 @@
package haxework.macro;
package hw.macro;
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;
using haxe.macro.ComplexTypeTools;
using haxework.macro.Util;
using hw.macro.MacroUtil;
using haxe.macro.MacroStringTools;
typedef TProperty<T> = {
@@ -13,21 +13,10 @@ typedef TProperty<T> = {
var defaultValue: T;
}
class StyleMacro {
private static inline var metaName:String = ':style';
class StyleMacro extends ClassTypeMacro {
public static function has(classType:ClassType):Bool {
return classType.getClassMeta(metaName) != null;
}
private var classType:ClassType;
private var fields:Array<Field>;
private var overrideStyle:Bool;
public function new(classType:ClassType, fields:Array<Field>) {
this.classType = classType;
this.fields = fields;
this.overrideStyle = classType.getClassMeta(":style").params.length > 0;
public function new() {
super(":style");
}
private static function processPropertyField(field:Field):Array<Field> {
@@ -154,7 +143,7 @@ class StyleMacro {
private static function buildStyleField(properties:Array<Field>, styleds:Array<Field>, hasOnStyle:Bool, overrideField:Bool):Array<Field> {
var result:Array<Field> = [];
var type:ComplexType = "haxework.view.theme.StyleId".toComplex();
var type:ComplexType = "hw.view.theme.StyleId".toComplex();
if (!overrideField) {
result.push({
name: "style",
@@ -173,11 +162,11 @@ class StyleMacro {
}
for (field in properties) {
var propertyName = 'theme_${field.name}';
expr.push(macro $i{propertyName} = haxework.provider.Provider.get(haxework.view.theme.ITheme).resolve((styleKey!=null?(styleKey+"."):"")+$v{field.name}, style));
expr.push(macro $i{propertyName} = hw.provider.Provider.instance.get(hw.view.theme.ITheme).resolve((styleKey!=null?(styleKey+"."):"")+$v{field.name}, style));
}
for (field in styleds) {
var propertyName = '${field.name}';
expr.push(macro $i{propertyName} = haxework.provider.Provider.get(haxework.view.theme.ITheme).resolve((styleKey!=null?(styleKey+"."):"")+$v{field.name}, style));
expr.push(macro $i{propertyName} = hw.provider.Provider.instance.get(hw.view.theme.ITheme).resolve((styleKey!=null?(styleKey+"."):"")+$v{field.name}, style));
}
if (hasOnStyle) {
expr.push(macro onStyle());
@@ -201,14 +190,15 @@ class StyleMacro {
return result;
}
public function apply():Array<Field> {
override public function apply(classType:ClassType, fields:Array<Field>):Array<Field> {
var overrideStyle = classType.getClassMeta(metaName).params.length > 0;
var result:Array<Field> = fields.slice(0);
var styleds:Array<Field> = [];
var properties:Array<Field> = [];
var newFields:Array<Field> = [];
var hasOnStyle:Bool = fields.getField("onStyle") != null;
for (field in fields) if (field.meta != null) {
var meta = field.getFieldMeta(":style");
var meta = field.getFieldMeta(metaName);
if (meta != null) {
if (meta.params.length > 0) {
newFields = newFields.concat(processPropertyField(field));

View File

@@ -1,45 +1,23 @@
package haxework.macro;
package hw.macro;
import Lambda;
import haxe.macro.Context;
import haxe.macro.Expr;
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 meta:MetadataEntry;
private var templateFile:String;
private var template:Dynamic;
private var i:Int;
public function new(classType:ClassType, fields:Array<Field>) {
this.classType = classType;
this.meta = classType.getClassMeta(metaName);
this.fields = fields;
var params = Util.getMetaParams(meta);
var filePath = params[0];
if (filePath == null) {
filePath = classType.pack.join("/") + "/" + classType.name + ".yaml";
public function new() {
super(":template");
}
templateFile = Context.resolvePath(filePath);
template = FileUtil.loadFile(templateFile);
bindings = findViewsBindings(fields);
}
private static function getSpecField(object:Dynamic, field:String):Dynamic {
if (Reflect.hasField(object, "@" + field)) {
@@ -68,11 +46,11 @@ class TemplateMacro {
a[2];
}
case "resource" | "r":
var bindExpr = 'haxework.provider.Provider.get(haxework.resources.IResources).${a[1]}.bind("${a[2]}", ${name}, "${key}")';
var bindExpr = 'hw.provider.Provider.instance.get(hw.resources.IResources).${a[1]}.bind("${a[2]}", ${name}, "${key}")';
exprs.push(Context.parse(bindExpr, getPosition(position)));
null;
case "translate" | "t":
'new haxework.translate.TranslateString("${a[1]}")';
'new hw.translate.TranslateString("${a[1]}")';
case "template":
var template = FileUtil.loadFile(a[1]);
return createValue(name, key, template, position, exprs);
@@ -149,7 +127,7 @@ class TemplateMacro {
case ECall(_, _): macro function(_) ${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 ["_", "_"]:
//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)));
@@ -176,57 +154,57 @@ class TemplateMacro {
}
}
private function buildConstructor(init:Bool, constructor:Field = null):Field {
var contstrExprs = [];
if (constructor != null) {
switch constructor.kind {
case FFun(f): contstrExprs.push(f.expr);
case _:
}
} else {
contstrExprs.push(macro super());
}
contstrExprs.push(macro build());
if (init) contstrExprs.push(macro init());
return {
private function upgradeConstructor(constructor:Field = null):Field {
if (constructor == null) {
constructor = {
name: "new",
access: [Access.APublic],
pos: getPosition(),
kind: FieldType.FFun({
args: [],
expr: macro $b{contstrExprs},
expr: macro super(),
params: [],
ret: null
})
};
}
}
MacroUtil.upgradeField(constructor, macro build(), 1);
return constructor;
}
private static function findViewsBindings(fields:Array<Field>):Map<String, String> {
var result:Map<String, String> = new Map();
for (field in fields) if (field.meta != null) {
for (meta in field.meta) {
if (meta.name == ':view') {
var viewId:String = meta.params.length == 0 ? field.name : Util.getExprString(meta.params[0].expr);
for (field in fields) {
var viewMeta = field.getFieldMeta(":view");
if (viewMeta != null) {
var viewId:String = viewMeta.params.length == 0 ? field.name : MacroUtil.getExprString(viewMeta.params[0].expr);
result.set(viewId, field.name);
}
}
}
return result;
}
public function apply():Array<Field> {
override public function apply(classType:ClassType, fields:Array<Field>):Array<Field> {
i = 0;
var meta = classType.getClassMeta(metaName);
var params = MacroUtil.getMetaParams(meta);
var filePath = params[0];
if (filePath == null) {
filePath = classType.pack.join("/") + "/" + classType.name + ".yaml";
}
// ToDo: template builder
templateFile = Context.resolvePath(filePath);
template = FileUtil.loadFile(templateFile);
bindings = findViewsBindings(fields);
var result:Array<Field> = fields.slice(0);
var exprs:Array<Expr> = [];
var init = Lambda.exists(result, function(f) return f.name == "init");
createElement("this", template, exprs);
result.push(buildBuild(exprs));
var constructor = Lambda.find(result, function(f) return f.name == "new");
if (constructor != null) {
result.remove(constructor);
}
result.push(buildConstructor(init, constructor));
result.push(upgradeConstructor(constructor));
if (Lambda.count(bindings) > 0) {
var keys = Lambda.map({iterator: bindings.keys}, function(k) return '"${k}"').join(",");
Context.error('Invalid @:view bindings: $keys', getPosition());

View File

@@ -1,11 +1,11 @@
package haxework.net;
package hw.net;
import promhx.Deferred;
import promhx.Promise;
import haxe.Timer;
import flash.net.URLRequestMethod;
import flash.events.ProgressEvent;
import haxework.net.manage.ILoaderManager;
import hw.net.manage.ILoaderManager;
import flash.utils.ByteArray;
import flash.events.Event;

View File

@@ -1,4 +1,4 @@
package haxework.net;
package hw.net;
import flash.events.ProgressEvent;
import flash.system.Security;
@@ -6,7 +6,7 @@ import flash.system.SecurityDomain;
import flash.system.ApplicationDomain;
import flash.system.LoaderContext;
import flash.utils.ByteArray;
import haxework.net.BaseLoader;
import hw.net.BaseLoader;
import flash.events.SecurityErrorEvent;
import flash.events.IOErrorEvent;
import flash.events.Event;

View File

@@ -1,4 +1,4 @@
package haxework.net;
package hw.net;
import flash.events.ErrorEvent;
import haxe.Timer;

View File

@@ -1,4 +1,4 @@
package haxework.net;
package hw.net;
import promhx.Promise;
import promhx.Deferred;

View File

@@ -1,4 +1,4 @@
package haxework.net;
package hw.net;
import flash.net.URLLoaderDataFormat;
import flash.utils.ByteArray;

View File

@@ -1,4 +1,4 @@
package haxework.net;
package hw.net;
import flash.system.Security;
import flash.utils.ByteArray;

View File

@@ -1,4 +1,4 @@
package haxework.net;
package hw.net;
import promhx.Promise;
import flash.utils.ByteArray;

View File

@@ -1,4 +1,4 @@
package haxework.net;
package hw.net;
import flash.display.LoaderInfo;
import flash.display.Loader;

View File

@@ -1,4 +1,4 @@
package haxework.net;
package hw.net;
import flash.utils.ByteArray;
import flash.events.Event;

View File

@@ -1,4 +1,4 @@
package haxework.net;
package hw.net;
import flash.display.MovieClip;
import flash.display.LoaderInfo;

View File

@@ -1,4 +1,4 @@
package haxework.net;
package hw.net;
import flash.net.URLLoader;
import flash.events.Event;

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