Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a6f7841e1 | |||
| 4a7403022b | |||
| 163e6d68c3 | |||
| f396c86a23 | |||
| e5f8d7834a | |||
| a4ca9a924c | |||
| 88b4459023 | |||
| ccfa8c05f8 | |||
| 4017df4d00 | |||
| fe60e78b74 | |||
| 279baa1113 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@ out/
|
||||
target/
|
||||
*.zip
|
||||
pack.sh
|
||||
.vscode/
|
||||
|
||||
55
README.md
55
README.md
@@ -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
1
build.hxml
Normal file
@@ -0,0 +1 @@
|
||||
-p src/main
|
||||
@@ -3,7 +3,7 @@
|
||||
-lib yaml
|
||||
-lib promhx
|
||||
-lib haxework
|
||||
--macro haxework.parser.Parser.auto()
|
||||
--macro hw.parser.Parser.auto()
|
||||
-debug
|
||||
-D native_trace
|
||||
#-D dev_layout
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<!--<haxelib name="promhx" version=""/>-->
|
||||
<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')"/>
|
||||
|
||||
<window fps="30"/>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
package demo;
|
||||
|
||||
import demo.storage.TestStorage;
|
||||
import haxework.resources.IResources;
|
||||
import haxework.provider.Provider;
|
||||
import demo.dispatch.DemoDispatcher;
|
||||
import demo.popup.ColorPopup;
|
||||
import demo.popup.FontPopup;
|
||||
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;
|
||||
@@ -46,16 +45,16 @@ import haxework.view.group.VGroupView;
|
||||
|
||||
class Demo extends App implements DemoListener {
|
||||
|
||||
@:provide static var resources:IResources;
|
||||
@:provide static var storage:TestStorage;
|
||||
|
||||
public static function main() {
|
||||
L.push(new TraceLogger());
|
||||
|
||||
resources.image.put("logo", HaxeLogo.resolve());
|
||||
var app = new Demo(new AppTheme(), resources.image.get("logo"));
|
||||
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");
|
||||
|
||||
@@ -73,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>) {
|
||||
resources.any.put("data", data);
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package demo.dispatch;
|
||||
|
||||
import haxework.App;
|
||||
import hw.app.App;
|
||||
|
||||
interface DemoListener {
|
||||
public function onTest1():Void;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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: |
|
||||
|
||||
@@ -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> {
|
||||
|
||||
|
||||
@@ -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%
|
||||
|
||||
@@ -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> {
|
||||
|
||||
|
||||
@@ -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%
|
||||
|
||||
@@ -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>> {
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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> {
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package demo.storage;
|
||||
|
||||
import haxework.storage.SharedObjectStorage;
|
||||
import hw.storage.SharedObjectStorage;
|
||||
|
||||
@:provide class TestStorage extends SharedObjectStorage {
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package demo.test;
|
||||
|
||||
import haxework.view.group.GroupView;
|
||||
import hw.view.group.GroupView;
|
||||
|
||||
@:template class TestView extends GroupView {
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1 +1 @@
|
||||
--macro haxework.parser.Parser.auto()
|
||||
--macro hw.parser.Parser.auto()
|
||||
|
||||
16
haxelib.json
16
haxelib.json
@@ -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.3.0",
|
||||
"version": "2.1.0",
|
||||
"releasenote": "Update.",
|
||||
"contributors": [
|
||||
"shmyga"
|
||||
],
|
||||
"contributors": ["shmyga"],
|
||||
"classPath": "src/main",
|
||||
"dependencies": {
|
||||
"promhx": "1.1.0",
|
||||
"yaml": "2.0.0"
|
||||
"protohx": "0.4.6",
|
||||
"haxe-crypto": "0.0.8",
|
||||
"yaml": "2.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package;
|
||||
|
||||
import haxework.log.ILogger;
|
||||
import hw.log.ILogger;
|
||||
|
||||
class L {
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
package haxework;
|
||||
|
||||
import flash.display.BitmapData;
|
||||
import flash.Lib;
|
||||
import haxework.animate.Animate;
|
||||
import haxework.animate.FadeAnimate;
|
||||
import haxework.animate.UnFadeAnimate;
|
||||
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 popupManager:PopupManager;
|
||||
|
||||
public function new(?theme:ITheme, ?icon:BitmapData) {
|
||||
this.theme = theme;
|
||||
#if linux
|
||||
if (icon != null) {
|
||||
haxework.app.LinuxIcon.value = icon;
|
||||
}
|
||||
#end
|
||||
popupManager.showAnimateFactory = function(v) return new UnFadeAnimate(v);
|
||||
popupManager.closeAnimateFactory = function(v) return new FadeAnimate(v);
|
||||
app = this;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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.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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.app;
|
||||
package hw.app;
|
||||
|
||||
import flash.display.BitmapData;
|
||||
import flash.filters.ColorMatrixFilter;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.color;
|
||||
package hw.color;
|
||||
|
||||
abstract Color(Int) {
|
||||
public var alpha(get, never):Int;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.color;
|
||||
package hw.color;
|
||||
|
||||
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}');
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.geom;
|
||||
package hw.geom;
|
||||
|
||||
abstract IntPoint(Array<Int>) {
|
||||
public var x(get, set):Int;
|
||||
@@ -1,6 +1,4 @@
|
||||
package haxework.geom;
|
||||
|
||||
import flash.geom.Point as FlashPoint;
|
||||
package hw.geom;
|
||||
|
||||
abstract Point(Array<Float>) {
|
||||
public var x(get, set):Float;
|
||||
@@ -33,8 +31,4 @@ abstract Point(Array<Float>) {
|
||||
public function toString():String {
|
||||
return 'Point{x=$x,y=$y}';
|
||||
}
|
||||
|
||||
@:from public static function fromFlashPoint(value:FlashPoint):Point {
|
||||
return new Point(value.x, value.y);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.geom;
|
||||
package hw.geom;
|
||||
|
||||
abstract Rectangle(Array<Float>) {
|
||||
public var x(get, set):Float;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.log;
|
||||
package hw.log;
|
||||
|
||||
import cpp.VarArg;
|
||||
import haxe.extern.Rest;
|
||||
@@ -1,6 +1,6 @@
|
||||
package haxework.log;
|
||||
package hw.log;
|
||||
|
||||
import haxework.log.ILogger.LogLevel;
|
||||
import hw.log.ILogger.LogLevel;
|
||||
import haxe.CallStack;
|
||||
|
||||
|
||||
@@ -20,8 +20,17 @@ class LoggerUtil {
|
||||
}
|
||||
}
|
||||
|
||||
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)}');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.log;
|
||||
package hw.log;
|
||||
|
||||
enum LogLevel {
|
||||
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 haxework.log.BaseLogger;
|
||||
import hw.log.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
|
||||
class SocketLogger extends BaseLogger {}
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.log;
|
||||
package hw.log;
|
||||
|
||||
import flash.text.TextField;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.log;
|
||||
package hw.log;
|
||||
|
||||
import haxe.PosInfos;
|
||||
#if cpp
|
||||
@@ -31,13 +31,13 @@ class TraceLogger extends BaseLogger {
|
||||
(untyped console).log(v);
|
||||
//untyped js.Boot.__trace(v, infos);
|
||||
#elseif android
|
||||
haxework.log.AndroidLog.write(3, "", ConstCharStar.fromString(Std.string(v)));
|
||||
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);
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.macro;
|
||||
package hw.macro;
|
||||
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.macro;
|
||||
package hw.macro;
|
||||
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.macro;
|
||||
package hw.macro;
|
||||
|
||||
import haxe.macro.TypeTools;
|
||||
import haxe.macro.Context;
|
||||
@@ -32,7 +32,7 @@ class DispatcherMacro extends ClassTypeMacro {
|
||||
}
|
||||
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))),
|
||||
@@ -41,7 +41,7 @@ class DispatcherMacro extends ClassTypeMacro {
|
||||
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({
|
||||
@@ -1,8 +1,8 @@
|
||||
package haxework.macro;
|
||||
package hw.macro;
|
||||
|
||||
import haxe.macro.Expr;
|
||||
|
||||
using haxework.macro.MacroUtil;
|
||||
using hw.macro.MacroUtil;
|
||||
|
||||
class FieldMacro {
|
||||
public var metaName(default, null):String;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.macro;
|
||||
package hw.macro;
|
||||
|
||||
import yaml.YamlException;
|
||||
import yaml.Parser;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.macro;
|
||||
package hw.macro;
|
||||
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.ExprTools;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.macro;
|
||||
package hw.macro;
|
||||
|
||||
typedef JsonKeyPosition = {
|
||||
var min:Int;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.macro;
|
||||
package hw.macro;
|
||||
|
||||
import haxe.DynamicAccess;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package haxework.macro;
|
||||
package hw.macro;
|
||||
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
|
||||
using haxework.macro.MacroUtil;
|
||||
using hw.macro.MacroUtil;
|
||||
|
||||
class ProvideMacro extends FieldMacro {
|
||||
|
||||
@@ -35,7 +35,7 @@ class ProvideMacro extends FieldMacro {
|
||||
pos: field.pos,
|
||||
kind: FFun({
|
||||
args: [],
|
||||
expr: Context.parse('return haxework.provider.Provider.instance.get(${args.join(',')})', field.pos),
|
||||
expr: Context.parse('return hw.provider.Provider.instance.get(${args.join(',')})', field.pos),
|
||||
params: [],
|
||||
ret: type,
|
||||
})
|
||||
@@ -47,7 +47,7 @@ class ProvideMacro extends FieldMacro {
|
||||
pos: field.pos,
|
||||
kind: FFun({
|
||||
args: [{name: 'value', type: type}],
|
||||
expr: Context.parse('{haxework.provider.Provider.instance.set(${args.join(',')}); return value;}', field.pos),
|
||||
expr: Context.parse('{hw.provider.Provider.instance.set(${args.join(',')}); return value;}', field.pos),
|
||||
params: [],
|
||||
ret: type,
|
||||
})
|
||||
@@ -1,6 +1,6 @@
|
||||
package haxework.macro;
|
||||
package hw.macro;
|
||||
|
||||
using haxework.macro.MacroUtil;
|
||||
using hw.macro.MacroUtil;
|
||||
|
||||
class ResourceMacro extends FieldMacro {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.macro;
|
||||
package hw.macro;
|
||||
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
@@ -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.MacroUtil;
|
||||
using hw.macro.MacroUtil;
|
||||
using haxe.macro.MacroStringTools;
|
||||
|
||||
typedef TProperty<T> = {
|
||||
@@ -143,7 +143,7 @@ class StyleMacro extends ClassTypeMacro {
|
||||
|
||||
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",
|
||||
@@ -162,11 +162,11 @@ class StyleMacro extends ClassTypeMacro {
|
||||
}
|
||||
for (field in properties) {
|
||||
var propertyName = 'theme_${field.name}';
|
||||
expr.push(macro $i{propertyName} = haxework.provider.Provider.instance.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.instance.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());
|
||||
@@ -1,12 +1,12 @@
|
||||
package haxework.macro;
|
||||
package hw.macro;
|
||||
|
||||
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.MacroUtil;
|
||||
using hw.macro.MacroUtil;
|
||||
|
||||
class TemplateMacro extends ClassTypeMacro {
|
||||
|
||||
@@ -46,11 +46,11 @@ class TemplateMacro extends ClassTypeMacro {
|
||||
a[2];
|
||||
}
|
||||
case "resource" | "r":
|
||||
var bindExpr = 'haxework.provider.Provider.instance.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);
|
||||
@@ -127,7 +127,7 @@ class TemplateMacro extends ClassTypeMacro {
|
||||
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)));
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.net;
|
||||
package hw.net;
|
||||
|
||||
import flash.events.ErrorEvent;
|
||||
import haxe.Timer;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.net;
|
||||
package hw.net;
|
||||
|
||||
import promhx.Promise;
|
||||
import promhx.Deferred;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.net;
|
||||
package hw.net;
|
||||
|
||||
import flash.net.URLLoaderDataFormat;
|
||||
import flash.utils.ByteArray;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.net;
|
||||
package hw.net;
|
||||
|
||||
import flash.system.Security;
|
||||
import flash.utils.ByteArray;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.net;
|
||||
package hw.net;
|
||||
|
||||
import promhx.Promise;
|
||||
import flash.utils.ByteArray;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.net;
|
||||
package hw.net;
|
||||
|
||||
import flash.display.LoaderInfo;
|
||||
import flash.display.Loader;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.net;
|
||||
package hw.net;
|
||||
|
||||
import flash.utils.ByteArray;
|
||||
import flash.events.Event;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.net;
|
||||
package hw.net;
|
||||
|
||||
import flash.display.MovieClip;
|
||||
import flash.display.LoaderInfo;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.net;
|
||||
package hw.net;
|
||||
|
||||
import flash.net.URLLoader;
|
||||
import flash.events.Event;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.net;
|
||||
package hw.net;
|
||||
|
||||
import flash.events.Event;
|
||||
import flash.net.URLLoader;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.net.manage;
|
||||
package hw.net.manage;
|
||||
|
||||
@:provide(LoaderManager) interface ILoaderManager {
|
||||
public var actives(default, null):Array<ILoader<Dynamic>>;
|
||||
@@ -1,4 +1,4 @@
|
||||
package haxework.net.manage;
|
||||
package hw.net.manage;
|
||||
|
||||
class LoaderManager implements ILoaderManager {
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
package haxework.parser;
|
||||
package hw.parser;
|
||||
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type;
|
||||
import haxe.macro.TypeTools;
|
||||
import haxework.macro.ClassProvideMacro;
|
||||
import haxework.macro.ClassTypeMacro;
|
||||
import haxework.macro.DispatcherMacro;
|
||||
import haxework.macro.FieldMacro;
|
||||
import haxework.macro.ProvideMacro;
|
||||
import haxework.macro.ResourceMacro;
|
||||
import haxework.macro.SingletonMacro;
|
||||
import haxework.macro.StyleMacro;
|
||||
import haxework.macro.TemplateMacro;
|
||||
import hw.macro.ClassProvideMacro;
|
||||
import hw.macro.ClassTypeMacro;
|
||||
import hw.macro.DispatcherMacro;
|
||||
import hw.macro.FieldMacro;
|
||||
import hw.macro.ProvideMacro;
|
||||
import hw.macro.ResourceMacro;
|
||||
import hw.macro.SingletonMacro;
|
||||
import hw.macro.StyleMacro;
|
||||
import hw.macro.TemplateMacro;
|
||||
|
||||
class Parser {
|
||||
|
||||
@@ -32,7 +32,7 @@ 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);
|
||||
haxe.macro.Compiler.addGlobalMetadata("", "@:build(hw.parser.Parser.autoRun())", true, true, false);
|
||||
}
|
||||
|
||||
private static macro function autoRun():Array<Field> {
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user