├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE.md
└── workflows
│ ├── build.hxml
│ └── build.yml
├── LICENSE.md
├── README.md
├── classpath.exclusions
├── extraParams.hxml
├── haxe
└── ui
│ └── backend
│ ├── AppImpl.hx
│ ├── AssetsImpl.hx
│ ├── BackendImpl.hx
│ ├── CallLaterImpl.hx
│ ├── ComponentGraphicsImpl.hx
│ ├── ComponentImpl.hx
│ ├── ComponentSurface.hx
│ ├── EventImpl.hx
│ ├── FontData.hx
│ ├── ImageData.hx
│ ├── ImageDisplayImpl.hx
│ ├── ImageSurface.hx
│ ├── OpenFileDialogImpl.hx
│ ├── PlatformImpl.hx
│ ├── SaveFileDialogImpl.hx
│ ├── ScreenImpl.hx
│ ├── TextDisplayImpl.hx
│ ├── TextInputImpl.hx
│ ├── TimerImpl.hx
│ ├── ToolkitOptions.hx
│ ├── heaps
│ ├── EventMapper.hx
│ ├── EventType.hx
│ ├── FilterConverter.hx
│ ├── KeyboardHelper.hx
│ ├── MouseHelper.hx
│ ├── SDFFonts.hx
│ ├── ScreenUtils.hx
│ ├── StyleHelper.hx
│ ├── TileCache.hx
│ └── _module
│ │ └── styles
│ │ ├── dark
│ │ └── main.css
│ │ ├── default
│ │ └── main.css
│ │ └── main.css
│ └── module.xml
├── haxelib.json
└── haxeui-heaps.properties
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [ianharrigan]
2 | patreon: haxeui
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Expected Behavior
4 |
5 |
6 |
7 | ## Current Behavior
8 |
9 |
10 |
11 | ## Possible Solution
12 |
13 |
14 |
15 | ## Steps to Reproduce (for bugs)
16 |
17 |
18 | 1.
19 | 2.
20 | 3.
21 | 4.
22 |
23 | ## Media
24 |
25 |
26 | ## Test app / minimal test case
27 |
28 |
29 |
30 | ## Context
31 |
32 |
33 |
34 | ## Your Environment
35 |
36 | * Version used:
37 | * Environment name and version (e.g. Chrome 39, node.js 5.4):
38 | * Operating System and version (desktop or mobile):
39 | * Link to your project:
40 |
--------------------------------------------------------------------------------
/.github/workflows/build.hxml:
--------------------------------------------------------------------------------
1 | -lib haxeui-core
2 | -lib heaps
3 |
4 | -hl main.hl
5 |
6 | -cp .
7 | --no-output
8 | --macro haxe.macro.Compiler.include("haxe.ui", ["haxe.ui.macros"])
9 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on: [push, repository_dispatch]
4 |
5 | jobs:
6 | build:
7 | runs-on: ${{ matrix.os }}
8 |
9 | strategy:
10 | matrix:
11 | os: [ubuntu-latest, macos-13, windows-latest]
12 | haxe-version: [4.3.0, 4.3.1]
13 |
14 | steps:
15 | - uses: actions/checkout@v1
16 | - name: Setup Haxe (haxe ${{ matrix.haxe-version }}, ${{ matrix.os }})
17 | uses: krdlab/setup-haxe@v1
18 | with:
19 | haxe-version: ${{ matrix.haxe-version }}
20 |
21 | - name: Setup app (haxe ${{ matrix.haxe-version }}, ${{ matrix.os }})
22 | run: |
23 | git clone --branch master https://github.com/haxeui/haxeui-core.git --depth=1
24 | haxelib dev haxeui-core haxeui-core
25 |
26 | git clone --branch master https://github.com/HeapsIO/heaps.git
27 | haxelib dev heaps heaps
28 |
29 | haxelib install hlsdl
30 |
31 | mkdir res
32 |
33 | - name: Build app (haxe ${{ matrix.haxe-version }}, ${{ matrix.os }})
34 | run: |
35 | cp .github/workflows/build.hxml build.hxml
36 | haxelib install build.hxml --always --quiet
37 | haxe build.hxml
38 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Ian Harrigan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # haxeui-heaps
4 | `haxeui-heaps` is the `Heaps` backend for `HaxeUI`.
5 |
6 | ## Installation
7 | `haxeui-heaps` relies on `haxeui-core` as well as `Heaps`. To install:
8 |
9 | ```
10 | haxelib install heaps
11 | haxelib install haxeui-core
12 | haxelib install haxeui-heaps
13 | ```
14 |
15 | ### Toolkit initialization and usage
16 | Before you start using `HaxeUI` in your project, you must first initialize the `Toolkit`.
17 |
18 | ```haxe
19 | Toolkit.init();
20 | ```
21 |
22 | Once the toolkit is initialized, you can add components using the methods specified here.
23 |
24 | ```haxe
25 | var app = new HaxeUIApp();
26 | app.ready(
27 | function() {
28 | var main = ComponentMacros.buildComponent("assets/xml/test.xml"); // whatever your XML layout path is
29 | app.addComponent(main);
30 | app.start();
31 | }
32 | );
33 | ```
34 |
35 | Some examples are [here](https://github.com/haxeui/component-examples).
36 |
37 | ## Addtional resources
38 | * component-explorer - Browse HaxeUI components
39 | * playground - Write and test HaxeUI layouts in your browser
40 | * component-examples - Various componet examples
41 | * haxeui-api - The HaxeUI api docs.
42 | * haxeui-guides - Set of guides to working with HaxeUI and backends.
43 |
--------------------------------------------------------------------------------
/classpath.exclusions:
--------------------------------------------------------------------------------
1 | ; exclude paths from classpath when searching for haxeui arifacts (module.xml, native.xml, etc)
2 | ; speeds up build
3 | \/heaps\/
4 | \/hlopenal\/
5 | \/hlsdl\/
6 |
7 | \/format\/
8 |
--------------------------------------------------------------------------------
/extraParams.hxml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haxeui/haxeui-heaps/396f1a0704bcd8836637b3cc87a2691caafd0232/extraParams.hxml
--------------------------------------------------------------------------------
/haxe/ui/backend/AppImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 | import haxe.ui.core.Screen;
3 |
4 | private class HeapsApp extends hxd.App {
5 | public var onInit:Void->Void = null;
6 | public var onUpdate:Float->Void = null;
7 |
8 | private override function init() {
9 | super.init();
10 | Screen.instance.root = this.s2d;
11 | if (onInit != null) {
12 | onInit();
13 | }
14 | }
15 |
16 | private override function update(dt:Float) {
17 | if (onUpdate != null) {
18 | onUpdate(dt);
19 | }
20 | }
21 | }
22 |
23 | class AppImpl extends AppBase {
24 | private var _app:HeapsApp;
25 |
26 | public function new() {
27 | _autoHandlePreload = false;
28 | _app = new HeapsApp();
29 | _app.onInit = onHeapsInit;
30 | _app.onUpdate = onHeapsUpdate;
31 | }
32 |
33 | private var _heapsInitialized:Bool = false;
34 | private var _heapsReadyCalled:Bool = false;
35 | private function onHeapsInit() {
36 | #if js
37 | //hxd.Res.initLocal();
38 | hxd.Res.initEmbed();
39 | #else
40 | hxd.Res.initEmbed();
41 | #end
42 |
43 | if (Toolkit.backendProperties.exists("haxe.ui.heaps.engine.background.color")) {
44 | h3d.Engine.getCurrent().backgroundColor = Toolkit.backendProperties.getPropCol("haxe.ui.heaps.engine.background.color");
45 | }
46 | _heapsInitialized = true;
47 | if (__onReady != null) {
48 | startPreload(function() {
49 | _heapsReadyCalled = true;
50 | __onReady();
51 | });
52 | }
53 | }
54 |
55 | private function onHeapsUpdate(dt:Float) {
56 | BackendImpl.update();
57 | }
58 |
59 | private var __onReady:Void->Void;
60 | private override function init(onReady:Void->Void, onEnd:Void->Void = null) {
61 | __onReady = onReady;
62 | if (_heapsInitialized == true && _heapsReadyCalled == false) {
63 | __onReady();
64 | }
65 | }
66 |
67 | private override function getToolkitInit():ToolkitOptions {
68 | return {
69 | root: _app.s2d,
70 | manualUpdate: true
71 | };
72 | }
73 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/AssetsImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import haxe.io.Bytes;
4 | import haxe.ui.assets.FontInfo;
5 | import hxd.Res;
6 | import hxd.fs.BytesFileSystem.BytesFileEntry;
7 | import hxd.res.Image;
8 |
9 | class AssetsImpl extends AssetsBase {
10 | public function embedFontSupported():Bool {
11 | return #if (lime || flash || js) true #else false #end;
12 | }
13 |
14 | private override function getImageInternal(resourceId:String, callback:haxe.ui.assets.ImageInfo->Void) {
15 | try {
16 | var loader:hxd.res.Loader = hxd.Res.loader;
17 | if (loader != null) {
18 | if (loader.exists(resourceId)) {
19 | var image:Image = loader.load(resourceId).toImage();
20 | var size:Dynamic = image.getSize();
21 | var imageInfo:haxe.ui.assets.ImageInfo = {
22 | width: size.width,
23 | height: size.height,
24 | data: image.toBitmap()
25 | };
26 | callback(imageInfo);
27 | } else {
28 | callback(null);
29 | }
30 | } else {
31 | callback(null);
32 | }
33 | } catch (e:Dynamic) {
34 | trace(e);
35 | callback(null);
36 | }
37 | }
38 |
39 | private override function getImageFromHaxeResource(resourceId:String, callback:String->haxe.ui.assets.ImageInfo->Void) {
40 | var bytes = Resource.getBytes(resourceId);
41 | imageFromBytes(bytes, function(imageInfo) {
42 | callback(resourceId, imageInfo);
43 | });
44 | }
45 |
46 | public override function imageFromBytes(bytes:Bytes, callback:haxe.ui.assets.ImageInfo->Void) {
47 | if (bytes == null) {
48 | callback(null);
49 | return;
50 | }
51 |
52 | try {
53 | var entry:BytesFileEntry = new BytesFileEntry("", bytes);
54 | var image:Image = new Image(entry);
55 |
56 | var size:Dynamic = image.getSize();
57 | var imageInfo:haxe.ui.assets.ImageInfo = {
58 | width: size.width,
59 | height: size.height,
60 | data: image.toBitmap()
61 | };
62 | callback(imageInfo);
63 | } catch (e:Dynamic) {
64 | callback(null);
65 | }
66 | }
67 |
68 | public override function imageInfoFromImageData(imageData:ImageData):haxe.ui.assets.ImageInfo {
69 | var imageInfo:haxe.ui.assets.ImageInfo = {
70 | width: imageData.width,
71 | height: imageData.height,
72 | data: imageData
73 | };
74 | return imageInfo;
75 | }
76 |
77 | private override function getFontInternal(resourceId:String, callback:FontInfo->Void) {
78 | try {
79 | var font = hxd.Res.loader.loadCache(resourceId, hxd.res.BitmapFont);
80 | callback({
81 | name: resourceId,
82 | data: font
83 | });
84 | } catch (error:Dynamic) {
85 | #if debug
86 | trace("WARNING: problem loading font '" + resourceId + "' (" + error + ")");
87 | #end
88 | callback(null);
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/haxe/ui/backend/BackendImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | class BackendImpl {
4 | public static var id:String = "heaps";
5 |
6 | public static function update() {
7 | TimerImpl.update();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/haxe/ui/backend/CallLaterImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | class CallLaterImpl {
4 | public function new(fn:Void->Void) {
5 | haxe.ui.util.Timer.delay(fn, 0);
6 | //MainLoop.runInMainThread(fn);
7 | }
8 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/ComponentGraphicsImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import h2d.Bitmap;
4 | import h2d.Graphics;
5 | import h2d.Tile;
6 | import h3d.mat.Texture;
7 | import haxe.io.Bytes;
8 | import haxe.ui.core.Component;
9 | import haxe.ui.util.Color;
10 | import haxe.ui.util.Variant;
11 | import hxd.PixelFormat;
12 | import hxd.Pixels;
13 |
14 | class ComponentGraphicsImpl extends ComponentGraphicsBase {
15 | private var _styleGraphics:Graphics = null;
16 | private var _hasSize:Bool = false;
17 |
18 | public function new(component:Component) {
19 | super(component);
20 | component.styleable = false;
21 | createGraphics();
22 | }
23 |
24 | public override function clear() {
25 | if (_hasSize == false) {
26 | return super.clear();
27 | }
28 | _styleGraphics.clear();
29 | }
30 |
31 | public override function setPixel(x:Float, y:Float, color:Color) {
32 | if (_hasSize == false) {
33 | return super.setPixel(x, y, color);
34 | }
35 | }
36 |
37 | private var _bitmap:Bitmap = null;
38 | private var _texture:Texture = null;
39 | public override function setPixels(pixels:Bytes) {
40 | if (_hasSize == false) {
41 | return super.setPixels(pixels);
42 | }
43 |
44 | if (_bitmap == null) {
45 | _bitmap = new Bitmap();
46 | _component.addChild(_bitmap);
47 | }
48 |
49 | var p = new Pixels(Std.int(_component.width), Std.int(_component.height), pixels, PixelFormat.RGBA);
50 | if (_texture == null) {
51 | _texture = Texture.fromPixels(p);
52 | _bitmap.tile = Tile.fromTexture(_texture);
53 | } else {
54 | if (_texture.width != _component.width || _texture.height != _component.height) {
55 | _texture.resize(Std.int(_component.width), Std.int(_component.height));
56 | _bitmap.tile = Tile.fromTexture(_texture); // To ensure size is correct.
57 | }
58 | _texture.uploadPixels(p);
59 | }
60 | }
61 |
62 | public override function moveTo(x:Float, y:Float) {
63 | if (_hasSize == false) {
64 | return super.moveTo(x, y);
65 | }
66 | _styleGraphics.moveTo(x, y);
67 | }
68 |
69 | public override function lineTo(x:Float, y:Float) {
70 | if (_hasSize == false) {
71 | return super.lineTo(x, y);
72 | }
73 | _styleGraphics.lineTo(x, y);
74 | }
75 |
76 | public override function strokeStyle( color:Null, thickness:Null = 1, alpha:Null = 1) {
77 | if (_hasSize == false) {
78 | return super.strokeStyle(color, thickness, alpha);
79 | }
80 | _styleGraphics.lineStyle(thickness, color, alpha);
81 | }
82 |
83 | public override function circle(x:Float, y:Float, radius:Float) {
84 | if (_hasSize == false) {
85 | return super.circle(x, y, radius);
86 | }
87 | _styleGraphics.drawCircle(x, y, radius, Std.int(radius * 10));
88 | }
89 |
90 | public override function fillStyle(color:Null, alpha:Null = 1) {
91 | if (_hasSize == false) {
92 | return super.fillStyle(color, alpha);
93 | }
94 | if (color == null) {
95 | _styleGraphics.endFill();
96 | return;
97 | }
98 | _styleGraphics.beginFill(color, alpha);
99 | }
100 |
101 | public override function curveTo(controlX:Float, controlY:Float, anchorX:Float, anchorY:Float) {
102 | if (_hasSize == false) {
103 | return super.curveTo(controlX, controlY, anchorX, anchorY);
104 | }
105 | _styleGraphics.curveTo(controlX, controlY, anchorX, anchorY);
106 | }
107 |
108 | public override function cubicCurveTo(controlX1:Float, controlY1:Float, controlX2:Float, controlY2:Float, anchorX:Float, anchorY:Float) {
109 | if (_hasSize == false) {
110 | return super.cubicCurveTo(controlX1, controlY1, controlX2, controlY2, anchorX, anchorY);
111 | }
112 | _styleGraphics.cubicCurveTo(controlX1, controlY1, controlX2, controlY2, anchorX, anchorY);
113 | }
114 |
115 | public override function rectangle(x:Float, y:Float, width:Float, height:Float) {
116 | if (_hasSize == false) {
117 | return super.rectangle(x, y, width, height);
118 | }
119 | _styleGraphics.drawRect(x, y, width, height);
120 | }
121 |
122 | public override function image(resource:Variant, x:Null = null, y:Null = null, width:Null = null, height:Null = null) {
123 | if (_hasSize == false) {
124 | return super.image(resource, x, y, width, height);
125 | }
126 | }
127 |
128 | private function createGraphics() {
129 | var container = _component.getChildAt(0); // first child is always the style-objects container
130 | if (container == null) {
131 | return; // fix crash resizing the window; container doesn't exist yet
132 | }
133 |
134 | _styleGraphics = cast(container.getObjectByName("styleGraphics"), Graphics);
135 | if (_styleGraphics == null) {
136 | _styleGraphics = new Graphics();
137 | _styleGraphics.name = "styleGraphics";
138 | container.addChildAt(_styleGraphics, 0);
139 | }
140 | }
141 |
142 | public override function resize(width:Null, height:Null) {
143 | if (width > 0 && height > 0) {
144 | if (_hasSize == false) {
145 | _hasSize = true;
146 | replayDrawCommands();
147 | }
148 | }
149 | }
150 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/ComponentImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import h2d.Camera;
4 | import h2d.Graphics;
5 | import h2d.Object;
6 | import h2d.RenderContext;
7 | import h2d.Scene;
8 | import h2d.col.Point;
9 | import h2d.filter.Filter;
10 | import h2d.filter.Group;
11 | import h2d.filter.Mask;
12 | import haxe.ui.Toolkit;
13 | import haxe.ui.backend.heaps.FilterConverter;
14 | import haxe.ui.backend.heaps.MouseHelper;
15 | import haxe.ui.backend.heaps.StyleHelper;
16 | import haxe.ui.core.Component;
17 | import haxe.ui.core.ImageDisplay;
18 | import haxe.ui.core.Screen;
19 | import haxe.ui.core.TextDisplay;
20 | import haxe.ui.core.TextInput;
21 | import haxe.ui.events.KeyboardEvent;
22 | import haxe.ui.events.MouseEvent;
23 | import haxe.ui.events.UIEvent;
24 | import haxe.ui.geom.Rectangle;
25 | import haxe.ui.styles.Style;
26 | import haxe.ui.util.MathUtil;
27 | import haxe.ui.validation.InvalidationFlags;
28 |
29 | class ComponentImpl extends ComponentBase {
30 | public var styleable:Bool = true;
31 |
32 | @:noCompletion
33 | private var _eventMap:MapVoid>;
34 | @:noCompletion
35 | private var _container:Object = null;
36 |
37 | @:noCompletion
38 | static inline var INDEX_OFFSET = 1; // offset everything because 0th-child is always the style graphics container
39 |
40 | public function new() {
41 | super();
42 | _eventMap = new MapVoid>();
43 | _container = new Object();
44 | _container.name = "container";
45 | var styleGraphics = new Graphics();
46 | styleGraphics.name = "styleGraphics";
47 | _container.addChild(styleGraphics);
48 | addChild(_container); // style graphics container
49 | //cast(this, Component).ready();
50 | }
51 |
52 | @:noCompletion
53 | private override function handlePosition(left:Null, top:Null, style:Style) {
54 | if (left == null || top == null) {
55 | return;
56 | }
57 |
58 | left = Math.fround(left);
59 | top = Math.fround(top);
60 |
61 | if (this.x != left) this.x = left;
62 | if (this.y != top) this.y = top;
63 | }
64 |
65 | @:noCompletion
66 | private override function handleSize(w:Null, h:Null, style:Style) {
67 | if (h == null || w == null || w <= 0 || h <= 0) {
68 | return;
69 | }
70 |
71 | if (this.styleable) {
72 | StyleHelper.apply(this, style, w, h);
73 | }
74 | }
75 |
76 | @:noCompletion
77 | private override function handleVisibility(show:Bool) {
78 | super.visible = show;
79 | }
80 |
81 | @:noCompletion
82 | private var _maskGraphics:Graphics = null;
83 | @:noCompletion
84 | private override function handleClipRect(value:Rectangle) {
85 | if (_maskGraphics == null) {
86 | _maskGraphics = new Graphics();
87 | _maskGraphics.name = "maskGraphics";
88 |
89 | _container.addChildAt(_maskGraphics, 0);
90 | _maskFilter = new Mask(_maskGraphics);
91 | this.filter = createFilterGroup();
92 | }
93 |
94 | var borderSize:Float = 0;
95 | if (parentComponent != null && parentComponent.style == null) {
96 | parentComponent.validateNow();
97 | }
98 | borderSize = parentComponent.style.borderSize;
99 |
100 | _maskGraphics.clear();
101 | _maskGraphics.beginFill(0xFF00FF, 1.0);
102 | _maskGraphics.drawRect(0, 0, value.width, value.height);
103 | _maskGraphics.endFill();
104 | _maskGraphics.x = value.left;//this.left;
105 | _maskGraphics.y = value.top;//this.top;
106 |
107 | // is this a hack? We dont want to move the component if the clip rect is the
108 | // full size of the component (like in the case of clip:true), feels wrong
109 | // for some reason, but without this, clip:true components move around
110 | // when they shouldnt (which i dont fully understand)
111 | if (this.width != value.width) {
112 | // multiple masks / clip rects in the same component (like tableview) can interfere with each
113 | // other in heaps, so lets find them and update our co-ords appropriately
114 | var offsetX:Float = 0;
115 | for (c in this.parentComponent.childComponents) {
116 | if (c._maskGraphics != null && c._maskGraphics != this._maskGraphics) {
117 | var clipComponent = c.findClipComponent();
118 | if (clipComponent != null && clipComponent.width != this.width) {
119 | trace(clipComponent.width, this.width);
120 | offsetX += clipComponent.width;
121 | }
122 | }
123 | }
124 | this.x = -value.left + borderSize + offsetX;
125 | }
126 | if (this.height != value.height) {
127 | // multiple masks / clip rects in the same component (like tableview) can interfere with each
128 | // other in heaps, so lets find them and update our co-ords appropriately
129 | var offsetY:Float = 0;
130 | for (c in this.parentComponent.childComponents) {
131 | if (c._maskGraphics != null && c._maskGraphics != this._maskGraphics) {
132 | var clipComponent = c.findClipComponent();
133 | if (clipComponent != null && clipComponent.height != this.height) {
134 | offsetY += clipComponent.height;
135 | }
136 | }
137 | }
138 | this.y = -value.top + borderSize + offsetY;
139 | }
140 | }
141 |
142 | //***********************************************************************************************************
143 | // Text related
144 | //***********************************************************************************************************
145 | @:noCompletion
146 | public override function createTextDisplay(text:String = null):TextDisplay {
147 | if (_textDisplay == null) {
148 | super.createTextDisplay(text);
149 | addChild(_textDisplay.sprite);
150 | }
151 |
152 | return _textDisplay;
153 | }
154 |
155 | @:noCompletion
156 | public override function createTextInput(text:String = null):TextInput {
157 | if (_textInput == null) {
158 | super.createTextInput(text);
159 | addChild(_textInput.sprite);
160 | }
161 |
162 | return _textInput;
163 | }
164 |
165 | //***********************************************************************************************************
166 | // Image related
167 | //***********************************************************************************************************
168 | @:noCompletion
169 | public override function createImageDisplay():ImageDisplay {
170 | if (_imageDisplay == null) {
171 | super.createImageDisplay();
172 | addChild(_imageDisplay.sprite);
173 | }
174 |
175 | return _imageDisplay;
176 | }
177 |
178 | @:noCompletion
179 | public override function removeImageDisplay() {
180 | if (_imageDisplay != null) {
181 | removeChild(_imageDisplay.sprite);
182 | _imageDisplay.dispose();
183 | _imageDisplay = null;
184 | }
185 | }
186 |
187 | //***********************************************************************************************************
188 | // Display tree
189 | //***********************************************************************************************************
190 | @:noCompletion
191 | private override function handleReady() {
192 | super.handleReady();
193 | @:privateAccess Screen.instance.addUpdateCallback();
194 | }
195 |
196 | @:noCompletion
197 | private override function handleSetComponentIndex(child:Component, index:Int) {
198 | addChildAt(child, index + INDEX_OFFSET);
199 | }
200 |
201 | @:noCompletion
202 | private override function handleAddComponent(child:Component):Component {
203 | addChild(child);
204 | return child;
205 | }
206 |
207 | @:noCompletion
208 | private override function handleAddComponentAt(child:Component, index:Int):Component {
209 | addChildAt(child, index + INDEX_OFFSET);
210 | return child;
211 | }
212 |
213 | @:noCompletion
214 | private override function handleRemoveComponent(child:Component, dispose:Bool = true):Component {
215 | removeChild(child);
216 |
217 | if (dispose == true) {
218 | child.dispose();
219 | }
220 |
221 | return child;
222 | }
223 |
224 | @:noCompletion
225 | private override function handleRemoveComponentAt(index:Int, dispose:Bool = true):Component {
226 | var child = _children[index];
227 | if (child != null) {
228 | removeChild(child);
229 |
230 | if (dispose == true) {
231 | child.dispose();
232 | }
233 | }
234 | return child;
235 | }
236 |
237 | @:noCompletion
238 | private var _deallocate:Bool = false;
239 | @:noCompletion
240 | private var deallocate(null, set):Bool;
241 | @:noCompletion
242 | private function set_deallocate(value:Bool) {
243 | _deallocate = value;
244 | for (c in this.childComponents) {
245 | c.deallocate = value;
246 | }
247 | return value;
248 | }
249 |
250 | @:noCompletion
251 | private var _disposed:Bool = false;
252 | @:noCompletion
253 | private function dispose() {
254 | if (_disposed == true) {
255 | return;
256 | }
257 | deallocate = true;
258 | removeChildren();
259 | _maskGraphics = null;
260 | remove();
261 | }
262 |
263 | @:noCompletion
264 | private var _currentStyleFilters:Array = null;
265 | @:noCompletion
266 | private var _maskFilter:Mask = null;
267 | @:noCompletion
268 | private function createFilterGroup() {
269 | var n = 0;
270 | var filterGroup = new Group();
271 | if (_maskFilter != null) {
272 | filterGroup.add(_maskFilter);
273 | n++;
274 | }
275 | if (_currentStyleFilters != null) {
276 | for (f in _currentStyleFilters) {
277 | filterGroup.add(f);
278 | n++;
279 | }
280 | }
281 | if (n == 0) {
282 | return null;
283 | }
284 | return filterGroup;
285 | }
286 |
287 | @:noCompletion
288 | private override function applyStyle(style:Style) {
289 | /*
290 | if (style.cursor != null && style.cursor == "pointer") {
291 | cursor = Cursor.Button;
292 | } else if (cursor != hxd.Cursor.Default) {
293 | cursor = Cursor.Default;
294 | }
295 | */
296 | if (style.filter != null && style.filter.length > 0) {
297 | _currentStyleFilters = [];
298 | for (f in style.filter) {
299 | var filter = FilterConverter.convertFilter(f);
300 | if (filter != null) {
301 | _currentStyleFilters.push(filter);
302 | }
303 | }
304 | this.filter = createFilterGroup();
305 | } else {
306 | _currentStyleFilters = null;
307 | this.filter = createFilterGroup();
308 | }
309 |
310 | if (style.hidden != null) {
311 | visible = !style.hidden;
312 | }
313 |
314 | if (style.opacity != null) {
315 | alpha = style.opacity;
316 | }
317 | }
318 |
319 | //***********************************************************************************************************
320 | // Events
321 | //***********************************************************************************************************
322 | @:noCompletion
323 | @:access(haxe.ui.core.Screen)
324 | private override function mapEvent(type:String, listener:UIEvent->Void) {
325 | switch (type) {
326 | case MouseEvent.MOUSE_MOVE:
327 | if (_eventMap.exists(MouseEvent.MOUSE_MOVE) == false) {
328 | MouseHelper.notify(MouseEvent.MOUSE_MOVE, __onMouseMove);
329 | _eventMap.set(MouseEvent.MOUSE_MOVE, listener);
330 | }
331 |
332 | case MouseEvent.MOUSE_OVER:
333 | if (_eventMap.exists(MouseEvent.MOUSE_OVER) == false) {
334 | MouseHelper.notify(MouseEvent.MOUSE_MOVE, __onMouseMove);
335 | _eventMap.set(MouseEvent.MOUSE_OVER, listener);
336 | }
337 |
338 | case MouseEvent.MOUSE_OUT:
339 | if (_eventMap.exists(MouseEvent.MOUSE_OUT) == false) {
340 | _eventMap.set(MouseEvent.MOUSE_OUT, listener);
341 | }
342 |
343 | case MouseEvent.MOUSE_DOWN:
344 | if (_eventMap.exists(MouseEvent.MOUSE_DOWN) == false) {
345 | MouseHelper.notify(MouseEvent.MOUSE_DOWN, __onMouseDown);
346 | MouseHelper.notify(MouseEvent.MOUSE_UP, __onMouseUp);
347 | _eventMap.set(MouseEvent.MOUSE_DOWN, listener);
348 | }
349 |
350 | case MouseEvent.MOUSE_UP:
351 | if (_eventMap.exists(MouseEvent.MOUSE_UP) == false) {
352 | MouseHelper.notify(MouseEvent.MOUSE_UP, __onMouseUp);
353 | _eventMap.set(MouseEvent.MOUSE_UP, listener);
354 | }
355 |
356 | case MouseEvent.MOUSE_WHEEL:
357 | if (_eventMap.exists(MouseEvent.MOUSE_WHEEL) == false) {
358 | MouseHelper.notify(MouseEvent.MOUSE_MOVE, __onMouseMove);
359 | MouseHelper.notify(MouseEvent.MOUSE_WHEEL, __onMouseWheel);
360 | _eventMap.set(MouseEvent.MOUSE_WHEEL, listener);
361 | }
362 |
363 | case MouseEvent.CLICK:
364 | if (_eventMap.exists(MouseEvent.CLICK) == false) {
365 | _eventMap.set(MouseEvent.CLICK, listener);
366 |
367 | if (_eventMap.exists(MouseEvent.MOUSE_DOWN) == false) {
368 | MouseHelper.notify(MouseEvent.MOUSE_DOWN, __onMouseDown);
369 | _eventMap.set(MouseEvent.MOUSE_DOWN, null);
370 | MouseHelper.notify(MouseEvent.MOUSE_UP, __onMouseUp);
371 | _eventMap.set(MouseEvent.MOUSE_UP, null);
372 | }
373 |
374 | if (_eventMap.exists(MouseEvent.MOUSE_UP) == false) {
375 | MouseHelper.notify(MouseEvent.MOUSE_UP, __onMouseUp);
376 | _eventMap.set(MouseEvent.MOUSE_UP, null);
377 | }
378 | }
379 |
380 | case MouseEvent.DBL_CLICK:
381 | if (_eventMap.exists(MouseEvent.DBL_CLICK) == false) {
382 | _eventMap.set(MouseEvent.DBL_CLICK, listener);
383 |
384 | if (_eventMap.exists(MouseEvent.MOUSE_UP) == false) {
385 | MouseHelper.notify(MouseEvent.MOUSE_UP, __onDoubleClick);
386 | _eventMap.set(MouseEvent.MOUSE_UP, listener);
387 | }
388 | }
389 |
390 | case MouseEvent.RIGHT_MOUSE_DOWN:
391 | if (_eventMap.exists(MouseEvent.RIGHT_MOUSE_DOWN) == false) {
392 | MouseHelper.notify(MouseEvent.MOUSE_DOWN, __onMouseDown);
393 | MouseHelper.notify(MouseEvent.MOUSE_UP, __onMouseUp);
394 | _eventMap.set(MouseEvent.RIGHT_MOUSE_DOWN, listener);
395 | }
396 |
397 | case MouseEvent.RIGHT_MOUSE_UP:
398 | if (_eventMap.exists(MouseEvent.RIGHT_MOUSE_UP) == false) {
399 | MouseHelper.notify(MouseEvent.MOUSE_UP, __onMouseUp);
400 | _eventMap.set(MouseEvent.RIGHT_MOUSE_UP, listener);
401 | }
402 |
403 | case MouseEvent.RIGHT_CLICK:
404 | if (_eventMap.exists(MouseEvent.RIGHT_CLICK) == false) {
405 | _eventMap.set(MouseEvent.RIGHT_CLICK, listener);
406 |
407 | if (_eventMap.exists(MouseEvent.RIGHT_MOUSE_DOWN) == false) {
408 | MouseHelper.notify(MouseEvent.MOUSE_DOWN, __onMouseDown);
409 | MouseHelper.notify(MouseEvent.MOUSE_UP, __onMouseUp);
410 | _eventMap.set(MouseEvent.RIGHT_MOUSE_DOWN, listener);
411 | }
412 |
413 | if (_eventMap.exists(MouseEvent.RIGHT_MOUSE_UP) == false) {
414 | MouseHelper.notify(MouseEvent.MOUSE_UP, __onMouseUp);
415 | _eventMap.set(MouseEvent.RIGHT_MOUSE_UP, listener);
416 | }
417 | }
418 |
419 | case MouseEvent.MIDDLE_MOUSE_DOWN:
420 | if (_eventMap.exists(MouseEvent.MIDDLE_MOUSE_DOWN) == false) {
421 | MouseHelper.notify(MouseEvent.MOUSE_DOWN, __onMouseDown);
422 | MouseHelper.notify(MouseEvent.MOUSE_UP, __onMouseUp);
423 | _eventMap.set(MouseEvent.MIDDLE_MOUSE_DOWN, listener);
424 | }
425 |
426 | case MouseEvent.MIDDLE_MOUSE_UP:
427 | if (_eventMap.exists(MouseEvent.MIDDLE_MOUSE_UP) == false) {
428 | MouseHelper.notify(MouseEvent.MOUSE_UP, __onMouseUp);
429 | _eventMap.set(MouseEvent.MIDDLE_MOUSE_UP, listener);
430 | }
431 |
432 | case MouseEvent.MIDDLE_CLICK:
433 | if (_eventMap.exists(MouseEvent.MIDDLE_CLICK) == false) {
434 | _eventMap.set(MouseEvent.MIDDLE_CLICK, listener);
435 |
436 | if (_eventMap.exists(MouseEvent.MIDDLE_MOUSE_DOWN) == false) {
437 | MouseHelper.notify(MouseEvent.MOUSE_DOWN, __onMouseDown);
438 | MouseHelper.notify(MouseEvent.MOUSE_UP, __onMouseUp);
439 | _eventMap.set(MouseEvent.MIDDLE_MOUSE_DOWN, listener);
440 | }
441 |
442 | if (_eventMap.exists(MouseEvent.MIDDLE_MOUSE_UP) == false) {
443 | MouseHelper.notify(MouseEvent.MOUSE_UP, __onMouseUp);
444 | _eventMap.set(MouseEvent.MIDDLE_MOUSE_UP, listener);
445 | }
446 | }
447 |
448 | case KeyboardEvent.KEY_DOWN:
449 | if (hasTextInput() && !_eventMap.exists(KeyboardEvent.KEY_DOWN)) {
450 | _eventMap.set(KeyboardEvent.KEY_DOWN, listener);
451 | getTextInput().onKeyDown = listener;
452 | }
453 |
454 | case KeyboardEvent.KEY_UP:
455 | if (hasTextInput() && !_eventMap.exists(KeyboardEvent.KEY_UP)) {
456 | _eventMap.set(KeyboardEvent.KEY_UP, listener);
457 | getTextInput().onKeyUp = listener;
458 | }
459 |
460 | case KeyboardEvent.KEY_PRESS:
461 | if (hasTextInput() && !_eventMap.exists(KeyboardEvent.KEY_PRESS)) {
462 | _eventMap.set(KeyboardEvent.KEY_PRESS, listener);
463 | getTextInput().onKeyPress = listener;
464 | }
465 | }
466 | }
467 |
468 | @:noCompletion
469 | private override function unmapEvent(type:String, listener:UIEvent->Void) {
470 | switch (type) {
471 | case MouseEvent.MOUSE_MOVE:
472 | _eventMap.remove(type);
473 | if (_eventMap.exists(MouseEvent.MOUSE_MOVE) == false
474 | && _eventMap.exists(MouseEvent.MOUSE_OVER) == false
475 | && _eventMap.exists(MouseEvent.MOUSE_WHEEL) == false) {
476 | MouseHelper.remove(MouseEvent.MOUSE_MOVE, __onMouseMove);
477 | }
478 |
479 | case MouseEvent.MOUSE_OVER:
480 | _eventMap.remove(type);
481 | if (_eventMap.exists(MouseEvent.MOUSE_MOVE) == false
482 | && _eventMap.exists(MouseEvent.MOUSE_OVER) == false
483 | && _eventMap.exists(MouseEvent.MOUSE_WHEEL) == false) {
484 | MouseHelper.remove(MouseEvent.MOUSE_MOVE, __onMouseMove);
485 | }
486 |
487 | case MouseEvent.MOUSE_OUT:
488 | _eventMap.remove(type);
489 |
490 | case MouseEvent.MOUSE_DOWN:
491 | _eventMap.remove(type);
492 | if (_eventMap.exists(MouseEvent.MOUSE_DOWN) == false
493 | && _eventMap.exists(MouseEvent.RIGHT_MOUSE_DOWN) == false) {
494 | MouseHelper.remove(MouseEvent.MOUSE_DOWN, __onMouseDown);
495 | }
496 |
497 | case MouseEvent.MOUSE_UP:
498 | _eventMap.remove(type);
499 | if (_eventMap.exists(MouseEvent.MOUSE_UP) == false
500 | && _eventMap.exists(MouseEvent.RIGHT_MOUSE_UP) == false) {
501 | MouseHelper.remove(MouseEvent.MOUSE_UP, __onMouseUp);
502 | }
503 |
504 | case MouseEvent.MOUSE_WHEEL:
505 | _eventMap.remove(type);
506 | MouseHelper.remove(MouseEvent.MOUSE_WHEEL, __onMouseWheel);
507 | if (_eventMap.exists(MouseEvent.MOUSE_MOVE) == false
508 | && _eventMap.exists(MouseEvent.MOUSE_OVER) == false
509 | && _eventMap.exists(MouseEvent.MOUSE_WHEEL) == false) {
510 | MouseHelper.remove(MouseEvent.MOUSE_MOVE, __onMouseMove);
511 | }
512 |
513 | case MouseEvent.CLICK:
514 | _eventMap.remove(type);
515 |
516 | case MouseEvent.DBL_CLICK:
517 | _eventMap.remove(type);
518 | MouseHelper.remove(MouseEvent.MOUSE_UP, __onDoubleClick);
519 |
520 | case MouseEvent.RIGHT_MOUSE_DOWN:
521 | _eventMap.remove(type);
522 | if (_eventMap.exists(MouseEvent.MOUSE_DOWN) == false
523 | && _eventMap.exists(MouseEvent.RIGHT_MOUSE_DOWN) == false) {
524 | MouseHelper.remove(MouseEvent.MOUSE_DOWN, __onMouseDown);
525 | }
526 |
527 | case MouseEvent.RIGHT_MOUSE_UP:
528 | _eventMap.remove(type);
529 | if (_eventMap.exists(MouseEvent.MOUSE_UP) == false
530 | && _eventMap.exists(MouseEvent.RIGHT_MOUSE_UP) == false) {
531 | MouseHelper.remove(MouseEvent.MOUSE_UP, __onMouseUp);
532 | }
533 |
534 | case MouseEvent.RIGHT_CLICK:
535 | _eventMap.remove(type);
536 |
537 | case MouseEvent.MIDDLE_MOUSE_DOWN:
538 | _eventMap.remove(type);
539 | if (_eventMap.exists(MouseEvent.MOUSE_DOWN) == false
540 | && _eventMap.exists(MouseEvent.MIDDLE_MOUSE_DOWN) == false) {
541 | MouseHelper.remove(MouseEvent.MOUSE_DOWN, __onMouseDown);
542 | }
543 |
544 | case MouseEvent.MIDDLE_MOUSE_UP:
545 | _eventMap.remove(type);
546 | if (_eventMap.exists(MouseEvent.MOUSE_UP) == false
547 | && _eventMap.exists(MouseEvent.MIDDLE_MOUSE_UP) == false) {
548 | MouseHelper.remove(MouseEvent.MOUSE_UP, __onMouseUp);
549 | }
550 |
551 | case MouseEvent.MIDDLE_CLICK:
552 | _eventMap.remove(type);
553 | }
554 | }
555 |
556 | // lets cache certain items so we dont have to loop multiple times per frame
557 | @:noCompletion
558 | private var _cachedScreenX:Null = null;
559 | @:noCompletion
560 | private var _cachedScreenY:Null = null;
561 | @:noCompletion
562 | private var _cachedClipComponent:Component = null;
563 | @:noCompletion
564 | private var _cachedClipComponentNone:Null = null;
565 | @:noCompletion
566 | private var _cachedRootComponent:Component = null;
567 |
568 | @:noCompletion
569 | private function clearCaches() {
570 | _cachedScreenX = null;
571 | _cachedScreenY = null;
572 | _cachedClipComponent = null;
573 | _cachedClipComponentNone = null;
574 | _cachedRootComponent = null;
575 | }
576 |
577 | @:noCompletion
578 | private function cacheScreenPos() {
579 | if (_cachedScreenX != null && _cachedScreenY != null) {
580 | return;
581 | }
582 |
583 | var c:Component = cast(this, Component);
584 | var last:Component = null;
585 | var xpos:Float = 0;
586 | var ypos:Float = 0;
587 | while (c != null) {
588 | xpos += c.left;
589 | ypos += c.top;
590 | if (c.componentClipRect != null) {
591 | xpos -= c.componentClipRect.left;
592 | ypos -= c.componentClipRect.top;
593 | }
594 | last = c;
595 | c = c.parentComponent;
596 | }
597 |
598 | if (last != null && last.parent != null) { // UI might have been added deep in a heaps hierachy, so lets get the _real_ screen pos
599 | var o = last.parent;
600 | while (o != null) {
601 | xpos += o.x;
602 | ypos += o.y;
603 | o = o.parent;
604 | }
605 | }
606 |
607 | xpos *= Toolkit.scaleX;
608 | ypos *= Toolkit.scaleY;
609 |
610 | if (Toolkit.scaleX != 1) {
611 | xpos -= last.left;
612 | }
613 | if (Toolkit.scaleY != 1) {
614 | ypos -= last.top;
615 | }
616 |
617 | _cachedScreenX = xpos;
618 | _cachedScreenY = ypos;
619 | }
620 |
621 | @:noCompletion
622 | private var screenX(get, null):Float;
623 | @:noCompletion
624 | private function get_screenX():Float {
625 | cacheScreenPos();
626 | return _cachedScreenX;
627 | }
628 |
629 | @:noCompletion
630 | private var screenY(get, null):Float;
631 | @:noCompletion
632 | private function get_screenY():Float {
633 | cacheScreenPos();
634 | return _cachedScreenY;
635 | }
636 |
637 | @:noCompletion
638 | private function findRootComponent():Component {
639 | if (_cachedRootComponent != null) {
640 | return _cachedRootComponent;
641 | }
642 |
643 | var c:Component = cast(this, Component);
644 | while (c.parentComponent != null) {
645 | c = c.parentComponent;
646 | }
647 |
648 | _cachedRootComponent = c;
649 |
650 | return c;
651 | }
652 |
653 | @:noCompletion
654 | private function isRootComponent():Bool {
655 | return (findRootComponent() == this);
656 | }
657 |
658 | @:noCompletion
659 | private function findClipComponent():Component {
660 | if (_cachedClipComponent != null) {
661 | return _cachedClipComponent;
662 | } else if (_cachedClipComponentNone == true) {
663 | return null;
664 | }
665 |
666 | var c:Component = cast(this, Component);
667 | var clip:Component = null;
668 | while (c != null) {
669 | if (c.componentClipRect != null) {
670 | clip = c;
671 | break;
672 | }
673 | c = c.parentComponent;
674 | }
675 |
676 | _cachedClipComponent = clip;
677 | if (clip == null) {
678 | _cachedClipComponentNone = true;
679 | }
680 |
681 | return clip;
682 | }
683 |
684 | @:noCompletion
685 | @:access(haxe.ui.core.Component)
686 | private function inBounds(x:Float, y:Float):Bool {
687 | if (cast(this, Component).hidden == true) {
688 | return false;
689 | }
690 |
691 | if (isOnScreen() == false) {
692 | return false;
693 | }
694 |
695 | x *= Toolkit.scaleX;
696 | y *= Toolkit.scaleY;
697 | var b:Bool = false;
698 | var sx = screenX;
699 | var sy = screenY;
700 | var cx = this.width * Toolkit.scaleX;
701 | var cy = this.height * Toolkit.scaleY;
702 |
703 | if (x >= sx && y >= sy && x <= sx + cx && y <= sy + cy) {
704 | b = true;
705 | }
706 |
707 | // let make sure its in the clip rect too
708 | if (b == true) {
709 | var clip:Component = findClipComponent();
710 | if (clip != null) {
711 | b = false;
712 | var sx = (clip.screenX + (clip.componentClipRect.left * Toolkit.scaleX));
713 | var sy = (clip.screenY + (clip.componentClipRect.top * Toolkit.scaleY));
714 | var cx = clip.componentClipRect.width * Toolkit.scaleX;
715 | var cy = clip.componentClipRect.height * Toolkit.scaleY;
716 | if (x >= sx && y >= sy && x <= sx + cx && y <= sy + cy) {
717 | b = true;
718 | }
719 | }
720 | }
721 | return b;
722 | }
723 |
724 | @:noCompletion
725 | private function isEventRelevant(children:Array, eventType:String):Bool {
726 | var relevant = false;
727 | for (c in children) {
728 | if (c == this) {
729 | relevant = true;
730 | }
731 | if (c.parentComponent == null) {
732 | break;
733 | }
734 | }
735 |
736 | return relevant;
737 | }
738 |
739 | @:noCompletion
740 | private function getComponentsAtPoint(x:Float, y:Float, reverse:Bool = false):Array {
741 | var array:Array = new Array();
742 | for (r in Screen.instance.rootComponents) {
743 | findChildrenAtPoint(r, x, y, array);
744 | }
745 |
746 | if (reverse == true) {
747 | array.reverse();
748 | }
749 |
750 | return array;
751 | }
752 |
753 | @:noCompletion
754 | private function findChildrenAtPoint(child:Component, x:Float, y:Float, array:Array) {
755 | if (child.inBounds(x, y) == true) {
756 | array.push(child);
757 | }
758 | for (c in child.childComponents) {
759 | findChildrenAtPoint(c, x, y, array);
760 | }
761 | }
762 |
763 | @:noCompletion
764 | public function hasChildRecursive(parent:Component, child:Component):Bool {
765 | if (parent == child) {
766 | return true;
767 | }
768 | var r = false;
769 | for (t in parent.childComponents) {
770 | if (t == child) {
771 | r = true;
772 | break;
773 | }
774 |
775 | r = hasChildRecursive(t, child);
776 | if (r == true) {
777 | break;
778 | }
779 | }
780 |
781 | return r;
782 | }
783 |
784 | @:noCompletion
785 | private override function sync(ctx:RenderContext) {
786 | var changed = posChanged;
787 | // if .x/.y property is access directly, we still want to honour it, so we will set haxeui's
788 | // .left/.top to keep them on sync, but only if the components position isnt already invalid
789 | // (which would mean this has come from a haxeui validation cycle)
790 | if (changed == true && isComponentInvalid(InvalidationFlags.POSITION) == false && _maskGraphics == null) {
791 | if (this.x != this.left) {
792 | this.left = this.x;
793 | }
794 | if (this.y != this.top) {
795 | this.top = this.y;
796 | }
797 | }
798 | super.sync(ctx);
799 | clearCaches();
800 | }
801 |
802 | @:noCompletion
803 | private override function onAdd() {
804 | super.onAdd();
805 | if (this.parentComponent == null && Screen.instance.rootComponents.indexOf(cast this) == -1) {
806 | Screen.instance.addComponent(cast this);
807 | }
808 | cast(this, Component).ready();
809 | }
810 |
811 | @:noCompletion
812 | private override function onRemove() {
813 | if (_deallocate == true) {
814 | _disposed = true;
815 | super.onRemove();
816 | }
817 | if (this.parentComponent == null && Screen.instance.rootComponents.indexOf(cast this) != -1) {
818 | Screen.instance.removeComponent(cast this, _deallocate);
819 | }
820 | }
821 |
822 | @:noCompletion
823 | private var lastMouseX:Float = -1;
824 | @:noCompletion
825 | private var lastMouseY:Float = -1;
826 |
827 | // For doubleclick detection
828 | @:noCompletion
829 | private var _lastClickTime:Float = 0;
830 | @:noCompletion
831 | private var _lastClickTimeDiff:Float = MathUtil.MAX_INT;
832 | @:noCompletion
833 | private var _lastClickX:Float = -1;
834 | @:noCompletion
835 | private var _lastClickY:Float = -1;
836 |
837 | @:noCompletion
838 | private function calcCursor():String {
839 | var c = null;
840 | var p = this;
841 | while (p != null) {
842 | if (p.style != null && p.style.cursor != null) {
843 | c = p.style.cursor;
844 | break;
845 | }
846 | p = p.parentComponent;
847 | }
848 | return c;
849 | }
850 |
851 | @:noCompletion
852 | private function findScene():Scene {
853 | if (this.getScene() != null) {
854 | return this.getScene();
855 | }
856 | return Screen.instance.scene;
857 | }
858 |
859 | @:noCompletion
860 | private function findCamera():Camera {
861 | var scene = findScene();
862 | if (scene == null) {
863 | return null;
864 | }
865 |
866 | if (scene.interactiveCamera != null) {
867 | return scene.interactiveCamera;
868 | }
869 | return scene.camera;
870 | }
871 |
872 | @:noCompletion
873 | private var _h2dPoint = new Point(); // we'll just reuse the same point rather than creating new ones
874 | @:noCompletion
875 | private function eventToCamera(event:MouseEvent) {
876 | _h2dPoint.x = event.screenX;
877 | _h2dPoint.y = event.screenY;
878 | var camera = findCamera();
879 | if (camera != null) {
880 | camera.screenToCamera(_h2dPoint);
881 | }
882 | event.screenX = _h2dPoint.x / Toolkit.scaleX;
883 | event.screenY = _h2dPoint.y / Toolkit.scaleY;
884 | }
885 |
886 | @:noCompletion
887 | private var _mouseOverFlag:Bool = false;
888 | @:noCompletion
889 | private function __onMouseMove(event:MouseEvent) {
890 | eventToCamera(event);
891 |
892 | var x = event.screenX;
893 | var y = event.screenY;
894 | lastMouseX = x;
895 | lastMouseY = y;
896 |
897 | var i = inBounds(x, y);
898 | if (i == true) {
899 | if (_mouseOverFlag && hasComponentOver(cast this, x, y) == true) {
900 | _mouseOverFlag = false;
901 | var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_OUT);
902 | if (fn != null) {
903 | var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OUT);
904 | mouseEvent.screenX = x;
905 | mouseEvent.screenY = y;
906 | fn(mouseEvent);
907 | event.canceled = mouseEvent.canceled;
908 | }
909 | return;
910 | }
911 |
912 | if (isEventRelevant(getComponentsAtPoint(x, y, true), MouseEvent.MOUSE_OVER)) {
913 | if (isInteractiveAbove(x, y)) {
914 | return;
915 | }
916 |
917 | var cursor = calcCursor();
918 | if (cursor != null) {
919 | Screen.instance.setCursor(cursor);
920 | }
921 | }
922 |
923 | var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_MOVE);
924 | if (fn != null) {
925 | var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_MOVE);
926 | mouseEvent.screenX = x;
927 | mouseEvent.screenY = y;
928 | fn(mouseEvent);
929 | event.canceled = mouseEvent.canceled;
930 | }
931 | }
932 |
933 | if (i == true && _mouseOverFlag == false) {
934 | if (hasComponentOver(cast this, x, y) == true) {
935 | return;
936 | }
937 |
938 | if (isEventRelevant(getComponentsAtPoint(x, y, true), MouseEvent.MOUSE_OVER)) {
939 | _mouseOverFlag = true;
940 | var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_OVER);
941 | if (fn != null) {
942 | var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OVER);
943 | mouseEvent.screenX = x;
944 | mouseEvent.screenY = y;
945 | fn(mouseEvent);
946 | event.canceled = mouseEvent.canceled;
947 | }
948 | }
949 | } else if (i == false && _mouseOverFlag == true) {
950 | _mouseOverFlag = false;
951 | Screen.instance.setCursor("default");
952 | var fn:UIEvent->Void = _eventMap.get(haxe.ui.events.MouseEvent.MOUSE_OUT);
953 | if (fn != null) {
954 | var mouseEvent = new haxe.ui.events.MouseEvent(haxe.ui.events.MouseEvent.MOUSE_OUT);
955 | mouseEvent.screenX = x;
956 | mouseEvent.screenY = y;
957 | fn(mouseEvent);
958 | event.canceled = mouseEvent.canceled;
959 | }
960 | }
961 | }
962 |
963 | @:noCompletion
964 | private var _mouseDownFlag:Bool = false;
965 | @:noCompletion
966 | private var _mouseDownButton:Int = -1;
967 | @:noCompletion
968 | private function __onMouseDown(event:MouseEvent) {
969 | eventToCamera(event);
970 |
971 | var button:Int = event.data;
972 | var x = event.screenX;
973 | var y = event.screenY;
974 | lastMouseX = x;
975 | lastMouseY = y;
976 | var i = inBounds(x, y);
977 | if (i == true && _mouseDownFlag == false) {
978 | /*
979 | if (hasComponentOver(cast this, x, y) == true) {
980 | return;
981 | }
982 | */
983 | if (isEventRelevant(getComponentsAtPoint(x, y, true), MouseEvent.MOUSE_DOWN)) {
984 | if (isInteractiveAbove(x, y)) {
985 | return;
986 | }
987 |
988 | _mouseDownFlag = true;
989 |
990 | /* TODO: feels hacky (ill-conceived?)
991 | if (this.style != null && (this.style.cursor == "row-resize" || this.style.cursor == "col-resize")) {
992 | Screen.instance.lockCursor();
993 | }
994 | */
995 |
996 | _mouseDownButton = button;
997 | var type = switch(button) {
998 | case 0: haxe.ui.events.MouseEvent.MOUSE_DOWN;
999 | case 1: haxe.ui.events.MouseEvent.RIGHT_MOUSE_DOWN;
1000 | case 2: haxe.ui.events.MouseEvent.MIDDLE_MOUSE_DOWN;
1001 | case _: haxe.ui.events.MouseEvent.MOUSE_DOWN;
1002 | }
1003 | var fn:UIEvent->Void = _eventMap.get(type);
1004 | if (fn != null) {
1005 | var mouseEvent = new haxe.ui.events.MouseEvent(type);
1006 | mouseEvent.data = button;
1007 | mouseEvent.screenX = x;
1008 | mouseEvent.screenY = y;
1009 | fn(mouseEvent);
1010 | event.canceled = mouseEvent.canceled;
1011 | }
1012 | }
1013 | }
1014 | }
1015 |
1016 | @:noCompletion
1017 | private function __onMouseUp(event:MouseEvent) {
1018 | eventToCamera(event);
1019 |
1020 | var button:Int = _mouseDownButton;
1021 | var x = event.screenX;
1022 | var y = event.screenY;
1023 |
1024 | lastMouseX = x;
1025 | lastMouseY = y;
1026 |
1027 | var i = inBounds(x, y);
1028 | if (i == true) {
1029 | /*
1030 | if (hasComponentOver(cast this, x, y) == true) {
1031 | return;
1032 | }
1033 | */
1034 |
1035 | if (_mouseDownFlag == true) {
1036 | var type = switch(button) {
1037 | case 0: haxe.ui.events.MouseEvent.CLICK;
1038 | case 1: haxe.ui.events.MouseEvent.RIGHT_CLICK;
1039 | case 2: haxe.ui.events.MouseEvent.MIDDLE_CLICK;
1040 | case _: haxe.ui.events.MouseEvent.CLICK;
1041 | }
1042 | var fn:UIEvent->Void = _eventMap.get(type);
1043 | if (fn != null) {
1044 | var mouseEvent = new haxe.ui.events.MouseEvent(type);
1045 | mouseEvent.data = button;
1046 | mouseEvent.screenX = x;
1047 | mouseEvent.screenY = y;
1048 | Toolkit.callLater(function() {
1049 | fn(mouseEvent);
1050 | event.canceled = mouseEvent.canceled;
1051 | });
1052 | }
1053 |
1054 | if (type == haxe.ui.events.MouseEvent.CLICK) {
1055 | _lastClickTimeDiff = Timer.stamp() - _lastClickTime;
1056 | _lastClickTime = Timer.stamp();
1057 | if (_lastClickTimeDiff >= 0.5) { // 0.5 seconds
1058 | _lastClickX = x;
1059 | _lastClickY = y;
1060 | }
1061 | }
1062 | }
1063 |
1064 | /* TODO: feels hacky (ill-conceived?)
1065 | if (_mouseDownFlag && this.style != null) {
1066 | Screen.instance.unlockCursor();
1067 | Screen.instance.setCursor(calcCursor());
1068 | }
1069 | */
1070 |
1071 | _mouseDownFlag = false;
1072 | var type = switch(button) {
1073 | case 0: haxe.ui.events.MouseEvent.MOUSE_UP;
1074 | case 1: haxe.ui.events.MouseEvent.RIGHT_MOUSE_UP;
1075 | case 2: haxe.ui.events.MouseEvent.MIDDLE_MOUSE_UP;
1076 | case _: haxe.ui.events.MouseEvent.MOUSE_UP;
1077 | }
1078 | var fn:UIEvent->Void = _eventMap.get(type);
1079 | if (fn != null) {
1080 | var mouseEvent = new haxe.ui.events.MouseEvent(type);
1081 | mouseEvent.data = button;
1082 | mouseEvent.screenX = x;
1083 | mouseEvent.screenY = y;
1084 | fn(mouseEvent);
1085 | event.canceled = mouseEvent.canceled;
1086 | }
1087 | } else {
1088 | /* TODO: feels hacky (ill-conceived?)
1089 | if (_mouseDownFlag) {
1090 | Screen.instance.unlockCursor();
1091 | Screen.instance.setCursor("default");
1092 | }
1093 | */
1094 | }
1095 | _mouseDownFlag = false;
1096 | }
1097 |
1098 | @:noCompletion
1099 | private function __onDoubleClick(event:MouseEvent) {
1100 | eventToCamera(event);
1101 |
1102 | var button:Int = _mouseDownButton;
1103 | var x = event.screenX;
1104 | var y = event.screenY;
1105 |
1106 | lastMouseX = x;
1107 | lastMouseY = y;
1108 | var i = inBounds(x, y);
1109 | if (i == true && button == 0) {
1110 | /*
1111 | if (hasComponentOver(cast this, x, y) == true) {
1112 | return;
1113 | }
1114 | */
1115 |
1116 | _mouseDownFlag = false;
1117 | var mouseDelta:Float = MathUtil.distance(x, y, _lastClickX, _lastClickY);
1118 | if (_lastClickTimeDiff < 0.5 && mouseDelta < 5) { // 0.5 seconds
1119 | var type = haxe.ui.events.MouseEvent.DBL_CLICK;
1120 | var fn:UIEvent->Void = _eventMap.get(type);
1121 | if (fn != null) {
1122 | var mouseEvent = new haxe.ui.events.MouseEvent(type);
1123 | mouseEvent.data = button;
1124 | mouseEvent.screenX = x;
1125 | mouseEvent.screenY = y;
1126 | fn(mouseEvent);
1127 | event.canceled = mouseEvent.canceled;
1128 | }
1129 | }
1130 | }
1131 | _mouseDownFlag = false;
1132 | }
1133 |
1134 | @:noCompletion
1135 | private function __onMouseWheel(event:MouseEvent) {
1136 | eventToCamera(event);
1137 |
1138 | var delta = event.delta;
1139 | var fn = _eventMap.get(MouseEvent.MOUSE_WHEEL);
1140 |
1141 | if (fn == null) {
1142 | return;
1143 | }
1144 |
1145 | if (!inBounds(lastMouseX, lastMouseY)) {
1146 | return;
1147 | }
1148 |
1149 | if (isInteractiveAbove(lastMouseX, lastMouseY)) {
1150 | return;
1151 | }
1152 |
1153 | var mouseEvent = new MouseEvent(MouseEvent.MOUSE_WHEEL);
1154 | mouseEvent.screenX = lastMouseX;
1155 | mouseEvent.screenY = lastMouseY;
1156 | mouseEvent.delta = Math.max(-1, Math.min(1, -delta));
1157 | fn(mouseEvent);
1158 | event.canceled = mouseEvent.canceled;
1159 | }
1160 |
1161 | //***********************************************************************************************************
1162 | // Helpers
1163 | //***********************************************************************************************************
1164 | @:noCompletion
1165 | private function hasComponentOver(ref:Component, x:Float, y:Float):Bool {
1166 | var array:Array = getComponentsAtPoint(x, y);
1167 | if (array.length == 0) {
1168 | return false;
1169 | }
1170 |
1171 | return !hasChildRecursive(cast ref, cast array[array.length - 1]);
1172 | }
1173 |
1174 | @:noCompletion
1175 | private override function set_visible(value:Bool):Bool {
1176 | if (value == this.visible) {
1177 | return value;
1178 | }
1179 | super.visible = value;
1180 | cast(this, Component).hidden = !value;
1181 | return value;
1182 | }
1183 |
1184 | @:noCompletion
1185 | private function calcObjectIndex(obj:Object):Int {
1186 | var n = 0;
1187 | while (obj.parent != null) {
1188 | n++;
1189 | if (obj.parent == obj.getScene()) {
1190 | break;
1191 | }
1192 | obj = obj.parent;
1193 | }
1194 | return obj.getScene().getChildIndex(obj);
1195 | }
1196 |
1197 | @:noCompletion
1198 | private function isOnScreen() {
1199 | var obj:Object = this;
1200 | while (obj.parent != null) {
1201 | if (obj.visible == false) {
1202 | return false;
1203 | }
1204 | obj = obj.parent;
1205 | if (obj == obj.getScene()) {
1206 | break;
1207 | }
1208 | }
1209 | return true;
1210 | }
1211 |
1212 | @:noCompletion
1213 | private function isInteractiveAbove(x:Float, y:Float) {
1214 | var scene = this.getScene();
1215 | if (scene != null) {
1216 | var interactive = scene.getInteractive(x, y);
1217 | if (interactive != null) {
1218 | var n1 = calcObjectIndex(interactive);
1219 | var n2 = calcObjectIndex(this);
1220 | if (n1 > n2) {
1221 | hxd.System.setNativeCursor(interactive.cursor);
1222 | return true;
1223 | }
1224 | }
1225 | }
1226 |
1227 | return false;
1228 | }
1229 | }
1230 |
--------------------------------------------------------------------------------
/haxe/ui/backend/ComponentSurface.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | typedef ComponentSurface = h2d.Object;
4 |
--------------------------------------------------------------------------------
/haxe/ui/backend/EventImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import haxe.ui.events.UIEvent;
4 |
5 | @:allow(haxe.ui.backend.ComponentImpl)
6 | @:allow(haxe.ui.backend.ScreenImpl)
7 | class EventImpl extends EventBase {
8 | private var _originalEvent:hxd.Event;
9 |
10 | public override function cancel() {
11 | if (_originalEvent != null) {
12 | _originalEvent.cancel = true;
13 | _originalEvent.propagate = false;
14 | }
15 | }
16 |
17 | private override function postClone(event:UIEvent) {
18 | event._originalEvent = this._originalEvent;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/haxe/ui/backend/FontData.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | typedef FontData = hxd.res.BitmapFont;
--------------------------------------------------------------------------------
/haxe/ui/backend/ImageData.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | typedef ImageData = hxd.BitmapData;
4 |
--------------------------------------------------------------------------------
/haxe/ui/backend/ImageDisplayImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 | import haxe.ui.Toolkit;
3 |
4 | class ImageDisplayImpl extends ImageBase {
5 | public var sprite:h2d.Bitmap;
6 |
7 | public function new() {
8 | super();
9 | sprite = new h2d.Bitmap();
10 | }
11 |
12 | private override function validateData() {
13 | if (_imageInfo != null) {
14 | sprite.tile = h2d.Tile.fromBitmap(_imageInfo.data);
15 | } else {
16 | sprite.tile.dispose();
17 | sprite.tile = null;
18 | }
19 | }
20 |
21 | private override function validatePosition() {
22 | if (sprite.x != _left) {
23 | sprite.x = _left;
24 | }
25 |
26 | if (sprite.y != _top) {
27 | sprite.y = _top;
28 | }
29 | }
30 |
31 | private override function validateDisplay() {
32 | if (sprite.tile != null) {
33 | var scaleX:Float = (_imageWidth / sprite.tile.width);
34 | if (sprite.scaleX != scaleX) {
35 | sprite.scaleX = scaleX;
36 | }
37 |
38 | var scaleY:Float = (_imageHeight / sprite.tile.height);
39 | if (sprite.scaleY != scaleY) {
40 | sprite.scaleY = scaleY;
41 | }
42 |
43 | sprite.smooth = false;//scaleX != Toolkit.scaleX || scaleY != Toolkit.scaleY;
44 | }
45 | }
46 |
47 | public override function dispose() {
48 | if (sprite.tile != null) {
49 | sprite.tile.dispose();
50 | sprite.tile = null;
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/ImageSurface.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | typedef ImageSurface = h2d.Bitmap;
--------------------------------------------------------------------------------
/haxe/ui/backend/OpenFileDialogImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import haxe.ui.containers.dialogs.Dialogs.SelectedFileInfo;
4 | import haxe.ui.core.Platform;
5 |
6 | using StringTools;
7 |
8 | class OpenFileDialogImpl extends OpenFileDialogBase {
9 | #if hl
10 |
11 | public override function show() {
12 | if (Platform.instance.isWindows) {
13 | var title = options.title;
14 | if (title == null) {
15 | title = "Open File";
16 | }
17 | var nativeOptions:hl.UI.FileOptions = { }
18 | nativeOptions.title = title;
19 | nativeOptions.filters = buildFilters();
20 |
21 | var allowTimeout = hxd.System.allowTimeout;
22 | hxd.System.allowTimeout = false;
23 | var file = hl.UI.loadFile(nativeOptions);
24 | hxd.System.allowTimeout = allowTimeout;
25 | if (file != null) {
26 | var infos:Array = [];
27 | infos.push({
28 | name: haxe.io.Path.withoutDirectory(file),
29 | fullPath: file,
30 | isBinary: false
31 | });
32 |
33 | if (options.readContents == true) {
34 | for (info in infos) {
35 | if (options.readAsBinary) {
36 | info.isBinary = true;
37 | info.bytes = sys.io.File.getBytes(info.fullPath);
38 | } else {
39 | info.isBinary = false;
40 | info.text = sys.io.File.getContent(info.fullPath);
41 | }
42 | }
43 | }
44 |
45 | dialogConfirmed(infos);
46 | } else {
47 | dialogCancelled();
48 | }
49 | } else {
50 | super.show();
51 | }
52 | }
53 |
54 | private function buildFilters():Array<{name:String, exts:Array}> {
55 | var filters = null;
56 | if (options.extensions != null) {
57 | filters = [];
58 | for (e in options.extensions) {
59 | var ext = e.extension;
60 | ext = ext.trim();
61 | if (ext.length == 0) {
62 | continue;
63 | }
64 | var single = e.label;
65 | var parts = ext.split(",");
66 | var finalParts = [];
67 | for (p in parts) {
68 | p = p.trim();
69 | if (p.length == 0) {
70 | continue;
71 | }
72 | finalParts.push(p);
73 | }
74 | single += " (" + finalParts.join(", ") + ")";
75 | filters.push({name: single, exts: finalParts});
76 | }
77 | }
78 | return filters;
79 | }
80 |
81 | #elseif js
82 |
83 | private var _fileSelector:haxe.ui.util.html5.FileSelector = new haxe.ui.util.html5.FileSelector();
84 |
85 | public override function show() {
86 | var readMode = haxe.ui.util.html5.FileSelector.ReadMode.None;
87 | if (options.readContents == true) {
88 | if (options.readAsBinary == false) {
89 | readMode = haxe.ui.util.html5.FileSelector.ReadMode.Text;
90 | } else {
91 | readMode = haxe.ui.util.html5.FileSelector.ReadMode.Binary;
92 | }
93 | }
94 | _fileSelector.selectFile(onFileSelected, readMode, options.multiple, options.extensions);
95 | }
96 |
97 | private function onFileSelected(cancelled:Bool, files:Array) {
98 | if (cancelled == false) {
99 | dialogConfirmed(files);
100 | } else {
101 | dialogCancelled();
102 | }
103 | }
104 |
105 | #end
106 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/PlatformImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | class PlatformImpl extends PlatformBase {
4 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/SaveFileDialogImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import haxe.ui.core.Platform;
4 |
5 | using StringTools;
6 |
7 | class SaveFileDialogImpl extends SaveFileDialogBase {
8 | #if hl
9 |
10 | public override function show() {
11 | if (fileInfo == null || (fileInfo.text == null && fileInfo.bytes == null)) {
12 | throw "Nothing to write";
13 | }
14 |
15 | if (Platform.instance.isWindows) {
16 | var title = options.title;
17 | if (title == null) {
18 | title = "Save File";
19 | }
20 | var nativeOptions:hl.UI.FileOptions = { }
21 | nativeOptions.title = title;
22 | nativeOptions.fileName = fileInfo.name;
23 | nativeOptions.filters = buildFilters();
24 |
25 | var allowTimeout = hxd.System.allowTimeout;
26 | hxd.System.allowTimeout = false;
27 | var file = hl.UI.saveFile(nativeOptions);
28 | hxd.System.allowTimeout = allowTimeout;
29 | if (file != null) {
30 | fullPath = file;
31 | if (fileInfo.text != null) {
32 | sys.io.File.saveContent(fullPath, fileInfo.text);
33 | } else if (fileInfo.bytes != null) {
34 | sys.io.File.saveBytes(fullPath, fileInfo.bytes);
35 | }
36 | dialogConfirmed();
37 | } else {
38 | dialogCancelled();
39 | }
40 | } else {
41 | super.show();
42 | }
43 | }
44 |
45 |
46 | private function buildFilters():Array<{name:String, exts:Array}> {
47 | var filters = null;
48 | if (options.extensions != null) {
49 | filters = [];
50 | for (e in options.extensions) {
51 | var ext = e.extension;
52 | ext = ext.trim();
53 | if (ext.length == 0) {
54 | continue;
55 | }
56 | var single = e.label;
57 | var parts = ext.split(",");
58 | var finalParts = [];
59 | for (p in parts) {
60 | p = p.trim();
61 | if (p.length == 0) {
62 | continue;
63 | }
64 | finalParts.push(p);
65 | }
66 | single += " (" + finalParts.join(", ") + ")";
67 | filters.push({name: single, exts: finalParts});
68 | }
69 | }
70 | return filters;
71 | }
72 |
73 | #elseif js
74 |
75 | private var _fileSaver:haxe.ui.util.html5.FileSaver = new haxe.ui.util.html5.FileSaver();
76 |
77 | public override function show() {
78 | if (fileInfo == null || (fileInfo.text == null && fileInfo.bytes == null)) {
79 | throw "Nothing to write";
80 | }
81 |
82 | if (fileInfo.text != null) {
83 | _fileSaver.saveText(fileInfo.name, fileInfo.text, onSaveResult);
84 | } else if (fileInfo.bytes != null) {
85 | _fileSaver.saveBinary(fileInfo.name, fileInfo.bytes, onSaveResult);
86 | }
87 | }
88 |
89 | private function onSaveResult(r:Bool) {
90 | if (r == true) {
91 | dialogConfirmed();
92 | } else {
93 | dialogCancelled();
94 | }
95 | }
96 |
97 | #end
98 | }
99 |
--------------------------------------------------------------------------------
/haxe/ui/backend/ScreenImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import h2d.Object;
4 | import h2d.Scene;
5 | import haxe.ui.Toolkit;
6 | import haxe.ui.backend.heaps.EventMapper;
7 | import haxe.ui.backend.heaps.KeyboardHelper;
8 | import haxe.ui.backend.heaps.MouseHelper;
9 | import haxe.ui.backend.heaps.ScreenUtils;
10 | import haxe.ui.core.Component;
11 | import haxe.ui.events.KeyboardEvent;
12 | import haxe.ui.events.MouseEvent;
13 | import haxe.ui.events.UIEvent;
14 | import hxd.Window;
15 |
16 | class ScreenImpl extends ScreenBase {
17 | private var _mapping:MapVoid>;
18 |
19 | public function new() {
20 | _mapping = new MapVoid>();
21 | addResizeListener();
22 | }
23 |
24 | private var _resizeListenerAdded:Bool = false;
25 | private function addResizeListener() {
26 | if (_resizeListenerAdded == true) {
27 | return;
28 | }
29 |
30 | if (Window.getInstance() != null) {
31 | Window.getInstance().addResizeEvent(onWindowResize);
32 | _resizeListenerAdded = true;
33 | }
34 | }
35 |
36 | private var _updateCallbackAdded:Bool = false;
37 | private function addUpdateCallback() {
38 | if (_updateCallbackAdded == true) {
39 | return;
40 | }
41 |
42 | if (options == null || options.manualUpdate == null || options.manualUpdate == false) {
43 | _updateCallbackAdded = true;
44 | MainLoop.add(BackendImpl.update);
45 | }
46 | }
47 |
48 | private function onWindowResize() {
49 | resizeRootComponents();
50 | if (_mapping.exists(UIEvent.RESIZE)) {
51 | _mapping.get(UIEvent.RESIZE)(new UIEvent(UIEvent.RESIZE));
52 | }
53 | }
54 |
55 | private var _root:Object = null;
56 | public var root(get, set):Object;
57 | private function get_root():Object {
58 | if (_root != null) {
59 | return _root;
60 | }
61 |
62 | if (options == null) {
63 | return null;
64 | }
65 | return options.root;
66 | }
67 | private function set_root(value:Object):Object {
68 | _root = value;
69 | return value;
70 | }
71 |
72 | public var scene(get, null):Scene;
73 | private function get_scene():Scene {
74 | if (root == null) {
75 | return null;
76 | }
77 | return root.getScene();
78 | }
79 |
80 |
81 | private override function set_options(value:ToolkitOptions):ToolkitOptions {
82 | super.set_options(value);
83 | addUpdateCallback();
84 | return value;
85 | }
86 |
87 | private override function get_width():Float {
88 | return Window.getInstance().width / Toolkit.scaleX;
89 | }
90 |
91 | private override function get_height():Float {
92 | return Window.getInstance().height / Toolkit.scaleY;
93 | }
94 |
95 | private override function get_dpi():Float {
96 | return ScreenUtils.dpi;
97 | }
98 |
99 | private override function get_isRetina():Bool {
100 | return ScreenUtils.isRetinaDisplay();
101 | }
102 |
103 | private var cursorLocked:Bool = false;
104 | public function setCursor(cursor:String, lock=false) {
105 | if (cursorLocked) {
106 | return;
107 | }
108 | cursorLocked = lock;
109 |
110 | if (cursor == "pointer") {
111 | hxd.System.setNativeCursor(Button);
112 | } else if (cursor == "text") {
113 | hxd.System.setNativeCursor(TextInput);
114 | } else if (cursor == "col-resize") {
115 | hxd.System.setNativeCursor(Move);
116 | } else if (cursor == "row-resize") {
117 | hxd.System.setNativeCursor(Move);
118 | }else {
119 | hxd.System.setNativeCursor(Default);
120 | }
121 | }
122 |
123 | public function lockCursor() {
124 | cursorLocked = true;
125 | }
126 | public function unlockCursor() {
127 | cursorLocked = false;
128 | }
129 |
130 | public override function addComponent(component:Component):Component {
131 | rootComponents.push(component);
132 | component.scaleX = Toolkit.scaleX;
133 | component.scaleY = Toolkit.scaleY;
134 | if (component.parent == null || component.parent == root) {
135 | if (_removedComponents.indexOf(component) != -1) {
136 | if (root == null) {
137 | trace("WARNING: trying to add a component to a null root. Either set Screen.instance.root or specify one in Toolkit.init");
138 | return component;
139 | }
140 | _removedComponents.remove(component);
141 | //rootScene.addChildAt(component, 0);
142 | component.visible = true;
143 | } else {
144 | if (root == null) {
145 | trace("WARNING: trying to add a component to a null root. Either set Screen.instance.root or specify one in Toolkit.init");
146 | return component;
147 | }
148 | root.addChild(component);
149 | }
150 | }
151 | resizeComponent(component);
152 | return component;
153 | }
154 |
155 | private var _removedComponents:Array = []; // TODO: probably ill conceived
156 | public override function removeComponent(component:Component, dispose:Bool = true, invalidate:Bool = true):Component {
157 | rootComponents.remove(component);
158 | if (_removedComponents.indexOf(component) == -1) {
159 | if (root == null) {
160 | trace("WARNING: trying to remove a component to a null root. Either set Screen.instance.root or specify one in Toolkit.init");
161 | return component;
162 | }
163 | //rootScene.removeChild(component);
164 | _removedComponents.push(component);
165 | component.visible = false;
166 | if (dispose == true && root != null) {
167 | root.removeChild(component);
168 | }
169 |
170 | if (@:privateAccess component.inBounds(MouseHelper.currentMouseX, MouseHelper.currentMouseY)) {
171 | setCursor(null);
172 | }
173 | }
174 | return component;
175 | }
176 |
177 | private override function handleSetComponentIndex(component:Component, index:Int) {
178 | if (root == null) {
179 | trace("WARNING: trying to set a component index in a null root. Either set Screen.instance.root or specify one in Toolkit.init");
180 | return;
181 | }
182 | root.addChildAt(component, index);
183 | resizeComponent(component);
184 | }
185 |
186 | //***********************************************************************************************************
187 | // Events
188 | //***********************************************************************************************************
189 | private override function supportsEvent(type:String):Bool {
190 | if (type == UIEvent.RESIZE) {
191 | return true;
192 | }
193 | return EventMapper.HAXEUI_TO_HEAPS.get(type) != null;
194 | }
195 |
196 | private var _deferredEvents:Array<{type:String, listener:UIEvent->Void}> = null;
197 | private function mapDeferredEvents() {
198 | if (hxd.Window.getInstance() == null) {
199 | return;
200 | }
201 |
202 | if (_deferredEvents == null) {
203 | return;
204 | }
205 |
206 | addResizeListener();
207 | while (_deferredEvents.length > 0) {
208 | var info = _deferredEvents.shift();
209 | mapEvent(info.type, info.listener);
210 | if (_deferredEvents == null) {
211 | break;
212 | }
213 | }
214 | _deferredEvents = null;
215 | }
216 |
217 | private override function mapEvent(type:String, listener:UIEvent->Void) {
218 | if (hxd.Window.getInstance() == null) {
219 | if (_deferredEvents == null) {
220 | _deferredEvents = [];
221 | }
222 | _deferredEvents.push({
223 | type: type,
224 | listener: listener
225 | });
226 | return;
227 | }
228 | mapDeferredEvents();
229 |
230 | switch (type) {
231 | case MouseEvent.MOUSE_MOVE:
232 | if (_mapping.exists(type) == false) {
233 | _mapping.set(type, listener);
234 | MouseHelper.notify(MouseEvent.MOUSE_MOVE, __onMouseMove);
235 | }
236 | case MouseEvent.MOUSE_DOWN:
237 | if (_mapping.exists(type) == false) {
238 | _mapping.set(type, listener);
239 | MouseHelper.notify(MouseEvent.MOUSE_DOWN, __onMouseDown);
240 | }
241 | case MouseEvent.MOUSE_UP:
242 | if (_mapping.exists(type) == false) {
243 | _mapping.set(type, listener);
244 | MouseHelper.notify(MouseEvent.MOUSE_UP, __onMouseUp);
245 | }
246 | case KeyboardEvent.KEY_DOWN:
247 | if (_mapping.exists(type) == false) {
248 | _mapping.set(type, listener);
249 | KeyboardHelper.notify(KeyboardEvent.KEY_DOWN, __onKeyDown);
250 | }
251 | case KeyboardEvent.KEY_UP:
252 | if (_mapping.exists(type) == false) {
253 | _mapping.set(type, listener);
254 | KeyboardHelper.notify(KeyboardEvent.KEY_UP, __onKeyUp);
255 | }
256 | case UIEvent.RESIZE:
257 | if (_mapping.exists(type) == false) {
258 | _mapping.set(type, listener);
259 | addResizeListener();
260 | }
261 | }
262 | }
263 |
264 | private override function unmapEvent(type:String, listener:UIEvent->Void) {
265 | switch (type) {
266 | case MouseEvent.MOUSE_MOVE:
267 | _mapping.remove(type);
268 | MouseHelper.remove(MouseEvent.MOUSE_MOVE, __onMouseMove);
269 | case MouseEvent.MOUSE_DOWN:
270 | _mapping.remove(type);
271 | MouseHelper.remove(MouseEvent.MOUSE_DOWN, __onMouseDown);
272 | case MouseEvent.MOUSE_UP:
273 | _mapping.remove(type);
274 | MouseHelper.remove(MouseEvent.MOUSE_UP, __onMouseUp);
275 | case KeyboardEvent.KEY_DOWN:
276 | _mapping.remove(type);
277 | KeyboardHelper.remove(KeyboardEvent.KEY_DOWN, __onKeyDown);
278 | case KeyboardEvent.KEY_UP:
279 | _mapping.remove(type);
280 | KeyboardHelper.remove(KeyboardEvent.KEY_UP, __onKeyUp);
281 | case UIEvent.RESIZE:
282 | _mapping.remove(type);
283 | }
284 | }
285 |
286 | private function __onMouseMove(event:MouseEvent) {
287 | var fn = _mapping.get(MouseEvent.MOUSE_MOVE);
288 | if (fn != null) {
289 | var mouseEvent = new MouseEvent(MouseEvent.MOUSE_MOVE);
290 | mouseEvent.screenX = event.screenX;
291 | mouseEvent.screenY = event.screenY;
292 | mouseEvent.buttonDown = event.data;
293 | fn(mouseEvent);
294 | }
295 | }
296 |
297 | private function __onMouseDown(event:MouseEvent) {
298 | var fn = _mapping.get(MouseEvent.MOUSE_DOWN);
299 | if (fn != null) {
300 | var mouseEvent = new MouseEvent(MouseEvent.MOUSE_DOWN);
301 | mouseEvent.screenX = event.screenX;
302 | mouseEvent.screenY = event.screenY;
303 | mouseEvent.buttonDown = event.data;
304 | fn(mouseEvent);
305 | }
306 | }
307 |
308 | private function __onMouseUp(event:MouseEvent) {
309 | var fn = _mapping.get(MouseEvent.MOUSE_UP);
310 | if (fn != null) {
311 | var mouseEvent = new MouseEvent(MouseEvent.MOUSE_UP);
312 | mouseEvent.screenX = event.screenX;
313 | mouseEvent.screenY = event.screenY;
314 | mouseEvent.buttonDown = event.data;
315 | fn(mouseEvent);
316 | }
317 | }
318 |
319 | private function __onKeyDown(event:KeyboardEvent) {
320 | var fn = _mapping.get(KeyboardEvent.KEY_DOWN);
321 | if (fn != null) {
322 | var keyboardEvent = new KeyboardEvent(KeyboardEvent.KEY_DOWN);
323 | keyboardEvent.keyCode = event.keyCode;
324 | keyboardEvent.shiftKey = event.shiftKey;
325 | keyboardEvent.ctrlKey = event.ctrlKey;
326 | keyboardEvent.altKey = event.altKey;
327 | fn(keyboardEvent);
328 | }
329 | }
330 |
331 | private function __onKeyUp(event:KeyboardEvent) {
332 | var fn = _mapping.get(KeyboardEvent.KEY_UP);
333 | if (fn != null) {
334 | var keyboardEvent = new KeyboardEvent(KeyboardEvent.KEY_UP);
335 | keyboardEvent.keyCode = event.keyCode;
336 | keyboardEvent.shiftKey = event.shiftKey;
337 | keyboardEvent.ctrlKey = event.ctrlKey;
338 | keyboardEvent.altKey = event.altKey;
339 | fn(keyboardEvent);
340 | }
341 | /* TODO? Not sure if its important
342 | var fn = _mapping.get(KeyboardEvent.KEY_PRESS);
343 | if (fn != null) {
344 | var keyboardEvent = new KeyboardEvent(KeyboardEvent.KEY_PRESS);
345 | keyboardEvent.keyCode = event.keyCode;
346 | fn(keyboardEvent);
347 | }
348 | */
349 | }
350 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/TextDisplayImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import h2d.Font;
4 | import haxe.ui.Toolkit;
5 | import haxe.ui.backend.heaps.SDFFonts;
6 |
7 | class TextDisplayImpl extends TextBase {
8 | public var sprite:h2d.Text;
9 |
10 | // defaults
11 | public static var defaultFontSize:Int = 12;
12 |
13 | public var isDefaultFont:Bool = true;
14 |
15 | public function new() {
16 | super();
17 | sprite = createText();
18 | sprite.visible = false;
19 | Toolkit.callLater(function() { // lets avoid text apearing at 0,0 initially by showing it 1 frame later
20 | sprite.visible = true;
21 | });
22 | }
23 |
24 | private override function validateData() {
25 | if (_text != null) {
26 | sprite.text = normalizeText(_text);
27 | } else if (_htmlText != null) {
28 | sprite.text = normalizeText(_htmlText);
29 | }
30 |
31 | }
32 |
33 | private var _currentFontData:FontData = null;
34 | private override function validateStyle():Bool {
35 | var measureTextRequired:Bool = false;
36 |
37 | var isBitmap = false;
38 | if (_fontInfo != null && _fontInfo.data != null) {
39 | if (_fontInfo.data != _currentFontData) {
40 | _currentFontData = _fontInfo.data;
41 |
42 | var font:Font = null;
43 | var sdfDetails = SDFFonts.get(_fontInfo.name);
44 | if (sdfDetails != null) {
45 | font = _currentFontData.toSdfFont(defaultFontSize, sdfDetails.channel, sdfDetails.alphaCutoff, sdfDetails.smoothing).clone();
46 | } else {
47 | font = _currentFontData.toFont().clone();
48 | isBitmap = true;
49 | }
50 |
51 | if (sprite.font != font) {
52 | sprite.font = font;
53 | measureTextRequired = true;
54 | }
55 |
56 | isDefaultFont = false;
57 | }
58 | }
59 |
60 | if (_textStyle != null) {
61 | var fontSizeValue = Std.int(_textStyle.fontSize);
62 | if (fontSizeValue <= 0) {
63 | fontSizeValue = Std.int(defaultFontSize);
64 | }
65 |
66 | var currentFontSize = sprite.font.size;
67 | if (currentFontSize < 0) { // no Math.fabs
68 | currentFontSize = -currentFontSize;
69 | }
70 |
71 | if (currentFontSize != fontSizeValue) {
72 | resizeFont(fontSizeValue, isBitmap);
73 | measureTextRequired = true;
74 | }
75 |
76 | if (_displayData.wordWrap != sprite.lineBreak) {
77 | sprite.lineBreak = _displayData.wordWrap;
78 | measureTextRequired = true;
79 | }
80 |
81 | var textAlign:h2d.Text.Align = getAlign(_textStyle.textAlign);
82 | if (sprite.textAlign != textAlign) {
83 | sprite.textAlign = textAlign;
84 | measureTextRequired = true;
85 | }
86 |
87 | if (sprite.textColor != _textStyle.color) {
88 | sprite.textColor = _textStyle.color;
89 | }
90 | }
91 |
92 | return measureTextRequired;
93 | }
94 |
95 | private function resizeFont(fontSizeValue:Int, isBitmap:Bool) {
96 | var temp = sprite.font.clone();
97 | sprite.font = null;
98 | if (isBitmap) {
99 | temp.resizeTo(-fontSizeValue);
100 | } else {
101 | if (temp == hxd.res.DefaultFont.get()) {
102 | temp = hxd.res.DefaultFont.get().clone();
103 | }
104 | temp.resizeTo(fontSizeValue);
105 | }
106 | sprite.font = temp;
107 | temp = null;
108 | }
109 |
110 | private override function validatePosition() {
111 | if (autoWidth == true && sprite.textAlign == h2d.Text.Align.Center) {
112 | sprite.x = (_left) + (_width / 2);
113 | } else {
114 | sprite.x = (_left);
115 | }
116 |
117 | var offset:Float = 0;
118 | if (!isDefaultFont) {
119 | var currentFontSize = sprite.font.size;
120 | if (currentFontSize < 0) { // no Math.fabs
121 | currentFontSize = -currentFontSize;
122 | }
123 | offset = ((currentFontSize - sprite.font.baseLine) / 2);
124 | }
125 |
126 | sprite.y = (_top) + offset;
127 | }
128 |
129 | private override function validateDisplay() {
130 | if (autoWidth == false) {
131 | sprite.maxWidth = _width != 0 ? _width : _textWidth;
132 | }else if (sprite.textAlign == h2d.Text.Align.Right){
133 | sprite.x =_width;
134 | }else if (sprite.textAlign == h2d.Text.Align.Center) {
135 | sprite.x = (_left) + (_width / 2);
136 | }
137 | }
138 |
139 | private var autoWidth(get, null):Bool;
140 | private function get_autoWidth():Bool {
141 | return parentComponent.autoWidth;
142 | }
143 |
144 | private override function measureText() {
145 | _textWidth = sprite.textWidth;
146 | _textHeight = sprite.textHeight;
147 |
148 | _textWidth = Math.round(_textWidth);
149 | _textHeight = Math.round(_textHeight);
150 |
151 | if (_textWidth % 2 != 0) {
152 | _textWidth++;
153 | }
154 | if (_textHeight % 2 == 0) {
155 | _textHeight++;
156 | }
157 | }
158 |
159 | private function createText():h2d.Text {
160 | var text = new h2d.Text(hxd.res.DefaultFont.get(), parentComponent);
161 | text.lineBreak = false;
162 | return text;
163 | }
164 |
165 | private function getAlign(align:String):h2d.Text.Align {
166 | return switch(align) {
167 | case "left": h2d.Text.Align.Left;
168 | case "right": h2d.Text.Align.Right;
169 | case "center": h2d.Text.Align.Center;
170 | case _: h2d.Text.Align.Left; //TODO - justify
171 | }
172 | }
173 |
174 | private function normalizeText(text:String):String {
175 | if (text == null) {
176 | return "";
177 | }
178 | text = StringTools.replace(text, "\\n", "\n");
179 | return text;
180 | }
181 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/TextInputImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import h2d.TextInput;
4 | import haxe.ui.core.InteractiveComponent;
5 | import haxe.ui.events.FocusEvent;
6 | import haxe.ui.events.KeyboardEvent;
7 | import haxe.ui.events.UIEvent;
8 | import hxd.Event;
9 | import hxd.Key;
10 |
11 | class TextInputImpl extends TextDisplayImpl {
12 |
13 | var textInput: TextInput;
14 |
15 | public function new() {
16 | super();
17 | }
18 |
19 | private override function createText() {
20 | textInput = new TextInput(hxd.res.DefaultFont.get());
21 | textInput.lineBreak = false;
22 | textInput.onChange = onChange;
23 | textInput.onClick = function(e) {
24 | cast(parentComponent, InteractiveComponent).focus = true;
25 | }
26 | return textInput;
27 | }
28 |
29 | // we're actually going to override this function so that it always returns
30 | // h2d.Text.Align.Left - this is because heaps text input doesnt seem to like
31 | // center aligned text (or right aligned), for now will simply turn it off
32 | /*private override function getAlign(align:String):h2d.Text.Align {
33 | return h2d.Text.Align.Left;
34 | }*/
35 |
36 | public override function focus() {
37 | Toolkit.callLater(function() {
38 | textInput.focus();
39 | });
40 | }
41 |
42 | public override function blur() {
43 | @:privateAccess textInput.interactive.blur();
44 | }
45 |
46 | private function onChange() {
47 | _text = textInput.text;
48 | _htmlText = textInput.text;
49 |
50 | measureText();
51 |
52 | if (_inputData.onChangedCallback != null) {
53 | _inputData.onChangedCallback();
54 | }
55 |
56 | if (parentComponent != null) {
57 | parentComponent.dispatch(new UIEvent(UIEvent.CHANGE));
58 | }
59 | }
60 |
61 | private override function validateDisplay() {
62 | super.validateDisplay();
63 |
64 | textInput.inputWidth = Math.round(textInput.maxWidth); // clip text input display to text component's width
65 | }
66 |
67 | private override function resizeFont(fontSizeValue:Int, isBitmap:Bool) {
68 | var temp = sprite.font.clone();
69 | if (isBitmap) {
70 | temp.resizeTo(-fontSizeValue);
71 | } else {
72 | if (temp == hxd.res.DefaultFont.get()) {
73 | temp = hxd.res.DefaultFont.get().clone();
74 | }
75 | temp.resizeTo(fontSizeValue);
76 | }
77 | sprite.font = temp;
78 | temp = null;
79 | }
80 |
81 | private override function validateStyle():Bool {
82 | var measureTextRequired:Bool = super.validateStyle();
83 |
84 | if ( _inputData.password) {
85 | trace("TextInput password mode isn't supported in Heaps.");
86 | _inputData.password = false;
87 | }
88 |
89 | if (parentComponent.disabled) {
90 | textInput.canEdit = false;
91 | } else {
92 | textInput.canEdit = true;
93 | }
94 |
95 | return measureTextRequired;
96 | }
97 |
98 | private var _onKeyDown:KeyboardEvent->Void = null;
99 | public var onKeyDown(null, set):KeyboardEvent->Void;
100 | private function set_onKeyDown(value:KeyboardEvent->Void):KeyboardEvent->Void {
101 | _onKeyDown = value;
102 | if (_onKeyDown == null && _onKeyUp == null && _onKeyPress == null) {
103 | unregisterInernalEvents();
104 | return value;
105 | }
106 | registerInternalEvents();
107 | return value;
108 | }
109 |
110 | private var _onKeyUp:KeyboardEvent->Void = null;
111 | public var onKeyUp(null, set):KeyboardEvent->Void;
112 | private function set_onKeyUp(value:KeyboardEvent->Void):KeyboardEvent->Void {
113 | _onKeyUp = value;
114 | if (_onKeyDown == null && _onKeyUp == null && _onKeyPress == null) {
115 | unregisterInernalEvents();
116 | return value;
117 | }
118 | registerInternalEvents();
119 | return value;
120 | }
121 |
122 | private var _onKeyPress:KeyboardEvent->Void = null;
123 | public var onKeyPress(null, set):KeyboardEvent->Void;
124 | private function set_onKeyPress(value:KeyboardEvent->Void):KeyboardEvent->Void {
125 | _onKeyPress = value;
126 | if (_onKeyDown == null && _onKeyUp == null && _onKeyPress == null) {
127 | unregisterInernalEvents();
128 | return value;
129 | }
130 | registerInternalEvents();
131 | return value;
132 | }
133 |
134 | private var _internalEventsRegistered = false;
135 | private function registerInternalEvents() {
136 | if (_internalEventsRegistered) {
137 | return;
138 | }
139 | _internalEventsRegistered = true;
140 | textInput.onKeyDown = onKeyDownInternal;
141 | textInput.onKeyUp = onKeyUpInternal;
142 | }
143 |
144 | // heaps doesnt have a keypress event, so we'll hold onto down keys in order to dispatch the press event
145 | private var _downKeys:Map = new Map();
146 | private function unregisterInernalEvents() {
147 | textInput.onKeyDown = null;
148 | textInput.onKeyUp = null;
149 | _internalEventsRegistered = false;
150 | }
151 |
152 | private function onKeyDownInternal(e:Event) {
153 | _downKeys.set(e.keyCode, true);
154 | dispatchEvent(KeyboardEvent.KEY_DOWN, e.keyCode);
155 | }
156 |
157 | private function onKeyUpInternal(e:Event) {
158 | var hadDownKey = (_downKeys.exists(e.keyCode) && _downKeys.get(e.keyCode) == true);
159 | _downKeys.remove(e.keyCode);
160 | dispatchEvent(KeyboardEvent.KEY_UP, e.keyCode);
161 | if (hadDownKey) {
162 | dispatchEvent(KeyboardEvent.KEY_PRESS, e.keyCode);
163 | }
164 | }
165 |
166 | private function dispatchEvent(type:String, keyCode:Int) {
167 | var event = new KeyboardEvent(type);
168 | event.keyCode = keyCode;
169 | event.altKey = Key.isDown(Key.ALT);
170 | event.shiftKey = Key.isDown(Key.SHIFT);
171 | event.ctrlKey = Key.isDown(Key.CTRL);
172 | switch (type) {
173 | case KeyboardEvent.KEY_DOWN:
174 | if (_onKeyDown != null) {
175 | _onKeyDown(event);
176 | }
177 | case KeyboardEvent.KEY_UP:
178 | if (_onKeyUp != null) {
179 | _onKeyUp(event);
180 | }
181 | case KeyboardEvent.KEY_PRESS:
182 | if (_onKeyPress != null) {
183 | _onKeyPress(event);
184 | }
185 | }
186 | }
187 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/TimerImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | class TimerImpl {
4 | static private var __timers:Array = [];
5 |
6 | static public function update() {
7 | var currentTime:Float = hxd.Timer.lastTimeStamp;
8 | var count:Int = __timers.length;
9 | for (i in 0...count) {
10 | var timer:TimerImpl = __timers[i];
11 | if (!timer._stopped && currentTime >= timer._end) {
12 | timer._end = currentTime + timer._delay;
13 | if (timer.callback != null) {
14 | timer.callback();
15 | }
16 | }
17 | }
18 |
19 | while(--count >= 0) {
20 | var timer:TimerImpl = __timers[count];
21 | if (timer._stopped) {
22 | __timers.remove(timer);
23 | }
24 | }
25 | }
26 |
27 | public var callback:Void->Void = null;
28 | private var _end:Float;
29 | private var _delay:Float;
30 | private var _stopped:Bool;
31 |
32 | public function new(delay:Int, callback:Void->Void) {
33 | this.callback = callback;
34 | _delay = delay / 1000;
35 | _end = hxd.Timer.lastTimeStamp + _delay;
36 | __timers.push(this);
37 | }
38 |
39 | public function stop() {
40 | callback = null;
41 | _stopped = true;
42 | }
43 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/ToolkitOptions.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import h2d.Object;
4 | import hxd.App;
5 |
6 | typedef ToolkitOptions = {
7 | @:optional var root:Object;
8 | @:optional var manualUpdate:Bool;
9 | }
10 |
--------------------------------------------------------------------------------
/haxe/ui/backend/heaps/EventMapper.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.heaps;
2 |
3 | class EventMapper {
4 | public static var HAXEUI_TO_HEAPS:Map = [
5 | haxe.ui.events.MouseEvent.MOUSE_MOVE => EventType.MOUSE_MOVE,
6 | haxe.ui.events.MouseEvent.MOUSE_OVER => EventType.MOUSE_OVER,
7 | haxe.ui.events.MouseEvent.MOUSE_OUT => EventType.MOUSE_OUT,
8 | haxe.ui.events.MouseEvent.MOUSE_DOWN => EventType.MOUSE_DOWN,
9 | haxe.ui.events.MouseEvent.MOUSE_UP => EventType.MOUSE_UP,
10 | haxe.ui.events.MouseEvent.MOUSE_WHEEL => EventType.MOUSE_WHEEL,
11 | haxe.ui.events.MouseEvent.CLICK => EventType.CLICK,
12 |
13 | haxe.ui.events.KeyboardEvent.KEY_DOWN => EventType.KEY_DOWN,
14 | haxe.ui.events.KeyboardEvent.KEY_UP => EventType.KEY_UP
15 | ];
16 |
17 | /*public static var HEAPS_TO_HAXEUI:Map = [
18 | EventType.MOUSE_MOVE => haxe.ui.events.MouseEvent.MOUSE_MOVE,
19 | EventType.MOUSE_OVER => haxe.ui.events.MouseEvent.MOUSE_OVER,
20 | EventType.MOUSE_OUT => haxe.ui.events.MouseEvent.MOUSE_OUT,
21 | EventType.MOUSE_DOWN => haxe.ui.events.MouseEvent.MOUSE_DOWN,
22 | EventType.MOUSE_UP => haxe.ui.events.MouseEvent.MOUSE_UP,
23 | EventType.MOUSE_WHEEL => haxe.ui.events.MouseEvent.MOUSE_WHEEL,
24 | EventType.CLICK => haxe.ui.events.MouseEvent.CLICK,
25 |
26 | EventType.KEY_DOWN => haxe.ui.events.KeyboardEvent.KEY_DOWN,
27 | EventType.KEY_UP => haxe.ui.events.KeyboardEvent.KEY_UP
28 | ];*/
29 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/heaps/EventType.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.heaps;
2 |
3 | enum abstract EventType(String) from String to String {
4 | var MOUSE_MOVE = "onMove";
5 | var MOUSE_OVER = "onOver";
6 | var MOUSE_OUT = "onOut";
7 | var MOUSE_DOWN = "onPush";
8 | var MOUSE_UP = "onRelease";
9 | var MOUSE_WHEEL = "onWheel";
10 | var CLICK = "onClick";
11 |
12 | var KEY_DOWN = "onKeyDown";
13 | var KEY_UP = "onKeyUp";
14 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/heaps/FilterConverter.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.heaps;
2 |
3 | import h2d.RenderContext;
4 | import h2d.filter.Blur;
5 | import h2d.filter.ColorMatrix;
6 | import h2d.filter.Filter;
7 | import h2d.filter.Glow;
8 | import h3d.Matrix;
9 | import h3d.mat.Pass;
10 | import haxe.ui.filters.Saturate;
11 | import haxe.ui.filters.Tint;
12 | import haxe.ui.util.Color;
13 |
14 | class FilterConverter {
15 | public static function convertFilter(input:haxe.ui.filters.Filter):Filter {
16 | if (input == null) {
17 | return null;
18 | }
19 |
20 | var output:Filter = null;
21 |
22 | if ((input is haxe.ui.filters.DropShadow)) {
23 | var inputDropShadow:haxe.ui.filters.DropShadow = cast(input, haxe.ui.filters.DropShadow);
24 | if (inputDropShadow.inner) { // TODO: temp
25 | return new h2d.filter.InnerGlow(inputDropShadow.color, .1, 1, 1);
26 | }
27 | var dropShadow = new h2d.filter.DropShadow(inputDropShadow.distance, 0.785, inputDropShadow.color, inputDropShadow.alpha * 2, 1, 1, 1, true);
28 | output = dropShadow;
29 | } else if ((input is haxe.ui.filters.BoxShadow)) {
30 | var inputDropShadow:haxe.ui.filters.BoxShadow = cast(input, haxe.ui.filters.BoxShadow);
31 | if (inputDropShadow.inset) { // TODO: temp
32 | return new h2d.filter.InnerGlow(inputDropShadow.color, .1, 1, 1);
33 | }
34 | var dropShadow = new BoxShadow(inputDropShadow.offsetX,inputDropShadow.offsetY, inputDropShadow.color, inputDropShadow.alpha, inputDropShadow.blurRadius, inputDropShadow.spreadRadius, false);
35 | output = dropShadow;
36 | } else if ((input is haxe.ui.filters.Tint)) {
37 | var inputTintFilter:haxe.ui.filters.Tint = cast(input, Tint);
38 | var cM = new ColorMatrix();
39 | var tintFilter = new TintFilter(inputTintFilter.color, inputTintFilter.amount);
40 | output = tintFilter;
41 | } else if ((input is haxe.ui.filters.Blur)) {
42 | var inputBlur:haxe.ui.filters.Blur = cast(input, haxe.ui.filters.Blur);
43 | output = new Blur(inputBlur.amount); // BlurFilter(inputBlur.amount, inputBlur.amount);
44 | } else if ((input is haxe.ui.filters.Grayscale)) {
45 | var inputGrayscale:haxe.ui.filters.Grayscale = cast(input, haxe.ui.filters.Grayscale);
46 | output = new GrayscaleFilter(inputGrayscale.amount / 100);
47 | } else if ((input is haxe.ui.filters.HueRotate)) {
48 | var inputHue:haxe.ui.filters.HueRotate = cast(input, haxe.ui.filters.HueRotate);
49 | var cM = new ColorMatrix();
50 | cM.matrix.colorHue(inputHue.angleDegree);
51 | output = cM;
52 | } else if ((input is haxe.ui.filters.Contrast)) {
53 | var contrast:haxe.ui.filters.Contrast = cast(input, haxe.ui.filters.Contrast);
54 | var cM = new ColorMatrix();
55 | cM.matrix.colorContrast(contrast.multiplier);
56 | output = cM;
57 | } else if ((input is haxe.ui.filters.Saturate)) {
58 | var saturate:haxe.ui.filters.Saturate = cast(input, Saturate);
59 | var cM = new ColorMatrix();
60 | cM.matrix.colorSaturate(saturate.multiplier);
61 | output = cM;
62 | } else if ((input is haxe.ui.filters.Invert)) {
63 | var inputInvert:haxe.ui.filters.Invert = cast(input, haxe.ui.filters.Invert);
64 | output = new InvertFilter(inputInvert.multiplier);
65 | } else if ((input is haxe.ui.filters.Brightness)) {
66 | var inputBrightness:haxe.ui.filters.Brightness = cast(input, haxe.ui.filters.Brightness);
67 | output = new BrightnessFilter(inputBrightness.multiplier);
68 | }
69 |
70 | return output;
71 | }
72 | }
73 |
74 | class TintFilter extends ColorMatrix {
75 |
76 | //public var filter:ColorMatrix;
77 |
78 | // These numbers come from the CIE XYZ Color Model
79 | public static inline var LUMA_R = 0.212671;
80 | public static inline var LUMA_G = 0.71516;
81 | public static inline var LUMA_B = 0.072169;
82 |
83 | public function new(color:Int = 0, amount:Float = 1) {
84 |
85 | var color:Color = cast color;
86 |
87 | var r:Float = color.r / 255;
88 | var g:Float = color.g / 255;
89 | var b:Float = color.b / 255;
90 | var q:Float = 1 - amount;
91 |
92 | var rA:Float = amount * r;
93 | var gA:Float = amount * g;
94 | var bA:Float = amount * b;
95 |
96 | var m = new Matrix();
97 | m.zero();
98 |
99 | m._11 = q + rA * LUMA_R;
100 | m._12 = gA * LUMA_R;
101 | m._13 = bA * LUMA_R;
102 | m._21 = rA * LUMA_G;
103 | m._22 = q + gA * LUMA_G;
104 | m._23 = bA * LUMA_G;
105 | m._31 = rA * LUMA_B;
106 | m._32 = gA * LUMA_B;
107 | m._33 = q + bA * LUMA_B;
108 | m._44 = 1;
109 |
110 | super(m);
111 | }
112 | }
113 |
114 | class GrayscaleFilter extends ColorMatrix {
115 | /**
116 | * Color multipliers recommended by the ITU to make the result appear to the
117 | * human eye to have the correct brightness. See page 3 of the article at
118 | * http://www.itu.int/rec/R-REC-BT.601-7-201103-I/en for more information.
119 | */
120 | private static inline var RED:Float = 0.299;
121 | private static inline var GREEN:Float = 0.587;
122 | private static inline var BLUE:Float = 0.114;
123 |
124 | public function new(amount:Float = 1) {
125 | var m = new Matrix();
126 | m.zero();
127 | m._11 = 1 + (RED - 1) * amount;
128 | m._12 = RED * amount;
129 | m._13 = RED * amount;
130 | m._21 = GREEN * amount;
131 | m._22 = 1 + (GREEN - 1) * amount;
132 | m._23 = GREEN * amount;
133 | m._31 = BLUE * amount;
134 | m._32 = BLUE * amount;
135 | m._33 = 1 + (BLUE - 1) * amount;
136 | m._44 = 1;
137 |
138 | super(m);
139 | }
140 | }
141 |
142 | class InvertFilter extends ColorMatrix {
143 | public function new(multiplier:Float = 1) {
144 | var m = new Matrix();
145 | m.zero();
146 | m._11 = -1 * multiplier;
147 | m._22 = -1 * multiplier;
148 | m._33 = -1 * multiplier;
149 | m._41 = 1;
150 | m._42 = 1;
151 | m._43 = 1;
152 | m._44 = 1;
153 | super(m);
154 | }
155 | }
156 |
157 | class BrightnessFilter extends ColorMatrix {
158 | public function new(multiplier:Float = 1) {
159 | // In html, 0 is a black image, 1 has no effect, over it's a multiplier
160 | // So we adapt
161 | if (multiplier <= 1) multiplier = (multiplier -1) * 1;
162 | if (multiplier > 1) multiplier = (multiplier -1) * 110/255;
163 |
164 | var m = new Matrix();
165 | m.identity();
166 | m._41 = multiplier;
167 | m._42 = multiplier;
168 | m._43 = multiplier;
169 | super(m);
170 | }
171 | }
172 |
173 | class BoxShadow extends Glow {
174 |
175 | public var offsetX:Float = 0;
176 | public var offsetY:Float = 0;
177 | public var spreadRadius:Float = 0;
178 |
179 | var alphaPass = new h3d.mat.Pass("");
180 | var sizePass = new h3d.mat.Pass("");
181 |
182 | /**
183 | Create a new Shadow filter.
184 | @param distance The offset of the shadow in the `angle` direction.
185 | @param angle Shadow offset direction angle.
186 | @param color The color of the shadow.
187 | @param alpha Transparency value of the shadow.
188 | @param radius The shadow glow distance in pixels.
189 | @param gain The shadow color intensity.
190 | @param quality The sample count on each pixel as a tradeoff of speed/quality.
191 | @param smoothColor Produce gradient shadow when enabled, otherwise creates hard shadow without smoothing.
192 | **/
193 | public function new( offsetX:Float = 4, offsetY:Float = 4, color : Int = 0, alpha = 1., blurRadius : Float = 1., spreadRadius : Float = 1., inset:Bool ) {
194 | super(color, alpha, blurRadius, 1, 1, true);
195 | this.offsetX = offsetX;
196 | this.offsetY = offsetY;
197 | this.spreadRadius = spreadRadius;
198 | alphaPass.addShader(new h3d.shader.UVDelta());
199 | sizePass.addShader(new h3d.shader.UVDelta());
200 | }
201 |
202 | override function sync(ctx, s) {
203 | super.sync(ctx, s);
204 | boundsExtend += Math.max(Math.abs(offsetX + spreadRadius), Math.abs(offsetY + spreadRadius));
205 | }
206 |
207 | override function draw( ctx : h3d.impl.RenderContext, t : h2d.Tile ) {
208 | setParams();
209 |
210 | var save = ctx.textures.allocTileTarget("glowSave", t);
211 | var perW = spreadRadius/t.width;
212 | var perH = spreadRadius/t.height;
213 | sizePass.getShader(h3d.shader.UVDelta).uvScale.set(1/(1+perW), 1/(1+perH));
214 |
215 | h3d.pass.Copy.run(t.getTexture(), save, sizePass);
216 |
217 | pass.apply(ctx, save);
218 | alphaPass.getShader(h3d.shader.UVDelta).uvDelta.set(offsetX/t.width, offsetY/t.height);
219 | h3d.pass.Copy.run(t.getTexture(), save, Alpha, alphaPass);
220 | var ret = h2d.Tile.fromTexture(save);
221 | ret.dx = offsetX;
222 | ret.dy = offsetY;
223 |
224 | return ret;
225 | }
226 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/heaps/KeyboardHelper.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.heaps;
2 |
3 | import hxd.Key;
4 | import haxe.ui.events.KeyboardEvent;
5 | import hxd.Window;
6 |
7 | class KeyboardHelper {
8 | private static var _hasOnEvent:Bool = false;
9 |
10 | private static var _callbacks:MapVoid>> = new MapVoid>>();
11 |
12 | public static function notify(event:String, callback:KeyboardEvent->Void) {
13 | switch (event) {
14 | case KeyboardEvent.KEY_DOWN:
15 | if (_hasOnEvent == false) {
16 | Window.getInstance().addEventTarget(onEvent);
17 | _hasOnEvent = true;
18 | }
19 | case KeyboardEvent.KEY_UP:
20 | if (_hasOnEvent == false) {
21 | Window.getInstance().addEventTarget(onEvent);
22 | _hasOnEvent = true;
23 | }
24 | case KeyboardEvent.KEY_PRESS:
25 | if (_hasOnEvent == false) {
26 | Window.getInstance().addEventTarget(onEvent);
27 | _hasOnEvent = true;
28 | }
29 | }
30 |
31 | var list = _callbacks.get(event);
32 | if (list == null) {
33 | list = new ArrayVoid>();
34 | _callbacks.set(event, list);
35 | }
36 |
37 | list.push(callback);
38 | }
39 |
40 | public static function remove(event:String, callback:KeyboardEvent->Void) {
41 | var list = _callbacks.get(event);
42 | if (list != null) {
43 | list.remove(callback);
44 | if (list.length == 0) {
45 | _callbacks.remove(event);
46 | }
47 | }
48 | }
49 |
50 | private static function onEvent(e:hxd.Event) {
51 | switch (e.kind) {
52 | case EKeyDown:
53 | onKeyDown(e);
54 | case EKeyUp:
55 | onKeyUp(e);
56 | case _:
57 | }
58 | }
59 |
60 | private static var _shiftDown:Bool = false;
61 | private static var _ctrlDown:Bool = false;
62 | private static var _altDown:Bool = false;
63 | private static function onKeyDown(e:hxd.Event) {
64 | var list = _callbacks.get(KeyboardEvent.KEY_DOWN);
65 | if (list == null || list.length == 0) {
66 | return;
67 | }
68 |
69 | switch (e.keyCode) {
70 | case Key.SHIFT:
71 | _shiftDown = true;
72 | case Key.ALT:
73 | _altDown = true;
74 | case Key.CTRL:
75 | _ctrlDown = true;
76 | }
77 |
78 | list = list.copy();
79 | var event = new KeyboardEvent(KeyboardEvent.KEY_DOWN);
80 | event.shiftKey = _shiftDown;
81 | event.ctrlKey = _ctrlDown;
82 | event.altKey = _altDown;
83 | @:privateAccess event._originalEvent = e;
84 | event.keyCode = e.keyCode;
85 | for (l in list) {
86 | l(event);
87 | }
88 | }
89 |
90 | private static function onKeyUp(e:hxd.Event) {
91 | var list = _callbacks.get(KeyboardEvent.KEY_UP);
92 | if (list == null || list.length == 0) {
93 | return;
94 | }
95 |
96 | switch (e.keyCode) {
97 | case Key.SHIFT:
98 | _shiftDown = false;
99 | case Key.ALT:
100 | _altDown = false;
101 | case Key.CTRL:
102 | _ctrlDown = false;
103 | }
104 |
105 | list = list.copy();
106 | var event = new KeyboardEvent(KeyboardEvent.KEY_UP);
107 | event.shiftKey = _shiftDown;
108 | event.ctrlKey = _ctrlDown;
109 | event.altKey = _altDown;
110 | @:privateAccess event._originalEvent = e;
111 | event.keyCode = e.keyCode;
112 | for (l in list) {
113 | l(event);
114 | }
115 | }
116 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/heaps/MouseHelper.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.heaps;
2 |
3 | import haxe.ui.components.TextArea;
4 | import haxe.ui.components.TextField;
5 | import haxe.ui.core.Screen;
6 | import haxe.ui.events.MouseEvent;
7 | import hxd.Window;
8 |
9 | class MouseHelper {
10 | public static var currentMouseX:Float = 0;
11 | public static var currentMouseY:Float = 0;
12 |
13 | private static var _hasOnEvent:Bool = false;
14 |
15 | private static var _callbacks:MapVoid>> = new MapVoid>>();
16 |
17 | public static function notify(event:String, callback:MouseEvent->Void) {
18 | switch (event) {
19 | case MouseEvent.MOUSE_DOWN:
20 | if (_hasOnEvent == false) {
21 | Window.getInstance().addEventTarget(onEvent);
22 | _hasOnEvent = true;
23 | }
24 | case MouseEvent.MOUSE_UP:
25 | if (_hasOnEvent == false) {
26 | Window.getInstance().addEventTarget(onEvent);
27 | _hasOnEvent = true;
28 | }
29 | case MouseEvent.MOUSE_MOVE:
30 | if (_hasOnEvent == false) {
31 | Window.getInstance().addEventTarget(onEvent);
32 | _hasOnEvent = true;
33 | }
34 | case MouseEvent.MOUSE_WHEEL:
35 | if (_hasOnEvent == false) {
36 | Window.getInstance().addEventTarget(onEvent);
37 | _hasOnEvent = true;
38 | }
39 | }
40 |
41 | var list = _callbacks.get(event);
42 | if (list == null) {
43 | list = new ArrayVoid>();
44 | _callbacks.set(event, list);
45 | }
46 |
47 | list.push(callback);
48 | }
49 |
50 | public static function remove(event:String, callback:MouseEvent->Void) {
51 | var list = _callbacks.get(event);
52 | if (list != null) {
53 | list.remove(callback);
54 | if (list.length == 0) {
55 | _callbacks.remove(event);
56 | }
57 | }
58 | }
59 |
60 | private static var _isCapturing:Bool = false;
61 | private static function onEvent(e:hxd.Event) {
62 | /*
63 | var scene = Screen.instance.scene;
64 | if (scene != null) {
65 | var xpos = Window.getInstance().mouseX / Toolkit.scaleX;
66 | var ypos = Window.getInstance().mouseY / Toolkit.scaleY;
67 | var b = Screen.instance.hasComponentUnderPoint(xpos, ypos);
68 | var i = scene.getInteractive(xpos, ypos);
69 | var isTextField = false;
70 | if (i != null && ((i.parent is TextField) || (i.parent is TextArea))) {
71 | isTextField = true;
72 | }
73 | var f = scene.getFocus();
74 | if (f != null && ((f.parent.parent is TextField) || (f.parent.parent is TextArea))) {
75 | isTextField = true;
76 | }
77 |
78 | if (b == true && isTextField == false) {
79 | e.cancel = true;
80 | e.propagate = false;
81 | if (_isCapturing == false) {
82 | _isCapturing = true;
83 | hxd.System.setNativeCursor(Default);
84 | scene.startCapture(onEvent);
85 | }
86 | } else {
87 | if (_isCapturing == true) {
88 | _isCapturing = false;
89 | if (i != null) {
90 | hxd.System.setNativeCursor(i.cursor);
91 | }
92 | scene.stopCapture();
93 | }
94 | }
95 | }
96 | */
97 |
98 | switch (e.kind) {
99 | case EMove:
100 | onMouseMove(e);
101 | case EPush:
102 | onMouseDown(e);
103 | case ERelease | EReleaseOutside:
104 | onMouseUp(e);
105 | case EWheel:
106 | onMouseWheel(e);
107 | case _:
108 | }
109 | }
110 |
111 | private static function onMouseMove(e:hxd.Event) {
112 | currentMouseX = e.relX;
113 | currentMouseY = e.relY;
114 | var list = _callbacks.get(MouseEvent.MOUSE_MOVE);
115 | if (list == null || list.length == 0) {
116 | return;
117 | }
118 |
119 | list = list.copy();
120 | list.reverse();
121 |
122 | var event = new MouseEvent(MouseEvent.MOUSE_MOVE);
123 | @:privateAccess event._originalEvent = e;
124 | event.screenX = e.relX;
125 | event.screenY = e.relY;
126 | for (l in list) {
127 | l(event);
128 | if (event.canceled) {
129 | break;
130 | }
131 | }
132 | }
133 |
134 | private static function onMouseDown(e:hxd.Event) {
135 | var list = _callbacks.get(MouseEvent.MOUSE_DOWN);
136 | if (list == null || list.length == 0) {
137 | return;
138 | }
139 |
140 | list = list.copy();
141 | list.reverse();
142 |
143 | var event = new MouseEvent(MouseEvent.MOUSE_DOWN);
144 | @:privateAccess event._originalEvent = e;
145 | event.screenX = e.relX;
146 | event.screenY = e.relY;
147 | event.data = e.button;
148 | for (l in list) {
149 | l(event);
150 | if (event.canceled) {
151 | break;
152 | }
153 | }
154 | }
155 |
156 | private static function onMouseUp(e:hxd.Event) {
157 | var list = _callbacks.get(MouseEvent.MOUSE_UP);
158 | if (list == null || list.length == 0) {
159 | return;
160 | }
161 |
162 | list = list.copy();
163 | list.reverse();
164 |
165 | var event = new MouseEvent(MouseEvent.MOUSE_UP);
166 | @:privateAccess event._originalEvent = e;
167 | event.screenX = e.relX;
168 | event.screenY = e.relY;
169 | event.data = e.button;
170 | for (l in list) {
171 | l(event);
172 | if (event.canceled) {
173 | break;
174 | }
175 | }
176 | }
177 |
178 | private static function onMouseWheel(e:hxd.Event) {
179 | var list = _callbacks.get(MouseEvent.MOUSE_WHEEL);
180 | if (list == null || list.length == 0) {
181 | return;
182 | }
183 |
184 | list = list.copy();
185 | list.reverse();
186 |
187 | var event = new MouseEvent(MouseEvent.MOUSE_WHEEL);
188 | @:privateAccess event._originalEvent = e;
189 | event.delta = e.wheelDelta;
190 | for (l in list) {
191 | l(event);
192 | if (event.canceled) {
193 | break;
194 | }
195 | }
196 | }
197 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/heaps/SDFFonts.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.heaps;
2 |
3 | class SDFFonts {
4 | private static var _sdfFonts:Map = new Map();
5 | public static function register(name:String, channel:h2d.Font.SDFChannel = 0, alphaCutoff:Float = 0.5, smoothing:Float = 0.5) {
6 | _sdfFonts.set(name, {
7 | channel: channel,
8 | alphaCutoff: alphaCutoff,
9 | smoothing: smoothing
10 | });
11 | }
12 |
13 | public static function get(name:String):{channel:h2d.Font.SDFChannel, alphaCutoff:Float, smoothing:Float} {
14 | return _sdfFonts.get(name);
15 | }
16 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/heaps/ScreenUtils.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.heaps;
2 |
3 | class ScreenUtils {
4 | private static var _dpi:Float = 0;
5 | public static var dpi(get, null):Float;
6 | private static function get_dpi():Float {
7 | #if js
8 |
9 | if (_dpi != 0) {
10 | return _dpi;
11 | }
12 |
13 | var div = js.Browser.document.createElement("div");
14 | div.style.width = "1in";
15 | div.style.height = "1in";
16 | div.style.position = "absolute";
17 | div.style.top = "-99999px"; // position off-screen!
18 | div.style.left = "-99999px"; // position off-screen!
19 | js.Browser.document.body.appendChild(div);
20 |
21 | var devicePixelRatio:Null = js.Browser.window.devicePixelRatio;
22 | if (devicePixelRatio == null) {
23 | devicePixelRatio = 1;
24 | }
25 |
26 | _dpi = div.offsetWidth * devicePixelRatio;
27 | removeElement(div);
28 | return _dpi;
29 |
30 | #else
31 |
32 | return hxd.System.screenDPI;
33 |
34 | #end
35 | }
36 |
37 | private static var _isRetina:Null = null;
38 | public static function isRetinaDisplay():Bool {
39 | #if js
40 |
41 | if (_isRetina == null) {
42 | var query = "(-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2), (min-resolution: 192dpi)";
43 | if (js.Browser.window.matchMedia(query).matches) {
44 | _isRetina = true;
45 | } else {
46 | _isRetina = false;
47 | }
48 | }
49 | return _isRetina;
50 |
51 | #else
52 |
53 | return false;
54 |
55 | #end
56 | }
57 |
58 | #if js
59 | private static function removeElement(el:js.html.Element) {
60 | // el.remove() - IE is crap
61 | if (el != null && el.parentElement != null) {
62 | el.parentElement.removeChild(el);
63 | }
64 | }
65 | #end
66 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/heaps/StyleHelper.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.heaps;
2 |
3 | import h2d.Graphics;
4 | import h2d.Tile;
5 | import haxe.ui.Toolkit;
6 | import haxe.ui.assets.ImageInfo;
7 | import haxe.ui.backend.heaps.TileCache;
8 | import haxe.ui.geom.Rectangle;
9 | import haxe.ui.geom.Slice9;
10 | import haxe.ui.styles.Style;
11 | import hxd.clipper.Rect;
12 |
13 |
14 | class StyleHelper {
15 | public static function apply(c:ComponentImpl, style:Style, w:Float, h:Float):Void {
16 | if (w <= 0 || h <= 0) {
17 | return;
18 | }
19 |
20 | var container = c.getChildAt(0); // first child is always the style-objects container
21 | if ( container == null ) {
22 | return; // fix crash resizing the window; container doesn't exist yet
23 | }
24 |
25 | var borderSize:Rectangle = new Rectangle();
26 | borderSize.left = style.borderLeftSize;
27 | borderSize.top = style.borderTopSize;
28 | borderSize.right = style.borderRightSize;
29 | borderSize.bottom = style.borderBottomSize;
30 |
31 | var borderColor:Rect = new Rect();
32 | borderColor.left = style.borderLeftColor;
33 | borderColor.top = style.borderTopColor;
34 | borderColor.right = style.borderRightColor;
35 | borderColor.bottom = style.borderBottomColor;
36 |
37 | var backgroundAlpha:Float = 1;
38 | if (style.backgroundOpacity != null) {
39 | backgroundAlpha = style.backgroundOpacity;
40 | }
41 | var borderAlpha:Float = 1;
42 | if (style.borderOpacity != null) {
43 | borderAlpha = style.borderOpacity;
44 | }
45 |
46 | var styleGraphics:Graphics = cast(container.getObjectByName("styleGraphics"), Graphics);
47 | if (styleGraphics == null) {
48 | styleGraphics = new Graphics();
49 | styleGraphics.name = "styleGraphics";
50 | container.addChildAt(styleGraphics, 0);
51 | }
52 |
53 | styleGraphics.clear();
54 |
55 | var borderRadius:Float = 0;
56 | var isCircle = (style.borderRadius == w && style.borderRadius == h);
57 | if (!isCircle && style.borderRadius != null && style.borderRadius > 0) {
58 | borderRadius = style.borderRadius + 1;
59 | }
60 |
61 | if (style.backgroundColor != null && backgroundAlpha > 0) {
62 | if (style.backgroundColorEnd != null && style.backgroundColor != style.backgroundColorEnd) {
63 | var gradientType:String = "vertical";
64 | if (style.backgroundGradientStyle != null) {
65 | gradientType = style.backgroundGradientStyle;
66 | }
67 |
68 | var gradientSize = 256;
69 | if (borderRadius == 0) {
70 | if (gradientType == "vertical" || gradientType == "horizontal") {
71 | var width = w - borderSize.right - borderSize.left;
72 | var height = h - borderSize.bottom - borderSize.top;
73 | var tile = TileCache.getGradient(gradientType, style.backgroundColor, style.backgroundColorEnd, gradientSize, Std.int(backgroundAlpha * 255));
74 | styleGraphics.beginTileFill(borderSize.left, borderSize.top, width / gradientSize, height / gradientSize, tile);
75 | styleGraphics.drawRect(borderSize.left, borderSize.top, width, height);
76 | styleGraphics.endFill();
77 | }
78 | } else {
79 | var width = w - borderSize.right - borderSize.left;
80 | var height = h - borderSize.bottom - borderSize.top;
81 | var tile = TileCache.getGradient(gradientType, style.backgroundColor, style.backgroundColorEnd, gradientSize, Std.int(backgroundAlpha * 255));
82 | styleGraphics.beginTileFill(borderSize.left, borderSize.top, width / gradientSize, height / gradientSize, tile);
83 | drawRoundedBackground(styleGraphics, w, h, borderSize, borderRadius);
84 | styleGraphics.endFill();
85 | }
86 | } else {
87 | if (borderRadius == 0) {
88 | styleGraphics.beginFill(style.backgroundColor, backgroundAlpha);
89 | styleGraphics.drawRect(borderSize.left, borderSize.top, w - borderSize.right - borderSize.left, h - borderSize.bottom - borderSize.top);
90 | styleGraphics.endFill();
91 | } else {
92 | styleGraphics.beginFill(style.backgroundColor, backgroundAlpha);
93 | drawRoundedBackground(styleGraphics, w, h, borderSize, borderRadius);
94 | styleGraphics.endFill();
95 | }
96 | }
97 | }
98 |
99 | if (style.backgroundImage != null) {
100 | Toolkit.assets.getImage(style.backgroundImage, function(imageInfo:ImageInfo) {
101 | var bgImageGraphics:Graphics = null;
102 | if (container.numChildren == 1) {
103 | bgImageGraphics = new Graphics();
104 | container.addChildAt(bgImageGraphics, 1);
105 | } else {
106 | bgImageGraphics = cast(container.getChildAt(1), Graphics);
107 | }
108 | bgImageGraphics.clear();
109 |
110 | var trc:Rectangle = new Rectangle(0, 0, imageInfo.width, imageInfo.height);
111 | if (style.backgroundImageClipTop != null
112 | && style.backgroundImageClipLeft != null
113 | && style.backgroundImageClipBottom != null
114 | && style.backgroundImageClipRight != null) {
115 | trc = new Rectangle(style.backgroundImageClipLeft,
116 | style.backgroundImageClipTop,
117 | style.backgroundImageClipRight - style.backgroundImageClipLeft,
118 | style.backgroundImageClipBottom - style.backgroundImageClipTop);
119 | }
120 |
121 | var tile = TileCache.get(style.backgroundImage);
122 | if (tile == null) {
123 | tile = h2d.Tile.fromBitmap(imageInfo.data);
124 | tile.getTexture().filter = Linear;
125 | TileCache.set(style.backgroundImage, tile);
126 | }
127 |
128 | if (trc != null) {
129 | /*
130 | var subTile = TileCache.get(style.backgroundImage, trc);
131 | if (subTile == null) {
132 | subTile = tile.sub(trc.left, trc.top, trc.width, trc.height);
133 | TileCache.set(style.backgroundImage, subTile, trc);
134 | }
135 | tile = subTile;
136 | */
137 | }
138 |
139 | var slice:Rectangle = null;
140 | if (style.backgroundImageSliceTop != null
141 | && style.backgroundImageSliceLeft != null
142 | && style.backgroundImageSliceBottom != null
143 | && style.backgroundImageSliceRight != null) {
144 | slice = new Rectangle(style.backgroundImageSliceLeft,
145 | style.backgroundImageSliceTop,
146 | style.backgroundImageSliceRight - style.backgroundImageSliceLeft,
147 | style.backgroundImageSliceBottom - style.backgroundImageSliceTop);
148 | }
149 |
150 | if (slice != null) {
151 | var rects:Slice9Rects = Slice9.buildRects(w, h, trc.width, trc.height, slice);
152 | var srcRects:Array = rects.src;
153 | var dstRects:Array = rects.dst;
154 |
155 | if (style.backgroundImageRepeat == "repeat") {
156 | // The image is slightly scaled down to make sure there is no visible clip one the sides
157 | var scaleX = dstRects[4].width / ( srcRects[4].width * Math.ceil(dstRects[4].width / srcRects[4].width) );
158 | var scaleY = dstRects[4].height / ( srcRects[4].height * Math.ceil(dstRects[4].height / srcRects[4].height) );
159 |
160 | paintTile(bgImageGraphics, tile, srcRects[0], dstRects[0], style.backgroundImage);
161 | paintTileRepeat(bgImageGraphics, tile, srcRects[1], scaleX, 1, dstRects[1], style.backgroundImage);
162 | paintTile(bgImageGraphics, tile, srcRects[2], dstRects[2], style.backgroundImage);
163 |
164 | srcRects[3].bottom--;
165 | paintTileRepeat(bgImageGraphics, tile, srcRects[3], 1, scaleY, dstRects[3], style.backgroundImage);
166 |
167 | srcRects[4].bottom--;
168 | paintTileRepeat(bgImageGraphics, tile, srcRects[4], scaleX, scaleY, dstRects[4], style.backgroundImage);
169 |
170 | srcRects[5].bottom--;
171 | paintTileRepeat(bgImageGraphics, tile, srcRects[5], 1, scaleY, dstRects[5], style.backgroundImage);
172 |
173 | dstRects[6].bottom++;
174 | paintTile(bgImageGraphics, tile, srcRects[6], dstRects[6], style.backgroundImage);
175 | dstRects[7].bottom++;
176 | paintTileRepeat(bgImageGraphics, tile, srcRects[7], scaleX, 1, dstRects[7], style.backgroundImage);
177 | dstRects[8].bottom++;
178 | paintTile(bgImageGraphics, tile, srcRects[8], dstRects[8], style.backgroundImage);
179 | }
180 | else {
181 | paintTile(bgImageGraphics, tile, srcRects[0], dstRects[0], style.backgroundImage);
182 | paintTile(bgImageGraphics, tile, srcRects[1], dstRects[1], style.backgroundImage);
183 | paintTile(bgImageGraphics, tile, srcRects[2], dstRects[2], style.backgroundImage);
184 |
185 | srcRects[3].bottom--;
186 | paintTile(bgImageGraphics, tile, srcRects[3], dstRects[3], style.backgroundImage);
187 |
188 | srcRects[4].bottom--;
189 | paintTile(bgImageGraphics, tile, srcRects[4], dstRects[4], style.backgroundImage);
190 |
191 | srcRects[5].bottom--;
192 | paintTile(bgImageGraphics, tile, srcRects[5], dstRects[5], style.backgroundImage);
193 |
194 | dstRects[6].bottom++;
195 | paintTile(bgImageGraphics, tile, srcRects[6], dstRects[6], style.backgroundImage);
196 | dstRects[7].bottom++;
197 | paintTile(bgImageGraphics, tile, srcRects[7], dstRects[7], style.backgroundImage);
198 | dstRects[8].bottom++;
199 | paintTile(bgImageGraphics, tile, srcRects[8], dstRects[8], style.backgroundImage);
200 | }
201 | } else {
202 | var scaleX:Float = 1;
203 | var scaleY:Float = 1;
204 |
205 | if (style.backgroundImageRepeat == null || style.backgroundImageRepeat == "stretch") {
206 | scaleX = w / trc.width;
207 | scaleY = h / trc.height;
208 | }
209 | else {
210 | if (style.backgroundWidth != null) {
211 | scaleX = style.backgroundWidth / trc.width;
212 | } else if (style.backgroundWidthPercent != null) {
213 | scaleX = ((w / trc.width) * style.backgroundWidthPercent) / 100;
214 | }
215 | if (style.backgroundHeight != null) {
216 | scaleY = style.backgroundHeight / trc.height;
217 | } else if (style.backgroundHeightPercent != null) {
218 | scaleY = ((h / trc.height) * style.backgroundHeightPercent) / 100;
219 | }
220 | }
221 |
222 | if (style.backgroundImageRepeat == "repeat") {
223 | paintTileRepeat(bgImageGraphics, tile, trc, scaleX, scaleY, new Rectangle(0, 0, w, h), style.backgroundImage);
224 | }
225 | else {
226 | paintTile(bgImageGraphics, tile, trc, new Rectangle(0, 0, trc.width * scaleX, trc.height * scaleY), style.backgroundImage);
227 | }
228 | }
229 | });
230 | }
231 |
232 | if (borderAlpha > 0) {
233 | if (isCircle) {
234 | styleGraphics.lineStyle(2, borderColor.left, borderAlpha);
235 | styleGraphics.drawCircle(w / 2, h / 2, w / 2, Std.int(w));
236 | styleGraphics.endFill();
237 | } else if (borderRadius == 0) {
238 | if (style.borderLeftSize != null && style.borderLeftSize > 0) {
239 | styleGraphics.lineStyle();
240 | styleGraphics.beginFill(borderColor.left, borderAlpha);
241 | styleGraphics.lineTo(0, 0);
242 | styleGraphics.lineTo(borderSize.left, borderSize.top);
243 | styleGraphics.lineTo(borderSize.left, h - borderSize.bottom);
244 | styleGraphics.lineTo(0, h);
245 | styleGraphics.endFill();
246 | }
247 |
248 | if (style.borderRightSize != null && style.borderRightSize > 0) {
249 | styleGraphics.lineStyle();
250 | styleGraphics.beginFill(borderColor.right, borderAlpha);
251 | styleGraphics.lineTo(w, 0);
252 | styleGraphics.lineTo(w, h);
253 | styleGraphics.lineTo(w - borderSize.right, h - borderSize.bottom);
254 | styleGraphics.lineTo(w - borderSize.right, borderSize.top);
255 | styleGraphics.endFill();
256 | }
257 |
258 | if (style.borderTopSize != null && style.borderTopSize > 0) {
259 | styleGraphics.lineStyle();
260 | styleGraphics.beginFill(borderColor.top, borderAlpha);
261 | styleGraphics.lineTo(0, 0);
262 | styleGraphics.lineTo(w, 0);
263 | styleGraphics.lineTo(w - borderSize.right, borderSize.top);
264 | styleGraphics.lineTo(borderSize.left, borderSize.top);
265 | styleGraphics.endFill();
266 | }
267 |
268 | if (style.borderBottomSize != null && style.borderBottomSize > 0) {
269 | styleGraphics.lineStyle();
270 | styleGraphics.beginFill(borderColor.bottom, borderAlpha);
271 | styleGraphics.lineTo(0, h);
272 | styleGraphics.lineTo(borderSize.left, h - borderSize.bottom);
273 | styleGraphics.lineTo(w - borderSize.right, h - borderSize.bottom);
274 | styleGraphics.lineTo(w, h);
275 | styleGraphics.endFill();
276 | }
277 | } else { // Border radius != 0
278 | // Left
279 | if (borderSize.left != 0) {
280 | // Left-Top corner
281 | if (borderSize.left == borderSize.top) {
282 | if (borderRadius <= borderSize.left) {
283 | // Left
284 | styleGraphics.beginFill(borderColor.left, borderAlpha);
285 | styleGraphics.drawPie(borderRadius, borderRadius, borderRadius, Math.PI, Math.PI * 0.25, 10);
286 | styleGraphics.lineTo(0, borderRadius);
287 | styleGraphics.lineTo(borderRadius, borderRadius);
288 | styleGraphics.lineTo(borderSize.left, borderSize.top);
289 | styleGraphics.lineTo(borderSize.left, h * 0.5);
290 | styleGraphics.lineTo(0, h * 0.5);
291 | styleGraphics.endFill();
292 | // Top
293 | styleGraphics.beginFill(borderColor.top, borderAlpha);
294 | styleGraphics.drawPie(borderRadius, borderRadius, borderRadius, Math.PI * 1.25, Math.PI * 0.25, 10);
295 | styleGraphics.lineTo(borderRadius, 0);
296 | styleGraphics.lineTo(w * 0.5, 0);
297 | styleGraphics.lineTo(w * 0.5, borderSize.top);
298 | styleGraphics.lineTo(borderSize.left, borderSize.top);
299 | styleGraphics.lineTo(borderRadius, borderRadius);
300 | styleGraphics.endFill();
301 | } else {
302 | var innerRadius = borderRadius - borderSize.left;
303 | // Left
304 | styleGraphics.beginFill(borderColor.left, borderAlpha);
305 | styleGraphics.drawPieInner(borderRadius, borderRadius, borderRadius, innerRadius, Math.PI, Math.PI * 0.25, 10);
306 | styleGraphics.lineTo(0, borderRadius);
307 | styleGraphics.lineTo(borderSize.left, borderRadius);
308 | styleGraphics.lineTo(borderSize.left, h * 0.5);
309 | styleGraphics.lineTo(0, h * 0.5);
310 | styleGraphics.endFill();
311 | // Top
312 | styleGraphics.beginFill(borderColor.top, borderAlpha);
313 | styleGraphics.drawPieInner(borderRadius, borderRadius, borderRadius, innerRadius, Math.PI * 1.25, Math.PI * 0.25, 10);
314 | styleGraphics.lineTo(borderRadius, 0);
315 | styleGraphics.lineTo(w * 0.5, 0);
316 | styleGraphics.lineTo(w * 0.5, borderSize.top);
317 | styleGraphics.lineTo(borderRadius, borderSize.top);
318 | styleGraphics.endFill();
319 | }
320 | } else {
321 | styleGraphics.beginFill(borderColor.left, borderAlpha);
322 | if (borderRadius <= borderSize.left || borderRadius <= borderSize.top) {
323 | drawUnevenBordersCurve(styleGraphics, borderRadius, borderRadius, borderRadius,
324 | Math.PI, Math.PI * 0.5 * borderSize.left / (borderSize.left + borderSize.top));
325 | styleGraphics.lineTo(borderSize.left, borderSize.top);
326 | styleGraphics.lineTo(borderSize.left, h * 0.5);
327 | styleGraphics.lineTo(0, h * 0.5);
328 | } else {
329 | drawUnevenBordersCorner(styleGraphics, borderRadius, borderRadius, borderRadius, borderRadius - borderSize.left, borderRadius - borderSize.top,
330 | Math.PI, Math.PI * 0.5 * borderSize.left / (borderSize.left + borderSize.top));
331 | styleGraphics.moveTo(0, borderRadius);
332 | styleGraphics.lineTo(borderSize.left, borderRadius);
333 | styleGraphics.lineTo(borderSize.left, h * 0.5);
334 | styleGraphics.lineTo(0, h * 0.5);
335 | }
336 | styleGraphics.endFill();
337 | }
338 | // Left-Bottom corner
339 | if (borderSize.left == borderSize.bottom) {
340 | if (borderRadius <= borderSize.left) {
341 | // Left
342 | styleGraphics.beginFill(borderColor.left, borderAlpha);
343 | styleGraphics.drawPie(borderRadius, h - borderRadius, borderRadius, Math.PI * 0.75, Math.PI * 0.25, 10);
344 | styleGraphics.lineTo(0, h * 0.5);
345 | styleGraphics.lineTo(borderSize.left, h * 0.5);
346 | styleGraphics.lineTo(borderSize.left, h - borderSize.bottom);
347 | styleGraphics.lineTo(borderRadius, h - borderRadius);
348 | styleGraphics.lineTo(0, h - borderRadius);
349 | styleGraphics.endFill();
350 | // Bottom
351 | styleGraphics.beginFill(borderColor.bottom, borderAlpha);
352 | styleGraphics.drawPie(borderRadius, h - borderRadius, borderRadius, Math.PI * 0.5, Math.PI * 0.25, 10);
353 | styleGraphics.lineTo(w * 0.5, h);
354 | styleGraphics.lineTo(w * 0.5, h - borderSize.bottom);
355 | styleGraphics.lineTo(borderSize.left, h - borderSize.bottom);
356 | styleGraphics.lineTo(borderRadius, h - borderRadius);
357 | styleGraphics.lineTo(borderRadius, h);
358 | styleGraphics.endFill();
359 | } else {
360 | var innerRadius = borderRadius - borderSize.left;
361 | // Left
362 | styleGraphics.beginFill(borderColor.left, borderAlpha);
363 | styleGraphics.drawPieInner(borderRadius, h - borderRadius, borderRadius, innerRadius, Math.PI * 0.75, Math.PI * 0.25, 10);
364 | styleGraphics.lineTo(0, h * 0.5);
365 | styleGraphics.lineTo(borderSize.left, h * 0.5);
366 | styleGraphics.lineTo(borderSize.left, h - borderRadius);
367 | styleGraphics.lineTo(0, h - borderRadius);
368 | styleGraphics.endFill();
369 | // Bottom
370 | styleGraphics.beginFill(borderColor.bottom, borderAlpha);
371 | styleGraphics.drawPieInner(borderRadius, h - borderRadius, borderRadius, innerRadius, Math.PI * 0.5, Math.PI * 0.25, 10);
372 | styleGraphics.lineTo(w * 0.5, h);
373 | styleGraphics.lineTo(w * 0.5, h - borderSize.bottom);
374 | styleGraphics.lineTo(borderRadius, h - borderSize.bottom);
375 | styleGraphics.lineTo(borderRadius, h);
376 | styleGraphics.endFill();
377 | }
378 | } else {
379 | styleGraphics.beginFill(borderColor.left, borderAlpha);
380 | if (borderRadius <= borderSize.left || borderRadius <= borderSize.bottom) {
381 | drawUnevenBordersCurve(styleGraphics, borderRadius, h - borderRadius, borderRadius,
382 | Math.PI * (0.5 + 0.5 * borderSize.bottom / (borderSize.left + borderSize.bottom)),
383 | Math.PI * 0.5 * borderSize.left / (borderSize.left + borderSize.bottom));
384 | styleGraphics.lineTo(0, h * 0.5);
385 | styleGraphics.lineTo(borderSize.left, h * 0.5);
386 | styleGraphics.lineTo(borderSize.left, h - borderSize.bottom);
387 | } else {
388 | drawUnevenBordersCorner(styleGraphics, borderRadius, h - borderRadius, borderRadius, borderRadius - borderSize.left, borderRadius - borderSize.bottom,
389 | Math.PI * (0.5 + 0.5 * borderSize.bottom / (borderSize.left + borderSize.bottom)),
390 | Math.PI * 0.5 * borderSize.left / (borderSize.left + borderSize.bottom));
391 | styleGraphics.moveTo(0, h * 0.5);
392 | styleGraphics.lineTo(borderSize.left, h * 0.5);
393 | styleGraphics.lineTo(borderSize.left, h - borderRadius);
394 | styleGraphics.lineTo(0, h - borderRadius);
395 | }
396 | styleGraphics.endFill();
397 | }
398 | }
399 |
400 | // Top
401 | if(borderSize.top != 0) {
402 | // Left-Top corner
403 | if (borderSize.left != borderSize.top) {
404 | styleGraphics.beginFill(borderColor.top, borderAlpha);
405 | if (borderRadius <= borderSize.left || borderRadius <= borderSize.top) {
406 | drawUnevenBordersCurve(styleGraphics, borderRadius, borderRadius, borderRadius,
407 | Math.PI * (1 + 0.5 * borderSize.left / (borderSize.left + borderSize.top)),
408 | Math.PI * 0.5 * borderSize.top / (borderSize.left + borderSize.top));
409 | styleGraphics.lineTo(w * 0.5, 0);
410 | styleGraphics.lineTo(w * 0.5, borderSize.top);
411 | styleGraphics.lineTo(borderSize.left, borderSize.top);
412 | } else {
413 | drawUnevenBordersCorner(styleGraphics, borderRadius, borderRadius, borderRadius, borderRadius - borderSize.left, borderRadius - borderSize.top,
414 | Math.PI * (1 + 0.5 * borderSize.left / (borderSize.left + borderSize.top)),
415 | Math.PI * 0.5 * borderSize.top / (borderSize.left + borderSize.top));
416 | styleGraphics.moveTo(borderRadius, 0);
417 | styleGraphics.lineTo(w * 0.5, 0);
418 | styleGraphics.lineTo(w * 0.5, borderSize.top);
419 | styleGraphics.lineTo(borderRadius, borderSize.top);
420 | }
421 | styleGraphics.endFill();
422 | }
423 | // Right-Top corner
424 | if (borderSize.right != borderSize.top) {
425 | styleGraphics.beginFill(borderColor.top, borderAlpha);
426 | if (borderRadius <= borderSize.right || borderRadius <= borderSize.top) {
427 | drawUnevenBordersCurve(styleGraphics, w - borderRadius, borderRadius, borderRadius,
428 | Math.PI * -0.5, Math.PI * 0.5 * borderSize.top / (borderSize.right + borderSize.top));
429 | styleGraphics.lineTo(w - borderSize.right, borderSize.top);
430 | styleGraphics.lineTo(w * 0.5, borderSize.top);
431 | styleGraphics.lineTo(w * 0.5, 0);
432 | } else {
433 | drawUnevenBordersCorner(styleGraphics, w - borderRadius, borderRadius, borderRadius, borderRadius - borderSize.right, borderRadius - borderSize.top,
434 | Math.PI * -0.5, Math.PI * 0.5 * borderSize.top / (borderSize.right + borderSize.top));
435 | styleGraphics.moveTo(w - borderRadius, 0);
436 | styleGraphics.lineTo(w * 0.5, 0);
437 | styleGraphics.lineTo(w * 0.5, borderSize.top);
438 | styleGraphics.lineTo(w - borderRadius, borderSize.top);
439 | }
440 | styleGraphics.endFill();
441 | }
442 | }
443 |
444 | // Right
445 | if(borderSize.right != 0) {
446 | // Right-Top corner
447 | if (borderSize.right == borderSize.top) {
448 | if (borderRadius <= borderSize.right) {
449 | // Right
450 | styleGraphics.beginFill(borderColor.right, borderAlpha);
451 | styleGraphics.drawPie(w - borderRadius, borderRadius, borderRadius, Math.PI * -0.25, Math.PI * 0.25, 10);
452 | styleGraphics.lineTo(w, borderRadius);
453 | styleGraphics.lineTo(w - borderRadius, borderRadius);
454 | styleGraphics.lineTo(w - borderSize.right, borderSize.top);
455 | styleGraphics.lineTo(w - borderSize.right, h * 0.5);
456 | styleGraphics.lineTo(w, h * 0.5);
457 | styleGraphics.endFill();
458 | // Top
459 | styleGraphics.beginFill(borderColor.top, borderAlpha);
460 | styleGraphics.drawPie(w - borderRadius, borderRadius, borderRadius, Math.PI * -0.5, Math.PI * 0.25, 10);
461 | styleGraphics.lineTo(w - borderRadius, 0);
462 | styleGraphics.lineTo(w * 0.5, 0);
463 | styleGraphics.lineTo(w * 0.5, borderSize.top);
464 | styleGraphics.lineTo(w - borderSize.right, borderSize.top);
465 | styleGraphics.lineTo(w - borderRadius, borderRadius);
466 | styleGraphics.endFill();
467 | } else {
468 | var innerRadius = borderRadius - borderSize.right;
469 | // Right
470 | styleGraphics.beginFill(borderColor.right, borderAlpha);
471 | styleGraphics.drawPieInner(w - borderRadius, borderRadius, borderRadius, innerRadius, Math.PI * -0.25, Math.PI * 0.25, 10);
472 | styleGraphics.lineTo(w, borderRadius);
473 | styleGraphics.lineTo(w - borderSize.right, borderRadius);
474 | styleGraphics.lineTo(w - borderSize.right, h * 0.5);
475 | styleGraphics.lineTo(w, h * 0.5);
476 | styleGraphics.endFill();
477 | // Top
478 | styleGraphics.beginFill(borderColor.top, borderAlpha);
479 | styleGraphics.drawPieInner(w - borderRadius, borderRadius, borderRadius, innerRadius, Math.PI * -0.5, Math.PI * 0.25, 10);
480 | styleGraphics.lineTo(w - borderRadius, 0);
481 | styleGraphics.lineTo(w * 0.5, 0);
482 | styleGraphics.lineTo(w * 0.5, borderSize.top);
483 | styleGraphics.lineTo(w - borderRadius, borderSize.top);
484 | styleGraphics.endFill();
485 | }
486 | } else {
487 | styleGraphics.beginFill(borderColor.right, borderAlpha);
488 | if (borderRadius <= borderSize.right || borderRadius <= borderSize.top) {
489 | drawUnevenBordersCurve(styleGraphics, w - borderRadius, borderRadius, borderRadius,
490 | Math.PI * (-0.5 + 0.5 * borderSize.top / (borderSize.right + borderSize.top)),
491 | Math.PI * 0.5 * borderSize.right / (borderSize.right + borderSize.top));
492 | styleGraphics.lineTo(w, h * 0.5);
493 | styleGraphics.lineTo(w - borderSize.right, h * 0.5);
494 | styleGraphics.lineTo(w - borderSize.right, borderSize.top);
495 | } else {
496 | drawUnevenBordersCorner(styleGraphics, w - borderRadius, borderRadius, borderRadius, borderRadius - borderSize.right, borderRadius - borderSize.top,
497 | Math.PI * (-0.5 + 0.5 * borderSize.top / (borderSize.right + borderSize.top)),
498 | Math.PI * 0.5 * borderSize.right / (borderSize.right + borderSize.top));
499 | styleGraphics.moveTo(w, borderRadius);
500 | styleGraphics.lineTo(w - borderSize.right, borderRadius);
501 | styleGraphics.lineTo(w - borderSize.right, h * 0.5);
502 | styleGraphics.lineTo(w, h * 0.5);
503 | }
504 | styleGraphics.endFill();
505 | }
506 | // Bottom-Right corner
507 | if (borderSize.right == borderSize.bottom) {
508 | if (borderRadius <= borderSize.right) {
509 | // Right
510 | styleGraphics.beginFill(borderColor.right, borderAlpha);
511 | styleGraphics.drawPie(w - borderRadius, h - borderRadius, borderRadius, 0, Math.PI * 0.25, 10);
512 | styleGraphics.lineTo(w, h * 0.5);
513 | styleGraphics.lineTo(w - borderSize.right, h * 0.5);
514 | styleGraphics.lineTo(w - borderSize.right, h - borderSize.bottom);
515 | styleGraphics.lineTo(w - borderRadius, h - borderRadius);
516 | styleGraphics.lineTo(w, h - borderRadius);
517 | styleGraphics.endFill();
518 | // Bottom
519 | styleGraphics.beginFill(borderColor.bottom, borderAlpha);
520 | styleGraphics.drawPie(w - borderRadius, h - borderRadius, borderRadius, Math.PI * 0.25, Math.PI * 0.25, 10);
521 | styleGraphics.lineTo(w * 0.5, h);
522 | styleGraphics.lineTo(w * 0.5, h - borderSize.bottom);
523 | styleGraphics.lineTo(w - borderSize.right, h - borderSize.bottom);
524 | styleGraphics.lineTo(w - borderRadius, h - borderRadius);
525 | styleGraphics.lineTo(w - borderRadius, h);
526 | styleGraphics.endFill();
527 | } else {
528 | var innerRadius = borderRadius - borderSize.right;
529 | // Right
530 | styleGraphics.beginFill(borderColor.right, borderAlpha);
531 | styleGraphics.drawPieInner(w - borderRadius, h - borderRadius, borderRadius, innerRadius, 0, Math.PI * 0.25, 10);
532 | styleGraphics.lineTo(w, h * 0.5);
533 | styleGraphics.lineTo(w - borderSize.right, h * 0.5);
534 | styleGraphics.lineTo(w - borderSize.right, h - borderRadius);
535 | styleGraphics.lineTo(w, h - borderRadius);
536 | styleGraphics.endFill();
537 | // Bottom
538 | styleGraphics.beginFill(borderColor.bottom, borderAlpha);
539 | styleGraphics.drawPieInner(w - borderRadius, h - borderRadius, borderRadius, innerRadius, Math.PI * 0.25, Math.PI * 0.25, 10);
540 | styleGraphics.lineTo(w * 0.5, h);
541 | styleGraphics.lineTo(w * 0.5, h - borderSize.bottom);
542 | styleGraphics.lineTo(w - borderRadius, h - borderSize.bottom);
543 | styleGraphics.lineTo(w - borderRadius, h);
544 | styleGraphics.endFill();
545 | }
546 | } else {
547 | styleGraphics.beginFill(borderColor.right, borderAlpha);
548 | if (borderRadius <= borderSize.right || borderRadius <= borderSize.bottom) {
549 | drawUnevenBordersCurve(styleGraphics, w - borderRadius, h - borderRadius, borderRadius,
550 | 0, Math.PI * 0.5 * borderSize.right / (borderSize.right + borderSize.bottom));
551 | styleGraphics.lineTo(w - borderSize.right, h - borderSize.bottom);
552 | styleGraphics.lineTo(w - borderSize.right, h * 0.5);
553 | styleGraphics.lineTo(w, h * 0.5);
554 | } else {
555 | drawUnevenBordersCorner(styleGraphics, w - borderRadius, h - borderRadius, borderRadius, borderRadius - borderSize.right, borderRadius - borderSize.bottom,
556 | 0, Math.PI * 0.5 * borderSize.right / (borderSize.right + borderSize.bottom));
557 | styleGraphics.moveTo(w, h * 0.5);
558 | styleGraphics.lineTo(w - borderSize.right, h * 0.5);
559 | styleGraphics.lineTo(w - borderSize.right, h - borderRadius);
560 | styleGraphics.lineTo(w, h - borderRadius);
561 | }
562 | styleGraphics.endFill();
563 | }
564 | }
565 |
566 | // Bottom
567 | if(borderSize.bottom != 0) {
568 | // Left-Bottom corner
569 | if (borderSize.left != borderSize.bottom) {
570 | styleGraphics.beginFill(borderColor.bottom, borderAlpha);
571 | if (borderRadius <= borderSize.left || borderRadius <= borderSize.bottom) {
572 | drawUnevenBordersCurve(styleGraphics, borderRadius, h - borderRadius, borderRadius,
573 | Math.PI * 0.5, Math.PI * 0.5 * borderSize.bottom / (borderSize.left + borderSize.bottom));
574 | styleGraphics.lineTo(borderSize.left, h - borderSize.bottom);
575 | styleGraphics.lineTo(w * 0.5, h - borderSize.bottom);
576 | styleGraphics.lineTo(w * 0.5, h);
577 | } else {
578 | drawUnevenBordersCorner(styleGraphics, borderRadius, h - borderRadius, borderRadius, borderRadius - borderSize.left, borderRadius - borderSize.bottom,
579 | Math.PI * 0.5, Math.PI * 0.5 * borderSize.bottom / (borderSize.left + borderSize.bottom));
580 | styleGraphics.moveTo(w * 0.5, h);
581 | styleGraphics.lineTo(w * 0.5, h - borderSize.bottom);
582 | styleGraphics.lineTo(borderRadius, h - borderSize.bottom);
583 | styleGraphics.lineTo(borderRadius, h);
584 | }
585 | styleGraphics.endFill();
586 | }
587 | // Right-Bottom corner
588 | if (borderSize.right != borderSize.bottom) {
589 | styleGraphics.beginFill(borderColor.bottom, borderAlpha);
590 | if (borderRadius <= borderSize.right || borderRadius <= borderSize.bottom) {
591 | drawUnevenBordersCurve(styleGraphics, w - borderRadius, h - borderRadius, borderRadius,
592 | Math.PI * 0.5 * borderSize.right / (borderSize.right + borderSize.bottom),
593 | Math.PI * 0.5 * borderSize.bottom / (borderSize.right + borderSize.bottom));
594 | styleGraphics.lineTo(w * 0.5, h);
595 | styleGraphics.lineTo(w * 0.5, h - borderSize.bottom);
596 | styleGraphics.lineTo(w - borderSize.right, h - borderSize.bottom);
597 | } else {
598 | drawUnevenBordersCorner(styleGraphics, w - borderRadius, h - borderRadius, borderRadius, borderRadius - borderSize.right, borderRadius - borderSize.bottom,
599 | Math.PI * 0.5 * borderSize.right / (borderSize.right + borderSize.bottom),
600 | Math.PI * 0.5 * borderSize.bottom / (borderSize.right + borderSize.bottom));
601 | styleGraphics.moveTo(w * 0.5, h);
602 | styleGraphics.lineTo(w * 0.5, h - borderSize.bottom);
603 | styleGraphics.lineTo(w - borderRadius, h - borderSize.bottom);
604 | styleGraphics.lineTo(w - borderRadius, h);
605 | }
606 | styleGraphics.endFill();
607 | }
608 | }
609 | }
610 | } // End borders
611 | }
612 |
613 | private static function paintTile(g:Graphics, tile:Tile, src:Rectangle, dst:Rectangle, backgroundImage:String) {
614 | var scaleX = dst.width / src.width;
615 | var scaleY = dst.height / src.height;
616 | var sub = TileCache.get(backgroundImage + "_" + scaleX + "_" + scaleY, src);
617 | if (sub == null) {
618 | sub = tile.sub(src.left * scaleX, src.top * scaleY, src.width, src.height);
619 | TileCache.set(backgroundImage + "_" + scaleX + "_" + scaleY, sub, src);
620 | }
621 | g.smooth = true;
622 | g.beginTileFill(dst.left, dst.top, scaleX, scaleY, sub);
623 | g.drawRect(dst.left, dst.top, dst.width, dst.height);
624 | g.endFill();
625 | }
626 |
627 | // Used to repeat part (src) of an image (tile) with a given scale (srcScaleX, srcScaleY) inside a target (dst)
628 | private static function paintTileRepeat(g:Graphics, tile:Tile, src:Rectangle, srcScaleX:Float, srcScaleY:Float, dst:Rectangle, backgroundImage:String) {
629 | var scaledw = srcScaleX * src.width;
630 | var scaledh = srcScaleY * src.height;
631 | var wCount = dst.width / scaledw;
632 | var hCount = dst.height / scaledh;
633 |
634 | var iwCount = Math.ceil(wCount);
635 | var ihCount = Math.ceil(hCount);
636 |
637 | var lastw = iwCount - 1;
638 | var lasth = ihCount - 1;
639 |
640 | // Full images
641 | for (iwCurr in 0...lastw) {
642 | for (ihCurr in 0...lasth) {
643 | paintTile(g, tile, src, new Rectangle(dst.left + iwCurr * scaledw, dst.top + ihCurr * scaledh, scaledw, scaledh), backgroundImage);
644 | }
645 | }
646 |
647 | var localRect = src.copy();
648 | // Images clipped in width
649 | var clippedw = (wCount - lastw) * scaledw;
650 | localRect.width = (wCount - lastw) * src.width;
651 | for (ihCurr in 0...lasth) {
652 | paintTile(g, tile, localRect, new Rectangle(dst.left + lastw * scaledw, dst.top + ihCurr * scaledh, clippedw, scaledh), backgroundImage);
653 | }
654 |
655 | // Images clipped in height
656 | var clippedh = (hCount - lasth) * scaledh;
657 | localRect.width = src.width;
658 | localRect.height = (hCount - lasth) * src.height;
659 | for (iwCurr in 0...lastw) {
660 | paintTile(g, tile, localRect, new Rectangle(dst.left + iwCurr * scaledw, dst.top + lasth * scaledh, scaledw, clippedh), backgroundImage);
661 | }
662 |
663 | // Image clipped in both
664 | localRect.width = (wCount - lastw) * src.width;
665 | if (localRect.width > 1 && localRect.height > 1) {
666 | paintTile(g, tile, localRect, new Rectangle(dst.left + lastw * scaledw, dst.top + lasth * scaledh, clippedw, clippedh), backgroundImage);
667 | }
668 | }
669 |
670 | private static function drawUnevenBordersCorner(graphics:Graphics, cx:Float, cy:Float, radius:Float, startInnerRadius:Float, endInnerRadius:Float, angleStart:Float, angleLength:Float) {
671 | var nsegments = 10;
672 | var angleOffset = angleLength / (nsegments - 1);
673 |
674 | graphics.lineTo(cx + Math.cos(angleStart) * startInnerRadius, cy + Math.sin(angleStart) * endInnerRadius);
675 | var a;
676 | // Circle on the outside
677 | for (i in 0...nsegments) {
678 | a = i * angleOffset + angleStart;
679 | graphics.lineTo(cx + Math.cos(a) * radius, cy + Math.sin(a) * radius);
680 | }
681 | // Ellipse on the inside
682 | graphics.lineTo(cx + Math.cos(angleStart + angleLength) * startInnerRadius, cy + Math.sin(angleStart + angleLength) * endInnerRadius);
683 | for (i in 0...nsegments) {
684 | a = (nsegments - 1 - i) * angleOffset + angleStart;
685 | graphics.lineTo(cx + Math.cos(a) * startInnerRadius, cy + Math.sin(a) * endInnerRadius);
686 | }
687 | }
688 |
689 | private static function drawUnevenBordersCurve(graphics:Graphics, cx:Float, cy:Float, radius:Float, angleStart:Float, angleLength:Float) {
690 | var nsegments = 10;
691 | var angleOffset = angleLength / (nsegments - 1);
692 | var a;
693 | for (i in 0...nsegments) {
694 | a = i * angleOffset + angleStart;
695 | graphics.lineTo(cx + Math.cos(a) * radius, cy + Math.sin(a) * radius);
696 | }
697 | }
698 |
699 | private static function drawRoundedBackground(graphics:Graphics, w:Float, h:Float, borderSize:Rectangle, borderRadius:Float) {
700 | // Left-Top
701 | if (borderRadius <= borderSize.left || borderRadius <= borderSize.top) {
702 | graphics.lineTo(borderSize.left, borderSize.top);
703 | } else {
704 | graphics.lineTo(borderSize.left, borderRadius);
705 | drawBackgroundCorner(graphics, borderRadius, borderRadius, borderRadius - borderSize.left, borderRadius - borderSize.top, Math.PI, Math.PI * 0.5);
706 | }
707 | // Top-Right
708 | if (borderRadius <= borderSize.right || borderRadius <= borderSize.top) {
709 | graphics.lineTo(w - borderSize.right, borderSize.top);
710 | } else {
711 | graphics.lineTo(w - borderRadius, borderSize.top);
712 | drawBackgroundCorner(graphics, w - borderRadius, borderRadius, borderRadius - borderSize.right, borderRadius - borderSize.top, -Math.PI * 0.5, Math.PI * 0.5);
713 | }
714 | // Right-Bottom
715 | if (borderRadius <= borderSize.right || borderRadius <= borderSize.bottom) {
716 | graphics.lineTo(w - borderSize.right, h - borderSize.bottom);
717 | } else {
718 | graphics.lineTo(w - borderSize.right, h - borderRadius);
719 | drawBackgroundCorner(graphics, w - borderRadius, h - borderRadius, borderRadius - borderSize.right, borderRadius - borderSize.bottom, 0, Math.PI * 0.5);
720 | }
721 | // Bottom-Left
722 | if (borderRadius <= borderSize.left || borderRadius <= borderSize.bottom) {
723 | graphics.lineTo(borderSize.left, h - borderSize.bottom);
724 | } else {
725 | graphics.lineTo(borderRadius, h - borderSize.bottom);
726 | drawBackgroundCorner(graphics, borderRadius, h - borderRadius, borderRadius - borderSize.left, borderRadius - borderSize.bottom, Math.PI * 0.5, Math.PI * 0.5);
727 | }
728 | }
729 |
730 | private static inline function drawBackgroundCorner(graphics:Graphics, cx:Float, cy:Float, startRadius:Float, endRadius:Float, angleStart:Float, angleLength:Float) {
731 | var nsegments = startRadius != endRadius ? 200 : 100;
732 | var angleOffset = angleLength / (nsegments - 1);
733 | var a;
734 | for (i in 0...nsegments) {
735 | a = i * angleOffset + angleStart;
736 | graphics.lineTo(cx + Math.cos(a) * startRadius, cy + Math.sin(a) * endRadius);
737 | }
738 | }
739 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/heaps/TileCache.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.heaps;
2 |
3 | import h2d.Tile;
4 | import haxe.ui.geom.Rectangle;
5 | import haxe.ui.util.ColorUtil;
6 |
7 | class TileCache {
8 | private static var _cache:Map = new Map();
9 |
10 | public static function set(resourceId:String, tile:Tile, trc:Rectangle = null):Tile {
11 | _cache.set(buildCacheKey(resourceId, trc), tile);
12 | return tile;
13 | }
14 |
15 | public static function get(resourceId:String, trc:Rectangle = null):Tile {
16 | return _cache.get(buildCacheKey(resourceId, trc));
17 | }
18 |
19 | private static inline function buildCacheKey(resourceId:String, trc:Rectangle = null):String {
20 | var key = resourceId;
21 | if (trc != null) {
22 | key += "_" + trc.left + "_" + trc.top + "_" + trc.width + "_" + trc.height;
23 | }
24 | return key;
25 | }
26 |
27 | public static function getGradient(type:String, startCol:Int, endCol:Int, size:Int = 256, alpha:Int = 255):Tile {
28 | var key = type + "_" + startCol + "_" + endCol + "_" + size + "_" + alpha;
29 | if (_cache.exists(key)) {
30 | return _cache.get(key);
31 | }
32 |
33 | var alphaMask = alpha << 24;
34 | var arr = ColorUtil.buildColorArray(startCol, endCol, size);
35 | var tile:Tile = null;
36 | if (type == "vertical") {
37 | var gradient = new hxd.BitmapData(1, size);
38 | var y = 0;
39 | for (col in arr) {
40 | gradient.line(0, y, 1, y, alphaMask | col);
41 | y++;
42 | }
43 | tile = h2d.Tile.fromBitmap(gradient);
44 | } else if (type == "horizontal") {
45 | var gradient = new hxd.BitmapData(size, 1);
46 | var x = 0;
47 | for (col in arr) {
48 | gradient.line(x, 0, x, 1, alphaMask | col);
49 | x++;
50 | }
51 | tile = h2d.Tile.fromBitmap(gradient);
52 | }
53 |
54 | return tile;
55 | }
56 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/heaps/_module/styles/dark/main.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haxeui/haxeui-heaps/396f1a0704bcd8836637b3cc87a2691caafd0232/haxe/ui/backend/heaps/_module/styles/dark/main.css
--------------------------------------------------------------------------------
/haxe/ui/backend/heaps/_module/styles/default/main.css:
--------------------------------------------------------------------------------
1 | .property-grid .scrollview-contents {
2 | padding-right: -1px;
3 | }
4 |
5 | .text-tiny {
6 | font-size: 12px;
7 | }
8 |
9 | .text-small {
10 | font-size: 12px;
11 | }
12 |
13 | .text-normal {
14 | font-size: 12px;
15 | }
16 |
17 | .color-picker .controls-container .label {
18 | width: 75px;
19 | }
20 |
--------------------------------------------------------------------------------
/haxe/ui/backend/heaps/_module/styles/main.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haxeui/haxeui-heaps/396f1a0704bcd8836637b3cc87a2691caafd0232/haxe/ui/backend/heaps/_module/styles/main.css
--------------------------------------------------------------------------------
/haxe/ui/backend/module.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/haxelib.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.7.0",
3 | "contributors": [
4 | "haxeui",
5 | "ianharrigan"
6 | ],
7 | "license": "MIT",
8 | "tags": [
9 | "ui",
10 | "gui",
11 | "heaps"
12 | ],
13 | "releasenote": "1.7.0 release",
14 | "dependencies": {
15 | "haxeui-core": "",
16 | "heaps": ""
17 | },
18 | "name": "haxeui-heaps",
19 | "description": "The Heaps backend of the HaxeUI framework",
20 | "url": "https://github.com/haxeui/haxeui-heaps"
21 | }
--------------------------------------------------------------------------------
/haxeui-heaps.properties:
--------------------------------------------------------------------------------
1 | haxe.ui.heaps.background.color=0xFFFFFFFF
--------------------------------------------------------------------------------