├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE.md
├── images
│ └── screen.png
└── workflows
│ ├── build.yml
│ └── project
│ ├── build.xml
│ └── src
│ └── Main.hx
├── .gitignore
├── LICENSE.md
├── README.md
├── classpath.exclusions
├── haxe
└── ui
│ └── backend
│ ├── AppImpl.hx
│ ├── AssetsImpl.hx
│ ├── BackendImpl.hx
│ ├── CallLaterImpl.hx
│ ├── ComponentGraphicsImpl.hx
│ ├── ComponentImpl.hx
│ ├── ComponentSurface.hx
│ ├── EventImpl.hx
│ ├── FocusManagerImpl.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
│ ├── module.xml
│ └── openfl
│ ├── BitmapCache.hx
│ ├── EventMapper.hx
│ ├── FilterConverter.hx
│ ├── OpenFLStyleHelper.hx
│ ├── _module
│ └── styles
│ │ ├── dark
│ │ └── main.css
│ │ ├── default
│ │ └── main.css
│ │ └── main.css
│ ├── filters
│ ├── BrightnessFilter.hx
│ ├── ContrastFilter.hx
│ ├── GrayscaleFilter.hx
│ ├── HueRotateFilter.hx
│ ├── InvertFilter.hx
│ ├── SaturateFilter.hx
│ └── TintFilter.hx
│ └── util
│ ├── FontDetect.hx
│ └── GraphicsExt.hx
├── haxelib.json
└── include.xml
/.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/images/screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haxeui/haxeui-openfl/7841e98e55fa118ba3a3d3644f4e0997e00147b3/.github/images/screen.png
--------------------------------------------------------------------------------
/.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.0.5, 4.1.5, 4.2.2, 4.3.0, 4.3.1]
13 | target: [html5, linux, windows, mac]
14 | exclude:
15 | - os: ubuntu-latest
16 | target: windows
17 | - os: ubuntu-latest
18 | target: mac
19 | - os: windows-latest
20 | target: linux
21 | - os: windows-latest
22 | target: mac
23 | - os: macos-13
24 | target: linux
25 | - os: macos-13
26 | target: windows
27 |
28 |
29 | steps:
30 | - uses: actions/checkout@v1
31 | - name: Setup Haxe (${{ matrix.target }}, haxe ${{ matrix.haxe-version }}, ${{ matrix.os }})
32 | uses: krdlab/setup-haxe@v1
33 | with:
34 | haxe-version: ${{ matrix.haxe-version }}
35 |
36 | - name: Setup app (${{ matrix.target }}, haxe ${{ matrix.haxe-version }}, ${{ matrix.os }})
37 | run: |
38 | git clone --branch master https://github.com/haxeui/haxeui-core.git --depth=1
39 | haxelib dev haxeui-core haxeui-core
40 | haxelib dev haxeui-openfl .
41 | haxelib install hxcpp --always --quiet
42 | haxelib install actuate --always --quiet
43 | haxelib install openfl --always --quiet
44 | echo "y" | haxelib run openfl setup
45 |
46 | - name: Build app (${{ matrix.target }}, haxe ${{ matrix.haxe-version }}, ${{ matrix.os }})
47 | run: |
48 | cd .github/workflows/project
49 | haxelib run openfl build ${{ matrix.target }}
50 |
--------------------------------------------------------------------------------
/.github/workflows/project/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.github/workflows/project/src/Main.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | class Main {
4 | public static function main() {
5 |
6 | }
7 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #################
2 | ## Eclipse
3 | #################
4 |
5 | *.pydevproject
6 | .project
7 | .metadata
8 | bin/
9 | tmp/
10 | *.tmp
11 | *.bak
12 | *.swp
13 | *~.nib
14 | local.properties
15 | .classpath
16 | .settings/
17 | .loadpath
18 |
19 | # External tool builders
20 | .externalToolBuilders/
21 |
22 | # Locally stored "Eclipse launch configurations"
23 | *.launch
24 |
25 | # CDT-specific
26 | .cproject
27 |
28 | # PDT-specific
29 | .buildpath
30 |
31 |
32 | #################
33 | ## Visual Studio
34 | #################
35 |
36 | ## Ignore Visual Studio temporary files, build results, and
37 | ## files generated by popular Visual Studio add-ons.
38 |
39 | # User-specific files
40 | *.suo
41 | *.user
42 | *.sln.docstates
43 |
44 | # Build results
45 | *_i.c
46 | *_p.c
47 | *.ilk
48 | *.meta
49 | *.obj
50 | *.pch
51 | *.pdb
52 | *.pgc
53 | *.pgd
54 | *.rsp
55 | *.sbr
56 | *.tlb
57 | *.tli
58 | *.tlh
59 | *.tmp
60 | *.vspscc
61 | .builds
62 | *.dotCover
63 |
64 | ## TODO: If you have NuGet Package Restore enabled, uncomment this
65 | #packages/
66 |
67 | # Visual C++ cache files
68 | ipch/
69 | *.aps
70 | *.ncb
71 | *.opensdf
72 | *.sdf
73 |
74 | # Visual Studio profiler
75 | *.psess
76 | *.vsp
77 |
78 | # ReSharper is a .NET coding add-in
79 | _ReSharper*
80 |
81 | # Installshield output folder
82 | [Ee]xpress
83 |
84 | # DocProject is a documentation generator add-in
85 | DocProject/buildhelp/
86 | DocProject/Help/*.HxT
87 | DocProject/Help/*.HxC
88 | DocProject/Help/*.hhc
89 | DocProject/Help/*.hhk
90 | DocProject/Help/*.hhp
91 | DocProject/Help/Html2
92 | DocProject/Help/html
93 |
94 | # Click-Once directory
95 | publish
96 |
97 | # Others
98 | [Bb]in
99 | [Oo]bj
100 | sql
101 | TestResults
102 | *.Cache
103 | ClientBin
104 | stylecop.*
105 | ~$*
106 | *.dbmdl
107 | Generated_Code #added for RIA/Silverlight projects
108 |
109 | # Backup & report files from converting an old project file to a newer
110 | # Visual Studio version. Backup files are not needed, because we have git ;-)
111 | _UpgradeReport_Files/
112 | Backup*/
113 | UpgradeLog*.XML
114 |
115 |
116 |
117 | ############
118 | ## Windows
119 | ############
120 |
121 | # Windows image file caches
122 | Thumbs.db
123 |
124 | # Folder config file
125 | Desktop.ini
126 |
127 |
128 | #############
129 | ## Python
130 | #############
131 |
132 | *.py[co]
133 |
134 | # Packages
135 | *.egg
136 | *.egg-info
137 | dist
138 | build
139 | eggs
140 | parts
141 | bin
142 | var
143 | sdist
144 | develop-eggs
145 | .installed.cfg
146 |
147 | # Installer logs
148 | pip-log.txt
149 |
150 | # Unit test / coverage reports
151 | .coverage
152 | .tox
153 |
154 | #Translations
155 | *.mo
156 |
157 | #Mr Developer
158 | .mr.developer.cfg
159 |
160 | # Mac crap
161 | .DS_Store
162 |
163 |
164 | *.backup
165 | dox.xml
--------------------------------------------------------------------------------
/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-openfl
4 | `haxeui-openfl` is the `OpenFL` backend for HaxeUI.
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Installation
12 | * `haxeui-openfl` has a dependency to `haxeui-core`, and so that too must be installed.
13 | * `haxeui-openfl` also has a dependency to OpenFL, please refer to the installation instructions on their site.
14 |
15 | Eventually all these libs will become haxelibs, however, currently in their alpha form they do not even contain a `haxelib.json` file (for dependencies, etc) and therefore can only be used by downloading the source and using the `haxelib dev` command or by directly using the git versions using the `haxelib git` command (recommended). Eg:
16 |
17 | ```
18 | haxelib git haxeui-core https://github.com/haxeui/haxeui-core
19 | haxelib dev haxeui-openfl path/to/expanded/source/archive
20 | ```
21 |
22 | ## Usage
23 | The simplest method to create a new `OpenFL` application that is HaxeUI ready is to use one of the haxeui-templates. These templates will allow you to start a new project rapidly with HaxeUI support baked in.
24 |
25 | If however you already have an existing application, then incorporating HaxeUI into that application is straight forward:
26 |
27 | ### project/application.xml
28 | Assuming `haxeui-core` and `haxeui-openfl` have been installed, then adding HaxeUI to your existing application is as simple as adding these two lines to your `project.xml` or your `application.xml`:
29 |
30 | ```xml
31 |
32 |
33 | ```
34 |
35 | _Note: Currently you must also include `haxeui-core` explicitly during the alpha, eventually `haxelib.json` files will exist to take care of this dependency automatically._
36 |
37 | ### Toolkit initialisation and usage
38 | Initialising the toolkit requires you to add this single line somewhere _before_ you start to actually use HaxeUI in your application:
39 |
40 | ```
41 | Toolkit.init();
42 | ```
43 | Once the toolkit is initialised you can add components using the methods specified here.
44 |
45 | ## OpenFL specifics
46 |
47 | As well as using the generic `Screen.instance.addComponent`, it is also possible to add components directly to any other `OpenFL` sprite (eg: `Lib.current.stage.addChild`)
48 |
49 | ## Addtional resources
50 | * component-explorer - Browse HaxeUI components
51 | * playground - Write and test HaxeUI layouts in your browser
52 | * component-examples - Various componet examples
53 | * haxeui-api - The HaxeUI api docs.
54 | * haxeui-guides - Set of guides to working with HaxeUI and backends.
55 |
--------------------------------------------------------------------------------
/classpath.exclusions:
--------------------------------------------------------------------------------
1 | ; exclude paths from classpath when searching for haxeui arifacts (module.xml, native.xml, etc)
2 | ; speeds up build
3 | \/lime\/_internal\/.*$
4 | \/lime\/src\/.*$
5 | \/lime\/.*\/src\/.*$
6 | \/lime\/app\/.*$
7 | \/lime\/graphics\/.*$
8 | \/lime\/math\/.*$
9 | \/lime\/media\/.*$
10 | \/lime\/net\/.*$
11 | \/lime\/system\/.*$
12 | \/lime\/text\/.*$
13 | \/lime\/tools\/.*$
14 | \/lime\/ui\/.*$
15 | \/lime\/utils\/.*$
16 | \/openfl\/src\/.*$
17 | \/openfl\/.*\/src\/.*$
18 | \/openfl\/desktop\/.*$
19 | \/openfl\/display\/.*$
20 | \/openfl\/display3D\/.*$
21 | \/openfl\/errors\/.*$
22 | \/openfl\/events\/.*$
23 | \/openfl\/external\/.*$
24 | \/openfl\/filters\/.*$
25 | \/openfl\/geom\/.*$
26 | \/openfl\/media\/.*$
27 | \/openfl\/net\/.*$
28 | \/openfl\/printing\/.*$
29 | \/openfl\/profiler\/.*$
30 | \/openfl\/sensors\/.*$
31 | \/openfl\/system\/.*$
32 | \/openfl\/text\/.*$
33 | \/openfl\/ui\/.*$
34 | \/openfl\/utils\/.*$
35 | \/actuate\/.*$
--------------------------------------------------------------------------------
/haxe/ui/backend/AppImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import haxe.ui.events.AppEvent;
4 |
5 | class AppImpl extends AppBase {
6 | public function new() {
7 | }
8 |
9 | private override function init(onReady:Void->Void, onEnd:Void->Void = null) {
10 | openfl.Lib.current.stage.application.onExit.add(function(_) {
11 | dispatch(new AppEvent(AppEvent.APP_EXITED));
12 | });
13 | onReady();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/haxe/ui/backend/AssetsImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import haxe.io.Bytes;
4 | import haxe.io.Path;
5 | import haxe.ui.assets.FontInfo;
6 | import haxe.ui.assets.ImageInfo;
7 | import openfl.Assets;
8 | import openfl.display.Bitmap;
9 | import openfl.display.BitmapData;
10 | import openfl.display.Loader;
11 | import openfl.events.Event;
12 | import openfl.utils.ByteArray;
13 |
14 | class AssetsImpl extends AssetsBase {
15 | private override function getTextDelegate(resourceId:String):String {
16 | if (Assets.exists(resourceId) == true) {
17 | return Assets.getText(resourceId);
18 | } else if (Resource.listNames().indexOf(resourceId) != -1) {
19 | return Resource.getString(resourceId);
20 | }
21 | return null;
22 | }
23 |
24 | private override function getImageInternal(resourceId:String, callback:ImageInfo->Void):Void {
25 | if (Assets.exists(resourceId) == true) {
26 | if(Path.extension(resourceId).toLowerCase() == "svg") {
27 | #if svg
28 | var content:String = Assets.getText(resourceId);
29 | var svg = new format.SVG(content);
30 | var imageInfo:ImageInfo = {
31 | svg: svg,
32 | width: Std.int(svg.data.width),
33 | height: Std.int(svg.data.height)
34 | };
35 | callback(imageInfo);
36 | #else
37 | trace("WARNING: SVG not supported");
38 | #end
39 | } else {
40 | Assets.loadBitmapData(resourceId).onComplete(function(bmpData:BitmapData) {
41 | var imageInfo:ImageInfo = {
42 | data: bmpData,
43 | width: bmpData.width,
44 | height: bmpData.height
45 | }
46 | callback(imageInfo);
47 | });
48 | }
49 | } else {
50 | callback(null);
51 | }
52 | }
53 |
54 | private override function getImageFromHaxeResource(resourceId:String, callback:String->ImageInfo->Void) {
55 | var imageInfo:ImageInfo = null;
56 | if (Path.extension(resourceId).toLowerCase() == "svg") {
57 | #if svg
58 | var svgContent = Resource.getString(resourceId);
59 | var svg = new format.SVG(svgContent);
60 | imageInfo = {
61 | svg: svg,
62 | width: Std.int(svg.data.width),
63 | height: Std.int(svg.data.height)
64 | }
65 | #else
66 | trace("WARNING: SVG not supported");
67 | #end
68 |
69 | callback(resourceId, imageInfo);
70 | return;
71 | }
72 |
73 | var bytes = Resource.getBytes(resourceId);
74 | imageFromBytes(bytes, function(imageInfo) {
75 | callback(resourceId, imageInfo);
76 | });
77 | }
78 |
79 | public override function imageFromBytes(bytes:Bytes, callback:ImageInfo->Void):Void {
80 | var ba:ByteArray = ByteArray.fromBytes(bytes);
81 | var loader:Loader = new Loader();
82 | var onCompleteEvent = null;
83 | onCompleteEvent = function(e) {
84 | if (loader.content != null) {
85 | var bmpData = cast(loader.content, Bitmap).bitmapData;
86 | var imageInfo:ImageInfo = {
87 | data: bmpData,
88 | width: bmpData.width,
89 | height: bmpData.height
90 | }
91 |
92 | callback(imageInfo);
93 | }
94 | loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onCompleteEvent);
95 | };
96 | loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteEvent, false, 0, false);
97 | loader.contentLoaderInfo.addEventListener("ioError", function(e) {
98 | trace(e);
99 | callback(null);
100 | loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onCompleteEvent);
101 | }, false, 0, true);
102 | loader.loadBytes(ba);
103 | }
104 |
105 | private override function getFontInternal(resourceId:String, callback:FontInfo->Void):Void {
106 | var fontInfo = null;
107 | if (isEmbeddedFont(resourceId) == true) {
108 | if (Assets.exists(resourceId)) {
109 | fontInfo = {
110 | data: Assets.getFont(resourceId).fontName
111 | }
112 | } else if (Resource.listNames().indexOf(resourceId) != -1) {
113 | getFontFromHaxeResource(resourceId, function(r, info) {
114 | callback(info);
115 | });
116 | } else {
117 | fontInfo = {
118 | data: resourceId
119 | }
120 | }
121 | } else {
122 | fontInfo = {
123 | data: resourceId
124 | }
125 | }
126 | callback(fontInfo);
127 | }
128 |
129 | private override function getFontFromHaxeResource(resourceId:String, callback:String->FontInfo->Void) {
130 | var bytes = Resource.getBytes(resourceId);
131 | if (bytes == null) {
132 | callback(resourceId, null);
133 | return;
134 | }
135 |
136 | #if (js && html5)
137 |
138 | loadWebFontFontResourceDynamically(resourceId, bytes, callback);
139 |
140 | #else
141 |
142 | var font = openfl.text.Font.fromBytes(bytes);
143 | openfl.text.Font.registerFont(font);
144 | var fontInfo = {
145 | data: font.fontName
146 | }
147 | callback(resourceId, fontInfo);
148 |
149 | #end
150 | }
151 |
152 | #if (js && html5)
153 | private function loadWebFontFontResourceDynamically(resourceId:String, bytes:Bytes, callback:String->FontInfo->Void) {
154 | var fontFamilyParts = resourceId.split("/");
155 | var fontFamily = fontFamilyParts[fontFamilyParts.length - 1];
156 | if (fontFamily.indexOf(".") != -1) {
157 | fontFamily = fontFamily.substr(0, fontFamily.indexOf("."));
158 | }
159 |
160 | var fontFace = new js.html.FontFace(fontFamily, bytes.getData());
161 | fontFace.load().then(function(loadedFace) {
162 | js.Browser.document.fonts.add(loadedFace);
163 | haxe.ui.backend.openfl.util.FontDetect.onFontLoaded(fontFamily, function(f) {
164 | var fontInfo = {
165 | data: fontFamily
166 | }
167 | callback(resourceId, fontInfo);
168 | }, function(f) {
169 | callback(resourceId, null);
170 | });
171 | }).catchError(function(error) {
172 | #if debug
173 | trace("WARNING: problem loading font '" + resourceId + "' (" + error + ")");
174 | #end
175 | // error occurred
176 | callback(resourceId, null);
177 | });
178 | }
179 | #end
180 |
181 |
182 | public override function imageInfoFromImageData(imageData:ImageData):ImageInfo {
183 | return {
184 | data: imageData,
185 | width: imageData.width,
186 | height: imageData.height
187 | }
188 | }
189 |
190 | //***********************************************************************************************************
191 | // Util functions
192 | //***********************************************************************************************************
193 |
194 | private static inline function isEmbeddedFont(name:String) {
195 | return (name != "_sans" && name != "_serif" && name != "_typewriter");
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/haxe/ui/backend/BackendImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | class BackendImpl {
4 | public static var id:String = "openfl";
5 | }
6 |
--------------------------------------------------------------------------------
/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 | }
7 | }
8 |
--------------------------------------------------------------------------------
/haxe/ui/backend/ComponentGraphicsImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import openfl.display.GraphicsPathCommand;
4 | import haxe.io.Bytes;
5 | import haxe.ui.core.Component;
6 | import haxe.ui.loaders.image.ImageLoader;
7 | import haxe.ui.util.Color;
8 | import haxe.ui.util.Variant;
9 | import openfl.display.Bitmap;
10 | import openfl.display.BitmapData;
11 | import openfl.display.GraphicsPath;
12 | import openfl.geom.Matrix;
13 | import openfl.geom.Rectangle;
14 | import openfl.utils.ByteArray;
15 |
16 | class ComponentGraphicsImpl extends ComponentGraphicsBase {
17 | private var _currentFillColor:Null = null;
18 | private var _currentFillAlpha:Null = null;
19 | private var _globalFillColor:Null = null;
20 | private var _globalFillAlpha:Null = null;
21 | private var _hasSize:Bool = false;
22 |
23 | private var _globalLineThickness :Null = null;
24 | private var _globalLineColor:Null = null;
25 | private var _globalLineAlpha:Null = null;
26 |
27 | private var currentPath:GraphicsPath;
28 |
29 | public function new(component:Component) {
30 | super(component);
31 | component.styleable = false;
32 | }
33 |
34 | public override function clear() {
35 | if (_hasSize == false) {
36 | return super.clear();
37 | }
38 | _component.graphics.clear();
39 | }
40 |
41 | public override function moveTo(x:Float, y:Float) {
42 | if (_hasSize == false) {
43 | return super.moveTo(x, y);
44 | }
45 | if (currentPath != null) {
46 | currentPath.moveTo(x,y);
47 | } else {
48 | _component.graphics.moveTo(x, y);
49 | }
50 |
51 | }
52 |
53 | public override function lineTo(x:Float, y:Float) {
54 | if (_hasSize == false) {
55 | return super.lineTo(x, y);
56 | }
57 | if (currentPath != null) {
58 | currentPath.lineTo(x,y);
59 | } else {
60 | _component.graphics.lineTo(x, y);
61 | }
62 | }
63 |
64 | public override function strokeStyle(color:Null, thickness:Null = 1, alpha:Null = 1) {
65 | if (_hasSize == false) {
66 | return super.strokeStyle(color, thickness, alpha);
67 | }
68 | if (currentPath == null) {
69 | _globalLineThickness = thickness;
70 | _globalLineColor = color;
71 | _globalLineAlpha = alpha;
72 | }
73 |
74 | _component.graphics.lineStyle(thickness, color, alpha);
75 | }
76 |
77 | public override function fillStyle(color:Null, alpha:Null = 1) {
78 | if (_hasSize == false) {
79 | return super.fillStyle(color, alpha);
80 | }
81 | if (currentPath == null) {
82 | _globalFillColor = color;
83 | _globalFillAlpha = alpha;
84 | }
85 | _currentFillColor = color;
86 | _currentFillAlpha = alpha;
87 | }
88 |
89 | public override function circle(x:Float, y:Float, radius:Float) {
90 | if (_hasSize == false) {
91 | return super.circle(x, y, radius);
92 | }
93 | if (_currentFillColor != null) {
94 | _component.graphics.beginFill(_currentFillColor, _currentFillAlpha);
95 | }
96 | _component.graphics.drawCircle(x, y, radius);
97 | if (_currentFillColor != null) {
98 | _component.graphics.endFill();
99 | }
100 | }
101 |
102 | public override function curveTo(controlX:Float, controlY:Float, anchorX:Float, anchorY:Float) {
103 | if (_hasSize == false) {
104 | return super.curveTo(controlX, controlY, anchorX, anchorY);
105 | }
106 |
107 | if (currentPath != null) {
108 | currentPath.curveTo(controlX, controlY, anchorX, anchorY);
109 | } else {
110 | _component.graphics.curveTo(controlX, controlY, anchorX, anchorY);
111 | }
112 | }
113 |
114 | public override function cubicCurveTo(controlX1:Float, controlY1:Float, controlX2:Float, controlY2:Float, anchorX:Float, anchorY:Float) {
115 | if (_hasSize == false) {
116 | return super.cubicCurveTo(controlX1, controlY1, controlX2, controlY2, anchorX, anchorY);
117 | }
118 | if (currentPath != null) {
119 | currentPath.cubicCurveTo(controlX1, controlY1, controlX2, controlY2, anchorX, anchorY);
120 | } else {
121 | _component.graphics.cubicCurveTo(controlX1, controlY1, controlX2, controlY2, anchorX, anchorY);
122 | }
123 |
124 | }
125 |
126 | public override function beginPath() {
127 | if (_hasSize == false) {
128 | return super.beginPath();
129 | }
130 | currentPath = new GraphicsPath();
131 | }
132 |
133 | public override function closePath() {
134 | if (_hasSize == false) {
135 | return super.closePath();
136 | }
137 | if (currentPath!=null && currentPath.commands != null && currentPath.commands.length>0 ) {
138 | if (_currentFillColor != null) {
139 | _component.graphics.beginFill(_currentFillColor, _currentFillAlpha);
140 | }
141 | if (currentPath.commands[0] != GraphicsPathCommand.MOVE_TO) {
142 | currentPath.commands.insertAt(0, GraphicsPathCommand.MOVE_TO);
143 | @:privateAccess currentPath.data.insertAt(0, _component.graphics.__positionX);
144 | @:privateAccess currentPath.data.insertAt(0, _component.graphics.__positionY);
145 | }
146 | _component.graphics.drawPath(currentPath.commands, currentPath.data);
147 | if (_currentFillColor != null) {
148 | _component.graphics.endFill();
149 | }
150 | }
151 | currentPath = null;
152 | _currentFillColor = _globalFillColor;
153 | _currentFillAlpha = _globalFillAlpha;
154 |
155 | // it seems openfl forgets about lineStyle after drawing a shape;
156 | _component.graphics.lineStyle(_globalLineThickness , _globalLineColor, _globalLineAlpha);
157 | }
158 |
159 | public override function rectangle(x:Float, y:Float, width:Float, height:Float) {
160 | if (_hasSize == false) {
161 | return super.rectangle(x, y, width, height);
162 | }
163 | if (_currentFillColor != null) {
164 | _component.graphics.beginFill(_currentFillColor, _currentFillAlpha);
165 | }
166 | _component.graphics.drawRect(x, y, width, height);
167 | if (_currentFillColor != null) {
168 | _component.graphics.endFill();
169 | }
170 | }
171 |
172 | public override function image(resource:Variant, x:Null = null, y:Null = null, width:Null = null, height:Null = null) {
173 | if (_hasSize == false) {
174 | return super.image(resource, x, y, width, height);
175 | }
176 | ImageLoader.instance.load(resource, function(imageInfo) {
177 | if (imageInfo != null) {
178 | if (x == null) x = 0;
179 | if (y == null) y = 0;
180 | if (width == null) width = imageInfo.width;
181 | if (height == null) height = imageInfo.height;
182 |
183 | var mat:Matrix = new Matrix();
184 | mat.scale(width / imageInfo.width, height / imageInfo.width);
185 | mat.translate(x, y);
186 |
187 | _component.graphics.beginBitmapFill(imageInfo.data, mat);
188 | _component.graphics.drawRect(x, y, width, height);
189 | _component.graphics.endFill();
190 | } else {
191 | trace("could not load: " + resource);
192 | }
193 | });
194 | }
195 |
196 | public override function setPixel(x:Float, y:Float, color:Color) {
197 | if (_hasSize == false) {
198 | return super.setPixel(x, y, color);
199 | }
200 | _component.graphics.beginFill(color);
201 | _component.graphics.drawRect(x, y, 1, 1);
202 | _component.graphics.endFill();
203 | }
204 |
205 | private var _bitmap:Bitmap = null;
206 | private var _bitmapData:BitmapData = null;
207 | public override function setPixels(pixels:Bytes) {
208 | if (_hasSize == false) {
209 | return super.setPixels(pixels);
210 | }
211 |
212 | if (_bitmap == null) {
213 | _bitmapData = new BitmapData(Std.int(_component.width), Std.int(_component.height), true, 0x00000000);
214 | _bitmap = new Bitmap(_bitmapData);
215 | _component.addChild(_bitmap);
216 | }
217 |
218 | // convert RGBA -> ARGB (well, actually BGRA for some reason)
219 | var bytesData = pixels.getData();
220 | var length:Int = pixels.length;
221 | var newPixels = Bytes.alloc(length);
222 | var i:Int = 0;
223 | while (i < length) {
224 | var r = Bytes.fastGet(bytesData, i + 0);
225 | var g = Bytes.fastGet(bytesData, i + 1);
226 | var b = Bytes.fastGet(bytesData, i + 2);
227 | var a = Bytes.fastGet(bytesData, i + 3);
228 | newPixels.set(i + 0, b);
229 | newPixels.set(i + 1, g);
230 | newPixels.set(i + 2, r);
231 | newPixels.set(i + 3, a);
232 | i += 4;
233 | }
234 |
235 | var byteArray = ByteArray.fromBytes(newPixels);
236 | _bitmapData.setPixels(new Rectangle(0, 0, _bitmapData.width, _bitmapData.height), byteArray);
237 | }
238 |
239 | public override function resize(width:Null, height:Null) {
240 | if (width > 0 && height > 0) {
241 | if (_hasSize == false) {
242 | _hasSize = true;
243 | replayDrawCommands();
244 | }
245 | }
246 | }
247 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/ComponentImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import haxe.ui.backend.openfl.EventMapper;
4 | import haxe.ui.backend.openfl.FilterConverter;
5 | import haxe.ui.backend.openfl.OpenFLStyleHelper;
6 | import haxe.ui.core.Component;
7 | import haxe.ui.core.ImageDisplay;
8 | import haxe.ui.core.Screen;
9 | import haxe.ui.core.TextDisplay;
10 | import haxe.ui.core.TextInput;
11 | import haxe.ui.events.KeyboardEvent;
12 | import haxe.ui.events.MouseEvent;
13 | import haxe.ui.events.UIEvent;
14 | import haxe.ui.focus.FocusManager;
15 | import haxe.ui.geom.Point;
16 | import haxe.ui.geom.Rectangle;
17 | import haxe.ui.styles.Style;
18 | import openfl.display.DisplayObjectContainer;
19 | import openfl.display.Sprite;
20 | import openfl.events.Event;
21 |
22 | class ComponentImpl extends ComponentBase {
23 | private var _eventMap:MapVoid>;
24 |
25 | public function new() {
26 | super();
27 | tabChildren = false;
28 | doubleClickEnabled = true;
29 | #if flash
30 | focusRect = false;
31 | #end
32 | _eventMap = new MapVoid>();
33 |
34 | #if mobile
35 | cast(this, Component).addClass(":mobile");
36 | #end
37 |
38 | addEventListener(Event.ADDED_TO_STAGE, onAddedToStage, false, 0, true);
39 | addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage, false, 0, true);
40 | }
41 |
42 | @:access(haxe.ui.backend.ScreenImpl)
43 | private function onAddedToStage(event:Event) {
44 | removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
45 | var component:Component = cast(this, Component);
46 | if (component.parentComponent == null && Screen.instance.rootComponents.indexOf(component) == -1) {
47 | this.scaleX = Toolkit.scaleX;
48 | this.scaleY = Toolkit.scaleY;
49 | Screen.instance.rootComponents.push(component);
50 | FocusManager.instance.pushView(component);
51 | Screen.instance.onContainerResize(null);
52 | }
53 | recursiveReady();
54 | }
55 |
56 | @:access(haxe.ui.backend.ScreenImpl)
57 | private function onRemovedFromStage(event:Event) {
58 | removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
59 | var component:Component = cast(this, Component);
60 | if (component.parentComponent == null && Screen.instance.rootComponents.indexOf(component) != -1) {
61 | Screen.instance.rootComponents.remove(component);
62 | FocusManager.instance.removeView(component);
63 | }
64 | }
65 |
66 | private function recursiveReady() {
67 | var component:Component = cast(this, Component);
68 | var isReady = component.isReady;
69 | component.ready();
70 | if (isReady == false) {
71 | component.syncComponentValidation();
72 | }
73 | for (child in component.childComponents) {
74 | child.recursiveReady();
75 | }
76 | }
77 |
78 | private override function handlePosition(left:Null, top:Null, style:Style):Void {
79 | if (left != null) {
80 | this.x = Math.fround(left);
81 | }
82 | if (top != null) {
83 | this.y = Math.fround(top);
84 | }
85 | }
86 |
87 | public var styleable:Bool = true;
88 | private override function handleSize(width:Null, height:Null, style:Style) {
89 | if (width == null || height == null || width <= 0 || height <= 0) {
90 | return;
91 | }
92 |
93 | if (styleable == true) {
94 | OpenFLStyleHelper.paintStyleSection(graphics, style, Math.fround(width), Math.fround(height));
95 | }
96 | }
97 |
98 | private override function handleClipRect(value:Rectangle):Void {
99 | if (value == null) {
100 | this.scrollRect = null;
101 | } else {
102 | this.scrollRect = new openfl.geom.Rectangle(Math.fround(value.left),
103 | Math.fround(value.top),
104 | Math.fround(value.width),
105 | Math.fround(value.height));
106 | }
107 | }
108 |
109 | //***********************************************************************************************************
110 | // Text related
111 | //***********************************************************************************************************
112 | public override function createTextDisplay(text:String = null):TextDisplay {
113 | if (_textDisplay == null) {
114 | super.createTextDisplay(text);
115 | addChild(_textDisplay.textField);
116 | }
117 |
118 | return _textDisplay;
119 | }
120 |
121 | public override function createTextInput(text:String = null):TextInput {
122 | if (_textInput == null) {
123 | super.createTextInput(text);
124 | addChild(_textInput.textField);
125 | }
126 | return _textInput;
127 | }
128 |
129 | //***********************************************************************************************************
130 | // Image related
131 | //***********************************************************************************************************
132 | public override function createImageDisplay():ImageDisplay {
133 | if (_imageDisplay == null) {
134 | super.createImageDisplay();
135 | addChild(_imageDisplay.sprite);
136 | }
137 | return _imageDisplay;
138 | }
139 |
140 | public override function removeImageDisplay():Void {
141 | if (_imageDisplay != null) {
142 | if (contains(_imageDisplay.sprite) == true) {
143 | removeChild(_imageDisplay.sprite);
144 | }
145 | _imageDisplay.dispose();
146 | _imageDisplay = null;
147 | }
148 | }
149 |
150 | //***********************************************************************************************************
151 | // Display tree
152 | //***********************************************************************************************************
153 | private override function handleAddComponent(child:Component):Component {
154 | addChild(child);
155 | return child;
156 | }
157 |
158 | private override function handleAddComponentAt(child:Component, index:Int):Component {
159 | addChildAt(child, index);
160 | return child;
161 | }
162 |
163 | private override function handleRemoveComponent(child:Component, dispose:Bool = true):Component {
164 | if (contains(child)) {
165 | removeChild(child);
166 | }
167 | return child;
168 | }
169 |
170 | private override function handleRemoveComponentAt(index:Int, dispose:Bool = true):Component {
171 | removeChildAt(index);
172 | return null;
173 | }
174 |
175 | private override function handleSetComponentIndex(child:Component, index:Int) {
176 | setChildIndex(child, index);
177 | }
178 |
179 | private override function applyStyle(style:Style) {
180 | var useHandCursor = false;
181 | if (style.cursor != null && style.cursor == "pointer") {
182 | useHandCursor = true;
183 | }
184 | applyUseHandCursor(useHandCursor);
185 |
186 | if (_imageDisplay != null) {
187 | _imageDisplay.applyStyle(style);
188 | }
189 |
190 | if (style.filter != null && style.filter.length > 0) {
191 | var array = [];
192 | for (fa in style.filter) {
193 | var f = FilterConverter.convertFilter(fa);
194 | if (f != null) {
195 | array.push(f);
196 | }
197 | }
198 | this.filters = array;
199 | } else {
200 | this.filters = null;
201 | }
202 |
203 | if (style.hidden != null) {
204 | this.visible = !style.hidden;
205 | }
206 |
207 | if (style.opacity != null) {
208 | this.alpha = style.opacity;
209 | }
210 | }
211 |
212 | private function applyUseHandCursor(use:Bool) {
213 | this.buttonMode = use;
214 | this.useHandCursor = use;
215 | if (hasImageDisplay()) {
216 | getImageDisplay().sprite.buttonMode = use;
217 | getImageDisplay().sprite.useHandCursor = use;
218 | }
219 | for (n in 0...this.numChildren) {
220 | var c = this.getChildAt(n);
221 | if ((c is Sprite)) {
222 | var s = cast(c, Sprite);
223 | s.buttonMode = use;
224 | s.useHandCursor = use;
225 | }
226 | }
227 | }
228 |
229 | #if flash override #else override #end
230 | private function set_visible(value:Bool): #if flash Bool #else Bool #end {
231 | #if flash
232 | super.visible = value;
233 | #else
234 | var v = super.set_visible(value);
235 | #end
236 | cast(this, Component).hidden = !value;
237 | #if !flash return v; #else return value; #end
238 | }
239 |
240 | private override function handleVisibility(show:Bool):Void {
241 | if (show != super.visible) {
242 | super.visible = show;
243 | }
244 | }
245 |
246 | private var _componentOffset:Point = new Point(0, 0);
247 | private override function getComponentOffset():Point {
248 | var p:DisplayObjectContainer = this;
249 | var s:DisplayObjectContainer = null;
250 | while (p != null) {
251 | if ((p is ComponentImpl) == false) {
252 | s = p;
253 | break;
254 | }
255 | p = p.parent;
256 | }
257 | if (s == null) {
258 | _componentOffset.x = 0;
259 | _componentOffset.y = 0;
260 | } else {
261 | _componentOffset.x = s.x;
262 | _componentOffset.y = s.y;
263 | }
264 | return _componentOffset;
265 | }
266 |
267 | private override function handleFrameworkProperty(id:String, value:Any) {
268 | switch (id) {
269 | case "allowMouseInteraction":
270 | if (value == true) {
271 | this.mouseEnabled = true;
272 | if (this.hasImageDisplay()) {
273 | this.getImageDisplay().sprite.mouseEnabled = true;
274 | }
275 | } else {
276 | this.mouseEnabled = false;
277 | if (this.hasImageDisplay()) {
278 | this.getImageDisplay().sprite.mouseEnabled = false;
279 | }
280 | }
281 | }
282 | }
283 |
284 | //***********************************************************************************************************
285 | // Events
286 | //***********************************************************************************************************
287 | private override function mapEvent(type:String, listener:UIEvent->Void) {
288 | switch (type) {
289 | case MouseEvent.MOUSE_MOVE | MouseEvent.MOUSE_OVER | MouseEvent.MOUSE_OUT
290 | | MouseEvent.MOUSE_DOWN | MouseEvent.MOUSE_UP | MouseEvent.MOUSE_WHEEL
291 | | MouseEvent.CLICK | MouseEvent.DBL_CLICK | MouseEvent.RIGHT_CLICK
292 | | MouseEvent.RIGHT_MOUSE_DOWN | MouseEvent.RIGHT_MOUSE_UP:
293 | if (_eventMap.exists(type) == false) {
294 | _eventMap.set(type, listener);
295 | addEventListener(EventMapper.HAXEUI_TO_OPENFL.get(type), __onMouseEvent, false, 0, true);
296 | }
297 |
298 | case KeyboardEvent.KEY_DOWN | KeyboardEvent.KEY_UP:
299 | if (_eventMap.exists(type) == false) {
300 | _eventMap.set(type, listener);
301 | addEventListener(EventMapper.HAXEUI_TO_OPENFL.get(type), __onKeyboardEvent, false, 0, true);
302 | }
303 | }
304 | }
305 |
306 | private override function unmapEvent(type:String, listener:UIEvent->Void) {
307 | switch (type) {
308 | case MouseEvent.MOUSE_MOVE | MouseEvent.MOUSE_OVER | MouseEvent.MOUSE_OUT
309 | | MouseEvent.MOUSE_DOWN | MouseEvent.MOUSE_UP | MouseEvent.MOUSE_WHEEL
310 | | MouseEvent.CLICK | MouseEvent.DBL_CLICK | MouseEvent.RIGHT_CLICK
311 | | MouseEvent.RIGHT_MOUSE_DOWN | MouseEvent.RIGHT_MOUSE_UP:
312 | _eventMap.remove(type);
313 | removeEventListener(EventMapper.HAXEUI_TO_OPENFL.get(type), __onMouseEvent);
314 |
315 | case KeyboardEvent.KEY_DOWN | KeyboardEvent.KEY_UP:
316 | _eventMap.remove(type);
317 | removeEventListener(EventMapper.HAXEUI_TO_OPENFL.get(type), __onKeyboardEvent);
318 |
319 | case UIEvent.CHANGE:
320 | _eventMap.remove(type);
321 | if (hasTextInput() == true) {
322 | getTextInput().textField.removeEventListener(Event.CHANGE, __onTextInputChange);
323 | }
324 | }
325 | }
326 |
327 | //***********************************************************************************************************
328 | // Event handlers
329 | //***********************************************************************************************************
330 | private function __onMouseEvent(event:openfl.events.MouseEvent) {
331 | var type:String = EventMapper.OPENFL_TO_HAXEUI.get(event.type);
332 | if (type != null) {
333 | var fn = _eventMap.get(type);
334 | if (fn != null) {
335 | var mouseEvent = new MouseEvent(type);
336 | mouseEvent._originalEvent = event;
337 | mouseEvent.screenX = event.stageX / Toolkit.scaleX;
338 | mouseEvent.screenY = event.stageY / Toolkit.scaleY;
339 | mouseEvent.buttonDown = event.buttonDown;
340 | mouseEvent.delta = event.delta;
341 | mouseEvent.ctrlKey = event.ctrlKey;
342 | mouseEvent.shiftKey = event.shiftKey;
343 | fn(mouseEvent);
344 | }
345 | }
346 | }
347 |
348 | private function __onKeyboardEvent(event:openfl.events.KeyboardEvent) {
349 | var type:String = EventMapper.OPENFL_TO_HAXEUI.get(event.type);
350 | if (type != null) {
351 | var fn = _eventMap.get(type);
352 | if (fn != null) {
353 | var keyboardEvent = new KeyboardEvent(type);
354 | keyboardEvent._originalEvent = event;
355 | keyboardEvent.keyCode = event.keyCode;
356 | keyboardEvent.altKey = event.altKey;
357 | keyboardEvent.ctrlKey = event.ctrlKey;
358 | keyboardEvent.shiftKey = event.shiftKey;
359 | fn(keyboardEvent);
360 | }
361 | }
362 | }
363 |
364 | private function __onTextInputChange(event:Event) {
365 | var fn:UIEvent->Void = _eventMap.get(UIEvent.CHANGE);
366 | if (fn != null) {
367 | fn(new UIEvent(UIEvent.CHANGE));
368 | }
369 | }
370 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/ComponentSurface.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | typedef ComponentSurface = openfl.display.Sprite;
--------------------------------------------------------------------------------
/haxe/ui/backend/EventImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import haxe.ui.events.UIEvent;
4 | import openfl.events.Event;
5 |
6 | @:allow(haxe.ui.backend.ScreenImpl)
7 | @:allow(haxe.ui.backend.ComponentImpl)
8 | class EventImpl extends EventBase {
9 | private var _originalEvent:Event;
10 |
11 | public override function cancel() {
12 | if (_originalEvent != null) {
13 | _originalEvent.preventDefault();
14 | _originalEvent.stopImmediatePropagation();
15 | _originalEvent.stopPropagation();
16 | }
17 | }
18 |
19 | private override function postClone(event:UIEvent) {
20 | event._originalEvent = this._originalEvent;
21 | }
22 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/FocusManagerImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import haxe.ui.core.Component;
4 | import openfl.Lib;
5 |
6 | class FocusManagerImpl extends FocusManagerBase {
7 | private override function applyFocus(c:Component) {
8 | super.applyFocus(c);
9 | if (c != null && c.hasTextInput()) {
10 | Lib.current.stage.focus = c.getTextInput().textField;
11 | } else {
12 | Lib.current.stage.focus = c;
13 | }
14 | }
15 |
16 | private override function unapplyFocus(c:Component) {
17 | super.unapplyFocus(c);
18 | Lib.current.stage.focus = null;
19 | }
20 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/FontData.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | typedef FontData = String;
--------------------------------------------------------------------------------
/haxe/ui/backend/ImageData.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | typedef ImageData = openfl.display.BitmapData;
4 |
--------------------------------------------------------------------------------
/haxe/ui/backend/ImageDisplayImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import haxe.ui.geom.Rectangle;
4 | import haxe.ui.styles.Style;
5 | import openfl.display.Bitmap;
6 | import openfl.display.BitmapData;
7 | import openfl.display.Sprite;
8 |
9 | class ImageDisplayImpl extends ImageBase {
10 | public var sprite:Sprite;
11 |
12 | private var _bmp:Bitmap;
13 |
14 | public function new() {
15 | super();
16 | sprite = new Sprite();
17 | sprite.mouseEnabled = true;
18 | }
19 |
20 | public override function dispose():Void {
21 | if (_bmp != null) {
22 | //_bmp.bitmapData.dispose();
23 | sprite.removeChild(_bmp);
24 | _bmp = null;
25 | }
26 | super.dispose();
27 | }
28 |
29 | private inline function containsBitmapDataInfo():Bool {
30 | return _imageInfo != null && _imageInfo.data != null && (_imageInfo.data is BitmapData);
31 | }
32 |
33 | #if svg
34 |
35 | private inline function containsSVGInfo():Bool {
36 | return _imageInfo != null && _imageInfo.svg != null && (_imageInfo.svg is format.SVG);
37 | }
38 |
39 | private function renderSVG():Void {
40 | sprite.graphics.clear();
41 | if(_imageInfo != null && _imageWidth > 0 && _imageHeight > 0) {
42 | var svg:format.SVG = cast _imageInfo.svg;
43 | svg.render(sprite.graphics, 0, 0, Std.int(_imageWidth), Std.int(_imageHeight));
44 | }
45 | }
46 |
47 | #end
48 |
49 | //***********************************************************************************************************
50 | // Validation functions
51 | //***********************************************************************************************************
52 |
53 | private override function validateData() {
54 | if (_imageInfo != null) {
55 | if(containsBitmapDataInfo()) {
56 | if (_bmp == null) {
57 | _bmp = new Bitmap(_imageInfo.data);
58 | sprite.addChild(_bmp);
59 | } else {
60 | _bmp.bitmapData = _imageInfo.data;
61 | }
62 | _imageWidth = _bmp.width;
63 | _imageHeight = _bmp.height;
64 | _bmp.smoothing = true;
65 | }
66 | #if svg
67 | else if(containsSVGInfo()) {
68 | var svg:format.SVG = cast _imageInfo.svg;
69 | _imageWidth = svg.data.width;
70 | _imageHeight = svg.data.height;
71 | renderSVG();
72 | }
73 | #end
74 | } else {
75 | if (_bmp != null && sprite.contains(_bmp) == true) {
76 | sprite.removeChild(_bmp);
77 | //_bmp.bitmapData.dispose();
78 | _bmp = null;
79 | } else {
80 | sprite.graphics.clear();
81 | }
82 |
83 | _imageWidth = 0;
84 | _imageHeight = 0;
85 | }
86 | }
87 |
88 | private override function validatePosition() {
89 | if (sprite.x != _left) {
90 | sprite.x = _left;
91 | }
92 |
93 | if (sprite.y != _top) {
94 | sprite.y = _top;
95 | }
96 | }
97 |
98 | private override function validateDisplay() {
99 | if(containsBitmapDataInfo()) {
100 | var scaleX:Float = _imageWidth / _bmp.bitmapData.width;
101 | if (_bmp.scaleX != scaleX) {
102 | _bmp.scaleX = scaleX;
103 | }
104 |
105 | var scaleY:Float = _imageHeight / _bmp.bitmapData.height;
106 | if (_bmp.scaleY != scaleY) {
107 | _bmp.scaleY = scaleY;
108 | }
109 | }
110 | #if svg
111 | else if(containsSVGInfo()) {
112 | renderSVG();
113 | }
114 | #end
115 |
116 | if(_imageClipRect == null) {
117 | sprite.scrollRect = null;
118 | } else {
119 | sprite.scrollRect = new openfl.geom.Rectangle(-_left, -_top, Math.fround(_imageClipRect.width), Math.fround(_imageClipRect.height));
120 | sprite.x = _imageClipRect.left;
121 | sprite.y = _imageClipRect.top;
122 | }
123 | }
124 |
125 | public function applyStyle(style:Style) {
126 | if (style != null && _bmp != null) {
127 | if (style.imageRendering == "pixelated") {
128 | _bmp.smoothing = false;
129 | } else {
130 | _bmp.smoothing = true;
131 | }
132 | }
133 | }
134 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/ImageSurface.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | class ImageSurface {
4 | public function new() {
5 | }
6 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/OpenFileDialogImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 |
4 | #if !js
5 | import haxe.io.Bytes;
6 | import haxe.ui.containers.dialogs.Dialog.DialogButton;
7 | import haxe.ui.containers.dialogs.Dialogs.FileDialogExtensionInfo;
8 | import haxe.ui.containers.dialogs.Dialogs.SelectedFileInfo;
9 | import openfl.events.Event;
10 | import openfl.net.FileFilter;
11 | import openfl.net.FileReference;
12 | import openfl.net.FileReferenceList;
13 |
14 | using StringTools;
15 | #end
16 |
17 |
18 |
19 | @:access(openfl.net.FileReference)
20 | class OpenFileDialogImpl extends OpenFileDialogBase {
21 | #if js
22 |
23 | private var _fileSelector:haxe.ui.util.html5.FileSelector = new haxe.ui.util.html5.FileSelector();
24 |
25 | public override function show() {
26 | var readMode = haxe.ui.util.html5.FileSelector.ReadMode.None;
27 | if (options.readContents == true) {
28 | if (options.readAsBinary == false) {
29 | readMode = haxe.ui.util.html5.FileSelector.ReadMode.Text;
30 | } else {
31 | readMode = haxe.ui.util.html5.FileSelector.ReadMode.Binary;
32 | }
33 | }
34 | _fileSelector.selectFile(onFileSelected, readMode, options.multiple, options.extensions);
35 | }
36 |
37 | private function onFileSelected(cancelled:Bool, files:Array) {
38 | if (cancelled == false) {
39 | dialogConfirmed(files);
40 | } else {
41 | dialogCancelled();
42 | }
43 | }
44 |
45 | #else
46 |
47 | private var _fr:FileReferenceList = null;
48 | private var _refToInfo:Map;
49 | private var _infos:Array;
50 |
51 | public override function show() {
52 | var extensions = null;
53 | if (options != null) {
54 | extensions = options.extensions;
55 | }
56 |
57 | _refToInfo = new Map();
58 | _infos = [];
59 | _fr = new FileReferenceList();
60 | _fr.addEventListener(Event.SELECT, onSelect, false, 0, true);
61 | _fr.addEventListener(Event.CANCEL, onCancel, false, 0, true);
62 | _fr.browse(buildFileFilters(extensions));
63 | }
64 |
65 | private function buildFileFilters(extensions:Array):Array {
66 | if (extensions == null) {
67 | return null;
68 | }
69 |
70 | var fileFilters:Array = [];
71 | for (extension in extensions) {
72 | var extensionList = extension.extension.split(",");
73 | var fileFilterExtensions = "";
74 | for (extensionItem in extensionList) {
75 | extensionItem = extensionItem.trim();
76 | if (extensionItem.length == 0) {
77 | continue;
78 | }
79 |
80 | fileFilterExtensions += "*." + extensionItem + ";";
81 | }
82 | if (fileFilterExtensions.length != 0) {
83 | fileFilters.push(new FileFilter(extension.label, fileFilterExtensions));
84 | }
85 |
86 | }
87 | return fileFilters;
88 | }
89 |
90 | private function onSelect(e:Event) {
91 | var fileList:Array = _fr.fileList;
92 | destroyFileRef();
93 | var infos:Array = [];
94 | for (fileRef in fileList) {
95 | var info:SelectedFileInfo = {
96 | isBinary: false,
97 | name: fileRef.name,
98 | fullPath : fileRef.__path
99 | }
100 | if (options.readContents == true) {
101 | _refToInfo.set(fileRef, info);
102 | }
103 | infos.push(info);
104 | }
105 |
106 | if (options.readContents == false) {
107 | dialogConfirmed(infos);
108 | } else {
109 | for (fileRef in _refToInfo.keys()) {
110 | fileRef.addEventListener(Event.COMPLETE, onFileComplete, false, 0, true);
111 | fileRef.load();
112 | }
113 | }
114 |
115 | }
116 |
117 | private function onFileComplete(e:Event) {
118 | var fileRef = cast(e.target, FileReference);
119 | fileRef.removeEventListener(Event.COMPLETE, onFileComplete);
120 | var info = _refToInfo.get(fileRef);
121 | if (options.readAsBinary == true) {
122 | info.isBinary = true;
123 | info.bytes = Bytes.ofData(fileRef.data);
124 | } else {
125 | info.isBinary = false;
126 | info.text = fileRef.data.toString();
127 | }
128 |
129 | _infos.push(info);
130 | _refToInfo.remove(fileRef);
131 | if (isMapEmpty()) {
132 | var copy = _infos.copy();
133 | _infos = null;
134 | _refToInfo = null;
135 | dialogConfirmed(copy);
136 | }
137 | }
138 |
139 | private function isMapEmpty() {
140 | if (_refToInfo == null) {
141 | return true;
142 | }
143 |
144 | var n = 0;
145 | for (_ in _refToInfo.keys()) {
146 | n++;
147 | }
148 |
149 | return (n == 0);
150 | }
151 |
152 | private function onCancel(e:Event) {
153 | destroyFileRef();
154 | dialogCancelled();
155 | }
156 |
157 | private function destroyFileRef() {
158 | if (_fr == null) {
159 | return;
160 | }
161 |
162 | _fr.removeEventListener(Event.SELECT, onSelect);
163 | _fr.removeEventListener(Event.CANCEL, onCancel);
164 | _fr = null;
165 | }
166 |
167 | #end
168 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/PlatformImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import openfl.system.Capabilities;
4 |
5 | class PlatformImpl extends PlatformBase {
6 | public override function getSystemLocale():String {
7 | return Capabilities.language;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/haxe/ui/backend/SaveFileDialogImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | #if !js
4 | import haxe.ui.containers.dialogs.Dialogs.FileDialogExtensionInfo;
5 | import haxe.ui.containers.dialogs.Dialogs.SelectedFileInfo;
6 | import openfl.events.Event;
7 | import openfl.filesystem.File;
8 | import openfl.net.FileFilter;
9 | import openfl.net.FileReference;
10 | import openfl.utils.ByteArray;
11 |
12 | using StringTools;
13 | #end
14 |
15 | class SaveFileDialogImpl extends SaveFileDialogBase {
16 | #if js
17 |
18 | private var _fileSaver:haxe.ui.util.html5.FileSaver = new haxe.ui.util.html5.FileSaver();
19 |
20 | public override function show() {
21 | if (fileInfo == null || (fileInfo.text == null && fileInfo.bytes == null)) {
22 | throw "Nothing to write";
23 | }
24 |
25 | if (fileInfo.text != null) {
26 | _fileSaver.saveText(fileInfo.name, fileInfo.text, onSaveResult);
27 | } else if (fileInfo.bytes != null) {
28 | _fileSaver.saveBinary(fileInfo.name, fileInfo.bytes, onSaveResult);
29 | }
30 | }
31 |
32 | private function onSaveResult(r:Bool) {
33 | if (r == true) {
34 | dialogConfirmed();
35 | } else {
36 | dialogCancelled();
37 | }
38 | }
39 |
40 | #else
41 |
42 | private var _file:File;
43 |
44 | public override function show() {
45 | var extensions = null;
46 | if (options != null) {
47 | extensions = options.extensions;
48 | }
49 | var data:Dynamic = null;
50 | var defaultFilename = null;
51 | if (fileInfo != null) {
52 | defaultFilename = fileInfo.name;
53 | if (fileInfo.text != null) {
54 | data = fileInfo.text;
55 | } else if (fileInfo.bytes != null) {
56 | data = ByteArray.fromBytes(fileInfo.bytes);
57 | }
58 | }
59 |
60 | _file = new File();
61 | _file.addEventListener(Event.SELECT, onSelect, false, 0, true);
62 | _file.addEventListener(Event.CANCEL, onCancel, false, 0, true);
63 | if (data != null) {
64 | _file.save(data, defaultFilename);
65 | } else {
66 | _file.browseForSave(options.title);
67 | }
68 | }
69 |
70 | private function buildFileFilters(extensions:Array):Array {
71 | if (extensions == null) {
72 | return null;
73 | }
74 |
75 | var fileFilters:Array = [];
76 | for (extension in extensions) {
77 | var extensionList = extension.extension.split(",");
78 | var fileFilterExtensions = "";
79 | for (extensionItem in extensionList) {
80 | extensionItem = extensionItem.trim();
81 | if (extensionItem.length == 0) {
82 | continue;
83 | }
84 |
85 | fileFilterExtensions += "*." + extensionItem + ";";
86 | }
87 | if (fileFilterExtensions.length != 0) {
88 | fileFilters.push(new FileFilter(extension.label, fileFilterExtensions));
89 | }
90 |
91 | }
92 | return fileFilters;
93 | }
94 |
95 | private function onSelect(e:Event) {
96 | var selectedFileInfo:SelectedFileInfo = {
97 | name: _file.name,
98 | fullPath: _file.nativePath
99 | }
100 | destroyFileRef();
101 | dialogConfirmed(selectedFileInfo);
102 | }
103 |
104 | private function onCancel(e:Event) {
105 | destroyFileRef();
106 | dialogCancelled();
107 | }
108 |
109 | private function destroyFileRef() {
110 | if (_file == null) {
111 | return;
112 | }
113 |
114 | _file.removeEventListener(Event.SELECT, onSelect);
115 | _file.removeEventListener(Event.CANCEL, onCancel);
116 | _file = null;
117 | }
118 |
119 | #end
120 | }
121 |
--------------------------------------------------------------------------------
/haxe/ui/backend/ScreenImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import haxe.ui.Toolkit;
4 | import haxe.ui.backend.openfl.EventMapper;
5 | import haxe.ui.core.Component;
6 | import haxe.ui.events.KeyboardEvent;
7 | import haxe.ui.events.MouseEvent;
8 | import haxe.ui.events.UIEvent;
9 | import lime.system.System;
10 | import openfl.Lib;
11 | import openfl.display.DisplayObjectContainer;
12 | import openfl.display.StageAlign;
13 | import openfl.display.StageQuality;
14 | import openfl.display.StageScaleMode;
15 |
16 | class ScreenImpl extends ScreenBase {
17 | private var _mapping:MapVoid>;
18 |
19 | public function new() {
20 | _mapping = new MapVoid>();
21 | }
22 |
23 | private override function get_width():Float {
24 | if (container == Lib.current.stage) {
25 | return Lib.current.stage.stageWidth / Toolkit.scaleX;
26 | }
27 | return container.width / Toolkit.scaleX;
28 | }
29 |
30 | private override function get_height():Float {
31 | if (container == Lib.current.stage) {
32 | return Lib.current.stage.stageHeight / Toolkit.scaleY;
33 | }
34 | return container.height / Toolkit.scaleY;
35 | }
36 |
37 | private override function get_dpi():Float {
38 | return System.getDisplay(0).dpi;
39 | }
40 |
41 | private override function set_title(s:String):String {
42 | #if (flash || android || ios )
43 | trace("WARNING: this platform doesnt support dynamic titles");
44 | #end
45 | Lib.current.stage.window.title = s;
46 | return s;
47 | }
48 | private override function get_title():String {
49 | #if (flash || android || ios )
50 | trace("WARNING: this platform doesnt support dynamic titles");
51 | #end
52 | return Lib.current.stage.window.title;
53 | }
54 |
55 | public override function addComponent(component:Component):Component {
56 | component.scaleX = Toolkit.scaleX;
57 | component.scaleY = Toolkit.scaleY;
58 | if (rootComponents.indexOf(component) == -1) {
59 | rootComponents.push(component);
60 | container.addChild(component);
61 | onContainerResize(null);
62 | }
63 | return component;
64 | }
65 |
66 | public override function removeComponent(component:Component, dispose:Bool = true, invalidate:Bool = true):Component {
67 | rootComponents.remove(component);
68 | container.removeChild(component);
69 | return component;
70 | }
71 |
72 | private override function handleSetComponentIndex(child:Component, index:Int) {
73 | rootComponents.remove(child);
74 | rootComponents.insert(index, child);
75 |
76 | var offset = 0;
77 | for (i in 0...container.numChildren) {
78 | var c = container.getChildAt(i);
79 | if ((c is Component)) {
80 | offset = i;
81 | break;
82 | }
83 | }
84 |
85 | container.setChildIndex(child, index + offset);
86 | }
87 |
88 | private function onContainerResize(event:openfl.events.Event) {
89 | resizeRootComponents();
90 |
91 | var fn = _mapping.get(UIEvent.RESIZE);
92 | if (fn != null) {
93 | var uiEvent = new UIEvent(UIEvent.RESIZE);
94 | fn(uiEvent);
95 | }
96 | }
97 |
98 | private var _containerReady:Bool = false;
99 | private var container(get, null):DisplayObjectContainer;
100 | private function get_container():DisplayObjectContainer {
101 | var c = null;
102 | if (options == null || options.container == null) {
103 | c = Lib.current.stage;
104 | } else {
105 | c = options.container;
106 | }
107 |
108 | if (_containerReady == false) {
109 | c.stage.quality = StageQuality.BEST;
110 | c.scaleMode = StageScaleMode.NO_SCALE;
111 | c.align = StageAlign.TOP_LEFT;
112 | c.addEventListener(openfl.events.Event.RESIZE, onContainerResize, false, 0, true);
113 | _containerReady = true;
114 | }
115 |
116 | return c;
117 | }
118 |
119 | //***********************************************************************************************************
120 | // Events
121 | //***********************************************************************************************************
122 | private override function supportsEvent(type:String):Bool {
123 | if (type == UIEvent.RESIZE) {
124 | return true;
125 | }
126 | return EventMapper.HAXEUI_TO_OPENFL.get(type) != null;
127 | }
128 |
129 | private override function mapEvent(type:String, listener:UIEvent->Void) {
130 | switch (type) {
131 | case MouseEvent.MOUSE_MOVE | MouseEvent.MOUSE_OVER | MouseEvent.MOUSE_OUT
132 | | MouseEvent.MOUSE_DOWN | MouseEvent.MOUSE_UP | MouseEvent.CLICK | MouseEvent.DBL_CLICK
133 | | MouseEvent.RIGHT_MOUSE_DOWN | MouseEvent.RIGHT_MOUSE_UP | MouseEvent.RIGHT_CLICK:
134 | if (_mapping.exists(type) == false) {
135 | _mapping.set(type, listener);
136 | Lib.current.stage.addEventListener(EventMapper.HAXEUI_TO_OPENFL.get(type), __onMouseEvent, false, 0, true);
137 | }
138 |
139 | case KeyboardEvent.KEY_DOWN | KeyboardEvent.KEY_UP:
140 | if (_mapping.exists(type) == false) {
141 | _mapping.set(type, listener);
142 | Lib.current.stage.addEventListener(EventMapper.HAXEUI_TO_OPENFL.get(type), __onKeyEvent, false, 0, true);
143 | }
144 |
145 | case UIEvent.RESIZE:
146 | if (_mapping.exists(type) == false) {
147 | _mapping.set(type, listener);
148 | }
149 | }
150 | }
151 |
152 | private override function unmapEvent(type:String, listener:UIEvent->Void) {
153 | switch (type) {
154 | case MouseEvent.MOUSE_MOVE | MouseEvent.MOUSE_OVER | MouseEvent.MOUSE_OUT
155 | | MouseEvent.MOUSE_DOWN | MouseEvent.MOUSE_UP | MouseEvent.CLICK | MouseEvent.DBL_CLICK
156 | | MouseEvent.RIGHT_MOUSE_DOWN | MouseEvent.RIGHT_MOUSE_UP | MouseEvent.RIGHT_CLICK:
157 | _mapping.remove(type);
158 | Lib.current.stage.removeEventListener(EventMapper.HAXEUI_TO_OPENFL.get(type), __onMouseEvent);
159 |
160 | case KeyboardEvent.KEY_DOWN | KeyboardEvent.KEY_UP:
161 | _mapping.remove(type);
162 | Lib.current.stage.removeEventListener(EventMapper.HAXEUI_TO_OPENFL.get(type), __onKeyEvent);
163 |
164 | case UIEvent.RESIZE:
165 | _mapping.remove(type);
166 | }
167 | }
168 |
169 | private function __onMouseEvent(event:openfl.events.MouseEvent) {
170 | var type:String = EventMapper.OPENFL_TO_HAXEUI.get(event.type);
171 | if (type != null) {
172 | var fn = _mapping.get(type);
173 | if (fn != null) {
174 | var mouseEvent = new MouseEvent(type);
175 | mouseEvent._originalEvent = event;
176 | mouseEvent.screenX = event.stageX / Toolkit.scaleX;
177 | mouseEvent.screenY = event.stageY / Toolkit.scaleY;
178 | mouseEvent.buttonDown = event.buttonDown;
179 | mouseEvent.ctrlKey = event.ctrlKey;
180 | mouseEvent.shiftKey = event.shiftKey;
181 | fn(mouseEvent);
182 | }
183 | }
184 | }
185 |
186 | private function __onKeyEvent(event:openfl.events.KeyboardEvent) {
187 | var type:String = EventMapper.OPENFL_TO_HAXEUI.get(event.type);
188 | if (type != null) {
189 | var fn = _mapping.get(type);
190 | if (fn != null) {
191 | var keyboardEvent = new KeyboardEvent(type);
192 | keyboardEvent._originalEvent = event;
193 | keyboardEvent.keyCode = event.keyCode;
194 | keyboardEvent.ctrlKey = event.ctrlKey;
195 | keyboardEvent.shiftKey = event.shiftKey;
196 | fn(keyboardEvent);
197 | }
198 | }
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/haxe/ui/backend/TextDisplayImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import openfl.text.TextField;
4 | import openfl.text.TextFieldAutoSize;
5 | import openfl.text.TextFieldType;
6 | import openfl.text.TextFormat;
7 |
8 | #if cache_text_metrics
9 | typedef TextMetricsCache = {
10 | var text:String;
11 | var width:Float;
12 | var textWidth:Float;
13 | var textHeight:Float;
14 | }
15 | #end
16 |
17 | class TextDisplayImpl extends TextBase {
18 | private var PADDING_X:Int = 4;
19 | private var PADDING_Y:Int = 0;
20 |
21 | public var textField:TextField;
22 |
23 | private var _resetHtmlText:Bool = true;
24 |
25 | public function new() {
26 | super();
27 |
28 | textField = createTextField();
29 |
30 | _text = "";
31 | }
32 |
33 | private function createTextField() {
34 | var tf:TextField = new TextField();
35 | tf.type = TextFieldType.DYNAMIC;
36 | tf.selectable = false;
37 | tf.mouseEnabled = false;
38 | tf.autoSize = TextFieldAutoSize.LEFT;
39 |
40 | #if flash
41 | var format:TextFormat = tf.getTextFormat();
42 | format.font = "_sans";
43 | format.size = 13;
44 | tf.defaultTextFormat = format;
45 | #end
46 |
47 | #if cache_text_metrics
48 | var format:TextFormat = tf.getTextFormat();
49 | format.font = "_sans";
50 | format.size = 13;
51 | tf.defaultTextFormat = format;
52 | tf.wordWrap = true;
53 | tf.multiline = true;
54 | #end
55 |
56 | return tf;
57 | }
58 |
59 | //***********************************************************************************************************
60 | // Validation functions
61 | //***********************************************************************************************************
62 |
63 | private override function validateData() {
64 | if (_text != null) {
65 | if (_dataSource == null) {
66 | textField.text = normalizeText(_text);
67 | }
68 | } else if (_htmlText != null) {
69 | textField.htmlText = normalizeText(_htmlText);
70 | }
71 | }
72 |
73 | private override function validateStyle():Bool {
74 | var measureTextRequired:Bool = false;
75 |
76 | var format:TextFormat = textField.getTextFormat();
77 |
78 | if (_textStyle != null) {
79 | if (format.align != _textStyle.textAlign) {
80 | format.align = _textStyle.textAlign;
81 | }
82 |
83 | var fontSizeValue = Std.int(_textStyle.fontSize);
84 | if (_textStyle.fontSize == null) {
85 | fontSizeValue = 13;
86 | }
87 | if (format.size != fontSizeValue) {
88 | format.size = fontSizeValue;
89 | measureTextRequired = true;
90 | }
91 |
92 | if (_fontInfo != null && format.font != _fontInfo.data) {
93 | format.font = _fontInfo.data;
94 | measureTextRequired = true;
95 | }
96 |
97 | if (format.color != _textStyle.color) {
98 | format.color = _textStyle.color;
99 | }
100 |
101 | if (_textStyle.fontBold != null && format.bold != _textStyle.fontBold) {
102 | format.bold = _textStyle.fontBold;
103 | measureTextRequired = true;
104 | }
105 |
106 | if (_textStyle.fontItalic != null && format.italic != _textStyle.fontItalic) {
107 | format.italic = _textStyle.fontItalic;
108 | measureTextRequired = true;
109 | }
110 |
111 | if (_textStyle.fontUnderline != null && format.underline != _textStyle.fontUnderline) {
112 | format.underline = _textStyle.fontUnderline;
113 | measureTextRequired = true;
114 | }
115 | }
116 |
117 | textField.defaultTextFormat = format;
118 | #if flash
119 | textField.setTextFormat(format);
120 | #end
121 | if (textField.wordWrap != _displayData.wordWrap) {
122 | textField.wordWrap = _displayData.wordWrap;
123 | measureTextRequired = true;
124 | }
125 | if (_resetHtmlText == true && _htmlText != null) {
126 | textField.htmlText = normalizeText(_htmlText);
127 | }
128 |
129 | if (textField.multiline != _displayData.multiline) {
130 | textField.multiline = _displayData.multiline;
131 | measureTextRequired = true;
132 | }
133 |
134 | #if cache_text_metrics
135 | if (measureTextRequired) {
136 | _cachedMetrics = null;
137 | }
138 | #end
139 |
140 | return measureTextRequired;
141 | }
142 |
143 | private override function validatePosition() {
144 | _left = Math.round(_left);
145 | _top = Math.round(_top);
146 |
147 | #if html5
148 | textField.x = _left;
149 | textField.y = _top - 2;
150 | #elseif flash
151 | textField.x = _left - 2;
152 | textField.y = _top - 2;
153 | #else
154 | textField.x = _left - 1;
155 | textField.y = _top - 2;
156 | #end
157 | }
158 |
159 | private override function validateDisplay() {
160 | if (textField.width != _width) {
161 | textField.width = _width;
162 | }
163 |
164 | if (textField.height != _height) {
165 | #if flash
166 | textField.height = _height;
167 | //textField.height = _height + 4;
168 | #else
169 | textField.height = _height + 1;
170 | #end
171 | }
172 | }
173 |
174 | #if cache_text_metrics
175 | private var _cachedMetrics:TextMetricsCache = null;
176 | #end
177 | private override function measureText() {
178 | #if cache_text_metrics
179 | if (_cachedMetrics != null) {
180 | if (_cachedMetrics.width == _width && _cachedMetrics.text == _text) {
181 | _textWidth = _cachedMetrics.textWidth;
182 | _textHeight = _cachedMetrics.textHeight;
183 | return;
184 | }
185 | }
186 | #end
187 |
188 | if (_width > 0) {
189 | textField.width = _width;
190 | }
191 |
192 | #if !flash
193 | _textWidth = textField.textWidth + PADDING_X;
194 | //_textWidth = textField.textWidth + PADDING_X;
195 | #else
196 | _textWidth = textField.textWidth - 2;
197 | #end
198 |
199 | _textHeight = textField.textHeight;
200 | if (_textHeight == 0) {
201 | var tmpText:String = textField.text;
202 | textField.text = "|";
203 | _textHeight = textField.textHeight;
204 | textField.text = tmpText;
205 | }
206 |
207 | #if !flash
208 | //_textHeight += PADDING_Y;
209 | #else
210 | //_textHeight += 2;
211 | #end
212 |
213 | _textWidth = Math.round(_textWidth);
214 | if (_textWidth % 2 != 0) {
215 | _textWidth += 1;
216 | }
217 | _textHeight = Math.round(_textHeight);
218 | if (_textHeight % 2 == 0) {
219 | _textHeight += 1;
220 | }
221 |
222 | #if cache_text_metrics
223 | _cachedMetrics = {
224 | text: _text,
225 | width: _width,
226 | textWidth: _textWidth,
227 | textHeight: _textHeight
228 | }
229 | #end
230 | }
231 |
232 | private override function get_supportsHtml():Bool {
233 | return true;
234 | }
235 |
236 | private function normalizeText(text:String):String {
237 | text = StringTools.replace(text, "\\n", "\n");
238 | text = StringTools.replace(text, "
", "\n");
239 | return text;
240 | }
241 |
242 | private var _tempField:TextField = null;
243 | public override function measureTextWidth():Float {
244 | if (_tempField == null) {
245 | _tempField = new TextField();
246 | _tempField.type = TextFieldType.DYNAMIC;
247 | _tempField.selectable = false;
248 | _tempField.mouseEnabled = false;
249 | _tempField.autoSize = TextFieldAutoSize.LEFT;
250 | }
251 |
252 | _tempField.defaultTextFormat = textField.defaultTextFormat;
253 | _tempField.text = textField.text;
254 | return _tempField.textWidth + PADDING_X;
255 | }
256 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/TextInputImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import haxe.ui.data.DataSource;
4 | import haxe.ui.validation.InvalidationFlags;
5 | import openfl.events.Event;
6 | import openfl.text.TextField;
7 | import openfl.text.TextFieldAutoSize;
8 | import openfl.text.TextFieldType;
9 | import openfl.text.TextFormat;
10 |
11 | class TextInputImpl extends TextDisplayImpl {
12 | public function new() {
13 | super();
14 |
15 | _resetHtmlText = false;
16 |
17 | textField.addEventListener(Event.CHANGE, onChange, false, 0, true);
18 | textField.addEventListener(Event.SCROLL, onScroll, false, 0, true);
19 | _inputData.vscrollPageStep = 1;
20 | _inputData.vscrollNativeWheel = true;
21 | }
22 |
23 | private override function createTextField() {
24 | var tf:TextField = new TextField();
25 | tf.type = TextFieldType.INPUT;
26 | tf.selectable = true;
27 | tf.mouseEnabled = true;
28 | tf.autoSize = TextFieldAutoSize.NONE;
29 | tf.multiline = true;
30 | tf.wordWrap = true;
31 |
32 | #if flash
33 | var format:TextFormat = tf.getTextFormat();
34 | format.font = "_sans";
35 | format.size = 13;
36 | tf.defaultTextFormat = format;
37 | #end
38 |
39 | return tf;
40 | }
41 |
42 | public override function focus() {
43 | if (textField.stage != null) {
44 | textField.stage.focus = textField;
45 | }
46 | }
47 |
48 | public override function blur() {
49 | if (textField.stage != null) {
50 | textField.stage.focus = null;
51 | }
52 | }
53 |
54 | public override function dispose() {
55 | if (textField != null) {
56 | if (parentComponent != null) {
57 | parentComponent.removeChild(textField);
58 | }
59 | textField.removeEventListener(Event.CHANGE, onChange);
60 | textField.removeEventListener(Event.SCROLL, onScroll);
61 | textField = null;
62 | }
63 | super.dispose();
64 | }
65 |
66 | private override function set_dataSource(value:DataSource):DataSource {
67 | if (_dataSource != null) {
68 | _dataSource.onAdd = null;
69 | _dataSource.onChange = null;
70 | }
71 | _dataSource = value;
72 | if (_dataSource != null) {
73 | _dataSource.onAdd = onDataSourceAdd;
74 | _dataSource.onClear = onDataSourceClear;
75 | }
76 | return value;
77 | }
78 |
79 | private function onDataSourceAdd(s:String) {
80 | textField.appendText(s);
81 | parentComponent.text = textField.text;
82 | measureText();
83 | parentComponent.syncComponentValidation();
84 | }
85 |
86 | private function onDataSourceClear() {
87 | textField.text = "";
88 | parentComponent.text = "";
89 | measureText();
90 | parentComponent.syncComponentValidation();
91 | }
92 |
93 | private override function get_caretIndex():Int {
94 | return textField.caretIndex;
95 | }
96 | private override function set_caretIndex(value:Int):Int {
97 | textField.setSelection(value, value);
98 | return value;
99 | }
100 |
101 | //***********************************************************************************************************
102 | // Validation functions
103 | //***********************************************************************************************************
104 | private override function validateData() {
105 | textField.removeEventListener(Event.SCROLL, onScroll);
106 |
107 | super.validateData();
108 |
109 | var changed = false;
110 | var hscrollValue:Int = Math.round(_inputData.hscrollPos);
111 | if (textField.scrollH != hscrollValue) {
112 | textField.scrollH = hscrollValue;
113 | changed = true;
114 | }
115 |
116 | var vscrollValue:Int = Math.round(_inputData.vscrollPos);
117 | if (textField.scrollV != vscrollValue) {
118 | textField.scrollV = vscrollValue;
119 | changed = true;
120 | }
121 |
122 | textField.addEventListener(Event.SCROLL, onScroll, false, 0, true);
123 |
124 | if (changed == true) {
125 | onScroll(null);
126 | }
127 | }
128 |
129 | private override function validateStyle():Bool {
130 | var measureTextRequired:Bool = super.validateStyle();
131 |
132 | if (textField.displayAsPassword != _inputData.password) {
133 | textField.displayAsPassword = _inputData.password;
134 | }
135 |
136 | if (parentComponent.disabled) {
137 | textField.selectable = false;
138 | } else {
139 | textField.selectable = true;
140 | }
141 |
142 | return measureTextRequired;
143 | }
144 |
145 | private override function validatePosition() {
146 | _left = Math.round(_left);
147 | _top = Math.round(_top);
148 |
149 | #if html5
150 | textField.x = _left - 3;
151 | textField.y = _top - 2;
152 | #elseif flash
153 | textField.x = _left;
154 | textField.y = _top;
155 | #else
156 | textField.x = _left - 3;
157 | textField.y = _top - 3;
158 | #end
159 | }
160 |
161 | private override function measureText() {
162 | #if openfl_textfield_workarounds // not required for alot of apps, or later versions of openfl
163 | if (_width <= 0) {
164 | return;
165 | }
166 | #end
167 | super.measureText();
168 |
169 | #if flash
170 | _textHeight += 2;
171 | #end
172 |
173 | #if openfl_textfield_workarounds // not required for alot of apps, or later versions of openfl
174 | if (StringTools.endsWith(_text, "\n")) {
175 | _textHeight += textField.getLineMetrics(textField.numLines - 2).height;
176 | }
177 | #end
178 |
179 | _inputData.hscrollMax = textField.maxScrollH;
180 | // see below
181 | _inputData.hscrollPageSize = (_width * _inputData.hscrollMax) / _textWidth;
182 |
183 | var msv = textField.maxScrollV;
184 | #if openfl_textfield_workarounds // not required for alot of apps, or later versions of openfl
185 | if (msv > 1) {
186 | msv--;
187 | }
188 | #end
189 | _inputData.vscrollMax = msv;
190 | // cant have page size yet as there seems to be an openfl issue with bottomScrollV
191 | // https://github.com/openfl/openfl/issues/2220
192 | _inputData.vscrollPageSize = (_height * _inputData.vscrollMax) / _textHeight;
193 | }
194 |
195 | private function onChange(e) {
196 | _text = textField.text;
197 | _htmlText = textField.htmlText;
198 |
199 | measureText();
200 |
201 | if (_inputData.onChangedCallback != null) {
202 | _inputData.onChangedCallback();
203 | }
204 | }
205 |
206 | private function onScroll(e) {
207 | if (_inputData.vscrollPos - textField.scrollV > 2) { // weird openfl bug - randomly throws out scroll event and scrollV = 1
208 | return;
209 | }
210 | _inputData.hscrollPos = textField.scrollH;
211 | _inputData.vscrollPos = textField.scrollV;
212 |
213 | if (_inputData.onScrollCallback != null) {
214 | _inputData.onScrollCallback();
215 | }
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/haxe/ui/backend/TimerImpl.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import haxe.Timer;
4 | import openfl.Lib;
5 | import openfl.events.Event;
6 |
7 | class TimerImpl {
8 | static private var __timers:Array = [];
9 |
10 | static public function update(e:Event) {
11 | var currentTime:Float = Timer.stamp();
12 | var count:Int = __timers.length;
13 | for (i in 0...count) {
14 | var timer:TimerImpl = __timers[i];
15 | if (timer._start <= currentTime && !timer._stopped) {
16 | timer._start = currentTime + (timer._delay / 1000);
17 | timer._callback();
18 | }
19 | }
20 |
21 | while (--count >= 0) {
22 | var timer:TimerImpl = __timers[count];
23 | if (timer._stopped) {
24 | timer._callback = null;
25 | __timers.remove(timer);
26 | }
27 | }
28 |
29 | if (__timers.length == 0) {
30 | Lib.current.stage.removeEventListener(Event.ENTER_FRAME, update);
31 | }
32 | }
33 |
34 | private var _callback:Void->Void;
35 | private var _start:Float;
36 | private var _stopped:Bool;
37 | private var _delay:Int;
38 |
39 | public function new(delay:Int, callback:Void->Void) {
40 | this._callback = callback;
41 | _delay = delay;
42 | _start = Timer.stamp() + (delay / 1000);
43 | __timers.push(this);
44 | if (__timers.length == 1) {
45 | Lib.current.stage.addEventListener(Event.ENTER_FRAME, update);
46 | }
47 | }
48 |
49 | public function stop() {
50 | _stopped = true;
51 | }
52 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/ToolkitOptions.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend;
2 |
3 | import openfl.display.Stage;
4 |
5 | typedef ToolkitOptions = {
6 | ?container:Stage
7 | }
8 |
--------------------------------------------------------------------------------
/haxe/ui/backend/module.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/haxe/ui/backend/openfl/BitmapCache.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.openfl;
2 |
3 | import openfl.display.BitmapData;
4 | import openfl.geom.Rectangle;
5 |
6 | class BitmapCache {
7 | private static var _instance:BitmapCache;
8 | public static var instance(get, null):BitmapCache;
9 | private static function get_instance():BitmapCache {
10 | if (_instance == null) {
11 | _instance = new BitmapCache();
12 | }
13 | return _instance;
14 | }
15 |
16 | public static function rectId(rc:Rectangle):String {
17 | return rc.left + "_" + rc.top + "_" + rc.width + "_" + rc.height;
18 | }
19 |
20 | private var _cache:Map;
21 | public function new() {
22 | _cache = new Map();
23 | }
24 |
25 |
26 | public function get(id:String):BitmapData {
27 | var bmpData:BitmapData = _cache.get(id);
28 | return bmpData;
29 | }
30 |
31 | public function set(id:String, bmpData:BitmapData) {
32 | _cache.set(id, bmpData);
33 | }
34 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/openfl/EventMapper.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.openfl;
2 |
3 | class EventMapper {
4 | public static var HAXEUI_TO_OPENFL:Map = [
5 | haxe.ui.events.MouseEvent.MOUSE_MOVE => openfl.events.MouseEvent.MOUSE_MOVE,
6 | haxe.ui.events.MouseEvent.MOUSE_OVER => openfl.events.MouseEvent.MOUSE_OVER,
7 | haxe.ui.events.MouseEvent.MOUSE_OUT => openfl.events.MouseEvent.MOUSE_OUT,
8 | haxe.ui.events.MouseEvent.MOUSE_DOWN => openfl.events.MouseEvent.MOUSE_DOWN,
9 | haxe.ui.events.MouseEvent.MOUSE_UP => openfl.events.MouseEvent.MOUSE_UP,
10 | haxe.ui.events.MouseEvent.MOUSE_WHEEL => openfl.events.MouseEvent.MOUSE_WHEEL,
11 | haxe.ui.events.MouseEvent.CLICK => openfl.events.MouseEvent.CLICK,
12 | haxe.ui.events.MouseEvent.DBL_CLICK => openfl.events.MouseEvent.DOUBLE_CLICK,
13 | haxe.ui.events.MouseEvent.RIGHT_CLICK => openfl.events.MouseEvent.RIGHT_CLICK,
14 | haxe.ui.events.MouseEvent.RIGHT_MOUSE_DOWN => openfl.events.MouseEvent.RIGHT_MOUSE_DOWN,
15 | haxe.ui.events.MouseEvent.RIGHT_MOUSE_UP => openfl.events.MouseEvent.RIGHT_MOUSE_UP,
16 |
17 | haxe.ui.events.KeyboardEvent.KEY_DOWN => openfl.events.KeyboardEvent.KEY_DOWN,
18 | haxe.ui.events.KeyboardEvent.KEY_UP => openfl.events.KeyboardEvent.KEY_UP
19 | ];
20 |
21 | public static var OPENFL_TO_HAXEUI:Map = [
22 | openfl.events.MouseEvent.MOUSE_MOVE => haxe.ui.events.MouseEvent.MOUSE_MOVE,
23 | openfl.events.MouseEvent.MOUSE_OVER => haxe.ui.events.MouseEvent.MOUSE_OVER,
24 | openfl.events.MouseEvent.MOUSE_OUT => haxe.ui.events.MouseEvent.MOUSE_OUT,
25 | openfl.events.MouseEvent.MOUSE_DOWN => haxe.ui.events.MouseEvent.MOUSE_DOWN,
26 | openfl.events.MouseEvent.MOUSE_UP => haxe.ui.events.MouseEvent.MOUSE_UP,
27 | openfl.events.MouseEvent.MOUSE_WHEEL => haxe.ui.events.MouseEvent.MOUSE_WHEEL,
28 | openfl.events.MouseEvent.CLICK => haxe.ui.events.MouseEvent.CLICK,
29 | openfl.events.MouseEvent.DOUBLE_CLICK => haxe.ui.events.MouseEvent.DBL_CLICK,
30 | openfl.events.MouseEvent.RIGHT_CLICK => haxe.ui.events.MouseEvent.RIGHT_CLICK,
31 | openfl.events.MouseEvent.RIGHT_MOUSE_DOWN => haxe.ui.events.MouseEvent.RIGHT_MOUSE_DOWN,
32 | openfl.events.MouseEvent.RIGHT_MOUSE_UP => haxe.ui.events.MouseEvent.RIGHT_MOUSE_UP,
33 |
34 | openfl.events.KeyboardEvent.KEY_DOWN => haxe.ui.events.KeyboardEvent.KEY_DOWN,
35 | openfl.events.KeyboardEvent.KEY_UP => haxe.ui.events.KeyboardEvent.KEY_UP
36 | ];
37 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/openfl/FilterConverter.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.openfl;
2 |
3 | import haxe.ui.backend.openfl.filters.GrayscaleFilter;
4 | import haxe.ui.filters.Filter;
5 | import openfl.filters.BitmapFilter;
6 | import openfl.filters.BitmapFilterQuality;
7 | import openfl.filters.BlurFilter;
8 | import openfl.filters.DropShadowFilter;
9 | import haxe.ui.backend.openfl.filters.HueRotateFilter;
10 | import haxe.ui.backend.openfl.filters.ContrastFilter;
11 | import haxe.ui.backend.openfl.filters.SaturateFilter;
12 | import haxe.ui.backend.openfl.filters.TintFilter;
13 | import haxe.ui.backend.openfl.filters.InvertFilter;
14 | import haxe.ui.backend.openfl.filters.BrightnessFilter;
15 |
16 | class FilterConverter {
17 | public static function convertFilter(input:Filter):BitmapFilter {
18 | if (input == null) {
19 | return null;
20 | }
21 | var output:BitmapFilter = null;
22 |
23 | #if haxe4
24 |
25 | if ((input is haxe.ui.filters.DropShadow)) {
26 | var inputDropShadow:haxe.ui.filters.DropShadow = cast(input, haxe.ui.filters.DropShadow);
27 | output = new DropShadowFilter(inputDropShadow.distance + 1,
28 | inputDropShadow.angle,
29 | inputDropShadow.color,
30 | .9,
31 | inputDropShadow.blurX,
32 | inputDropShadow.blurY,
33 | 1,
34 | BitmapFilterQuality.HIGH,
35 | inputDropShadow.inner);
36 | } else if ((input is haxe.ui.filters.Blur)) {
37 | var inputBlur:haxe.ui.filters.Blur = cast(input, haxe.ui.filters.Blur);
38 | output = new BlurFilter(inputBlur.amount, inputBlur.amount);
39 | } else if ((input is haxe.ui.filters.Grayscale)) {
40 | var inputGrayscale:haxe.ui.filters.Grayscale = cast(input, haxe.ui.filters.Grayscale);
41 | output = new GrayscaleFilter(inputGrayscale.amount / 100).filter;
42 | } else if ((input is haxe.ui.filters.Tint)) {
43 | var tint:haxe.ui.filters.Tint = cast(input, haxe.ui.filters.Tint);
44 | output = new TintFilter(tint.color, tint.amount).filter;
45 | } else if ((input is haxe.ui.filters.HueRotate)) {
46 | var inputHue:haxe.ui.filters.HueRotate = cast(input, haxe.ui.filters.HueRotate);
47 | output = new HueRotateFilter(inputHue.angleDegree).filter;
48 | } else if ((input is haxe.ui.filters.Contrast)) {
49 | var contrast:haxe.ui.filters.Contrast = cast(input, haxe.ui.filters.Contrast);
50 | output = new ContrastFilter(contrast.multiplier).filter;
51 | } else if ((input is haxe.ui.filters.Saturate)) {
52 | var saturate:haxe.ui.filters.Saturate = cast(input, haxe.ui.filters.Saturate);
53 | output = new SaturateFilter(saturate.multiplier).filter;
54 | } else if (input is haxe.ui.filters.Invert) {
55 | var invert:haxe.ui.filters.Invert = cast(input, haxe.ui.filters.Invert);
56 | output = new InvertFilter(invert.multiplier).filter;
57 | } else if (input is haxe.ui.filters.Brightness) {
58 | var brightness:haxe.ui.filters.Brightness = cast(input, haxe.ui.filters.Brightness);
59 | output = new BrightnessFilter(brightness.multiplier).filter;
60 | }
61 |
62 | #end
63 |
64 | return output;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/haxe/ui/backend/openfl/OpenFLStyleHelper.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.openfl;
2 |
3 | import haxe.ui.assets.ImageInfo;
4 | import haxe.ui.geom.Slice9;
5 | import haxe.ui.loaders.image.ImageLoader;
6 | import haxe.ui.styles.Style;
7 | import openfl.display.BitmapData;
8 | import openfl.display.GradientType;
9 | import openfl.display.Graphics;
10 | import openfl.display.InterpolationMethod;
11 | import openfl.display.SpreadMethod;
12 | import openfl.geom.Matrix;
13 | import openfl.geom.Point;
14 | import openfl.geom.Rectangle;
15 |
16 | #if haxeui_extended_borders
17 | using haxe.ui.backend.openfl.util.GraphicsExt;
18 | #end
19 |
20 | class OpenFLStyleHelper {
21 | public function new() {
22 | }
23 |
24 | public static function paintStyleSection(graphics:Graphics, style:Style, width:Float, height:Float, left:Float = 0, top:Float = 0, clear:Bool = true) {
25 | if (clear == true) {
26 | graphics.clear();
27 | }
28 |
29 | if (width <= 0 || height <= 0) {
30 | return;
31 | }
32 |
33 | /*
34 | left = Math.fround(left);
35 | top = Math.fround(top);
36 | width = Math.fround(width);
37 | height = Math.fround(height);
38 | */
39 |
40 | left = Std.int(left);
41 | top = Std.int(top);
42 | width = Std.int(width);
43 | height = Std.int(height);
44 |
45 | var hasFullStyledBorder:Bool = false;
46 | var borderStyle = style.borderStyle;
47 | if (borderStyle == null) {
48 | borderStyle = "solid";
49 | }
50 |
51 | var rc:Rectangle = new Rectangle(top, left, width, height);
52 | var borderRadius:Float = 0;
53 | if (style.borderRadius != null) {
54 | borderRadius = style.borderRadius;
55 | }
56 |
57 | if (style.borderLeftSize != null && style.borderLeftSize != 0
58 | && style.borderLeftSize == style.borderRightSize
59 | && style.borderLeftSize == style.borderBottomSize
60 | && style.borderLeftSize == style.borderTopSize
61 |
62 | && style.borderLeftColor != null
63 | && style.borderLeftColor == style.borderRightColor
64 | && style.borderLeftColor == style.borderBottomColor
65 | && style.borderLeftColor == style.borderTopColor) { // full border
66 |
67 | #if haxeui_extended_borders
68 | // if the borderStyle is not solid and is among the supported StyledLineTypes...
69 | if (borderStyle != "solid" && Type.getEnumConstructs(StyledLineType).indexOf(borderStyle.toUpperCase()) > -1) {
70 | hasFullStyledBorder = true;
71 | }
72 | #end
73 |
74 | graphics.lineStyle(style.borderLeftSize, style.borderLeftColor);
75 | rc.left += style.borderLeftSize / 2;
76 | rc.top += style.borderLeftSize / 2;
77 | rc.bottom -= style.borderLeftSize / 2;
78 | rc.right -= style.borderLeftSize / 2;
79 | //rc.inflate( -(style.borderLeftSize / 2), -(style.borderLeftSize / 2));
80 | } else { // compound border
81 | if ((style.borderTopSize != null && style.borderTopSize > 0)
82 | || (style.borderBottomSize != null && style.borderBottomSize > 0)
83 | || (style.borderLeftSize != null && style.borderLeftSize > 0)
84 | || (style.borderRightSize != null && style.borderRightSize > 0)) {
85 |
86 | var org = rc.clone();
87 |
88 | if (style.borderTopSize != null && style.borderTopSize > 0) {
89 | graphics.beginFill(style.borderTopColor);
90 | graphics.drawRect(0, 0, org.width, style.borderTopSize);
91 | graphics.endFill();
92 |
93 | rc.top += style.borderTopSize;
94 | }
95 |
96 | if (style.borderBottomSize != null && style.borderBottomSize > 0) {
97 | graphics.beginFill(style.borderBottomColor);
98 | graphics.drawRect(0, org.height - style.borderBottomSize, org.width, style.borderBottomSize);
99 | graphics.endFill();
100 |
101 | rc.bottom -= style.borderBottomSize;
102 | }
103 |
104 | if (style.borderLeftSize != null && style.borderLeftSize > 0) {
105 | graphics.beginFill(style.borderLeftColor);
106 | graphics.drawRect(0, rc.top, style.borderLeftSize, org.height - rc.top);
107 | graphics.endFill();
108 |
109 | rc.left += style.borderLeftSize;
110 | }
111 |
112 | if (style.borderRightSize != null && style.borderRightSize > 0) {
113 | graphics.beginFill(style.borderRightColor);
114 | graphics.drawRect(org.width - style.borderRightSize, rc.top, style.borderRightSize, org.height - rc.top);
115 | graphics.endFill();
116 |
117 | rc.right -= style.borderRightSize;
118 | }
119 | }
120 | }
121 |
122 | var backgroundColor:Null = style.backgroundColor;
123 | var backgroundColorEnd:Null = style.backgroundColorEnd;
124 | var backgroundOpacity:Null = style.backgroundOpacity;
125 | #if html5 // TODO: fix for html5 not working with non-gradient fills
126 | if (backgroundColor != null && backgroundColorEnd == null) {
127 | backgroundColorEnd = backgroundColor;
128 | }
129 | #end
130 |
131 | if(backgroundOpacity == null) {
132 | backgroundOpacity = 1;
133 | }
134 |
135 | if (backgroundColor != null) {
136 | if (backgroundColorEnd != null) {
137 | var w:Int = Std.int(rc.width);
138 | var h:Int = Std.int(rc.height);
139 | var colors:Array = [backgroundColor, backgroundColorEnd];
140 | var alphas:Array = [backgroundOpacity, backgroundOpacity];
141 | var ratios:Array = [0, 255];
142 | var matrix:Matrix = new Matrix();
143 |
144 | var gradientType:String = "vertical";
145 | if (style.backgroundGradientStyle != null) {
146 | gradientType = style.backgroundGradientStyle;
147 | }
148 |
149 | if (gradientType == "vertical") {
150 | matrix.createGradientBox(w - 2, h - 2, Math.PI / 2, 0, 0);
151 | } else if (gradientType == "horizontal") {
152 | matrix.createGradientBox(w - 2, h - 2, 0, 0, 0);
153 | }
154 |
155 | graphics.beginGradientFill(GradientType.LINEAR,
156 | colors,
157 | alphas,
158 | ratios,
159 | matrix,
160 | SpreadMethod.PAD,
161 | InterpolationMethod.LINEAR_RGB,
162 | 0);
163 | } else {
164 | graphics.beginFill(backgroundColor, backgroundOpacity);
165 | }
166 | }
167 |
168 | if (borderRadius == 0) {
169 | if (style.borderRadiusTopLeft != null || style.borderRadiusTopRight != null || style.borderRadiusBottomLeft != null || style.borderRadiusBottomRight != null) {
170 | graphics.drawRoundRectComplex(rc.left, rc.top, rc.width, rc.height, style.borderRadiusTopLeft, style.borderRadiusTopRight, style.borderRadiusBottomLeft, style.borderRadiusBottomRight);
171 | } else if (hasFullStyledBorder) {
172 | #if (!flash && haxeui_extended_borders)
173 | if (borderStyle == "dotted") {
174 | graphics.drawDottedRect(rc.left, rc.top, rc.width, rc.height);
175 | } else if (borderStyle == "dashed") {
176 | graphics.drawDashedRect(rc.left, rc.top, rc.width, rc.height);
177 | } else if (borderStyle == "double") {
178 | graphics.drawDoubleRect(rc.left, rc.top, rc.width, rc.height);
179 | } else {
180 | graphics.drawRect(rc.left, rc.top, rc.width, rc.height);
181 | }
182 | #else
183 | graphics.drawRect(rc.left, rc.top, rc.width, rc.height);
184 | #end
185 | } else {
186 | graphics.drawRect(rc.left, rc.top, rc.width, rc.height);
187 | }
188 | } else {
189 | if (rc.width == rc.height && borderRadius >= rc.width / 2) {
190 | borderRadius = rc.width - 1;
191 | }
192 | graphics.drawRoundRect(rc.left, rc.top, rc.width, rc.height, borderRadius + 1, borderRadius + 1);
193 | }
194 |
195 | graphics.endFill();
196 |
197 | if (style.backgroundImage != null) {
198 | ImageLoader.instance.load(style.backgroundImage, function(imageInfo:ImageInfo) {
199 | if (imageInfo != null && imageInfo.data != null) {
200 | paintBitmapBackground(graphics, imageInfo.data, style, rc);
201 | }
202 | });
203 | }
204 | }
205 |
206 | private static function paintBitmapBackground(graphics:Graphics, data:ImageData, style:Style, rc:Rectangle) {
207 | var fillBmp:BitmapData = null;
208 | var fillRect:Rectangle = rc;
209 |
210 | if((data is BitmapData)) {
211 | fillBmp = cast data;
212 | }
213 | #if svg
214 | else if((data is format.SVG)) {
215 | var svg:format.SVG = cast data;
216 | var renderer = new format.svg.SVGRenderer (svg.data);
217 | fillBmp = renderer.renderBitmap(rc);
218 | }
219 | #end
220 | else {
221 | return;
222 | }
223 |
224 | var cacheId:String = style.backgroundImage;
225 | if (style.backgroundImageClipTop != null
226 | && style.backgroundImageClipLeft != null
227 | && style.backgroundImageClipBottom != null
228 | && style.backgroundImageClipRight != null) {
229 |
230 | var clip:Rectangle = new Rectangle(style.backgroundImageClipLeft,
231 | style.backgroundImageClipTop,
232 | style.backgroundImageClipRight - style.backgroundImageClipLeft,
233 | style.backgroundImageClipBottom - style.backgroundImageClipTop);
234 | cacheId += "_" + BitmapCache.rectId(clip);
235 | var clipBmp:BitmapData = BitmapCache.instance.get(cacheId);
236 | if (clipBmp == null) {
237 | clipBmp = new BitmapData(Std.int(clip.width), Std.int(clip.height), true, 0x00000000);
238 | clipBmp.copyPixels(fillBmp, clip, new Point(0, 0));
239 | BitmapCache.instance.set(cacheId, clipBmp);
240 | }
241 | fillBmp = clipBmp;
242 | }
243 |
244 | var borderSize:Float = 0;
245 | if (style.borderSize != null && style.borderSize > 0) {
246 | borderSize = style.borderSize;
247 | fillRect.inflate( -(style.borderSize / 2), -(style.borderSize / 2));
248 | }
249 |
250 | var slice:Rectangle = null;
251 | if (style.backgroundImageSliceTop != null
252 | && style.backgroundImageSliceLeft != null
253 | && style.backgroundImageSliceBottom != null
254 | && style.backgroundImageSliceRight != null) {
255 | slice = new Rectangle(style.backgroundImageSliceLeft,
256 | style.backgroundImageSliceTop,
257 | style.backgroundImageSliceRight - style.backgroundImageSliceLeft,
258 | style.backgroundImageSliceBottom - style.backgroundImageSliceTop);
259 | //trace(slice);
260 | }
261 |
262 | if (slice == null) {
263 | var smooth = true;
264 | if (style.imageRendering == "pixelated") {
265 | smooth = false;
266 | }
267 |
268 | var matrix:Matrix = new Matrix();
269 | matrix.translate(style.backgroundPositionX, style.backgroundPositionY);
270 | var scaleX:Float = 1;
271 | var scaleY:Float = 1;
272 | var repeat = (style.backgroundImageRepeat == "repeat");
273 | if (style.backgroundImageRepeat == null || style.backgroundImageRepeat == "no-repeat" || style.backgroundImageRepeat == "repeat") {
274 | if (style.backgroundWidth != null) {
275 | scaleX = style.backgroundWidth / fillBmp.width;
276 | } else if (style.backgroundWidthPercent != null) {
277 | scaleX = ((fillRect.width / fillBmp.width) * style.backgroundWidthPercent) / 100;
278 | }
279 | if (style.backgroundHeight != null) {
280 | scaleY = style.backgroundHeight / fillBmp.height;
281 | } else if (style.backgroundHeightPercent != null) {
282 | scaleY = ((fillRect.height / fillBmp.height) * style.backgroundHeightPercent) / 100;
283 | }
284 | if (scaleX != 1 || scaleY != 1) {
285 | matrix.scale(scaleX, scaleY);
286 | }
287 | } else if (style.backgroundImageRepeat == "stretch") {
288 | scaleX = fillRect.width / fillBmp.width;
289 | scaleY = fillRect.height / fillBmp.height;
290 | matrix.scale(scaleX, scaleY);
291 | }
292 |
293 | graphics.beginBitmapFill(fillBmp, matrix, repeat, smooth);
294 | if (style.backgroundImageRepeat == null || style.backgroundImageRepeat == "no-repeat") {
295 | if (scaleX == 1 && scaleY == 1) {
296 | fillRect.width = fillBmp.width;
297 | fillRect.height = fillBmp.height;
298 | }
299 | }
300 |
301 | var borderRadius:Float = 0;
302 | if (style.borderRadius != null) {
303 | borderRadius = style.borderRadius;
304 | }
305 |
306 | graphics.lineStyle(0, 0, 0);
307 | fillRect.left = Std.int(fillRect.left);
308 | fillRect.top = Std.int(fillRect.top);
309 | fillRect.bottom = Std.int(fillRect.bottom);
310 | fillRect.right = Std.int(fillRect.right);
311 |
312 | fillRect.left += style.backgroundPositionX;
313 | fillRect.top += style.backgroundPositionY;
314 |
315 | graphics.drawRect(fillRect.left, fillRect.top, fillRect.width, fillRect.height);
316 | graphics.endFill();
317 | } else {
318 | graphics.clear();
319 |
320 | var w:Float = rc.width + borderSize;
321 | var h:Float = rc.height + borderSize;
322 | var rects:Slice9Rects = Slice9.buildRects(w, h, fillBmp.width, fillBmp.height, convertToHaxeUIRect(slice));
323 | var srcRects:Array = convertToOpenFLRectArr(rects.src);
324 | var dstRects:Array = convertToOpenFLRectArr(rects.dst);
325 | for (i in 0...srcRects.length) {
326 | var srcRect = srcRects[i];
327 | var dstRect = dstRects[i];
328 | dstRect.x += style.backgroundPositionX;
329 | dstRect.y += style.backgroundPositionY;
330 | paintBitmap(graphics, fillBmp, cacheId, srcRect, dstRect);
331 | }
332 | }
333 | }
334 |
335 | private static function paintBitmap(graphics:Graphics, bmp:BitmapData, cacheId:String, srcRect:Rectangle, dstRect:Rectangle) {
336 | srcRect.left = Std.int(srcRect.left);
337 | srcRect.top = Std.int(srcRect.top);
338 | srcRect.bottom = Std.int(srcRect.bottom);
339 | srcRect.right = Std.int(srcRect.right);
340 | dstRect.left = Std.int(dstRect.left);
341 | dstRect.top = Std.int(dstRect.top);
342 | dstRect.bottom = Std.int(dstRect.bottom);
343 | dstRect.right = Std.int(dstRect.right);
344 |
345 | if (srcRect.width <= 0 || srcRect.height <= 0) {
346 | return;
347 | }
348 |
349 | if (dstRect.width <= 0 || dstRect.height <= 0) {
350 | return;
351 | }
352 |
353 | cacheId += "__" + BitmapCache.rectId(srcRect);
354 | var srcBmp:BitmapData = BitmapCache.instance.get(cacheId);
355 | if (srcBmp == null) {
356 | srcBmp = new BitmapData(Std.int(srcRect.width), Std.int(srcRect.height), true, 0x00000000);
357 | srcBmp.copyPixels(bmp, srcRect, new Point(0, 0));
358 | //BitmapCache.instance.set(cacheId, srcBmp);
359 | }
360 |
361 | var mat:Matrix = new Matrix();
362 | mat.scale(dstRect.width / srcBmp.width, dstRect.height / srcBmp.height);
363 | mat.translate(dstRect.left, dstRect.top);
364 |
365 | graphics.lineStyle(0, 0, 0);
366 | graphics.beginBitmapFill(srcBmp, mat, false, false);
367 | graphics.drawRect(dstRect.x, dstRect.y, dstRect.width, dstRect.height);
368 | graphics.endFill();
369 |
370 | }
371 |
372 | private static function convertToOpenFLRectArr(arr:Array):Array {
373 | var r:Array = new Array();
374 | for (a in arr) {
375 | r.push(convertToOpenFLRect(a));
376 | }
377 | return r;
378 | }
379 |
380 | private static function convertToOpenFLRect(rc:haxe.ui.geom.Rectangle):Rectangle {
381 | return new Rectangle(rc.left, rc.top, rc.width, rc.height);
382 | }
383 |
384 | private static function convertToHaxeUIRect(rc:Rectangle):haxe.ui.geom.Rectangle {
385 | return new haxe.ui.geom.Rectangle(rc.x, rc.y, rc.width, rc.height);
386 | }
387 |
388 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/openfl/_module/styles/dark/main.css:
--------------------------------------------------------------------------------
1 | .popup {
2 | filter: drop-shadow(1, 45, #000000, 0.15, 1, 1, 1, 3, false);
3 | }
4 |
5 | .dialog {
6 | filter: drop-shadow(0, 45, #000000, 0.2, 30, 30, 1, 15, false);
7 | }
8 |
9 | .menubar {
10 | filter: drop-shadow(1, 45, #000000, 0.15, 1, 1, 1, 3, false);
11 | }
12 |
13 | .menu {
14 | filter: drop-shadow(1, 45, #000000, 0.15, 1, 1, 1, 3, false);
15 | }
16 |
17 | .sidebar {
18 | filter: drop-shadow(0, 45, #222222, 0.1, 30, 30, 1, 15, false);
19 | }
20 |
21 | .treeview {
22 | background-color: #252728;
23 | }
24 |
25 | .treeview .itemrenderer {
26 | background-color: #252728;
27 | }
28 |
29 | .treeview .itemrenderer:hover {
30 | background-color: #2f3746;
31 | }
32 |
33 | .treeview .itemrenderer:node-selected {
34 | background-color: #415982;
35 | }
36 |
37 | .treeview .itemrenderer:node-selected .label {
38 | color: white;
39 | }
40 |
41 | /************************************************************************
42 | ** MOBILE VARIANTS
43 | *************************************************************************/
44 | .popup:mobile {
45 | filter: none;
46 | }
47 |
48 | .dialog:mobile {
49 | filter: none;
50 | }
51 |
52 | .menubar:mobile {
53 | filter: none;
54 | }
55 |
56 | .menu:mobile {
57 | filter: none;
58 | }
59 |
60 | .sidebar:mobile {
61 | filter: drop-shadow(10, 45, #222222, 0.1, 5, 5, 1, 3, false);
62 | }
63 |
--------------------------------------------------------------------------------
/haxe/ui/backend/openfl/_module/styles/default/main.css:
--------------------------------------------------------------------------------
1 | .label, .textfield, .textarea {
2 | __font-name: "haxeui-openfl/styles/fonts/Roboto-Regular.ttf";
3 | font-name: "_sans";
4 | font-size: 13px;
5 | }
6 |
7 | .text-tiny {
8 | font-size: 10px;
9 | }
10 |
11 | .text-small {
12 | font-size: 11px;
13 | }
14 |
15 | .text-normal {
16 | font-size: 13px;
17 | }
18 |
19 | /* https://github.com/openfl/openfl/issues/2215 */
20 | .textfield, .textarea {
21 | filter: none;
22 | }
23 |
24 | .popup {
25 | filter: drop-shadow(1, 45, #D0D0D0, 0.15, 1, 1, 1, 3, false);
26 | }
27 |
28 | .dialog {
29 | filter: drop-shadow(0, 45, #CCCCCC, 0.2, 30, 30, 1, 15, false);
30 | }
31 |
32 | .card {
33 | filter: drop-shadow(1, 45, #D0D0D0, 0.1, 10, 10, 1, 5, false);
34 | }
35 |
36 | .menubar {
37 | filter: drop-shadow(1, 45, #D0D0D0, 0.15, 1, 1, 1, 3, false);
38 | }
39 |
40 | .menu {
41 | filter: drop-shadow(1, 45, #D0D0D0, 0.15, 1, 1, 1, 3, false);
42 | }
43 |
44 | .sidebar {
45 | filter: drop-shadow(0, 45, #CCCCCC, 0.1, 30, 30, 1, 15, false);
46 | }
47 |
48 | .treeview {
49 | background-color: white;
50 | }
51 |
52 | .treeview .itemrenderer {
53 | background-color: white;
54 | }
55 |
56 | .treeview .itemrenderer:hover {
57 | background-color: #d9e5f2;
58 | }
59 |
60 | .treeview .itemrenderer:node-selected {
61 | background-color: #a7c4e2;
62 | }
63 |
64 | /************************************************************************
65 | ** FIX SOME OPENFL ODDITIES
66 | *************************************************************************/
67 | .number-stepper.classic-stepper .stepper-deinc {
68 | margin-top: -1px;
69 | }
70 |
71 | .property-group-item-editor-container .numberstepper {
72 | filter: none;
73 | }
74 |
75 | .property-grid {
76 | }
77 |
78 | .tooltip {
79 | filter: none;
80 | }
81 |
82 | /************************************************************************
83 | ** MOBILE VARIANTS
84 | *************************************************************************/
85 | .popup:mobile {
86 | /* MAKES THINGS RUN SUPER SLOW - OPENFL ISSUE :( */
87 | __filter: drop-shadow(0, 45, #CCCCCC, 0.2, 30, 30, 1, 15, false);
88 | /* THIS IS _OK_ */
89 | filter: drop-shadow(4, 45, #CCCCCC, 0.15, 1, 1, 1, 3, false);
90 | }
91 |
92 |
93 | .popup:mobile {
94 | filter: none;
95 | }
96 |
97 | .dialog:mobile {
98 | filter: none;
99 | }
100 |
101 | .menubar:mobile {
102 | filter: none;
103 | }
104 |
105 | .menu:mobile {
106 | filter: none;
107 | }
108 |
109 | .sidebar:mobile {
110 | filter: drop-shadow(10, 45, #CCCCCC, 0.1, 5, 5, 1, 3, false);
111 | }
112 |
--------------------------------------------------------------------------------
/haxe/ui/backend/openfl/_module/styles/main.css:
--------------------------------------------------------------------------------
1 | .label, .textfield, .textarea {
2 | font-size: 13px;
3 | __font-name: "_sans";
4 | }
5 |
6 | .checkbox, .optionbox, .link {
7 | background-color: white;
8 | background-opacity: 0;
9 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/openfl/filters/BrightnessFilter.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.openfl.filters;
2 |
3 | import openfl.filters.ColorMatrixFilter;
4 |
5 | class BrightnessFilter {
6 | public var filter:ColorMatrixFilter;
7 |
8 | public function new(multiplier:Float = 1) {
9 | // In html, 0 is a black image, 1 has no effect, over it's a multiplier
10 | // So we adapt
11 | if (multiplier <= 1) multiplier = (multiplier -1) * 255;
12 | if (multiplier > 1) multiplier = (multiplier -1) * 110;
13 |
14 | filter = new ColorMatrixFilter([
15 | 1,0,0,0,multiplier,
16 | 0,1,0,0,multiplier,
17 | 0,0,1,0,multiplier,
18 | 0,0,0,1,0,
19 | 0,0,0,0,1]);
20 | }
21 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/openfl/filters/ContrastFilter.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.openfl.filters;
2 |
3 | import openfl.filters.ColorMatrixFilter;
4 |
5 | class ContrastFilter {
6 | public var filter:ColorMatrixFilter;
7 |
8 | public function new(multiplier:Float = 1) {
9 |
10 | var s = multiplier;
11 | var o:Float = 128 * (1 - s);
12 |
13 | filter = new ColorMatrixFilter([
14 | s, 0, 0, 0, o,
15 | 0, s, 0, 0, o,
16 | 0, 0, s, 0, o,
17 | 0, 0, 0, 1, 0]);
18 | }
19 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/openfl/filters/GrayscaleFilter.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.openfl.filters;
2 |
3 | import openfl.filters.ColorMatrixFilter;
4 |
5 | // adapted from: https://github.com/player-03/haxeutils/blob/master/com/player03/display/Greyscale.hx
6 | class GrayscaleFilter {
7 | /**
8 | * Color multipliers recommended by the ITU to make the result appear to the
9 | * human eye to have the correct brightness. See page 3 of the article at
10 | * http://www.itu.int/rec/R-REC-BT.601-7-201103-I/en for more information.
11 | */
12 | private static inline var RED:Float = 0.299;
13 | private static inline var GREEN:Float = 0.587;
14 | private static inline var BLUE:Float = 0.114;
15 |
16 | public var filter:ColorMatrixFilter;
17 |
18 | public function new(amount:Float = 1) {
19 | filter = new ColorMatrixFilter([
20 | 1 + (RED - 1) * amount, GREEN * amount, BLUE * amount, 0, 0,
21 | RED * amount, 1 + (GREEN - 1) * amount, BLUE * amount, 0, 0,
22 | RED * amount, GREEN * amount, 1 + (BLUE - 1) * amount, 0, 0,
23 | 0, 0, 0, 1, 0]);
24 | }
25 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/openfl/filters/HueRotateFilter.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.openfl.filters;
2 |
3 | import openfl.filters.ColorMatrixFilter;
4 |
5 | class HueRotateFilter {
6 | private static inline var LUMA_R:Float = 0.213;
7 | private static inline var LUMA_G:Float = 0.715;
8 | private static inline var LUMA_B:Float = 0.072;
9 |
10 | public var filter:ColorMatrixFilter;
11 |
12 | public function new(degreeAngle:Float = 90) {
13 |
14 | var value = degreeAngle /180 * Math.PI;
15 | if (value == 0) filter = new ColorMatrixFilter();
16 |
17 | var cosVal = Math.cos(value);
18 | var sinVal = Math.sin(value);
19 |
20 | filter = new ColorMatrixFilter([
21 | LUMA_R + cosVal * (1 - LUMA_R) + sinVal * (-LUMA_R), LUMA_G + cosVal * (-LUMA_G) + sinVal * (-LUMA_G), LUMA_B + cosVal * (-LUMA_B) + sinVal * (1 - LUMA_B), 0, 0,
22 | LUMA_R + cosVal * (-LUMA_R) + sinVal * (0.143) , LUMA_G + cosVal * (1 - LUMA_G) + sinVal * (0.14), LUMA_B + cosVal * (-LUMA_B) + sinVal * (-0.283) , 0, 0,
23 | LUMA_R + cosVal * (-LUMA_R) + sinVal * (-(1 - LUMA_R)), LUMA_G + cosVal * (-LUMA_G) + sinVal * (LUMA_G), LUMA_B + cosVal * (1 - LUMA_B) + sinVal * (LUMA_B), 0, 0,
24 | 0 , 0 , 0 , 1, 0,
25 | 0 , 0 , 0 , 0, 1]);
26 | }
27 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/openfl/filters/InvertFilter.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.openfl.filters;
2 |
3 | import openfl.filters.ColorMatrixFilter;
4 |
5 | class InvertFilter {
6 | public var filter:ColorMatrixFilter;
7 |
8 | /*
9 |
10 |
11 |
12 |
13 |
14 | */
15 |
16 | public function new(multiplier:Float = 1) {
17 | filter = new ColorMatrixFilter([
18 | -1*multiplier, 0, 0, 0, 255,
19 | 0, -1*multiplier, 0, 0, 255,
20 | 0, 0, -1*multiplier, 0, 255,
21 | 0, 0, 0, 1, 0]);
22 | }
23 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/openfl/filters/SaturateFilter.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.openfl.filters;
2 |
3 | import openfl.filters.ColorMatrixFilter;
4 |
5 | class SaturateFilter {
6 |
7 | private static inline var LUMA_R:Float = 0.299;
8 | private static inline var LUMA_G:Float = 0.587;
9 | private static inline var LUMA_B:Float = 0.114;
10 |
11 | public var filter:ColorMatrixFilter;
12 |
13 | public function new(multiplier:Float = 1) {
14 |
15 | var sat = multiplier;
16 | var invSat:Float = 1 - multiplier;
17 | var invLumR:Float = invSat * LUMA_R;
18 | var invLumG:Float = invSat * LUMA_G;
19 | var invLumB:Float = invSat * LUMA_B;
20 |
21 | filter = new ColorMatrixFilter([
22 | (invLumR + sat), invLumG, invLumB, 0, 0,
23 | invLumR, (invLumG + sat), invLumB, 0, 0,
24 | invLumR, invLumG, (invLumB + sat), 0, 0,
25 | 0, 0, 0, 1, 0]);
26 | }
27 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/openfl/filters/TintFilter.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.openfl.filters;
2 |
3 | import openfl.filters.ColorMatrixFilter;
4 | import haxe.ui.util.Color;
5 |
6 | class TintFilter {
7 |
8 | public var filter:ColorMatrixFilter;
9 |
10 | // These numbers come from the CIE XYZ Color Model
11 | public static inline var LUMA_R = 0.212671;
12 | public static inline var LUMA_G = 0.71516;
13 | public static inline var LUMA_B = 0.072169;
14 |
15 | public function new(color:Int = 0, amount:Float = 1) {
16 |
17 | var color:Color = cast color;
18 |
19 | var r:Float = color.r / 255;
20 | var g:Float = color.g / 255;
21 | var b:Float = color.b / 255;
22 | var q:Float = 1 - amount;
23 |
24 | var rA:Float = amount * r;
25 | var gA:Float = amount * g;
26 | var bA:Float = amount * b;
27 |
28 | filter = new ColorMatrixFilter([
29 | q + rA * LUMA_R, rA * LUMA_G, rA * LUMA_B, 0, 0,
30 | gA * LUMA_R, q + gA * LUMA_G, gA * LUMA_B, 0, 0,
31 | bA * LUMA_R, bA * LUMA_G, q + bA * LUMA_B, 0, 0,
32 | 0, 0, 0, 1, 0]);
33 | }
34 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/openfl/util/FontDetect.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.openfl.util;
2 |
3 | // port of js lib "FontDetect"
4 | class FontDetect {
5 | private static var _initialized = false;
6 | private static var span = null;
7 | private static var _aFallbackFonts = ['serif', 'sans-serif', 'monospace', 'cursive', 'fantasy'];
8 |
9 | private function new() {
10 | }
11 |
12 | public static function init() {
13 | #if js
14 |
15 | if (_initialized == true) {
16 | return;
17 | }
18 |
19 | _initialized = true;
20 |
21 | var body = js.Browser.document.body;
22 | var firstChild = js.Browser.document.body.firstChild;
23 |
24 | var div = js.Browser.document.createElement('div');
25 | div.id = 'fontdetectHelper';
26 | span = js.Browser.document.createElement('span');
27 | span.innerText = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
28 | div.appendChild(span);
29 |
30 | body.insertBefore(div, firstChild);
31 |
32 | div.style.position = 'absolute';
33 | div.style.visibility = 'hidden';
34 | div.style.top = '-200px';
35 | div.style.left = '-100000px';
36 | div.style.width = '100000px';
37 | div.style.height = '200px';
38 | div.style.fontSize = '100px';
39 |
40 | #end
41 | }
42 |
43 | public static function onFontLoaded(cssFontName:String, onLoad:String->Void, onFail:String->Void = null, options:Dynamic = null) {
44 | #if js
45 |
46 | if (cssFontName == null) {
47 | return;
48 | }
49 |
50 | var msInterval = 10;
51 | if (options != null && options.msInterval != null) {
52 | msInterval = options.msInterval;
53 | }
54 |
55 | var msTimeout = 2000;
56 | if (options != null && options.msTimeout != null) {
57 | msTimeout = options.msTimeout;
58 | }
59 |
60 | if (onLoad == null && onFail == null) {
61 | return;
62 | }
63 |
64 | if (_initialized == false) {
65 | init();
66 | }
67 |
68 | if (isFontLoaded(cssFontName)) { // It's already here, so no need to poll.
69 | if (onLoad != null) {
70 | onLoad(cssFontName);
71 | }
72 | return;
73 | }
74 |
75 | // At this point we know the font hasn't loaded yet. Add it to the list of fonts to monitor.
76 |
77 | // Set up an interval using msInterval. The callback calls isFontLoaded(), & if true
78 | // it closes the interval & calls p_onLoad, else if the current time has timed out
79 | // it closes the interval & calls onFail if there is one.
80 |
81 | var utStart = Date.now().getTime();
82 | var idInterval = 0;
83 | idInterval = js.Browser.window.setInterval(function() {
84 | if (isFontLoaded(cssFontName)) {
85 | js.Browser.window.clearInterval(idInterval);
86 | if (onLoad != null) {
87 | onLoad(cssFontName);
88 | }
89 | return;
90 | } else {
91 | var utNow = Date.now().getTime();
92 | if ((utNow - utStart) > msTimeout) {
93 | js.Browser.window.clearInterval(idInterval);
94 | if (onFail != null) {
95 | onFail(cssFontName);
96 | }
97 | }
98 | }
99 | }, msInterval);
100 |
101 | #end
102 | }
103 |
104 | public static function isFontLoaded(cssFontName:String):Bool {
105 | #if js
106 |
107 | var wThisFont = 0;
108 | var wPrevFont = 0;
109 |
110 | if (_initialized == false) {
111 | init();
112 | }
113 |
114 | for (ix in 0..._aFallbackFonts.length) {
115 | span.style.fontFamily = cssFontName + ',' + _aFallbackFonts[ix];
116 | wThisFont = span.offsetWidth;
117 | if (ix > 0 && wThisFont != wPrevFont) {
118 | // This iteration's font was different than the previous iteration's font, so it must
119 | // have fallen back on a generic font. So our font must not exist.
120 | return false;
121 | }
122 |
123 | wPrevFont = wThisFont;
124 | }
125 |
126 | // The widths were all the same, therefore the browser must have rendered the text in the same
127 | // font every time. So unless all the generic fonts are identical widths (highly unlikely), it
128 | // couldn't have fallen back to a generic font. It's our font.
129 |
130 | #end
131 |
132 | return true;
133 | }
134 | }
--------------------------------------------------------------------------------
/haxe/ui/backend/openfl/util/GraphicsExt.hx:
--------------------------------------------------------------------------------
1 | package haxe.ui.backend.openfl.util;
2 |
3 | #if haxeui_extended_borders
4 |
5 | #if !flash
6 |
7 | import openfl.geom.Point;
8 | import openfl.display._internal.DrawCommandReader;
9 | import openfl.display._internal.DrawCommandType;
10 | import openfl.display.Graphics;
11 |
12 | /**
13 | * Static extention for openfl.display.Graphics
14 | */
15 | @:access(openfl.display.Graphics)
16 | @:access(openfl.display._internal.DrawCommandBuffer)
17 | @:access(openfl.display._internal.DrawCommandReader)
18 | class GraphicsExt
19 | {
20 | //----------------------------------------------------------------------
21 | //
22 | // Properties
23 | //
24 | //----------------------------------------------------------------------
25 |
26 | private static var _posChangeTypes:Array = [DrawCommandType.CUBIC_CURVE_TO, DrawCommandType.CURVE_TO, DrawCommandType.DRAW_CIRCLE, DrawCommandType.DRAW_ELLIPSE, DrawCommandType.DRAW_RECT, DrawCommandType.DRAW_ROUND_RECT, DrawCommandType.LINE_TO, DrawCommandType.MOVE_TO];
27 |
28 | //----------------------------------------------------------------------
29 | //
30 | // Methods
31 | //
32 | //----------------------------------------------------------------------
33 |
34 | /**
35 | * Draws a dotted line.
36 | * @param gfx
37 | * @param x
38 | * @param y
39 | */
40 | static public inline function dottedLineTo(gfx:Graphics, x:Float, y:Float):Void {
41 | _periodicLineTo(gfx, x, y, StyledLineType.DOTTED);
42 | }
43 |
44 | /**
45 | * Draws a dashed line.
46 | * @param gfx
47 | * @param x
48 | * @param y
49 | */
50 | static public inline function dashedLineTo(gfx:Graphics, x:Float, y:Float):Void {
51 | _periodicLineTo(gfx, x, y, StyledLineType.DASHED);
52 | }
53 |
54 | /**
55 | * Draws 2 parallel lines whose combined thickness and the space between them adds up to the current lineStyle thickness
56 | * @param gfx
57 | * @param x
58 | * @param y
59 | */
60 | static public inline function doubleLineTo(gfx:Graphics, x:Float, y:Float):Void {
61 | _doubleLineTo(gfx, x, y);
62 | }
63 |
64 | /**
65 | * Draws a rectangle using dotted lines.
66 | * @param gfx
67 | * @param x
68 | * @param y
69 | * @param width
70 | * @param height
71 | */
72 | static public inline function drawDottedRect(gfx:Graphics, x:Float, y:Float, width:Float, height:Float):Void {
73 | _drawPeriodicRect(gfx, x, y, width, height, StyledLineType.DOTTED);
74 | }
75 |
76 | /**
77 | * Draws a rectangle using dashed lines.
78 | * @param gfx
79 | * @param x
80 | * @param y
81 | * @param width
82 | * @param height
83 | */
84 | static public inline function drawDashedRect(gfx:Graphics, x:Float, y:Float, width:Float, height:Float):Void {
85 | _drawPeriodicRect(gfx, x, y, width, height, StyledLineType.DASHED);
86 | }
87 |
88 | /**
89 | * Draws a rectangle using double lines.
90 | * @param gfx
91 | * @param x
92 | * @param y
93 | * @param width
94 | * @param height
95 | */
96 | static public inline function drawDoubleRect(gfx:Graphics, x:Float, y:Float, width:Float, height:Float):Void {
97 | _drawDoubleRect(gfx, x, y, width, height);
98 | }
99 |
100 | /**
101 | * Draws a regular polygon with specified number of sides.
102 | * @param gfx
103 | * @param x
104 | * @param y
105 | * @param sides
106 | * @param radius
107 | */
108 | static public function drawRegularPolygon(gfx:Graphics, x:Float, y:Float, sides:Int, radius:Float):Void {
109 | _drawRegularPolygon(gfx, x, y, sides, radius, StyledLineType.SOLID);
110 | }
111 |
112 | /**
113 | * Draws a regular polygon with specified number of sides using dotted lines.
114 | * @param gfx
115 | * @param x
116 | * @param y
117 | * @param sides
118 | * @param radius
119 | */
120 | static public function drawDottedRegularPolygon(gfx:Graphics, x:Float, y:Float, sides:Int, radius:Float):Void {
121 | _drawRegularPolygon(gfx, x, y, sides, radius, StyledLineType.DOTTED);
122 | }
123 |
124 | /**
125 | * Draws a regular polygon with specified number of sides using dashed lines.
126 | * @param gfx
127 | * @param x
128 | * @param y
129 | * @param sides
130 | * @param radius
131 | */
132 | static public function drawDashedRegularPolygon(gfx:Graphics, x:Float, y:Float, sides:Int, radius:Float):Void {
133 | _drawRegularPolygon(gfx, x, y, sides, radius, StyledLineType.DASHED);
134 | }
135 |
136 | /**
137 | * Draws a regular polygon with specified number of sides using double lines.
138 | * @param gfx
139 | * @param x
140 | * @param y
141 | * @param sides
142 | * @param radius
143 | */
144 | static public function drawDoubleRegularPolygon(gfx:Graphics, x:Float, y:Float, sides:Int, radius:Float):Void {
145 | _drawRegularPolygon(gfx, x, y, sides, radius, StyledLineType.DOUBLE);
146 | }
147 |
148 | /**
149 | * Gets the current line style.
150 | * @param gfx
151 | * @return LineStyleView
152 | */
153 | static public function getLineStyle(gfx:Graphics):LineStyleView {
154 | // get DrawCommandReader for current DrawCommandBuffer
155 | var data:DrawCommandReader = new DrawCommandReader(gfx.__commands);
156 |
157 | // Find last possible index of DrawCommandType.LINE_STYLE
158 | var lastLineStyleIndex:Int = data.buffer.types.lastIndexOf(DrawCommandType.LINE_STYLE);
159 |
160 | // skip through commands until we get to one just before the last lineStyle
161 | for (i in 0...lastLineStyleIndex) {
162 | data.skip(data.buffer.types[i]);
163 | }
164 |
165 | return data.readLineStyle();
166 | }
167 |
168 | /**
169 | * Gets the current draw head position.
170 | * @param gfx
171 | * @return Point
172 | */
173 | static public function getDrawHeadPos(gfx:Graphics):Point {
174 | var point:Point = new Point();
175 |
176 | // get DrawCommandReader for current DrawCommandBuffer
177 | var data:DrawCommandReader = new DrawCommandReader(gfx.__commands);
178 |
179 | // Find last possible index and type of DrawCommandType that changed draw head position //
180 | var lastPosChangeIndex:Int = 0;
181 | var lastPosChangeType:DrawCommandType = DrawCommandType.UNKNOWN;
182 | for (i in 0..._posChangeTypes.length) {
183 | var curIndex:Int = data.buffer.types.lastIndexOf(_posChangeTypes[i]);
184 | if (curIndex > lastPosChangeIndex) {
185 | lastPosChangeIndex = curIndex;
186 | lastPosChangeType = _posChangeTypes[i];
187 | }
188 | }
189 | // We actually want to step into the appropriate index
190 | lastPosChangeIndex++;
191 |
192 | // skip through commands until we get to current position changing command
193 | for (i in 0...lastPosChangeIndex) {
194 | data.skip(data.buffer.types[i]);
195 | }
196 |
197 | if (lastPosChangeType == DrawCommandType.CUBIC_CURVE_TO || lastPosChangeType == DrawCommandType.CURVE_TO) {
198 | data.advance(); // advance to 1 after current drawCommand array buffers
199 | // draw head moved to anchorX/anchorY, which are the previous 2 buffer float indexes
200 | point.setTo(data.buffer.f[data.fPos - 2], data.buffer.f[data.fPos - 1]);
201 | } else {
202 | // draw head moved to x/y, which are the next 2 buffer float indexes
203 | point.setTo(data.buffer.f[data.fPos], data.buffer.f[data.fPos + 1]);
204 | }
205 |
206 | return point;
207 | }
208 |
209 | static private function _periodicLineTo(gfx:Graphics, x:Float, y:Float, lineType:StyledLineType):Void {
210 | if (lineType == StyledLineType.SOLID) {
211 | gfx.lineTo(x, y);
212 | } else {
213 | var lineData:LineStyleView = getLineStyle(gfx);
214 | var drawHeadPos:Point = getDrawHeadPos(gfx);
215 |
216 | var dX:Float = x - drawHeadPos.x;
217 | var dY:Float = y - drawHeadPos.y;
218 | var dist:Float = Math.sqrt(dX * dX + dY * dY);
219 |
220 | var lineThickness:Float = Math.max(lineData.thickness, 1);
221 | var lineLength:Float = (lineType == StyledLineType.DASHED) ? Math.max(lineThickness * 2, 3) : 0.5;
222 | var numLines:Int = Math.ceil(dist / Math.max(lineLength, lineThickness * 2) * .5);
223 | var gapLength:Float = (dist - lineLength * numLines) / (numLines - 1);
224 | // adjust the gapLength to acurately fit any distance diff
225 | gapLength *= dist / (lineLength * numLines + gapLength * (numLines - 1));
226 |
227 | // radian angle of the line
228 | var rads:Float = Math.atan2(y - drawHeadPos.y, x - drawHeadPos.x);
229 |
230 | var toX:Float = drawHeadPos.x;
231 | var toY:Float = drawHeadPos.y;
232 |
233 | var i:Int = 0;
234 | while (++i < numLines) {
235 | // draw visible line
236 | toX += Math.cos(rads) * lineLength;
237 | toY += Math.sin(rads) * lineLength;
238 | gfx.lineTo(toX, toY);
239 |
240 | // set lineStyle to hairline and invisible
241 | gfx.lineStyle(0, 0, 0);
242 | // draw invisible gap line
243 | toX += Math.cos(rads) * gapLength;
244 | toY += Math.sin(rads) * gapLength;
245 | gfx.lineTo(toX, toY);
246 |
247 | // reset lineStyle
248 | gfx.lineStyle(lineData.thickness, lineData.color, lineData.alpha, lineData.pixelHinting, lineData.scaleMode, lineData.caps, lineData.joints, lineData.miterLimit);
249 | }
250 |
251 | // draw final visible line
252 | gfx.lineTo(x, y);
253 | }
254 | }
255 |
256 | static private function _doubleLineTo(gfx:Graphics, x:Float, y:Float):Void {
257 | var lineData:LineStyleView = getLineStyle(gfx);
258 |
259 | if (lineData.thickness < 1.5) {
260 | gfx.lineTo(x, y);
261 | } else {
262 | var drawHeadPos:Point = getDrawHeadPos(gfx);
263 |
264 | // radian angle of the line
265 | var rads:Float = Math.atan2(y - drawHeadPos.y, x - drawHeadPos.x);
266 | var quarterPI:Float = Math.PI * .25; // 45 degrees
267 |
268 | var lineThickness:Float = lineData.thickness * .5;
269 | var lineOffset:Float = Math.sqrt(2 * lineThickness * lineThickness);
270 |
271 | // set lineStyle to just under a 3rd thickness
272 | lineThickness = lineData.thickness * .3;
273 | gfx.lineStyle(lineThickness, lineData.color, lineData.alpha, lineData.pixelHinting, lineData.scaleMode, lineData.caps, lineData.joints, lineData.miterLimit);
274 |
275 | gfx.moveTo(drawHeadPos.x + Math.cos(rads - quarterPI * 3) * lineOffset, drawHeadPos.y + Math.sin(rads - quarterPI * 3) * lineOffset);
276 | gfx.lineTo(x + Math.cos(rads - quarterPI) * lineOffset, y + Math.sin(rads - quarterPI) * lineOffset);
277 | gfx.moveTo(drawHeadPos.x + Math.cos(rads + quarterPI) * lineOffset, drawHeadPos.y + Math.sin(rads + quarterPI) * lineOffset);
278 | gfx.lineTo(x + Math.cos(rads + quarterPI * 3) * lineOffset, y + Math.sin(rads + quarterPI * 3) * lineOffset);
279 |
280 | // move draw head to end position
281 | gfx.moveTo(x, y);
282 | // reset lineStyle
283 | gfx.lineStyle(lineData.thickness, lineData.color, lineData.alpha, lineData.pixelHinting, lineData.scaleMode, lineData.caps, lineData.joints, lineData.miterLimit);
284 | }
285 | }
286 |
287 | static private inline function _drawPeriodicRect(gfx:Graphics, x:Float, y:Float, width:Float, height:Float, lineType:StyledLineType):Void {
288 | gfx.moveTo(x, y);
289 | _periodicLineTo(gfx, x + width, y, lineType);
290 | _periodicLineTo(gfx, x + width, y + height, lineType);
291 | _periodicLineTo(gfx, x, y + height, lineType);
292 | _periodicLineTo(gfx, x, y, lineType);
293 | }
294 |
295 | static private inline function _drawDoubleRect(gfx:Graphics, x:Float, y:Float, width:Float, height:Float):Void {
296 | var lineData:LineStyleView = getLineStyle(gfx);
297 |
298 | gfx.moveTo(x, y);
299 | if (lineData.thickness < 1.5) {
300 | gfx.drawRect(x, y, width, height);
301 | } else {
302 | _doubleLineTo(gfx, x + width, y);
303 | _doubleLineTo(gfx, x + width, y + height);
304 | _doubleLineTo(gfx, x, y + height);
305 | _doubleLineTo(gfx, x, y);
306 |
307 | // in case of fills, we have to draw an invisible rect 1st bc of the nature of double lines and fills
308 | gfx.lineStyle(0, 0, 0);
309 | gfx.drawRect(x, y, width, height);
310 | // reset lineStyle
311 | // sadly, openfl issue is causing an erroneous dot to be drawn here (https://github.com/openfl/openfl/issues/2336)
312 | gfx.lineStyle(lineData.thickness, lineData.color, lineData.alpha, lineData.pixelHinting, lineData.scaleMode, lineData.caps, lineData.joints, lineData.miterLimit);
313 | }
314 | }
315 |
316 | static private inline function _drawRegularPolygon(gfx:Graphics, x:Float, y:Float, sides:Int, radius:Float, lineType:StyledLineType):Void {
317 | var step = Math.PI / sides * 2;
318 | var rad = Math.PI * .5;
319 |
320 | gfx.moveTo(x + Math.cos(rad) * radius, y - Math.sin(rad) * radius);
321 | if (lineType == StyledLineType.DOUBLE) {
322 | var lineData:LineStyleView = getLineStyle(gfx);
323 |
324 | // in case of fills, we have to draw an invisible poly 1st bc of the nature of double lines and fills
325 | gfx.lineStyle(0, 0, 0);
326 | _drawRegularPolygon(gfx, x, y, sides, radius, StyledLineType.SOLID);
327 | // reset lineStyle
328 | gfx.lineStyle(lineData.thickness, lineData.color, lineData.alpha, lineData.pixelHinting, lineData.scaleMode, lineData.caps, lineData.joints, lineData.miterLimit);
329 | }
330 | while (sides-- > 0) {
331 | if (lineType == StyledLineType.SOLID) {
332 | gfx.lineTo(x + Math.cos(rad + (step * sides)) * radius, y - Math.sin(rad + (step * sides)) * radius);
333 | } else if (lineType == StyledLineType.DOUBLE) {
334 | _doubleLineTo(gfx, x + Math.cos(rad + (step * sides)) * radius, y - Math.sin(rad + (step * sides)) * radius);
335 | } else {
336 | _periodicLineTo(gfx, x + Math.cos(rad + (step * sides)) * radius, y - Math.sin(rad + (step * sides)) * radius, lineType);
337 | }
338 | }
339 | }
340 |
341 | }
342 | #end
343 |
344 | enum StyledLineType
345 | {
346 | SOLID;
347 | DOTTED;
348 | DASHED;
349 | DOUBLE;
350 | }
351 |
352 | #end
353 |
354 |
--------------------------------------------------------------------------------
/haxelib.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.7.0",
3 | "contributors": [
4 | "haxeui",
5 | "ianharrigan",
6 | "_ibilon",
7 | "aW4KeNiNG"
8 | ],
9 | "license": "MIT",
10 | "tags": [
11 | "ui",
12 | "gui",
13 | "openfl"
14 | ],
15 | "releasenote": "1.7.0 release",
16 | "dependencies": {
17 | "haxeui-core": "",
18 | "openfl": ""
19 | },
20 | "name": "haxeui-openfl",
21 | "description": "The OpenFL backend of the HaxeUI framework",
22 | "url": "https://github.com/haxeui/haxeui-openfl"
23 | }
--------------------------------------------------------------------------------
/include.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------