├── .github └── workflows │ └── main.yml ├── .gitignore ├── .vscode └── settings.json ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── assets ├── images │ ├── box.png │ ├── button.png │ ├── button_arrow_down.png │ ├── button_arrow_left.png │ ├── button_arrow_right.png │ ├── button_arrow_up.png │ ├── button_thin.png │ ├── button_toggle.png │ ├── check_box.png │ ├── check_mark.png │ ├── chrome.png │ ├── chrome_flat.png │ ├── chrome_inset.png │ ├── chrome_light.png │ ├── dropdown_mark.png │ ├── finger_big.png │ ├── finger_small.png │ ├── hilight.png │ ├── invis.png │ ├── minus_mark.png │ ├── plus_mark.png │ ├── radio.png │ ├── radio_dot.png │ ├── swatch.png │ ├── tab.png │ ├── tab_back.png │ └── tooltip_arrow.png └── xml │ ├── default_loading_screen.xml │ ├── default_popup.xml │ └── defaults.xml ├── flixel └── addons │ └── ui │ ├── Anchor.hx │ ├── AnchorPoint.hx │ ├── BorderDef.hx │ ├── ButtonLabelStyle.hx │ ├── FlxBaseMultiInput.hx │ ├── FlxInputText.hx │ ├── FlxMultiGamepad.hx │ ├── FlxMultiGamepadAnalogStick.hx │ ├── FlxMultiKey.hx │ ├── FlxUI.hx │ ├── FlxUI9SliceSprite.hx │ ├── FlxUIAssets.hx │ ├── FlxUIBar.hx │ ├── FlxUIButton.hx │ ├── FlxUICheckBox.hx │ ├── FlxUIColorSwatch.hx │ ├── FlxUIColorSwatchSelecter.hx │ ├── FlxUICursor.hx │ ├── FlxUIDropDownMenu.hx │ ├── FlxUIGroup.hx │ ├── FlxUIInputText.hx │ ├── FlxUILine.hx │ ├── FlxUIList.hx │ ├── FlxUILoadingScreen.hx │ ├── FlxUIMouse.hx │ ├── FlxUINumericStepper.hx │ ├── FlxUIPopup.hx │ ├── FlxUIRadioGroup.hx │ ├── FlxUIRegion.hx │ ├── FlxUISlider.hx │ ├── FlxUISprite.hx │ ├── FlxUISpriteButton.hx │ ├── FlxUIState.hx │ ├── FlxUISubState.hx │ ├── FlxUITabMenu.hx │ ├── FlxUIText.hx │ ├── FlxUITileTest.hx │ ├── FlxUITooltip.hx │ ├── FlxUITooltipManager.hx │ ├── FlxUITypedButton.hx │ ├── FontDef.hx │ ├── FontFixer.hx │ ├── StrNameLabel.hx │ ├── SwatchData.hx │ ├── U.hx │ ├── interfaces │ ├── ICursorPointable.hx │ ├── IEventGetter.hx │ ├── IFireTongue.hx │ ├── IFlxUIButton.hx │ ├── IFlxUIClickable.hx │ ├── IFlxUIState.hx │ ├── IFlxUIWidget.hx │ ├── IHasParams.hx │ ├── ILabeled.hx │ └── IResizable.hx │ └── system │ └── macros │ └── FlxUIDefines.hx ├── haxelib.json ├── hxformat.json ├── include.xml ├── release.bat └── release.sh /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | repository_dispatch: 8 | 9 | jobs: 10 | build: 11 | strategy: 12 | matrix: 13 | haxe-version: ["4.2.5", "4.3.3"] 14 | target: [html5, hl, neko, flash, cpp] 15 | fail-fast: false 16 | runs-on: ubuntu-latest 17 | steps: 18 | - run: sudo apt-get update 19 | 20 | - uses: actions/checkout@v3 21 | 22 | - uses: krdlab/setup-haxe@v1 23 | with: 24 | haxe-version: ${{matrix.haxe-version}} 25 | 26 | - name: "Configure Haxelib" 27 | run: | 28 | haxelib setup /home/runner/haxe/haxelib/ 29 | haxelib install haxelib 4.0.3 30 | haxelib dev flixel-ui . 31 | 32 | - uses: HaxeFlixel/setup-flixel@v1 33 | with: 34 | haxe-version: current 35 | flixel-versions: dev 36 | target: ${{matrix.target}} 37 | run-tests: true 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | psds/ 3 | *.psd 4 | export/* 5 | flixel-ui.zip 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[haxe]": { 3 | "editor.formatOnSave": true 4 | } 5 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2.6.4 (December 10, 2024) 2 | ------------------------------ 3 | `FlxUITypedButton`: Avoid deprecated `statusAnimations` field ([#291](https://github.com/HaxeFlixel/flixel-ui/pull/291)) 4 | 5 | 2.6.3 (December 10, 2024) 6 | ------------------------------ 7 | Fix compile error with Flixel 5.8.0 ([289](https://github.com/HaxeFlixel/flixel-ui/pull/289)) 8 | 9 | 2.6.2 (December 10, 2024) 10 | ------------------------------ 11 | #### Changes and improvements: 12 | - Fixed compatibility with upcoming Flixel version 5.9.0 ([277](https://github.com/HaxeFlixel/flixel-ui/pull/277)) 13 | - `FlxUIDropdownMenu`: Prevent premature closing when selecting items ([275](https://github.com/HaxeFlixel/flixel-ui/pull/275)) 14 | - `FlxUISlider`: Check for correct Flixel-addons version ([280](https://github.com/HaxeFlixel/flixel-ui/pull/280)) 15 | - Assets: Run oxipng on all images ([284](https://github.com/HaxeFlixel/flixel-ui/pull/284)) 16 | - `FlxInputText`(legacy): Prevent using destroyed graphic ([285](https://github.com/HaxeFlixel/flixel-ui/pull/285)) 17 | - `FlxUICheckBox`: Fix docs ([287](https://github.com/HaxeFlixel/flixel-ui/pull/287)) 18 | 19 | #### Bugfixes 20 | - `FlxUICheckBox`: Fix `checked` always `false` in params ([288](https://github.com/HaxeFlixel/flixel-ui/pull/288)) 21 | 22 | 23 | 2.6.1 (april 16, 2024) 24 | ------------------------------ 25 | Fixed compatibility with upcoming Flixel version 5.7.0 26 | 27 | 28 | 2.6.0 (March 15, 2024) 29 | ------------------------------ 30 | 31 | #### New features: 32 | - `FlxInputText`: Various features 33 | - Add paste support ([#253](https://github.com/HaxeFlixel/flixel-ui/pull/253)) 34 | - Add mobile keyboard support ([#257](https://github.com/HaxeFlixel/flixel-ui/pull/257)) 35 | - `FlxUIGroup`: add `FlxTypedUIGroup` ([#246](https://github.com/HaxeFlixel/flixel-ui/pull/246)) 36 | 37 | #### Changes and improvements: 38 | - Changed references to the `flash` package to their `openfl` equivalent, whenever possible ([#252](https://github.com/HaxeFlixel/flixel-ui/pull/252)) 39 | - `FlxInputText`: Various changes 40 | - Use `FlxKey` instead of raw ints ([#250](https://github.com/HaxeFlixel/flixel-ui/pull/250)) 41 | - Remove unnecessary variables ([#257](https://github.com/HaxeFlixel/flixel-ui/pull/257)) 42 | - `FlxUIList`: Properly destroy members ([#254](https://github.com/HaxeFlixel/flixel-ui/pull/254)) 43 | - `FlxUI9SliceSprite`: Warn on invalid slice arrays ([#256](https://github.com/HaxeFlixel/flixel-ui/pull/256)) 44 | 45 | 46 | #### Dependencies: 47 | - Dropped support for haxe 4.0 and 4.1, use 4.2.5 or higher 48 | 49 | #### Bugfixes: 50 | - `FlxUICursor`: Prevent warning on recent haxe versions ([#244](https://github.com/HaxeFlixel/flixel-ui/pull/244)) 51 | - `FlxInputText`: Fix maxLength input ([#253](https://github.com/HaxeFlixel/flixel-ui/pull/253)) 52 | 53 | 2.5.0 (November 19, 2022) 54 | ------------------------------ 55 | * Deprecate haxe 3 56 | * Fix FlxUICursor camera scroll (#233) 57 | 58 | 2.4.0 (September 12, 2021) 59 | ------------------------------ 60 | * Compatibility with flixel 4.10.0 61 | 62 | 2.3.3 (July 2, 2020) 63 | ------------------------------ 64 | * Fixed `Std.is()` deprecation warnings with Haxe 4.2 65 | 66 | 2.3.2 (February 4, 2019) 67 | ------------------------------ 68 | * Compatibility with Haxe 4.0.0-rc.1 69 | * Fixed `` path when `src` is `RAW:` (#212) 70 | 71 | 2.3.1 (August 10, 2018) 72 | ------------------------------ 73 | * Compatibility with latest Haxe dev 74 | * Compatibility with Lime 7's HL target 75 | 76 | 2.3.0 (May 4, 2018) 77 | ------------------------------ 78 | * Compatibility with flixel 4.4.0 79 | * `FlxUIDropDownMenu`: fixed menus dropping in the wrong direction sometimes (flixel-demos#256) 80 | * `FlxUI`: disabled warnings for using flixel-ui elements outside of a `FlxUIState` 81 | 82 | 2.2.0 (October 11, 2016) 83 | ------------------------------ 84 | * Compatibility with flixel 4.2.0 85 | * `FlxUICheckBox`: fixed alignment on HTML5 (#192) 86 | * `FlxInputText`: added `focusGained` and `focusLost` (#176) 87 | * `FlxUITooltipManager`: 88 | * fixed tooltips being off-screen sometimes (#181) 89 | * added support for tooltips on non-clickable elements (#182) 90 | * added `cameras` (#187) 91 | * `FlxUIState` / `FlxUISubState`: finished `reload_ui_on_resize` (#188) 92 | * `FlxUIButton` / `FlxUI9SliceSprite`: added `color` arguments to `new()` (#180) 93 | * `FlxInputText`: fixed an issue with caret positions in empty textfields (#193) 94 | * Assets are now included with `"embed=true"` (#198) 95 | 96 | 2.1.0 (July 10, 2016) 97 | ------------------------------ 98 | * Compatibility with flixel 4.1.0 99 | * `FlxUI`: 100 | * added `tolerance_plus` / `tolerance_minus` attributes for `` 101 | * added `fontStr()`, `fontSize()` and `font()` 102 | * added support for overriding the internal `"screen"` asset 103 | * fixed a spacing issue in alignments 104 | * `FlxUIState`: added `onShowTooltip()` 105 | * `FlxUISubState`: 106 | * added `createUI()` (#169) 107 | * added `onShowTooltip()` 108 | * `FlxUITooltip`: 109 | * added a `ShowArrow` argument to `show()` 110 | * fixed rendering artifacts by using integer rounding 111 | * `FlxUITooltipManager`: added `fixedPosition`, `showTooltipArrow`, `isVisible()`, `stickyTooltipFor()` and `showTooltipFor()` 112 | * `FlxUILine`: [Cpp] fixed `thickness` 113 | * `FlxUIButton`: added support for `labelOffsets` in `addIcon()` (#175) 114 | * `FlxMultiGamepadAnalogStick`: added null safety checks 115 | * `FlxUICursor`: 116 | * added `getCurrentWidget()` and `clearWidgets()` 117 | * fixed several bugs 118 | * `FlxUIList`: fixed a minor positioning issue 119 | * `U`: added `setButtonLabel()` 120 | * Added support for Firteongue font replacement rule integration 121 | 122 | 2.0.0 (February 16, 2016) 123 | ------------------------------ 124 | * Compatibility with flixel 4.0.0 125 | * `FlxUI`: 126 | * added `getAllAssets()` 127 | * added `getAssetKeys()` 128 | * added support for auto-scaled images in xml 129 | * added `` 130 | * added `liveFilePath` and support for live reloading 131 | * added support for different rounding modes in xml 132 | * added basic support for setting and comparing variables in xml 133 | * added `` 134 | * the `spacing` attribute in `` can now use formulas 135 | * added `to_height` attribute to `` 136 | * 9-slice sprites can now be scaled before 9-slice-scaling in xml 137 | * added `setVariable()` 138 | * added `sendToFront()` and `sendToBack()` 139 | * added `getAssetGroup()` 140 | * added `` 141 | * added support for an `alpha` attribute to all widget tags 142 | * `IFlxUIWidget`: 143 | * renamed `id` to `name` 144 | * `FlxUITypedButton`: 145 | * can now have a separate toggle label 146 | * added `copyStyle()` 147 | * added `getCenterLabelOffset()` 148 | * added `clone()` 149 | * `active` can now be set in xml 150 | * added `autoResizeLabel` 151 | * `up` / `over` / `down` colors are now nullable 152 | * `loadGraphicSlice9()` and `loadGraphicsMultiple()` now take an array of `FlxGraphicAsset`s instead of `String` 153 | * `FlxUIText`: 154 | * now implements `IHasParams` 155 | * `border="none"` / `border="false"` is now supported in xml 156 | * added `clone()` 157 | * added support for resizing 158 | * `FlxUISprite`: 159 | * added support for resizing 160 | * now automatically scales if `width`, `height` or `resize_ratio` are specified in xml 161 | * `FlxUIRadioGroup`: 162 | * added `getLabel()` 163 | * added `getId()` 164 | * added support for active / inactive states 165 | * `FlxUIRadioButton`: 166 | * the box and dot can now be loaded as sprites (`` and ``) 167 | * `FlxUIInputText`: 168 | * `password_mode` can now be set in xml 169 | * `FlxUIState`: 170 | * added `loadUIFromData()` 171 | * added `createUI()` 172 | * no longer sets `FlxG.mouse.visible` to `true` automatically 173 | * added `setUIVariable()` 174 | * added `tooltips` 175 | * `FlxUISubState`: 176 | * added `BGColor` argument to `new()` 177 | * added `tooltips` 178 | * `FlxUINumericStepper`: 179 | * addeds support for decimals 180 | * `FlxUICursor`: 181 | * added gamepad support 182 | * `FlxUIDropDownMenu`: 183 | * now drops upwards if height exceeds `FlxG.height` 184 | * added `dropDirection` and `FlxUIDropDownMenuDropDirection` 185 | * `FlxUIColorSwatchSelecter`: 186 | * added support for custom swatch graphics 187 | * `FlxUIGroup`: 188 | * added `setScrollFactor()` 189 | * `U`: 190 | * added `endline()` 191 | * added `loadImageScaleToHeight()` 192 | * added `unparentXML()` 193 | * Added `FontDef` 194 | * Added `BorderDef` 195 | * Added `ButtonLabelStyle` 196 | * Added `FlxUIBar` 197 | * Added `FlxMultiGamepad` 198 | * Added `FlxMultiGamepadAnalogStick` 199 | * Renamed `MultiKey` to `FlxMultiKey` 200 | * Added `FlxUITooltip` and `FlxUITooltipManager` 201 | * Added `FlxUILine` 202 | 203 | 1.0.2 (April 24, 2014) 204 | ------------------------------ 205 | * Compatibility with flixel 3.3.0 206 | * Added FlxUIList 207 | * A configurable, scrollable list that is an arbitrary collection of IFlxUIWidgets 208 | * Added FlxUICursor 209 | * A configurable keyboard-controlled cursor that can click anything clickable 210 | * Added FlxUISlider 211 | * As seen in FlxBunnyMark 212 | * Rudimentary for now, will be improved later 213 | * Added FontDef, BorderDef, and ButtonLabelStyle style structure 214 | * FlxUITypedButton: 215 | * Added "CLICK_EVENT" to forceStateHandler() 216 | * Exposed setCenterLabelOffset() 217 | * Added "round_labels" parameter for better bitmap font rendering, true by default 218 | * Fixed bug where non-toggling buttons still had toggling behavior 219 | * Fixed "first frame flutter" where label correctly positions only after first update() 220 | * Newly constructed unstyled instances use default flixel-ui assets immediately 221 | * FlxUIButton 222 | * Resizing now updates label's width AND fieldWidth 223 | * FlxInputText/FlxUIInputText: 224 | * Fixed bugs with caret positions 225 | * Minor cleanup / bugfixes 226 | * FlxUIPopup 227 | * Fixed bug where events were sent to itself rather than parent state 228 | * FlxUIColorSwatch / FlxUIColorSwatchSelecter 229 | * Cleanup 230 | * Fixed null errors on neko 231 | * FlxUITabMenu 232 | * Make "back" parameter optional, creates default asset if null 233 | * FlxUI 234 | * Fixes to _loadButton that solve weird neko crashes 235 | * XML Layout: Assigning a sprite AND a text label to a button will now add them both (uses a group) 236 | * XML Layout: You can now change "params" values via modes 237 | * Lots of cleanup in various classes 238 | * Improved internal pooling and safe destruction 239 | * Added pretty-printed XML output to U.hx 240 | * Updated documentation a little. Still need to catch up. 241 | 242 | 1.0.1 (February 21, 2014) 243 | ------------------------------ 244 | * Compatibility with flixel 3.2.0 245 | * Refactored the event system 246 | * FlxUIInputText: 247 | * fixed issue with RegExp error 248 | * fixed background not showing up on native targets 249 | * fixed the destruction logic 250 | * added workaround for missing getCharIndexAtPoint() / getCharBoundary() on non-flash targets 251 | * FlxUIDropDownMenu: 252 | * content can now be changed after creation 253 | * fixed list destruction logic 254 | * Added FlxUIColorSwatch / FlxUIColorSwatchSelector 255 | 256 | 1.0.0 (February 6, 2014) 257 | ------------------------------ 258 | * Initial haxelib release 259 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Level Up Labs, LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /assets/images/box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/box.png -------------------------------------------------------------------------------- /assets/images/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/button.png -------------------------------------------------------------------------------- /assets/images/button_arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/button_arrow_down.png -------------------------------------------------------------------------------- /assets/images/button_arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/button_arrow_left.png -------------------------------------------------------------------------------- /assets/images/button_arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/button_arrow_right.png -------------------------------------------------------------------------------- /assets/images/button_arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/button_arrow_up.png -------------------------------------------------------------------------------- /assets/images/button_thin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/button_thin.png -------------------------------------------------------------------------------- /assets/images/button_toggle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/button_toggle.png -------------------------------------------------------------------------------- /assets/images/check_box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/check_box.png -------------------------------------------------------------------------------- /assets/images/check_mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/check_mark.png -------------------------------------------------------------------------------- /assets/images/chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/chrome.png -------------------------------------------------------------------------------- /assets/images/chrome_flat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/chrome_flat.png -------------------------------------------------------------------------------- /assets/images/chrome_inset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/chrome_inset.png -------------------------------------------------------------------------------- /assets/images/chrome_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/chrome_light.png -------------------------------------------------------------------------------- /assets/images/dropdown_mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/dropdown_mark.png -------------------------------------------------------------------------------- /assets/images/finger_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/finger_big.png -------------------------------------------------------------------------------- /assets/images/finger_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/finger_small.png -------------------------------------------------------------------------------- /assets/images/hilight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/hilight.png -------------------------------------------------------------------------------- /assets/images/invis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/invis.png -------------------------------------------------------------------------------- /assets/images/minus_mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/minus_mark.png -------------------------------------------------------------------------------- /assets/images/plus_mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/plus_mark.png -------------------------------------------------------------------------------- /assets/images/radio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/radio.png -------------------------------------------------------------------------------- /assets/images/radio_dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/radio_dot.png -------------------------------------------------------------------------------- /assets/images/swatch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/swatch.png -------------------------------------------------------------------------------- /assets/images/tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/tab.png -------------------------------------------------------------------------------- /assets/images/tab_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/tab_back.png -------------------------------------------------------------------------------- /assets/images/tooltip_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaxeFlixel/flixel-ui/d606db7b8512f827cd59a1e74b42ec543a1244ec/assets/images/tooltip_arrow.png -------------------------------------------------------------------------------- /assets/xml/default_loading_screen.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 21 | 22 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /assets/xml/default_popup.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /assets/xml/defaults.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /flixel/addons/ui/Anchor.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.FlxObject; 4 | import flixel.util.FlxDestroyUtil.IFlxDestroyable; 5 | 6 | /** 7 | * A class that describes how some object should be positioned relative to another 8 | */ 9 | class Anchor implements IFlxDestroyable 10 | { 11 | public var x:AnchorPoint; 12 | public var y:AnchorPoint; 13 | 14 | public static inline var LEFT:String = "left"; 15 | public static inline var RIGHT:String = "right"; 16 | public static inline var TOP:String = "top"; 17 | public static inline var BOTTOM:String = "bottom"; 18 | public static inline var CENTER:String = "center"; 19 | public static inline var UNKNOWN:String = "unknown"; 20 | 21 | public function new(XOff:Float, YOff:Float, XSide:String, YSide:String, XFlush:String, YFlush:String) 22 | { 23 | x = new AnchorPoint(XOff, XSide, XFlush); 24 | y = new AnchorPoint(YOff, YSide, YFlush); 25 | } 26 | 27 | public function destroy():Void 28 | { 29 | x = null; 30 | y = null; 31 | } 32 | 33 | public function anchorThing(thing:FlxObject, destination:FlxObject):Void 34 | { 35 | var destX:Float = 0; 36 | var destY:Float = 0; 37 | 38 | destX = switch (x.side) 39 | { 40 | case Anchor.LEFT: destination.x; 41 | case Anchor.RIGHT: destination.x + destination.width; 42 | case Anchor.CENTER: destination.x + (destination.width / 2); 43 | default: destination.x; 44 | } 45 | destY = switch (y.side) 46 | { 47 | case Anchor.TOP: destination.y; 48 | case Anchor.BOTTOM: destination.y + destination.height; 49 | case Anchor.CENTER: destination.y + (destination.height / 2); 50 | default: destination.y; 51 | } 52 | destX = switch (x.flush) 53 | { 54 | case Anchor.LEFT: destX; // no change 55 | case Anchor.RIGHT: destX - thing.width; 56 | case Anchor.CENTER: destX = destX - (thing.width / 2); 57 | default: destX; 58 | } 59 | destY = switch (y.flush) 60 | { 61 | case Anchor.TOP: destY; // no change 62 | case Anchor.BOTTOM: destY - thing.height; 63 | case Anchor.CENTER: destY - (thing.height / 2); 64 | default: destY; 65 | } 66 | thing.x = destX + x.offset; 67 | thing.y = destY + y.offset; 68 | } 69 | 70 | public function getFlipped(FlipX:Bool, FlipY:Bool, ?AnchorObject:Anchor):Anchor 71 | { 72 | var xoff = FlipX ? -1 * x.offset : x.offset; 73 | var yoff = FlipY ? -1 * y.offset : y.offset; 74 | 75 | var xside = FlipX ? flipAnchorSide(x.side) : x.side; 76 | var yside = FlipY ? flipAnchorSide(y.side) : y.side; 77 | 78 | var xflush = FlipX ? flipAnchorSide(x.flush) : x.flush; 79 | var yflush = FlipY ? flipAnchorSide(y.flush) : y.flush; 80 | 81 | if (AnchorObject == null) 82 | { 83 | AnchorObject = new Anchor(xoff, yoff, xside, yside, xflush, yflush); 84 | } 85 | else 86 | { 87 | AnchorObject.x.offset = xoff; 88 | AnchorObject.y.offset = yoff; 89 | AnchorObject.x.side = xside; 90 | AnchorObject.y.side = yside; 91 | AnchorObject.x.flush = xflush; 92 | AnchorObject.y.flush = yflush; 93 | } 94 | 95 | return AnchorObject; 96 | } 97 | 98 | public function clone():Anchor 99 | { 100 | return new Anchor(x.offset, y.offset, x.side, y.side, x.flush, y.flush); 101 | } 102 | 103 | private function flipAnchorSide(str:String):String 104 | { 105 | if (str == Anchor.LEFT) 106 | return Anchor.RIGHT; 107 | if (str == Anchor.RIGHT) 108 | return Anchor.LEFT; 109 | if (str == Anchor.TOP) 110 | return Anchor.BOTTOM; 111 | if (str == Anchor.BOTTOM) 112 | return Anchor.TOP; 113 | return str; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /flixel/addons/ui/AnchorPoint.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | class AnchorPoint 4 | { 5 | public var offset:Float = 0; // Manual offset from the anchor point 6 | public var side:String = Anchor.CENTER; // Which side of thing B is the anchor? Anchor.LEFT/RIGHT/TOP/BOTTOM/CENTER 7 | public var flush:String = Anchor.CENTER; // Which side of thing A is flush against the anchor? Anchor.LEFT/RIGHT/TOP/BOTTOM/CENTER 8 | 9 | public function new(Offset:Float, Side:String, Flush:String) 10 | { 11 | offset = Offset; 12 | side = Side; 13 | flush = Flush; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /flixel/addons/ui/BorderDef.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.text.FlxText; 4 | import flixel.util.FlxColor; 5 | 6 | class BorderDef 7 | { 8 | public var style:FlxTextBorderStyle; 9 | public var color:FlxColor; 10 | public var size:Float; 11 | public var quality:Float; 12 | 13 | public function new(Style:FlxTextBorderStyle, Color:FlxColor, Size:Float = 1, Quality:Float = 1) 14 | { 15 | style = Style; 16 | color = Color; 17 | size = Size; 18 | quality = Quality; 19 | } 20 | 21 | public function clone():BorderDef 22 | { 23 | return new BorderDef(style, color, size, quality); 24 | } 25 | 26 | public function apply(f:FlxText):FlxText 27 | { 28 | f.setBorderStyle(style, color, size, quality); 29 | return f; 30 | } 31 | 32 | public static function fromXML(data:Xml):BorderDef 33 | { 34 | var border_str:String = U.xml_str(data, "border"); 35 | var border_style:FlxTextBorderStyle = NONE; 36 | var border_color:Int = U.xml_color(data, "border_color", true, FlxColor.TRANSPARENT); 37 | var border_size:Float = U.xml_f(data, "border_size", 1); 38 | var border_quality:Float = U.xml_f(data, "border_quality", 0); 39 | 40 | var borderDef = new BorderDef(border_style, border_color, border_size, border_quality); 41 | 42 | switch (border_str) 43 | { 44 | case "false", "none": 45 | borderDef.style = NONE; 46 | case "shadow": 47 | borderDef.style = SHADOW; 48 | case "outline": 49 | borderDef.style = OUTLINE; 50 | case "outline_fast": 51 | borderDef.style = OUTLINE_FAST; 52 | case "": 53 | // no "border" value, check for shortcuts: 54 | // try "outline" 55 | border_str = U.xml_str(data, "shadow", true, ""); 56 | if (border_str != "" && border_str != "false" && border_str != "none") 57 | { 58 | borderDef.style = SHADOW; 59 | borderDef.color = U.parseHex(border_str, false, true); 60 | } 61 | else 62 | { 63 | border_str = U.xml_str(data, "outline", true, ""); 64 | if (border_str != "" && border_str != "false" && border_str != "none") 65 | { 66 | borderDef.style = OUTLINE; 67 | borderDef.color = U.parseHex(border_str, false, true); 68 | } 69 | else 70 | { 71 | border_str = U.xml_str(data, "outline_fast"); 72 | if (border_str != "" && border_str != "false" && border_str != "none") 73 | { 74 | borderDef.style = OUTLINE_FAST; 75 | borderDef.color = U.parseHex(border_str, false, true); 76 | } 77 | } 78 | } 79 | } 80 | return borderDef; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /flixel/addons/ui/ButtonLabelStyle.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.text.FlxText; 4 | 5 | class ButtonLabelStyle 6 | { 7 | public var font:FontDef = null; 8 | public var border:BorderDef = null; 9 | public var color:Null = null; 10 | public var align:FlxTextAlign = null; 11 | 12 | public function new(?Font:FontDef, ?Align:FlxTextAlign, ?Color:Int, ?Border:BorderDef) 13 | { 14 | font = Font; 15 | border = Border; 16 | color = Color; 17 | align = Align; 18 | } 19 | 20 | public function apply(f:FlxText):Void 21 | { 22 | if (font != null) 23 | { 24 | font.apply(f); 25 | } 26 | if (border != null) 27 | { 28 | border.apply(f); 29 | } 30 | if (color != null) 31 | { 32 | f.color = color; 33 | } 34 | if (align != null) 35 | { 36 | f.alignment = align; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxBaseMultiInput.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.FlxG; 4 | import flixel.input.gamepad.FlxGamepadInputID; 5 | import flixel.input.gamepad.FlxGamepad; 6 | import flixel.input.keyboard.FlxKey; 7 | import flixel.util.FlxDestroyUtil; 8 | 9 | /** 10 | * Makes it easier to check if, say, SHIFT+Tab is being pressed rather than just Tab by itself 11 | */ 12 | class FlxBaseMultiInput implements IFlxDestroyable 13 | { 14 | /** 15 | * The code for the main input itself, ie, tab, or the A button 16 | */ 17 | public var input:Int; 18 | 19 | /** 20 | * Any other inputs that must be pressed at the same time, ie, shift, alt, etc 21 | */ 22 | public var combos:Array; 23 | 24 | /** 25 | * Any other inputs, that if pressed at the same time, forbid the press. 26 | * (Forbidden is useful so you can distinguish a "TAB" from a "SHIFT+TAB" 27 | * -- you add "SHIFT" to the first one's forbidden list) 28 | */ 29 | public var forbiddens:Array; 30 | 31 | public function new() 32 | { 33 | // nothing 34 | } 35 | 36 | public function destroy():Void 37 | { 38 | combos = null; 39 | forbiddens = null; 40 | } 41 | 42 | private function checkJustPressed():Bool 43 | { 44 | return false; 45 | // override 46 | } 47 | 48 | private function checkJustReleased():Bool 49 | { 50 | return false; 51 | // override 52 | } 53 | 54 | private function checkPressed():Bool 55 | { 56 | return false; 57 | // override 58 | } 59 | 60 | /** 61 | * Was the main key JUST pressed, AND are all of the combo keys currently pressed? (and none of the forbiddens?) 62 | */ 63 | public function justPressed():Bool 64 | { 65 | return checkJustPressed() && passCombosAndForbiddens(); 66 | } 67 | 68 | /** 69 | * Was the main key JUST released, AND are no forbidden keys currently pressed? (Ignore whether combos were just released) 70 | */ 71 | public function justReleased():Bool 72 | { 73 | return checkJustReleased() && ((forbiddens == null) || (checkForbiddens(false))); 74 | } 75 | 76 | /** 77 | * Is the main key and all of the combo keys currently pressed? (and none of the forbiddens?) 78 | */ 79 | public function pressed():Bool 80 | { 81 | return checkPressed() && passCombosAndForbiddens(); 82 | } 83 | 84 | public function equals(other:FlxBaseMultiInput):Bool 85 | { 86 | if (other == null) 87 | { 88 | return false; 89 | } 90 | if (Type.typeof(other) != Type.typeof(this)) 91 | { 92 | return false; 93 | } 94 | if (input != other.input) 95 | { 96 | return false; 97 | } 98 | if ((combos == null) != (other.combos == null)) 99 | { 100 | return false; 101 | } 102 | if ((forbiddens == null) != (other.forbiddens == null)) 103 | { 104 | return false; 105 | } 106 | if (combos != null && other.combos != null) 107 | { 108 | for (i in combos) 109 | { 110 | if (other.combos.indexOf(i) == -1) 111 | { 112 | return false; 113 | } 114 | } 115 | } 116 | if (forbiddens != null && other.forbiddens != null) 117 | { 118 | for (i in forbiddens) 119 | { 120 | if (other.forbiddens.indexOf(i) == -1) 121 | { 122 | return false; 123 | } 124 | } 125 | } 126 | return true; 127 | } 128 | 129 | /** 130 | * Check Combo/Forbidden values. Default--are combos all pressed, AND are forbiddens all NOT pressed? 131 | */ 132 | private function passCombosAndForbiddens(comboValue:Bool = true, forbiddenValue:Bool = false):Bool 133 | { 134 | // Pass if combos don't exist, or if ALL of them match the specified boolean value 135 | var passCombos = (combos == null) || checkCombos(comboValue); 136 | // Pass if forbiddens don't exist, or if ALL of them match the specified boolean value 137 | var passForbiddens = (forbiddens == null) || checkForbiddens(forbiddenValue); 138 | 139 | // All must pass! 140 | return passCombos && passForbiddens; 141 | } 142 | 143 | private function checkCombos(value:Bool):Bool 144 | { 145 | // override 146 | return false; 147 | } 148 | 149 | private function checkForbiddens(value:Bool):Bool 150 | { 151 | // override 152 | return false; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxMultiGamepad.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.input.gamepad.FlxGamepad; 4 | import flixel.input.gamepad.FlxGamepadInputID; 5 | 6 | /** 7 | * ... 8 | * @author larsiusprime 9 | */ 10 | class FlxMultiGamepad extends FlxBaseMultiInput 11 | { 12 | public var gamepad:FlxGamepad; 13 | 14 | public function new(Gamepad:FlxGamepad, Input:FlxGamepadInputID, ?Combos:Array, ?Forbiddens:Array) 15 | { 16 | super(); 17 | input = Input; 18 | gamepad = Gamepad; 19 | combos = Combos; 20 | forbiddens = Forbiddens; 21 | } 22 | 23 | override public function destroy():Void 24 | { 25 | super.destroy(); 26 | gamepad = null; 27 | } 28 | 29 | private override function checkJustPressed():Bool 30 | { 31 | return gamepad.checkStatus(input, JUST_PRESSED); 32 | } 33 | 34 | private override function checkJustReleased():Bool 35 | { 36 | return gamepad.checkStatus(input, JUST_RELEASED); 37 | } 38 | 39 | private override function checkPressed():Bool 40 | { 41 | return gamepad.checkStatus(input, PRESSED); 42 | } 43 | 44 | private override function checkCombos(value:Bool):Bool 45 | { 46 | return gamepad.anyPressed(combos) == value; 47 | } 48 | 49 | private override function checkForbiddens(value:Bool):Bool 50 | { 51 | return gamepad.anyPressed(forbiddens) == value; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxMultiGamepadAnalogStick.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.addons.ui.FlxMultiGamepadAnalogStick.StickInput; 4 | import flixel.input.gamepad.FlxGamepad; 5 | import flixel.input.gamepad.FlxGamepadInputID; 6 | 7 | /** 8 | * ... 9 | * @author larsiusprime 10 | */ 11 | class FlxMultiGamepadAnalogStick extends FlxMultiGamepad 12 | { 13 | private var sInput:StickInput; 14 | 15 | public function new(Gamepad:FlxGamepad, Input:StickInput, ?Combos:Array, ?Forbiddens:Array) 16 | { 17 | sInput = Input; 18 | super(Gamepad, Input.id, Combos, Forbiddens); 19 | } 20 | 21 | override public function destroy():Void 22 | { 23 | super.destroy(); 24 | sInput = null; 25 | } 26 | 27 | /** 28 | * Given a string of the form "left_analog_stick_x_plus", returns a StickInput object with the corresponding values 29 | * @param str 30 | * @return 31 | */ 32 | public static function getStickInput(str:String):StickInput 33 | { 34 | str = str.toLowerCase(); 35 | switch (str) 36 | { 37 | case "left_analog_stick_x_minus": 38 | return {id: LEFT_ANALOG_STICK, axis: X, positive: false}; 39 | case "left_analog_stick_x_plus": 40 | return {id: LEFT_ANALOG_STICK, axis: X, positive: true}; 41 | case "left_analog_stick_y_minus": 42 | return {id: LEFT_ANALOG_STICK, axis: Y, positive: false}; 43 | case "left_analog_stick_y_plus": 44 | return {id: LEFT_ANALOG_STICK, axis: Y, positive: true}; 45 | case "right_analog_stick_x_minus": 46 | return {id: RIGHT_ANALOG_STICK, axis: X, positive: false}; 47 | case "right_analog_stick_x_plus": 48 | return {id: RIGHT_ANALOG_STICK, axis: X, positive: true}; 49 | case "right_analog_stick_y_minus": 50 | return {id: RIGHT_ANALOG_STICK, axis: Y, positive: false}; 51 | case "right_analog_stick_y_plus": 52 | return {id: RIGHT_ANALOG_STICK, axis: Y, positive: true}; 53 | } 54 | return null; 55 | } 56 | 57 | private override function checkJustPressed():Bool 58 | { 59 | if (gamepad == null) 60 | return false; 61 | var dz = gamepad.deadZone; 62 | return switch (sInput.id) 63 | { 64 | case LEFT_ANALOG_STICK: 65 | if (sInput.axis == X) 66 | { 67 | if (gamepad.analog.justMoved.LEFT_STICK_X) 68 | { 69 | sInput.positive ? gamepad.analog.value.LEFT_STICK_X > dz : gamepad.analog.value.LEFT_STICK_X < -dz; 70 | } 71 | else 72 | { 73 | false; 74 | } 75 | } 76 | else 77 | { 78 | if (gamepad.analog.justMoved.LEFT_STICK_Y) 79 | { 80 | sInput.positive ? gamepad.analog.value.LEFT_STICK_Y > dz : gamepad.analog.value.LEFT_STICK_Y < -dz; 81 | } 82 | else 83 | { 84 | false; 85 | } 86 | } 87 | case RIGHT_ANALOG_STICK: 88 | if (sInput.axis == X) 89 | { 90 | if (gamepad.analog.justMoved.RIGHT_STICK_X) 91 | { 92 | sInput.positive ? gamepad.analog.value.RIGHT_STICK_X > dz : gamepad.analog.value.RIGHT_STICK_X < -dz; 93 | } 94 | else 95 | { 96 | false; 97 | } 98 | } 99 | else 100 | { 101 | if (gamepad.analog.justMoved.RIGHT_STICK_Y) 102 | { 103 | sInput.positive ? gamepad.analog.value.RIGHT_STICK_Y > dz : gamepad.analog.value.RIGHT_STICK_Y < -dz; 104 | } 105 | else 106 | { 107 | false; 108 | } 109 | } 110 | default: false; 111 | } 112 | } 113 | 114 | private override function checkJustReleased():Bool 115 | { 116 | if (gamepad == null) 117 | return false; 118 | return switch (sInput.id) 119 | { 120 | case LEFT_ANALOG_STICK: 121 | sInput.axis == X ? gamepad.analog.justReleased.LEFT_STICK_X : gamepad.analog.justReleased.LEFT_STICK_Y; 122 | case RIGHT_ANALOG_STICK: 123 | sInput.axis == X ? gamepad.analog.justReleased.RIGHT_STICK_X : gamepad.analog.justReleased.RIGHT_STICK_Y; 124 | default: false; 125 | } 126 | } 127 | 128 | private override function checkPressed():Bool 129 | { 130 | if (gamepad == null) 131 | return false; 132 | var value = false; 133 | var dz = gamepad.deadZone; 134 | return switch (sInput.id) 135 | { 136 | case LEFT_ANALOG_STICK: 137 | if (sInput.axis == X) 138 | { 139 | sInput.positive ? gamepad.analog.value.LEFT_STICK_X > dz : gamepad.analog.value.LEFT_STICK_X < -dz; 140 | } 141 | else 142 | { 143 | sInput.positive ? gamepad.analog.value.LEFT_STICK_Y > dz : gamepad.analog.value.LEFT_STICK_Y < -dz; 144 | } 145 | case RIGHT_ANALOG_STICK: 146 | if (sInput.axis == X) 147 | { 148 | sInput.positive ? gamepad.analog.value.RIGHT_STICK_X > dz : gamepad.analog.value.RIGHT_STICK_X < -dz; 149 | } 150 | else 151 | { 152 | sInput.positive ? gamepad.analog.value.RIGHT_STICK_Y > dz : gamepad.analog.value.RIGHT_STICK_Y < -dz; 153 | } 154 | default: value = false; 155 | } 156 | return value; 157 | } 158 | 159 | private override function checkCombos(value:Bool):Bool 160 | { 161 | if (gamepad == null) 162 | return false; 163 | return gamepad.anyPressed(combos) == value; 164 | } 165 | 166 | private override function checkForbiddens(value:Bool):Bool 167 | { 168 | if (gamepad == null) 169 | return false; 170 | return gamepad.anyPressed(forbiddens) == value; 171 | } 172 | } 173 | 174 | enum XY 175 | { 176 | X; 177 | Y; 178 | } 179 | 180 | typedef StickInput = 181 | { 182 | var id:FlxGamepadInputID; 183 | var axis:XY; 184 | var positive:Bool; 185 | } 186 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxMultiKey.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.input.keyboard.FlxKey; 4 | 5 | /** 6 | * ... 7 | * @author larsiusprime 8 | */ 9 | class FlxMultiKey extends FlxBaseMultiInput 10 | { 11 | public function new(Input:FlxKey, ?Combos:Array, ?Forbiddens:Array) 12 | { 13 | super(); 14 | input = Input; 15 | combos = Combos; 16 | forbiddens = Forbiddens; 17 | } 18 | 19 | #if FLX_KEYBOARD 20 | private override function checkJustPressed():Bool 21 | { 22 | return FlxG.keys.checkStatus(input, JUST_PRESSED); 23 | } 24 | 25 | private override function checkJustReleased():Bool 26 | { 27 | return FlxG.keys.checkStatus(input, JUST_RELEASED); 28 | } 29 | 30 | private override function checkPressed():Bool 31 | { 32 | return FlxG.keys.checkStatus(input, PRESSED); 33 | } 34 | 35 | private override function checkCombos(value:Bool):Bool 36 | { 37 | return FlxG.keys.anyPressed(combos) == value; 38 | } 39 | 40 | private override function checkForbiddens(value:Bool):Bool 41 | { 42 | return FlxG.keys.anyPressed(forbiddens) == value; 43 | } 44 | #end 45 | } 46 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUIAssets.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | class FlxUIAssets 4 | { 5 | // images 6 | public static inline var IMG_BUTTON:String = "flixel/flixel-ui/img/button.png"; 7 | public static inline var IMG_BUTTON_ARROW_DOWN:String = "flixel/flixel-ui/img/button_arrow_down.png"; 8 | public static inline var IMG_BUTTON_ARROW_LEFT:String = "flixel/flixel-ui/img/button_arrow_left.png"; 9 | public static inline var IMG_BUTTON_ARROW_RIGHT:String = "flixel/flixel-ui/img/button_arrow_right.png"; 10 | public static inline var IMG_BUTTON_ARROW_UP:String = "flixel/flixel-ui/img/button_arrow_up.png"; 11 | public static inline var IMG_BUTTON_THIN:String = "flixel/flixel-ui/img/button_thin.png"; 12 | public static inline var IMG_BUTTON_TOGGLE:String = "flixel/flixel-ui/img/button_toggle.png"; 13 | 14 | public static inline var IMG_BUTTON_SIZE:Int = 18; // each of the above buttons is 18x18 15 | 16 | public static inline var IMG_CHECK_MARK:String = "flixel/flixel-ui/img/check_mark.png"; 17 | public static inline var IMG_CHECK_BOX:String = "flixel/flixel-ui/img/check_box.png"; 18 | public static inline var IMG_CHROME:String = "flixel/flixel-ui/img/chrome.png"; 19 | public static inline var IMG_CHROME_LIGHT:String = "flixel/flixel-ui/img/chrome_light.png"; 20 | public static inline var IMG_CHROME_FLAT:String = "flixel/flixel-ui/img/chrome_flat.png"; 21 | public static inline var IMG_CHROME_INSET:String = "flixel/flixel-ui/img/chrome_inset.png"; 22 | public static inline var IMG_RADIO:String = "flixel/flixel-ui/img/radio.png"; 23 | public static inline var IMG_RADIO_DOT:String = "flixel/flixel-ui/img/radio_dot.png"; 24 | public static inline var IMG_TAB:String = "flixel/flixel-ui/img/tab.png"; 25 | public static inline var IMG_TAB_BACK:String = "flixel/flixel-ui/img/tab_back.png"; 26 | public static inline var IMG_BOX:String = "flixel/flixel-ui/img/box.png"; 27 | public static inline var IMG_DROPDOWN:String = "flixel/flixel-ui/img/dropdown_mark.png"; 28 | public static inline var IMG_PLUS:String = "flixel/flixel-ui/img/plus_mark.png"; 29 | public static inline var IMG_MINUS:String = "flixel/flixel-ui/img/minus_mark.png"; 30 | public static inline var IMG_HILIGHT:String = "flixel/flixel-ui/img/hilight.png"; 31 | public static inline var IMG_INVIS:String = "flixel/flixel-ui/img/invis.png"; 32 | public static inline var IMG_SWATCH:String = "flixel/flixel-ui/img/swatch.png"; 33 | public static inline var IMG_TOOLTIP_ARROW:String = "flixel/flixel-ui/img/tooltip_arrow.png"; 34 | 35 | public static inline var IMG_FINGER_SMALL:String = "flixel/flixel-ui/img/finger_small.png"; 36 | public static inline var IMG_FINGER_BIG:String = "flixel/flixel-ui/img/finger_big.png"; 37 | 38 | // slice9 rules 39 | public static inline var SLICE9_BUTTON:String = "6,6,11,11"; 40 | public static inline var SLICE9_BUTTON_THIN:String = "2,2,15,15"; 41 | public static inline var SLICE9_BUTTON_TOGGLE:String = "6,6,11,11"; 42 | public static inline var SLICE9_TAB:String = "6,6,11,11"; 43 | 44 | // xml (default definitions) 45 | public static inline var XML_DEFAULTS_ID:String = "flixel/flixel-ui/xml/defaults"; 46 | public static inline var XML_DEFAULT_POPUP_ID:String = "flixel/flixel-ui/xml/default_popup"; 47 | public static inline var XML_DEFAULT_LOADING_SCREEN_ID:String = "flixel/flixel-ui/xml/default_loading_screen"; 48 | 49 | public static var index_size:Map> = null; 50 | } 51 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUIBar.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.addons.ui.FlxUIBar.FlxBarStyle; 4 | import flixel.addons.ui.interfaces.IFlxUIWidget; 5 | import flixel.addons.ui.interfaces.IHasParams; 6 | import flixel.addons.ui.interfaces.IResizable; 7 | import flixel.system.FlxAssets.FlxGraphicAsset; 8 | import flixel.ui.FlxBar; 9 | import flixel.util.FlxColor; 10 | 11 | /** 12 | * ... 13 | * @author larsiusprime 14 | */ 15 | class FlxUIBar extends FlxBar implements IResizable implements IFlxUIWidget implements IHasParams 16 | { 17 | public var name:String; 18 | public var style(default, set):FlxBarStyle; 19 | public var params(default, set):Array; 20 | public var broadcastToFlxUI:Bool; 21 | 22 | /** 23 | * Create a new FlxBar Object 24 | * 25 | * @param x The x coordinate location of the resulting bar (in world pixels) 26 | * @param y The y coordinate location of the resulting bar (in world pixels) 27 | * @param direction The fill direction, LEFT_TO_RIGHT by default 28 | * @param width The width of the bar in pixels 29 | * @param height The height of the bar in pixels 30 | * @param parentRef A reference to an object in your game that you wish the bar to track 31 | * @param variable The variable of the object that is used to determine the bar position. For example if the parent was an FlxSprite this could be "health" to track the health value 32 | * @param min The minimum value. I.e. for a progress bar this would be zero (nothing loaded yet) 33 | * @param max The maximum value the bar can reach. I.e. for a progress bar this would typically be 100. 34 | * @param showBorder Include a 1px border around the bar? (if true it adds +2 to width and height to accommodate it) 35 | */ 36 | public function new(x:Float = 0, y:Float = 0, ?direction:FlxBarFillDirection, width:Int = 100, height:Int = 10, ?parentRef:Dynamic, variable:String = "", 37 | min:Float = 0, max:Float = 100, showBorder:Bool = false) 38 | { 39 | super(x, y, direction, width, height, parentRef, variable, min, max, showBorder); 40 | } 41 | 42 | override public function clone():FlxSprite 43 | { 44 | var w:Int = Std.int(width); 45 | var h:Int = Std.int(height); 46 | var showBorder = (style != null && style.borderColor != null); 47 | if (showBorder) 48 | { 49 | w -= 2; 50 | h -= 2; 51 | } 52 | var b:FlxUIBar = new FlxUIBar(x, y, fillDirection, w, h, parent, parentVariable, min, max, showBorder); 53 | b.style = style; 54 | b.value = value; 55 | return b; 56 | } 57 | 58 | /** 59 | * Applies a new style to this FlxBar and redraws it 60 | */ 61 | public function set_style(Style:FlxBarStyle):FlxBarStyle 62 | { 63 | style = Style; 64 | resize(barWidth, barHeight); 65 | return style; 66 | } 67 | 68 | public function resize(w:Float, h:Float):Void 69 | { 70 | width = w; 71 | height = h; 72 | 73 | barWidth = Std.int(width); 74 | barHeight = Std.int(height); 75 | 76 | if (FlxG.renderBlit) 77 | { 78 | makeGraphic(barWidth, barHeight, FlxColor.TRANSPARENT, true); 79 | } 80 | 81 | var showBorder = (style.borderColor != null); 82 | 83 | var ec = style.emptyColor == null ? FlxColor.BLACK : style.emptyColor; 84 | var fc = style.filledColor == null ? FlxColor.RED : style.filledColor; 85 | var bc = style.borderColor == null ? FlxColor.BLACK : style.borderColor; 86 | 87 | if (style.filledColor != null) 88 | { 89 | createFilledBar(ec, fc, showBorder, bc); 90 | } 91 | 92 | if (style.filledColors != null) 93 | { 94 | var ecs = style.emptyColors == null ? [FlxColor.BLACK] : style.emptyColors; 95 | var fcs = style.filledColors == null ? [FlxColor.RED] : style.filledColors; 96 | var chunk = style.chunkSize == null ? 1 : style.chunkSize; 97 | var gradRot = style.emptyImgSrc == null ? 180 : style.gradRotation; 98 | createGradientBar(ecs, fcs, chunk, gradRot, showBorder, bc); 99 | } 100 | 101 | if (style.filledImgSrc != "") 102 | { 103 | createImageBar(style.emptyImgSrc, style.filledImgSrc, ec, fc); 104 | } 105 | 106 | setRange(min, max); 107 | value = value; 108 | } 109 | 110 | private function set_params(p:Array):Array 111 | { 112 | params = p; 113 | return params; 114 | } 115 | } 116 | 117 | typedef FlxBarStyle = 118 | { 119 | var filledColors:Array; 120 | var emptyColors:Array; 121 | 122 | var chunkSize:Null; 123 | var gradRotation:Null; 124 | var filledColor:Null; 125 | var emptyColor:Null; 126 | var borderColor:Null; 127 | var filledImgSrc:String; 128 | var emptyImgSrc:String; 129 | } 130 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUIButton.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import openfl.display.BitmapData; 4 | import openfl.geom.Point; 5 | import openfl.geom.Rectangle; 6 | import openfl.text.Font; 7 | import openfl.text.TextFormat; 8 | import flixel.addons.ui.BorderDef; 9 | import flixel.addons.ui.FontDef; 10 | import flixel.addons.ui.interfaces.IFlxUIButton; 11 | import flixel.addons.ui.interfaces.IHasParams; 12 | import flixel.addons.ui.interfaces.ILabeled; 13 | import flixel.FlxSprite; 14 | import flixel.math.FlxMath; 15 | import flixel.system.FlxAssets; 16 | import flixel.text.FlxText; 17 | import flixel.util.FlxColor; 18 | import flixel.util.FlxDestroyUtil; 19 | import openfl.Assets; 20 | import openfl.text.TextFormatAlign; 21 | 22 | /** 23 | * This class extends FlxUITypedButton and has a Text label, and is thus 24 | * most analagous to the regular FlxButton 25 | * 26 | * Like all FlxUITypedButton's, it can work as a toggle button, and load 27 | * 9-slice sprites for its button images, and be dynamically resized 28 | * accordingly. 29 | * 30 | * Furthermore, you have the ability to set the text's coloring for each 31 | * state just by adjusting a few public variables 32 | */ 33 | class FlxUIButton extends FlxUITypedButton implements ILabeled implements IFlxUIButton 34 | { 35 | private var _noIconGraphicsBkup:BitmapData; 36 | 37 | public var up_style:ButtonLabelStyle = null; 38 | public var over_style:ButtonLabelStyle = null; 39 | public var down_style:ButtonLabelStyle = null; 40 | 41 | public var up_toggle_style:ButtonLabelStyle = null; 42 | public var over_toggle_style:ButtonLabelStyle = null; 43 | public var down_toggle_style:ButtonLabelStyle = null; 44 | 45 | /** 46 | * Creates a new FlxUIButton. 47 | * 48 | * @param X The X position of the button. 49 | * @param Y The Y position of the button. 50 | * @param Label The text that you want to appear on the button. 51 | * @param OnClick The function to call whenever the button is clicked. 52 | * @param LoadDefaultGraphics By default it will load up with placeholder graphics. Pass false if you want to skip this (i.e. if you will provide your own graphics subsequently, can save time) 53 | * @param LoadBlank Load this button without ANY visible graphics, but still functions (in case you need an invisible click area) 54 | */ 55 | public function new(X:Float = 0, Y:Float = 0, ?Label:String, ?OnClick:Void->Void, ?LoadDefaultGraphics:Bool = true, ?LoadBlank:Bool = false, 56 | ?Color:FlxColor = FlxColor.WHITE) 57 | { 58 | super(X, Y, OnClick); 59 | color = Color; 60 | if (Label != null) 61 | { 62 | // create a FlxUIText label 63 | label = new FlxUIText(0, 0, 80, Label, 8); 64 | label.setFormat(null, 8, 0x333333, FlxTextAlign.CENTER); 65 | } 66 | 67 | if (LoadBlank) 68 | { 69 | _no_graphic = true; 70 | } 71 | 72 | if (LoadDefaultGraphics) 73 | { 74 | resize(width, height); // force it to be "FlxUI style" 75 | } 76 | else 77 | { 78 | if (_no_graphic == false) 79 | { 80 | doResize(width, height, false); 81 | // initialize dimensions but don't initialize any graphics yet. 82 | // this is ugly, but if you're about to set the graphics 83 | // yourself in a subsequent call it's much faster to skip! 84 | } 85 | else 86 | { 87 | doResize(width, height, true); 88 | } 89 | } 90 | } 91 | 92 | /** 93 | * You can use this if you have a lot of text parameters 94 | * to set instead of the individual properties. 95 | * 96 | * @param Font The name of the font face for the text display. 97 | * @param Size The size of the font (in pixels essentially). 98 | * @param Color The color of the text in traditional flash 0xRRGGBB format. 99 | * @param Alignment The desired alignment 100 | * @param BorderStyle NONE, SHADOW, OUTLINE, or OUTLINE_FAST (use setBorderFormat) 101 | * @param BorderColor Int, color for the border, 0xRRGGBB format 102 | * @param EmbeddedFont Whether this text field uses embedded fonts or not 103 | * @return This FlxText instance (nice for chaining stuff together, if you're into that). 104 | */ 105 | public function setLabelFormat(?Font:String, Size:Int = 8, Color:FlxColor = FlxColor.WHITE, ?Alignment:FlxTextAlign, ?BorderStyle:FlxTextBorderStyle, 106 | BorderColor:FlxColor = FlxColor.TRANSPARENT, Embedded:Bool = true):FlxText 107 | { 108 | if (label != null) 109 | { 110 | label.setFormat(Font, Size, Color, Alignment, BorderStyle, BorderColor, Embedded); 111 | #if flash 112 | // A VERY NECESSARY HACK 113 | // on Flash target, the height does not update for another frame, so autocentering will break 114 | // HOWEVER! height is always equal to the truncated textHeight + 4 (there's a 2-pixel gutter on top & bottom) 115 | // so we go ahead and set that right away for autocentering purposes: 116 | label.height = Std.int(label.textField.textHeight) + 4; 117 | #end 118 | return label; 119 | } 120 | return null; 121 | } 122 | 123 | public override function autoCenterLabel():Void 124 | { 125 | super.autoCenterLabel(); 126 | } 127 | 128 | public override function clone():FlxUIButton 129 | { 130 | var newButton = new FlxUIButton(0, 0, (label == null) ? null : label.text, onUp.callback, false); 131 | newButton.copyGraphic(cast this); 132 | newButton.copyStyle(cast this); 133 | return newButton; 134 | } 135 | 136 | public override function copyStyle(other:FlxUITypedButton):Void 137 | { 138 | super.copyStyle(other); 139 | if ((other is FlxUIButton)) 140 | { 141 | var fuib:FlxUIButton = cast other; 142 | 143 | up_style = fuib.up_style; 144 | over_style = fuib.over_style; 145 | down_style = fuib.down_style; 146 | 147 | up_toggle_style = fuib.up_toggle_style; 148 | over_toggle_style = fuib.over_toggle_style; 149 | down_toggle_style = fuib.down_toggle_style; 150 | 151 | var t:FlxUIText = fuib.label; 152 | 153 | var tf:TextFormat = t.textField.defaultTextFormat; 154 | 155 | if (t.font.indexOf(FlxAssets.FONT_DEFAULT) == -1) 156 | { 157 | var fd:FontDef = FontDef.copyFromFlxText(t); 158 | fd.apply(label); 159 | } 160 | else 161 | { 162 | var flxAlign = FlxTextAlign.fromOpenFL(tf.align); 163 | 164 | // put "null" for the default font 165 | label.setFormat(null, Std.int(tf.size), tf.color, flxAlign, t.borderStyle, t.borderColor, t.embedded); 166 | } 167 | } 168 | } 169 | 170 | /**For ILabeled:**/ 171 | public function setLabel(t:FlxUIText):FlxUIText 172 | { 173 | label = t; 174 | return label; 175 | } 176 | 177 | public function getLabel():FlxUIText 178 | { 179 | return label; 180 | } 181 | 182 | /**For IResizable:**/ 183 | public override function resize(W:Float, H:Float):Void 184 | { 185 | super.resize(W, H); 186 | } 187 | 188 | public function addIcon(icon:FlxSprite, X:Int = 0, Y:Int = 0, ?center:Bool = true) 189 | { 190 | // Creates a backup of current button image. 191 | _noIconGraphicsBkup = graphic.bitmap.clone(); 192 | 193 | // create a new bitmap to avoid caching issues 194 | var newBmp = _noIconGraphicsBkup.clone(); 195 | 196 | // create a unique key for the new graphic 197 | var key = graphic.key + ",icon:" + icon.graphic.key; 198 | var newGraphic = FlxG.bitmap.add(newBmp, false, key); 199 | 200 | // load the new bitmap 201 | loadGraphic(newGraphic, true, Std.int(width), Std.int(height)); 202 | 203 | var sx:Int = X; 204 | var sy:Int = Y; 205 | 206 | if (center) 207 | { 208 | sx = Std.int((width - icon.width) / 2); 209 | sy = Std.int((height - icon.height) / 2); 210 | } 211 | 212 | // Stamps the icon in every frame of this button. 213 | for (i in 0...numFrames) 214 | { 215 | stamp(icon, sx 216 | + Std.int(labelOffsets[FlxMath.minInt(i, 2)].x), sy 217 | + Std.int(i * height) 218 | + Std.int(labelOffsets[FlxMath.minInt(i, 2)].y)); 219 | } 220 | } 221 | 222 | public function removeIcon() 223 | { 224 | if (_noIconGraphicsBkup != null) 225 | { 226 | // Retreives the stored button image before icon was applied. 227 | graphic.bitmap.fillRect(graphic.bitmap.rect, 0x0); // clears the bitmap first. 228 | graphic.bitmap.copyPixels(_noIconGraphicsBkup, new Rectangle(0, 0, _noIconGraphicsBkup.width, _noIconGraphicsBkup.height), new Point()); 229 | dirty = true; 230 | 231 | #if flash 232 | calcFrame(); 233 | #end 234 | } 235 | } 236 | 237 | public function changeIcon(newIcon:FlxSprite) 238 | { 239 | removeIcon(); 240 | addIcon(newIcon); 241 | } 242 | 243 | override public function destroy():Void 244 | { 245 | _noIconGraphicsBkup = FlxDestroyUtil.dispose(_noIconGraphicsBkup); 246 | super.destroy(); 247 | } 248 | 249 | /**********PRIVATE*********/ 250 | override function loadDefaultGraphic():Void 251 | { 252 | // do nothing -- suppresses FlxTypedButton's default graphics loader 253 | } 254 | 255 | /** 256 | * Updates the size of the text field to match the button. 257 | */ 258 | override private function resetHelpers():Void 259 | { 260 | super.resetHelpers(); 261 | 262 | if (label != null) 263 | { 264 | label.width = label.frameWidth = Std.int(width); 265 | label.fieldWidth = label.width; 266 | label.size = label.size; 267 | } 268 | } 269 | 270 | override private function onDownHandler():Void 271 | { 272 | super.onDownHandler(); 273 | if (label != null) 274 | { 275 | if (toggled && down_toggle_style != null) 276 | { 277 | label.color = down_toggle_style.color; 278 | if (down_toggle_style.border != null) 279 | { 280 | label.borderStyle = down_toggle_style.border.style; 281 | label.borderColor = down_toggle_style.border.color; 282 | label.borderSize = down_toggle_style.border.size; 283 | label.borderQuality = down_toggle_style.border.quality; 284 | } 285 | } 286 | else if (!toggled && down_style != null) 287 | { 288 | label.color = down_style.color; 289 | if (down_style.border != null) 290 | { 291 | label.borderStyle = down_style.border.style; 292 | label.borderColor = down_style.border.color; 293 | label.borderSize = down_style.border.size; 294 | label.borderQuality = down_style.border.quality; 295 | } 296 | } 297 | } 298 | } 299 | 300 | override private function onOverHandler():Void 301 | { 302 | super.onOverHandler(); 303 | if (label != null) 304 | { 305 | if (toggled && over_toggle_style != null) 306 | { 307 | label.color = over_toggle_style.color; 308 | if (over_toggle_style.border != null) 309 | { 310 | label.borderStyle = over_toggle_style.border.style; 311 | label.borderColor = over_toggle_style.border.color; 312 | label.borderSize = over_toggle_style.border.size; 313 | label.borderQuality = over_toggle_style.border.quality; 314 | } 315 | } 316 | else if (!toggled && over_style != null) 317 | { 318 | label.color = over_style.color; 319 | if (over_style.border != null) 320 | { 321 | label.borderStyle = over_style.border.style; 322 | label.borderColor = over_style.border.color; 323 | label.borderSize = over_style.border.size; 324 | label.borderQuality = over_style.border.quality; 325 | } 326 | } 327 | } 328 | } 329 | 330 | override private function onOutHandler():Void 331 | { 332 | super.onOutHandler(); 333 | if (label != null) 334 | { 335 | if (toggled && up_toggle_style != null) 336 | { 337 | label.color = up_toggle_style.color; 338 | if (up_toggle_style.border != null) 339 | { 340 | label.borderStyle = up_toggle_style.border.style; 341 | label.borderColor = up_toggle_style.border.color; 342 | label.borderSize = up_toggle_style.border.size; 343 | label.borderQuality = up_toggle_style.border.quality; 344 | } 345 | } 346 | else if (!toggled && up_style != null) 347 | { 348 | label.color = up_style.color; 349 | if (up_style.border != null) 350 | { 351 | label.borderStyle = up_style.border.style; 352 | label.borderColor = up_style.border.color; 353 | label.borderSize = up_style.border.size; 354 | label.borderQuality = up_style.border.quality; 355 | } 356 | } 357 | } 358 | } 359 | 360 | override private function onUpHandler():Void 361 | { 362 | super.onUpHandler(); 363 | if (label != null) 364 | { 365 | if (toggled && up_toggle_style != null) 366 | { 367 | label.color = up_toggle_style.color; 368 | if (up_toggle_style.border != null) 369 | { 370 | label.borderStyle = up_toggle_style.border.style; 371 | label.borderColor = up_toggle_style.border.color; 372 | label.borderSize = up_toggle_style.border.size; 373 | label.borderQuality = up_toggle_style.border.quality; 374 | } 375 | } 376 | else if (!toggled && up_style != null) 377 | { 378 | label.color = up_style.color; 379 | if (up_style.border != null) 380 | { 381 | label.borderStyle = up_style.border.style; 382 | label.borderColor = up_style.border.color; 383 | label.borderSize = up_style.border.size; 384 | label.borderQuality = up_style.border.quality; 385 | } 386 | } 387 | } 388 | } 389 | } 390 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUICheckBox.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.addons.ui.FlxUI.NamedBool; 4 | import flixel.addons.ui.interfaces.ICursorPointable; 5 | import flixel.addons.ui.interfaces.IFlxUIButton; 6 | import flixel.addons.ui.interfaces.IFlxUIClickable; 7 | import flixel.addons.ui.interfaces.IHasParams; 8 | import flixel.addons.ui.interfaces.ILabeled; 9 | import flixel.FlxSprite; 10 | import flixel.text.FlxText; 11 | import flixel.ui.FlxButton; 12 | import flixel.util.FlxTimer; 13 | 14 | /** 15 | * @author Lars Doucet 16 | */ 17 | class FlxUICheckBox extends FlxUIGroup implements ILabeled implements IFlxUIClickable implements IHasParams implements ICursorPointable 18 | { 19 | public var box:FlxSprite; 20 | public var mark:FlxSprite; 21 | public var button:FlxUIButton; 22 | public var max_width:Float = -1; 23 | 24 | public var checked(default, set):Bool = false; 25 | public var params(default, set):Array; 26 | 27 | // Set this to false if you just want the checkbox itself to be clickable 28 | public var textIsClickable:Bool = true; 29 | 30 | public var checkbox_dirty:Bool = false; 31 | 32 | public var textX(default, set):Float = 0; 33 | public var textY(default, set):Float = 0; 34 | 35 | public var box_space:Float = 2; 36 | 37 | public var skipButtonUpdate(default, set):Bool = false; 38 | 39 | public var callback:Void->Void; 40 | 41 | public static inline var CLICK_EVENT:String = "click_check_box"; 42 | 43 | private function set_skipButtonUpdate(b:Bool):Bool 44 | { 45 | skipButtonUpdate = b; 46 | button.skipButtonUpdate = skipButtonUpdate; 47 | return skipButtonUpdate; 48 | } 49 | 50 | private function set_params(p:Array):Array 51 | { 52 | params = p; 53 | if (params == null) 54 | { 55 | params = []; 56 | } 57 | var nb:NamedBool = {name: "checked", value: checked}; 58 | params.push(nb); 59 | return params; 60 | } 61 | 62 | private override function set_color(Value:Int):Int 63 | { 64 | if (button != null) 65 | { 66 | button.label.color = Value; 67 | } 68 | return super.set_color(Value); 69 | } 70 | 71 | public function new(X:Float = 0, Y:Float = 0, ?Box:Dynamic, ?Check:Dynamic, ?Label:String, ?LabelW:Int = 100, ?Params:Array, ?Callback:Void->Void) 72 | { 73 | super(); 74 | 75 | callback = Callback; 76 | 77 | params = Params; 78 | 79 | if (Box == null) 80 | { 81 | // if null create a simple checkbox outline 82 | Box = FlxUIAssets.IMG_CHECK_BOX; 83 | } 84 | 85 | if ((Box is FlxSprite)) 86 | { 87 | box = cast Box; 88 | } 89 | else 90 | { 91 | box = new FlxSprite(); 92 | box.loadGraphic(Box, true); 93 | } 94 | 95 | button = new FlxUIButton(0, 0, Label, _clickCheck); 96 | 97 | // set default checkbox label format 98 | button.label.setFormat(null, 8, 0xffffff, "left", OUTLINE); 99 | button.label.fieldWidth = LabelW; 100 | button.up_color = 0xffffff; 101 | button.down_color = 0xffffff; 102 | button.over_color = 0xffffff; 103 | button.up_toggle_color = 0xffffff; 104 | button.down_toggle_color = 0xffffff; 105 | button.over_toggle_color = 0xffffff; 106 | 107 | button.loadGraphicSlice9(["", "", ""], Std.int(box.width + box_space + LabelW), Std.int(box.height)); 108 | 109 | max_width = Std.int(box.width + box_space + LabelW); 110 | 111 | button.onUp.callback = _clickCheck; // for internal use, check/uncheck box, bubbles up to _externalCallback 112 | 113 | if (Check == null) 114 | { 115 | // if null load from default assets: 116 | Check = FlxUIAssets.IMG_CHECK_MARK; 117 | } 118 | 119 | if ((Check is FlxSprite)) 120 | { 121 | mark = cast Check; 122 | } 123 | else 124 | { 125 | mark = new FlxSprite(); 126 | mark.loadGraphic(Check); 127 | } 128 | 129 | add(box); 130 | add(mark); 131 | add(button); 132 | 133 | anchorLabelX(); 134 | anchorLabelY(); 135 | 136 | checked = false; 137 | 138 | // set all these to 0 139 | button.setAllLabelOffsets(0, 0); 140 | 141 | x = X; 142 | y = Y; 143 | 144 | textX = 0; 145 | textY = 0; // forces anchorLabel() to be called and upate correctly 146 | } 147 | 148 | /* 149 | public function copy(?Params:Array,?Callback:Void->Void):FlxUICheckBox { 150 | var boxAsset:String = box != null ? box.cachedGraphics.key : null; 151 | var checkAsset:String = mark != null ? mark.cachedGraphics.key : null; 152 | var label:String = (button != null && button.label != null) ? button.label.text : null; 153 | var labelW:Int = (label != null) ? Std.int(button.label.width) : 100; 154 | return new FlxUICheckBox(x, y, boxAsset, checkAsset, label, labelW, Params, Callback); 155 | }*/ 156 | /**For ILabeled:**/ 157 | public function setLabel(t:FlxUIText):FlxUIText 158 | { 159 | if (button == null) 160 | { 161 | return null; 162 | } 163 | button.label = t; 164 | return button.label; 165 | } 166 | 167 | public function getLabel():FlxUIText 168 | { 169 | if (button == null) 170 | { 171 | return null; 172 | } 173 | return button.label; 174 | } 175 | 176 | private override function set_visible(Value:Bool):Bool 177 | { 178 | // don't cascade to my members 179 | visible = Value; 180 | return visible; 181 | } 182 | 183 | private function anchorTime(f:FlxTimer):Void 184 | { 185 | anchorLabelY(); 186 | } 187 | 188 | private function set_textX(n:Float):Float 189 | { 190 | textX = n; 191 | anchorLabelX(); 192 | return textX; 193 | } 194 | 195 | private function set_textY(n:Float):Float 196 | { 197 | textY = n; 198 | anchorLabelY(); 199 | return textY; 200 | } 201 | 202 | public function anchorLabelX():Void 203 | { 204 | if (button != null) 205 | { 206 | button.label.offset.x = -((box.width + box_space) + textX); 207 | } 208 | } 209 | 210 | public function anchorLabelY():Void 211 | { 212 | if (button != null) 213 | { 214 | button.y = box.y + (box.height - button.height) / 2 + textY; 215 | } 216 | } 217 | 218 | public override function destroy():Void 219 | { 220 | super.destroy(); 221 | if (mark != null) 222 | { 223 | mark.destroy(); 224 | mark = null; 225 | } 226 | if (box != null) 227 | { 228 | box.destroy(); 229 | box = null; 230 | } 231 | if (button != null) 232 | { 233 | button.destroy(); 234 | button = null; 235 | } 236 | } 237 | 238 | public var text(get, set):String; 239 | 240 | private function get_text():String 241 | { 242 | return button.label.text; 243 | } 244 | 245 | private function set_text(value:String):String 246 | { 247 | button.label.text = value; 248 | checkbox_dirty = true; 249 | return value; 250 | } 251 | 252 | public override function update(elapsed:Float):Void 253 | { 254 | super.update(elapsed); 255 | 256 | if (checkbox_dirty) 257 | { 258 | if (button.label != null) 259 | { 260 | if ((button.label is FlxUIText)) 261 | { 262 | var ftu:FlxUIText = cast button.label; 263 | ftu.drawFrame(); // force update 264 | } 265 | anchorLabelX(); 266 | anchorLabelY(); 267 | button.width = box.frameWidth + box_space + 268 | button.label.textField.textWidth; // makes the clickable size exactly match the visible size of checkbox+label 269 | checkbox_dirty = false; 270 | } 271 | } 272 | } 273 | 274 | /*****GETTER/SETTER***/ 275 | private function set_checked(b:Bool):Bool 276 | { 277 | mark.visible = b; 278 | return checked = b; 279 | } 280 | 281 | /*****PRIVATE******/ 282 | private function _clickCheck():Void 283 | { 284 | if (!visible) 285 | { 286 | return; 287 | } 288 | checked = !checked; 289 | if (callback != null) 290 | { 291 | callback(); 292 | } 293 | if (broadcastToFlxUI) 294 | { 295 | FlxUI.event(FlxUICheckBox.CLICK_EVENT, this, checked, params); 296 | } 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUIColorSwatch.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import openfl.geom.Rectangle; 4 | import flixel.addons.ui.FlxUISprite; 5 | import flixel.addons.ui.interfaces.ICursorPointable; 6 | import flixel.FlxG; 7 | import flixel.FlxSprite; 8 | import flixel.util.FlxColor; 9 | import flixel.util.FlxStringUtil; 10 | 11 | class FlxUIColorSwatch extends FlxUIButton 12 | { 13 | public var multiColored(default, set):Bool; 14 | public var hilight(default, set):Int; 15 | public var midtone(default, set):Int; 16 | public var shadowMid(default, set):Int; 17 | public var shadowDark(default, set):Int; 18 | public var colors(default, set):SwatchData; 19 | 20 | public var callback:Void->Void; 21 | 22 | public static inline var CLICK_EVENT:String = "click_color_swatch"; 23 | 24 | /**SETTERS**/ 25 | private override function set_color(Color:Int):Int 26 | { 27 | midtone = Color; // color does double duty for midtone 28 | return super.set_color(color); 29 | } 30 | 31 | public override function destroy():Void 32 | { 33 | callback = null; 34 | super.destroy(); 35 | } 36 | 37 | /** 38 | * Set a color at a specific index in the swatch 39 | * @param Color 40 | * @param index 41 | */ 42 | public function setColorAtIndex(Color:Int, index:Int):Void 43 | { 44 | _skipRefresh = true; 45 | switch (index) 46 | { 47 | case 0: 48 | hilight = Color; 49 | case 1: 50 | midtone = Color; 51 | case 2: 52 | shadowMid = Color; 53 | case 3: 54 | shadowDark = Color; 55 | default: 56 | colors.colors[index] = Color; 57 | } 58 | _skipRefresh = false; 59 | refreshColor(); 60 | } 61 | 62 | private function set_colors(Colors:SwatchData):SwatchData 63 | { 64 | if (colors != null) 65 | { 66 | colors.destroy(); 67 | colors = null; 68 | } 69 | 70 | _skipRefresh = true; 71 | 72 | colors = Colors.copy(); 73 | 74 | hilight = colors.hilight; 75 | midtone = colors.midtone; 76 | shadowMid = colors.shadowMid; 77 | shadowDark = colors.shadowDark; 78 | 79 | _skipRefresh = false; 80 | refreshColor(); 81 | return Colors; 82 | } 83 | 84 | /** 85 | * If true, the swatch will draw itself dynamically based on the four colors provided 86 | */ 87 | private function set_multiColored(b:Bool):Bool 88 | { 89 | multiColored = b; 90 | refreshColor(); 91 | return multiColored; 92 | } 93 | 94 | private function set_hilight(i:Int):Int 95 | { 96 | hilight = i; 97 | colors.hilight = hilight; 98 | refreshColor(); 99 | return hilight; 100 | } 101 | 102 | private function set_midtone(i:Int):Int 103 | { 104 | midtone = i; 105 | colors.midtone = midtone; 106 | refreshColor(); 107 | return midtone; 108 | } 109 | 110 | private function set_shadowMid(i:Int):Int 111 | { 112 | shadowMid = i; 113 | colors.shadowMid = shadowMid; 114 | refreshColor(); 115 | return shadowMid; 116 | } 117 | 118 | private function set_shadowDark(i:Int):Int 119 | { 120 | shadowDark = i; 121 | colors.shadowDark = shadowDark; 122 | refreshColor(); 123 | return shadowDark; 124 | } 125 | 126 | /** 127 | * Creates a new color swatch that can store and display a color value 128 | * @param Color Single color for the swatch 129 | * @param Colors Multiple colors for the swatch 130 | * @param Asset An asset for the swatch graphic (optional) 131 | * @param Callback Function to call when clicked 132 | */ 133 | public function new(X:Float, Y:Float, ?Color:Int = 0xFFFFFF, ?Colors:SwatchData, ?Asset:Dynamic, ?Callback:Void->Void, Width:Int = -1, Height:Int = -1) 134 | { 135 | super(X, Y, onClick); 136 | 137 | callback = Callback; 138 | 139 | _skipRefresh = true; 140 | 141 | if (Width != -1 && Height != -1) 142 | { 143 | makeGraphic(Width, Height, FlxColor.WHITE, true, "Swatch" + Width + "x" + Height); 144 | } 145 | else if (Asset != null) 146 | { 147 | loadGraphic(Asset); // load custom asset if provided 148 | } 149 | else 150 | { 151 | loadGraphic(FlxUIAssets.IMG_SWATCH); // load default monochrome swatch 152 | } 153 | 154 | _origKey = graphic.key; 155 | 156 | if (Color != 0xFFFFFF) 157 | { 158 | multiColored = false; 159 | color = Color; 160 | } 161 | 162 | if (Colors != null) 163 | { 164 | multiColored = true; 165 | colors = Colors; 166 | } 167 | 168 | _skipRefresh = false; 169 | refreshColor(); 170 | } 171 | 172 | public function equalsSwatch(swatch:SwatchData):Bool 173 | { 174 | return swatch.doColorsEqual(colors); 175 | } 176 | 177 | public function getRawDifferenceSwatch(swatch:SwatchData):Int 178 | { 179 | return swatch.getRawDifference(colors); 180 | } 181 | 182 | public function refreshColor():Void 183 | { 184 | if (_skipRefresh) 185 | { 186 | return; 187 | } 188 | 189 | var key:String = colorKey(); 190 | 191 | if (multiColored) 192 | { 193 | if (graphic.key != key) 194 | { 195 | if (FlxG.bitmap.checkCache(key) == false) // draw the swatch dynamically from supplied color values 196 | { 197 | makeGraphic(Std.int(width), Std.int(height), 0xFFFFFFFF, true, key); 198 | _flashRect.x = 0; 199 | _flashRect.y = 0; 200 | _flashRect.width = pixels.width; 201 | _flashRect.height = pixels.height; 202 | pixels.fillRect(_flashRect, 0xFF000000); // start with black outline 203 | 204 | var tempCols:Array = []; 205 | 206 | for (i in 0...colors.colors.length) 207 | { 208 | var col:Int = colors.colors[i]; 209 | if (col != 0) 210 | { 211 | tempCols.push(col); 212 | } 213 | } 214 | 215 | var thickW:Int = Std.int(Std.int((width - 2) / 2) / tempCols.length); 216 | var thickH:Int = Std.int(Std.int((height - 2) / 2) / tempCols.length); 217 | 218 | _flashRect.x += 1; 219 | _flashRect.y += 1; 220 | _flashRect.width -= 2; 221 | _flashRect.height -= 2; 222 | for (i in 0...tempCols.length) 223 | { 224 | var col:Int = tempCols[(tempCols.length - 1) - i]; 225 | pixels.fillRect(_flashRect, col); 226 | _flashRect.width -= (thickW * 2); 227 | _flashRect.height -= (thickH * 2); 228 | _flashRect.x += thickW; 229 | _flashRect.y += thickH; 230 | } 231 | 232 | U.clearArray(tempCols); 233 | tempCols = null; 234 | 235 | calcFrame(); 236 | } 237 | else 238 | { 239 | loadGraphic(key); 240 | } 241 | } 242 | } 243 | else 244 | { 245 | if (graphic.key != key) // load the right asset 246 | { 247 | loadGraphic(key); 248 | } 249 | color = midtone; // just rely on color-tinting 250 | } 251 | } 252 | 253 | private var _origKey:String = ""; 254 | private var _skipRefresh:Bool = false; 255 | 256 | private function onClick():Void 257 | { 258 | if (callback != null) 259 | { 260 | callback(); 261 | } 262 | if (broadcastToFlxUI) 263 | { 264 | if (multiColored) 265 | { 266 | FlxUI.event(CLICK_EVENT, this, colors); 267 | } 268 | else 269 | { 270 | FlxUI.event(CLICK_EVENT, this, color); 271 | } 272 | } 273 | } 274 | 275 | public function colorKey():String 276 | { 277 | if (multiColored) 278 | { 279 | var str:String = _origKey; 280 | for (c in colors.colors) 281 | { 282 | str += "+" + c.toWebString(); 283 | } 284 | return str; 285 | } 286 | return _origKey; 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUIColorSwatchSelecter.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import openfl.geom.Rectangle; 4 | import flixel.addons.ui.FlxUIColorSwatchSelecter.SwatchGraphic; 5 | import flixel.addons.ui.interfaces.IFlxUIClickable; 6 | import flixel.FlxSprite; 7 | import flixel.group.FlxSpriteGroup; 8 | import flixel.system.FlxAssets.FlxGraphicAsset; 9 | 10 | /** 11 | * ... 12 | * @author larsiusprime 13 | */ 14 | class FlxUIColorSwatchSelecter extends FlxUIGroup implements IFlxUIClickable 15 | { 16 | public static inline var CLICK_EVENT:String = "click_color_swatch_selecter"; 17 | 18 | public var spacingH(default, set):Float; 19 | public var spacingV(default, set):Float; 20 | public var maxColumns(default, set):Float; 21 | 22 | var _previewSwatch:FlxUIColorSwatch; 23 | 24 | private function set_spacingH(f:Float):Float 25 | { 26 | spacingH = f; 27 | _dirtyLayout = true; 28 | return f; 29 | } 30 | 31 | private function set_spacingV(f:Float):Float 32 | { 33 | spacingV = f; 34 | _dirtyLayout = true; 35 | return f; 36 | } 37 | 38 | private function set_maxColumns(f:Float):Float 39 | { 40 | maxColumns = f; 41 | _dirtyLayout = true; 42 | return f; 43 | } 44 | 45 | public var skipButtonUpdate(default, set):Bool; 46 | 47 | private function set_skipButtonUpdate(b:Bool):Bool 48 | { 49 | skipButtonUpdate = b; 50 | for (thing in members) 51 | { 52 | if (thing != _selectionSprite) 53 | { 54 | var swatch:FlxUIColorSwatch = cast thing; 55 | swatch.skipButtonUpdate = b; 56 | } 57 | } 58 | return b; 59 | } 60 | 61 | public var numSwatches(get, never):Int; 62 | 63 | private function get_numSwatches() 64 | { 65 | return members.length - 2; 66 | } 67 | 68 | /** 69 | * A handy little group for selecting color swatches from 70 | * @param X X location 71 | * @param Y Y location 72 | * @param SelectionSprite The selection box sprite (optional, auto-generated if not supplied) 73 | * @param list_colors A list of single-colors to generate swatches from. 1st of 3 alternatives. 74 | * @param list_data A list of swatch data to generate swatches from. 2nd of 3 alternatives. 75 | * @param list_swatches A list of the actual swatch widgets themselves. 3rd of 3 alternatives. 76 | * @param SpacingH Horizontal spacing between swatches 77 | * @param SpacingV Vertical spacing between swatches 78 | * @param MaxColumns Number of horizontal swatches in a row before a line break 79 | * @param Preview Graphic information for the preview swatch 80 | * @param Swatch Graphic information for the regular swatches 81 | */ 82 | public function new(X:Float, Y:Float, ?SelectionSprite:FlxSprite, ?list_colors:Array, ?list_data:Array, 83 | ?list_swatches:Array, SpacingH:Int = 2, SpacingV:Int = 2, MaxColumns:Int = -1, ?Preview:SwatchGraphic = null, 84 | ?Swatch:SwatchGraphic = null) 85 | { 86 | super(X, Y); 87 | 88 | _previewGraphic = Preview; 89 | _swatchGraphic = Swatch; 90 | 91 | if (_previewGraphic == null) 92 | { 93 | _previewGraphic = {asset: null, width: -1, height: -1}; 94 | } 95 | if (_swatchGraphic == null) 96 | { 97 | _swatchGraphic = {asset: null, width: -1, height: -1}; 98 | } 99 | 100 | if (SelectionSprite != null) 101 | { 102 | _selectionSprite = SelectionSprite; 103 | } 104 | 105 | var i:Int = 0; 106 | var swatch:FlxUIColorSwatch; 107 | 108 | if (list_data != null) 109 | { 110 | for (data in list_data) 111 | { 112 | swatch = new FlxUIColorSwatch(0, 0, null, data, _swatchGraphic.asset, null, _swatchGraphic.width, _swatchGraphic.height); 113 | swatch.callback = selectCallback.bind(i); 114 | swatch.broadcastToFlxUI = false; 115 | swatch.name = data.name; 116 | add(swatch); 117 | i++; 118 | } 119 | } 120 | else if (list_colors != null) 121 | { 122 | for (color in list_colors) 123 | { 124 | swatch = new FlxUIColorSwatch(0, 0, color, null, _swatchGraphic.asset, null, _swatchGraphic.width, _swatchGraphic.height); 125 | swatch.callback = selectCallback.bind(i); 126 | swatch.broadcastToFlxUI = false; 127 | swatch.name = "0x" + StringTools.hex(color, 6); 128 | add(swatch); 129 | i++; 130 | } 131 | } 132 | else if (list_swatches != null) 133 | { 134 | for (swatch in list_swatches) 135 | { 136 | swatch.name = "swatch_" + i; 137 | swatch.callback = selectCallback.bind(i); 138 | swatch.broadcastToFlxUI = false; 139 | add(swatch); 140 | i++; 141 | } 142 | } 143 | 144 | spacingH = SpacingH; 145 | spacingV = SpacingV; 146 | maxColumns = MaxColumns; 147 | 148 | if (_selectionSprite == null) 149 | { 150 | if (members.length >= 1) 151 | { 152 | var ww:Int = Std.int(members[0].width); 153 | var hh:Int = Std.int(members[0].height); 154 | 155 | _selectionSprite = new FlxSprite(); 156 | _selectionSprite.makeGraphic(ww + 4, hh + 4, 0xFFFFFFFF, false, "selection_sprite_" + ww + "x" + hh + "0xFFFFFFFF"); 157 | 158 | if (_flashRect == null) 159 | { 160 | _flashRect = new Rectangle(); 161 | } 162 | 163 | _flashRect.x = 2; 164 | _flashRect.y = 2; 165 | _flashRect.width = ww; 166 | _flashRect.height = hh; 167 | _selectionSprite.pixels.fillRect(_flashRect, 0x00000000); 168 | add(_selectionSprite); 169 | } 170 | } 171 | 172 | _previewSwatch = new FlxUIColorSwatch(0, 0, null, new SwatchData("dummy", [0xffffffff, 0xff888888, 0xff444444, 0xff000000]), _previewGraphic.asset, 173 | null, _previewGraphic.width, _previewGraphic.height); 174 | _previewSwatch.broadcastToFlxUI = false; 175 | add(_previewSwatch); 176 | 177 | updateLayout(); 178 | 179 | selectByIndex(0); 180 | } 181 | 182 | public override function update(elapsed:Float):Void 183 | { 184 | if (_dirtyLayout) 185 | { 186 | updateLayout(); 187 | updateSelected(); // FIX - update selected sprite position 188 | } 189 | super.update(elapsed); 190 | } 191 | 192 | public function updateLayout():Void 193 | { 194 | if (members == null || members.length == 0) 195 | { 196 | return; 197 | } 198 | 199 | var firstSprite:FlxSprite = members[0]; 200 | var firstX:Float = x; 201 | var firstY:Float = y; 202 | if (firstSprite != null) 203 | { 204 | firstX = firstSprite.x; 205 | firstY = firstSprite.y; 206 | } 207 | 208 | var xx:Float = firstX; 209 | var yy:Float = firstY; 210 | var columns:Int = 0; 211 | 212 | for (sprite in members) 213 | { 214 | if (sprite != null && sprite != _selectionSprite) 215 | { 216 | sprite.x = xx; 217 | sprite.y = yy; 218 | xx += (sprite.width + spacingH); 219 | columns++; 220 | if (maxColumns != -1 && columns >= maxColumns) 221 | { 222 | columns = 0; 223 | xx = firstX; 224 | yy += sprite.height + spacingV; 225 | } 226 | } 227 | } 228 | 229 | _previewSwatch.x = firstX - _previewSwatch.width - spacingH - 5; 230 | 231 | _dirtyLayout = false; 232 | } 233 | 234 | public function changeColors(list:Array):Void 235 | { 236 | remove(_previewSwatch); 237 | var swatchForSelect:SwatchData = null; 238 | 239 | if (_selectedSwatch != null) 240 | { 241 | swatchForSelect = selectedSwatch.colors; 242 | } 243 | 244 | for (thing in members) 245 | { 246 | if (thing != _selectionSprite) 247 | { 248 | thing.visible = false; 249 | thing.active = false; 250 | } 251 | else 252 | { 253 | remove(_selectionSprite, true); 254 | } 255 | } 256 | 257 | for (i in 0...list.length) 258 | { 259 | var fuics:FlxUIColorSwatch = null; 260 | 261 | if (i < members.length) 262 | { 263 | var sprite = members[i]; 264 | if (sprite != null) 265 | { 266 | if ((sprite is FlxUIColorSwatch)) 267 | { 268 | fuics = cast sprite; 269 | if (fuics.equalsSwatch(list[i]) == false) 270 | { 271 | fuics.colors = list[i]; 272 | } 273 | } 274 | } 275 | } 276 | 277 | if (fuics == null) 278 | { 279 | fuics = new FlxUIColorSwatch(0, 0, null, list[i], _swatchGraphic.asset, null, _swatchGraphic.width, _swatchGraphic.height); 280 | fuics.name = list[i].name; 281 | fuics.broadcastToFlxUI = false; 282 | fuics.callback = selectCallback.bind(i); 283 | add(fuics); 284 | } 285 | 286 | fuics.visible = true; 287 | fuics.active = true; 288 | } 289 | 290 | var length:Int = members.length; 291 | for (i in 0...length) 292 | { 293 | var j:Int = (length - 1) - i; 294 | var thing:FlxSprite = members[j]; 295 | if (thing != _selectionSprite) 296 | { 297 | if (thing == null) 298 | { 299 | members.splice(j, 1); 300 | } 301 | else if (thing.visible == false && thing.active == false) 302 | { 303 | thing.destroy(); 304 | remove(thing, true); 305 | thing = null; 306 | } 307 | } 308 | } 309 | 310 | _dirtyLayout = true; 311 | 312 | add(_selectionSprite); 313 | add(_previewSwatch); 314 | 315 | if (swatchForSelect != null) 316 | { 317 | selectByColors(swatchForSelect, true); 318 | } 319 | else 320 | { 321 | unselect(); 322 | } 323 | } 324 | 325 | public var selectedSwatch(get, never):FlxUIColorSwatch; 326 | 327 | private function get_selectedSwatch():FlxUIColorSwatch 328 | { 329 | return _selectedSwatch; 330 | } 331 | 332 | private var destroyed:Bool = false; 333 | 334 | public override function destroy():Void 335 | { 336 | destroyed = true; 337 | _selectedSwatch = null; 338 | _selectionSprite = null; 339 | super.destroy(); 340 | } 341 | 342 | private function selectCallback(i:Int):Void 343 | { 344 | selectByIndex(i); 345 | if (broadcastToFlxUI) 346 | { 347 | if (_selectedSwatch != null) 348 | { 349 | if (_selectedSwatch.multiColored) 350 | { 351 | FlxUI.event(CLICK_EVENT, this, _selectedSwatch.colors); 352 | } 353 | else 354 | { 355 | FlxUI.event(CLICK_EVENT, this, _selectedSwatch.color); 356 | } 357 | } 358 | } 359 | } 360 | 361 | public function selectByIndex(i:Int):Void 362 | { 363 | _selectedSwatch = cast members[i]; 364 | updateSelected(); 365 | } 366 | 367 | public function selectByColor(Color:Int):Void 368 | { 369 | _selectedSwatch = null; 370 | 371 | for (sprite in members) 372 | { 373 | if (sprite != _selectedSwatch && (sprite is FlxUIColorSwatch)) 374 | { 375 | var swatch:FlxUIColorSwatch = cast sprite; 376 | if (swatch.color == Color) 377 | { 378 | _selectedSwatch = swatch; 379 | break; 380 | } 381 | } 382 | } 383 | updateSelected(); 384 | } 385 | 386 | public function selectByColors(Data:SwatchData, PickClosest:Bool = true, IgnoreInvisible:Bool = true):Void 387 | { 388 | var best_delta:Int = 99999999; 389 | var curr_delta:Int = 0; 390 | var best_swatch:FlxUIColorSwatch = null; 391 | 392 | _selectedSwatch = null; 393 | for (sprite in members) 394 | { 395 | if (sprite != _selectionSprite && sprite != _selectedSwatch && sprite.visible == true && sprite.active == true) 396 | { 397 | var swatch:FlxUIColorSwatch = cast sprite; 398 | var swatchData:SwatchData = swatch.colors; 399 | if (PickClosest) 400 | { 401 | // Ignore the "dummy" swatch 402 | if (swatch.colors.name == "dummy" && Data.name == "dummy") 403 | { 404 | continue; 405 | } 406 | 407 | curr_delta = Data.getRawDifference(swatchData, IgnoreInvisible); 408 | if (curr_delta < best_delta) 409 | { 410 | best_swatch = swatch; 411 | best_delta = curr_delta; 412 | } 413 | } 414 | else 415 | { 416 | if (Data.doColorsEqual(swatchData)) 417 | { 418 | best_swatch = swatch; 419 | break; 420 | } 421 | } 422 | } 423 | } 424 | 425 | _selectedSwatch = best_swatch; 426 | 427 | updateSelected(); 428 | } 429 | 430 | public function selectByName(Name:String):Void 431 | { 432 | _selectedSwatch = null; 433 | 434 | for (sprite in members) 435 | { 436 | if (sprite != _selectedSwatch) 437 | { 438 | var swatch:FlxUIColorSwatch = cast sprite; 439 | if (swatch.name == Name) 440 | { 441 | _selectedSwatch = swatch; 442 | break; 443 | } 444 | } 445 | } 446 | updateSelected(); 447 | } 448 | 449 | public function unselect():Void 450 | { 451 | _selectedSwatch = null; 452 | updateSelected(); 453 | } 454 | 455 | public function updateSelected():Void 456 | { 457 | if (_selectedSwatch != null) 458 | { 459 | _selectionSprite.visible = true; 460 | _selectionSprite.x = _selectedSwatch.x + ((_selectedSwatch.width - _selectionSprite.width) / 2); 461 | _selectionSprite.y = _selectedSwatch.y + ((_selectedSwatch.height - _selectionSprite.height) / 2); 462 | _previewSwatch.colors = _selectedSwatch.colors; 463 | } 464 | else 465 | { 466 | _selectionSprite.visible = false; 467 | } 468 | } 469 | 470 | private var _previewGraphic:SwatchGraphic; 471 | private var _swatchGraphic:SwatchGraphic; 472 | private var _selectedSwatch:FlxUIColorSwatch; 473 | private var _selectionSprite:FlxSprite; 474 | private var _dirtyLayout:Bool = false; 475 | } 476 | 477 | typedef SwatchGraphic = 478 | { 479 | var width:Int; 480 | var height:Int; 481 | var asset:FlxGraphicAsset; 482 | } 483 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUIGroup.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.FlxSprite; 4 | import flixel.group.FlxSpriteGroup; 5 | import flixel.math.FlxRect; 6 | import flixel.addons.ui.interfaces.IFlxUIWidget; 7 | #if (flixel >= version("5.7.0")) 8 | import flixel.group.FlxSpriteContainer; 9 | #end 10 | 11 | #if (flixel < version("5.4.0") && FLX_NO_POINT_POOL) 12 | /* This is a weird haxe bug I haven't figured out, fixed in 5.4.0 13 | * via https://github.com/HaxeFlixel/flixel/pull/2808 14 | * Note: this is only the case when FLX_NO_POINT_POOL is defined. 15 | */ 16 | #error "This version of flixel-ui is not compatible with flixel versions less than 5.4.0"; 17 | #end 18 | 19 | /** 20 | * A cheap extension of FlxSpriteGroup that lets you move all the children around 21 | * without having to call reset() 22 | * @author Lars Doucet 23 | */ 24 | typedef FlxUIGroup = FlxTypedUIGroup; 25 | /** 26 | * A cheap extension of FlxSpriteGroup that lets you move all the children around 27 | * without having to call reset() 28 | * @author Lars Doucet 29 | */ 30 | class FlxTypedUIGroup 31 | extends #if(flixel < "5.7.0") FlxTypedSpriteGroup #else FlxTypedSpriteContainer #end 32 | implements IFlxUIWidget 33 | { 34 | /** a handy string handler name for this thing */ 35 | public var name:String; 36 | 37 | /** If true, will issue FlxUI.event() and FlxUI.request() calls */ 38 | public var broadcastToFlxUI:Bool = true; 39 | 40 | /** Will automatically adjust the width and height to the members, on add/remove calls */ 41 | public var autoBounds:Bool = true; 42 | 43 | public function new(x = 0.0, y = 0.0) 44 | { 45 | super(x, y); 46 | } 47 | 48 | override function add(sprite:T):T 49 | { 50 | final obj = super.add(sprite); 51 | if (autoBounds) 52 | { 53 | calcBounds(); 54 | } 55 | return sprite; 56 | } 57 | 58 | public override function remove(sprite:T, splice:Bool = false):T 59 | { 60 | final obj = super.remove(sprite, splice); 61 | if (autoBounds) 62 | { 63 | calcBounds(); 64 | } 65 | return obj; 66 | } 67 | 68 | public function setScrollFactor(x:Float, y:Float):Void 69 | { 70 | for (sprite in members) 71 | { 72 | if (sprite != null) 73 | { 74 | sprite.scrollFactor.set(x, y); 75 | } 76 | } 77 | } 78 | 79 | /** 80 | * Whether this group contains the sprite. 81 | */ 82 | @:deprecated("Use contains, instead") 83 | inline public function hasThis(sprite:T):Bool 84 | { 85 | return contains(sprite); 86 | } 87 | 88 | /** 89 | * Whether this group contains the sprite. 90 | */ 91 | public function contains(sprite:T):Bool 92 | { 93 | return members.contains(sprite); 94 | } 95 | 96 | /** 97 | * Calculates the bounds of the group and sets width/height 98 | * @param rect If supplied, populates this with the boundaries of the group 99 | */ 100 | public function calcBounds(?rect:FlxRect) 101 | { 102 | if (members == null || members.length == 0) 103 | { 104 | width = height = 0; 105 | if (rect != null) rect.set(); 106 | return; 107 | } 108 | 109 | var left:Float = Math.POSITIVE_INFINITY; 110 | var right:Float = Math.NEGATIVE_INFINITY; 111 | var top:Float = Math.POSITIVE_INFINITY; 112 | var bottom:Float = Math.NEGATIVE_INFINITY; 113 | for (sprite in members) 114 | { 115 | if (sprite != null) 116 | { 117 | if (sprite.x < left) 118 | { 119 | left = sprite.x; 120 | } 121 | 122 | if (sprite.x + sprite.width > right) 123 | { 124 | right = sprite.x + sprite.width; 125 | } 126 | 127 | if (sprite.y < top) 128 | { 129 | top = sprite.y; 130 | } 131 | 132 | if (sprite.y + sprite.height > bottom) 133 | { 134 | bottom = sprite.y + sprite.height; 135 | } 136 | } 137 | } 138 | 139 | width = (right - left); 140 | height = (bottom - top); 141 | if (rect != null) 142 | { 143 | rect.x = left; 144 | rect.y = top; 145 | rect.width = width; 146 | rect.height = height; 147 | } 148 | } 149 | 150 | /** 151 | * Floor the positions of all children 152 | */ 153 | public function floorAll():Void 154 | { 155 | for (sprite in members) 156 | { 157 | sprite.x = Math.floor(sprite.x); 158 | sprite.y = Math.floor(sprite.y); 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUIInputText.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.addons.ui.interfaces.IFlxUIWidget; 4 | import flixel.addons.ui.interfaces.IHasParams; 5 | import flixel.addons.ui.interfaces.IResizable; 6 | 7 | /** 8 | * @author Lars Doucet 9 | */ 10 | class FlxUIInputText extends FlxInputText implements IResizable implements IFlxUIWidget implements IHasParams 11 | { 12 | public var name:String; 13 | 14 | public var broadcastToFlxUI:Bool = true; 15 | 16 | public static inline var CHANGE_EVENT:String = "change_input_text"; // change in any way 17 | public static inline var ENTER_EVENT:String = "enter_input_text"; // hit enter in this text field 18 | public static inline var DELETE_EVENT:String = "delete_input_text"; // delete text in this text field 19 | public static inline var INPUT_EVENT:String = "input_input_text"; // input text in this text field 20 | 21 | public function resize(w:Float, h:Float):Void 22 | { 23 | width = w; 24 | height = h; 25 | calcFrame(); 26 | } 27 | 28 | private override function onChange(action:String):Void 29 | { 30 | super.onChange(action); 31 | if (broadcastToFlxUI) 32 | { 33 | switch (action) 34 | { 35 | case FlxInputText.ENTER_ACTION: // press enter 36 | FlxUI.event(ENTER_EVENT, this, text, params); 37 | case FlxInputText.DELETE_ACTION, FlxInputText.BACKSPACE_ACTION: // deleted some text 38 | FlxUI.event(DELETE_EVENT, this, text, params); 39 | FlxUI.event(CHANGE_EVENT, this, text, params); 40 | case FlxInputText.INPUT_ACTION: // text was input 41 | FlxUI.event(INPUT_EVENT, this, text, params); 42 | FlxUI.event(CHANGE_EVENT, this, text, params); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUILine.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.addons.ui.FlxUILine.LineAxis; 4 | import flixel.addons.ui.interfaces.IResizable; 5 | import flixel.util.FlxColor; 6 | 7 | /** 8 | * ... 9 | * @author larsiusprime 10 | */ 11 | class FlxUILine extends FlxUISprite implements IResizable 12 | { 13 | public var axis(default, set):LineAxis = HORIZONTAL; 14 | public var length(default, set):Float = 10; 15 | public var thickness(default, set):Float = 1; 16 | 17 | public function new(X:Int, Y:Int, Axis:LineAxis, Length:Float, Thickness:Float, Color:FlxColor) 18 | { 19 | super(X, Y); 20 | makeGraphic(2, 2, FlxColor.WHITE); 21 | color = Color; 22 | axis = Axis; 23 | length = Length; 24 | thickness = Thickness; 25 | } 26 | 27 | private function set_axis(a:LineAxis):LineAxis 28 | { 29 | axis = a; 30 | refresh(); 31 | return a; 32 | } 33 | 34 | private function set_length(l:Float):Float 35 | { 36 | length = l; 37 | refresh(); 38 | return l; 39 | } 40 | 41 | private function set_thickness(t:Float):Float 42 | { 43 | thickness = t; 44 | refresh(); 45 | return t; 46 | } 47 | 48 | private function refresh():Void 49 | { 50 | if (axis == HORIZONTAL) 51 | { 52 | scale.set(0.5 * length, 0.5 * thickness); 53 | } 54 | else 55 | { 56 | scale.set(0.5 * thickness, 0.5 * length); 57 | } 58 | updateHitbox(); 59 | } 60 | 61 | public override function resize(width:Float, height:Float):Void 62 | { 63 | if (axis == HORIZONTAL) 64 | { 65 | length = width; 66 | thickness = height; 67 | } 68 | else 69 | { 70 | length = height; 71 | thickness = width; 72 | } 73 | } 74 | } 75 | 76 | enum LineAxis 77 | { 78 | HORIZONTAL; 79 | VERTICAL; 80 | } 81 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUIList.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.addons.ui.interfaces.IFlxUIButton; 4 | import flixel.addons.ui.interfaces.IFlxUIWidget; 5 | import flixel.FlxObject; 6 | import flixel.FlxSprite; 7 | import flixel.ui.FlxButton; 8 | import flixel.math.FlxPoint; 9 | import flixel.util.FlxDestroyUtil; 10 | 11 | class FlxUIList extends FlxUIGroup 12 | { 13 | public static inline var STACK_HORIZONTAL:Int = 0; 14 | public static inline var STACK_VERTICAL:Int = 1; 15 | 16 | // The array index value of the first visible item in the list 17 | public var scrollIndex(default, set):Int = 0; 18 | 19 | public function set_scrollIndex(i:Int):Int 20 | { 21 | scrollIndex = i; 22 | refreshList(); 23 | return i; 24 | } 25 | 26 | // Stack widgets horizontally or vertically? 27 | public var stacking(default, set):Int; 28 | 29 | public function set_stacking(Stacking:Int):Int 30 | { 31 | stacking = Stacking; 32 | refreshList(); 33 | return Stacking; 34 | } 35 | 36 | // Spacing between widgets 37 | public var spacing(default, set):Float; 38 | 39 | public function set_spacing(Spacing:Float):Float 40 | { 41 | spacing = Spacing; 42 | refreshList(); 43 | return Spacing; 44 | } 45 | 46 | public var prevButtonOffset:FlxPoint; 47 | public var nextButtonOffset:FlxPoint; 48 | 49 | public var prevButton:IFlxUIButton; 50 | public var nextButton:IFlxUIButton; 51 | 52 | public var moreString(default, set):String; 53 | 54 | public function set_moreString(str:String):String 55 | { 56 | moreString = str; 57 | refreshList(); 58 | return moreString; 59 | } 60 | 61 | public var amountPrevious(default, null):Int; 62 | public var amountNext(default, null):Int; 63 | 64 | /** 65 | * Creates a scrollable list of widgets 66 | * @param X X position of the list 67 | * @param Y Y position of the list 68 | * @param Widgets List of widgets themselves (optional) 69 | * @param W Width of the invisible "canvas" available for putting widgets in before we have to scroll to see more 70 | * @param H Height of the invisible "canvas" available for putting widgets in before we have to scroll to see more 71 | * @param MoreString String that says " more..." in your language (must use variable!) 72 | * @param Stacking How to stack the widgets? STACK_HORIZONTAL or STACK_VERTICAL 73 | * @param Spacing Space between widgets 74 | * @param PrevButtonOffset Offset for Scroll - Button 75 | * @param NextButtonOffset Offset for Scroll + Button 76 | * @param PrevButton Button to Scroll - 77 | * @param NextButton Button to Scroll + 78 | */ 79 | public function new(X:Float = 0, Y:Float = 0, ?Widgets:Array = null, W:Float = 0, H:Float = 0, ?MoreString:String = " more...", 80 | ?Stacking:Int = STACK_VERTICAL, ?Spacing:Float = 0, PrevButtonOffset:FlxPoint = null, NextButtonOffset:FlxPoint = null, 81 | PrevButton:IFlxUIButton = null, NextButton:IFlxUIButton = null) 82 | { 83 | _skipRefresh = true; 84 | super(X, Y); 85 | stacking = Stacking; 86 | spacing = Spacing; 87 | if (Widgets != null) 88 | { 89 | for (widget in Widgets) 90 | { 91 | add(cast widget); 92 | } 93 | } 94 | 95 | prevButton = PrevButton; 96 | nextButton = NextButton; 97 | prevButtonOffset = PrevButtonOffset; 98 | nextButtonOffset = NextButtonOffset; 99 | moreString = MoreString; 100 | 101 | if (prevButton == null) 102 | { 103 | var pButton = new FlxUIButton(0, 0, " ", onClick.bind(-1)); 104 | if (stacking == STACK_HORIZONTAL) 105 | { 106 | pButton.loadGraphicsUpOverDown(FlxUIAssets.IMG_BUTTON_ARROW_LEFT); 107 | pButton.label.width = pButton.label.fieldWidth = 100; 108 | pButton.label.text = getMoreString(0); 109 | 110 | pButton.setAllLabelOffsets(pButton.width - pButton.label.width, pButton.height + 2); 111 | pButton.label.alignment = "right"; 112 | } 113 | else 114 | { 115 | pButton.loadGraphicsUpOverDown(FlxUIAssets.IMG_BUTTON_ARROW_UP); 116 | pButton.label.width = pButton.label.fieldWidth = 100; 117 | pButton.label.text = getMoreString(0); 118 | pButton.setAllLabelOffsets(0, 0); 119 | pButton.setCenterLabelOffset(pButton.width + 2, pButton.height - pButton.label.height); 120 | pButton.label.alignment = "left"; 121 | } 122 | prevButton = pButton; 123 | } 124 | else 125 | { 126 | if ((prevButton is FlxUIButton)) 127 | { 128 | var fuib:FlxUIButton = cast prevButton; 129 | fuib.onUp.callback = onClick.bind(-1); 130 | } 131 | if ((prevButton is FlxUISpriteButton)) 132 | { 133 | var fusb:FlxUISpriteButton = cast prevButton; 134 | fusb.onUp.callback = onClick.bind(-1); 135 | } 136 | } 137 | 138 | if (nextButton == null) 139 | { 140 | var nButton = new FlxUIButton(0, 0, " ", onClick.bind(1)); 141 | if (stacking == STACK_HORIZONTAL) 142 | { 143 | nButton.loadGraphicsUpOverDown(FlxUIAssets.IMG_BUTTON_ARROW_RIGHT); 144 | nButton.label.width = nButton.label.fieldWidth = 100; 145 | nButton.label.text = getMoreString(0); 146 | nButton.setAllLabelOffsets(0, nButton.height + 2); 147 | nButton.label.alignment = "left"; 148 | } 149 | else 150 | { 151 | nButton.loadGraphicsUpOverDown(FlxUIAssets.IMG_BUTTON_ARROW_DOWN); 152 | nButton.label.width = nButton.label.fieldWidth = 100; 153 | nButton.label.text = getMoreString(0); 154 | nButton.setAllLabelOffsets(0, 0); 155 | nButton.setCenterLabelOffset(nButton.width + 2, 0); 156 | nButton.label.alignment = "left"; 157 | } 158 | nextButton = nButton; 159 | } 160 | else 161 | { 162 | if ((nextButton is FlxUIButton)) 163 | { 164 | var fuib:FlxUIButton = cast nextButton; 165 | fuib.onUp.callback = onClick.bind(1); 166 | } 167 | if ((nextButton is FlxUISpriteButton)) 168 | { 169 | var fusb:FlxUISpriteButton = cast nextButton; 170 | fusb.onUp.callback = onClick.bind(1); 171 | } 172 | } 173 | 174 | if (prevButtonOffset == null) 175 | { 176 | prevButtonOffset = FlxPoint.get(0, 0); 177 | } 178 | if (nextButtonOffset == null) 179 | { 180 | nextButtonOffset = FlxPoint.get(0, 0); 181 | } 182 | _skipRefresh = false; 183 | setSize(W, H); 184 | } 185 | 186 | public override function destroy():Void 187 | { 188 | prevButton = FlxDestroyUtil.destroy(prevButton); 189 | nextButton = FlxDestroyUtil.destroy(nextButton); 190 | prevButtonOffset = FlxDestroyUtil.put(prevButtonOffset); 191 | nextButtonOffset = FlxDestroyUtil.put(nextButtonOffset); 192 | super.destroy(); 193 | } 194 | 195 | public override function setSize(W:Float, H:Float):Void 196 | { 197 | var flip:Bool = false; 198 | if (_skipRefresh == false) 199 | { 200 | _skipRefresh = true; 201 | flip = true; 202 | } 203 | width = W; 204 | height = H; 205 | if (flip) 206 | { 207 | _skipRefresh = false; 208 | } 209 | refreshList(); 210 | } 211 | 212 | public override function add(Object:FlxSprite):FlxSprite 213 | { 214 | super.add(Object); 215 | refreshList(); 216 | return Object; 217 | } 218 | 219 | /****PRIVATE****/ 220 | private function safeAdd(Object:FlxSprite):FlxSprite 221 | { 222 | return super.add(Object); 223 | } 224 | 225 | @:allow(flixel.addons.ui.FlxUIRadioGroup) private var _skipRefresh:Bool = false; 226 | 227 | private function getMoreString(i:Int):String 228 | { 229 | var newString:String = moreString; 230 | while (newString.indexOf("") != -1) 231 | { 232 | newString = StringTools.replace(newString, "", Std.string(i)); 233 | } 234 | return newString; 235 | } 236 | 237 | private override function set_visible(Value:Bool):Bool 238 | { 239 | super.set_visible(Value); 240 | refreshList(); 241 | return Value; 242 | } 243 | 244 | private function onClick(i:Int):Void 245 | { 246 | scrollIndex += i; 247 | refreshList(); 248 | } 249 | 250 | @:allow(flixel.addons.ui.FlxUIRadioGroup) private function refreshList():Void 251 | { 252 | if (_skipRefresh) 253 | { 254 | return; 255 | } 256 | 257 | autoBounds = false; 258 | 259 | if (group.members.indexOf(cast prevButton) != -1) 260 | { 261 | remove(cast prevButton, true); 262 | } 263 | if (group.members.indexOf(cast nextButton) != -1) 264 | { 265 | remove(cast nextButton, true); 266 | } 267 | 268 | var XX:Float = 0; 269 | var YY:Float = 0; 270 | 271 | var i:Int = 0; 272 | var inBounds:Bool = true; 273 | 274 | if (stacking == STACK_HORIZONTAL) 275 | { 276 | prevButton.x = prevButtonOffset.x - prevButton.width - 2; 277 | prevButton.y = prevButtonOffset.y; 278 | nextButton.x = nextButtonOffset.x + width + 2; 279 | nextButton.y = nextButtonOffset.y; 280 | } 281 | else 282 | { 283 | prevButton.x = prevButtonOffset.x; 284 | prevButton.y = prevButtonOffset.y - prevButton.height - 2; 285 | nextButton.x = nextButtonOffset.x; 286 | nextButton.y = nextButtonOffset.y + height + 2; 287 | } 288 | 289 | prevButton.x = Std.int(prevButton.x); 290 | prevButton.y = Std.int(prevButton.y); 291 | nextButton.x = Std.int(nextButton.x); 292 | nextButton.y = Std.int(nextButton.y); 293 | 294 | var highestIndex:Int = 0; 295 | 296 | for (widget in group.members) 297 | { 298 | inBounds = false; 299 | if (i >= scrollIndex) 300 | { 301 | if (stacking == STACK_VERTICAL) 302 | { 303 | inBounds = YY + widget.height <= height || height <= 0; 304 | } 305 | else 306 | { 307 | inBounds = XX + widget.width <= width || width <= 0; 308 | } 309 | } 310 | if (inBounds) 311 | { 312 | highestIndex = i; 313 | widget.visible = widget.active = true; 314 | widget.x = x + XX; 315 | widget.y = y + YY; 316 | if (stacking == STACK_VERTICAL) 317 | { 318 | YY += widget.height + spacing; 319 | } 320 | else 321 | { 322 | XX += widget.width + spacing; 323 | } 324 | } 325 | else 326 | { 327 | widget.x = widget.y = 0; 328 | widget.visible = widget.active = false; 329 | } 330 | i++; 331 | } 332 | 333 | amountPrevious = scrollIndex; 334 | amountNext = group.members.length - (highestIndex + 1); 335 | 336 | var fuibutton:FlxUIButton; 337 | 338 | if (amountPrevious > 0) 339 | { 340 | safeAdd(cast prevButton); 341 | if ((prevButton is FlxUIButton)) 342 | { 343 | fuibutton = cast prevButton; 344 | fuibutton.label.text = getMoreString(amountPrevious); 345 | } 346 | } 347 | if (amountNext > 0) 348 | { 349 | safeAdd(cast nextButton); 350 | if ((nextButton is FlxUIButton)) 351 | { 352 | fuibutton = cast nextButton; 353 | fuibutton.label.text = getMoreString(amountNext); 354 | } 355 | } 356 | } 357 | 358 | private override function get_width():Float 359 | { 360 | return width; 361 | } 362 | 363 | private override function get_height():Float 364 | { 365 | return height; 366 | } 367 | 368 | private override function set_width(W:Float):Float 369 | { 370 | width = W; 371 | refreshList(); 372 | return W; 373 | } 374 | 375 | private override function set_height(H:Float):Float 376 | { 377 | height = H; 378 | refreshList(); 379 | return H; 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUILoadingScreen.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.addons.ui.FlxUI9SliceSprite; 4 | import flixel.addons.ui.FlxUIPopup; 5 | import flixel.addons.ui.FlxUIText; 6 | import flixel.addons.ui.FlxUITypedButton.FlxUITypedButton; 7 | import flixel.addons.ui.interfaces.IFlxUIWidget; 8 | import flixel.FlxG; 9 | import flixel.util.FlxTimer; 10 | 11 | /** 12 | * A simple loading screen -- you must drive the churning of tasks externally 13 | * 14 | * @author larsiusprime 15 | */ 16 | class FlxUILoadingScreen extends FlxUIPopup 17 | { 18 | public static inline var PROGRESS:String = "loading_screen_progress"; // whenever the bar updates 19 | public static inline var FINISHED:String = "loading_screen_finished"; // whenever the bar has reached 100% 20 | public static inline var CANCELLED:String = "loading_screen_cancelled"; // user clicks "cancel" 21 | public static inline var ACCEPTED:String = "loading_screen_accepted"; // user clicks "okay" after progress is complete 22 | 23 | public var invisibleTime:Float = 0; // if I have been alive less time than this, I am invisible 24 | 25 | public var body(get, set):String; 26 | 27 | private function get_body():String 28 | { 29 | if (_body != null) 30 | { 31 | return _body.text; 32 | } 33 | return _body_temp_txt; 34 | } 35 | 36 | private function set_body(str:String):String 37 | { 38 | if (_body != null) 39 | { 40 | _body.text = str; 41 | } 42 | _body_temp_txt = str; 43 | return _body_temp_txt; 44 | } 45 | 46 | public var title(get, set):String; 47 | 48 | private function get_title():String 49 | { 50 | if (_title != null) 51 | { 52 | return _title.text; 53 | } 54 | return _title_temp_txt; 55 | } 56 | 57 | private function set_title(str:String):String 58 | { 59 | if (_title != null) 60 | { 61 | _title.text = str; 62 | } 63 | _title_temp_txt = str; 64 | return _title_temp_txt; 65 | } 66 | 67 | public var canCancel(default, set):Bool; 68 | 69 | private function set_canCancel(b:Bool):Bool 70 | { 71 | canCancel = b; 72 | if (_ui != null) 73 | { 74 | if (canCancel) 75 | { 76 | _ui.setMode("can_cancel"); 77 | } 78 | else 79 | { 80 | _ui.setMode("no_cancel"); 81 | } 82 | } 83 | return canCancel; 84 | } 85 | 86 | public var progress(get, set):Float; 87 | 88 | private function get_progress():Float 89 | { 90 | return _progress; 91 | } 92 | 93 | private function set_progress(f:Float):Float 94 | { 95 | if (f < 0) 96 | { 97 | f = 0; 98 | } 99 | if (f > 1) 100 | { 101 | f = 1; 102 | } 103 | _progress = f; 104 | if (_bar != null && _bar_back != null) 105 | { 106 | var w:Int = Std.int(f * _bar_back.width); 107 | if (w < 3) 108 | { 109 | w = 3; 110 | _bar.visible = false; 111 | } 112 | else 113 | { 114 | _bar.visible = true; 115 | } 116 | _bar.resize(w, _bar.height); 117 | _bar.x = Std.int(_bar_back.x); 118 | } 119 | return _progress; 120 | } 121 | 122 | public function set(progress_:Float, ?body_:String, ?title_:String, ?canCancel_:Bool = false) 123 | { 124 | canCancel = canCancel_; 125 | progress = progress_; 126 | if (body_ != null) 127 | { 128 | body = body_; 129 | } 130 | if (title_ != null) 131 | { 132 | title = title_; 133 | } 134 | } 135 | 136 | public override function create():Void 137 | { 138 | if (_xml_id == "") 139 | { 140 | _xml_id = FlxUIAssets.XML_DEFAULT_LOADING_SCREEN_ID; 141 | } 142 | 143 | getTextFallback = myGetTextFallback; 144 | 145 | super.create(); 146 | 147 | _bar = cast _ui.getAsset("bar"); 148 | _bar_back = cast _ui.getAsset("bar_back"); 149 | _title = cast _ui.getAsset("title"); 150 | _body = cast _ui.getAsset("body"); 151 | 152 | if (_quickSetupParams != null) 153 | { 154 | _doQuickSetup(); 155 | } 156 | 157 | canCancel = canCancel; // refresh this 158 | progress = _progress; 159 | title = _title_temp_txt; 160 | body = _body_temp_txt; 161 | } 162 | 163 | public override function getEvent(name:String, sender:IFlxUIWidget, data:Dynamic, ?params:Array):Void 164 | { 165 | switch (name) 166 | { 167 | case FlxUITypedButton.CLICK_EVENT: 168 | var btnName:String = cast data; 169 | if (btnName == "ok") 170 | { 171 | castParent().getEvent(ACCEPTED, this, null); 172 | close(); 173 | } 174 | else if (btnName == "cancel") 175 | { 176 | if (_currTimer != null) 177 | { 178 | _currTimer.cancel(); 179 | _currTimer = null; 180 | } 181 | castParent().getEvent(CANCELLED, this, null); 182 | close(); 183 | } 184 | } 185 | } 186 | 187 | public override function update(elapsed:Float):Void 188 | { 189 | super.update(elapsed); 190 | if (invisibleTime != 0) 191 | { 192 | _timeSpentAlive += FlxG.elapsed; 193 | if (_timeSpentAlive < invisibleTime) 194 | { 195 | visible = false; 196 | } 197 | else 198 | { 199 | visible = true; 200 | } 201 | } 202 | } 203 | 204 | private override function myGetTextFallback(flag:String, context:String = "ui", safe:Bool = true):String 205 | { 206 | switch (flag) 207 | { 208 | case "$LOADING_TITLE": 209 | return "Loading"; 210 | case "$LOADING_BODY": 211 | return "Please Wait..."; 212 | } 213 | return super.myGetTextFallback(flag, context, safe); 214 | } 215 | 216 | private override function _doQuickSetupButtons():Void 217 | { 218 | // override super behavior and do nothing 219 | } 220 | 221 | private var _timeSpentAlive:Float = 0; 222 | private var _currTimer:FlxTimer; 223 | private var _task:Void->Float = null; 224 | private var _sleepTime:Float = 0; 225 | private var _closeOnFinished:Bool = true; 226 | 227 | private var _progress:Float = 0; 228 | private var _bar:FlxUI9SliceSprite; 229 | private var _bar_back:FlxUI9SliceSprite; 230 | private var _title:FlxUIText; 231 | private var _body:FlxUIText; 232 | 233 | // used if "body" and "title" vars are set before create() is called 234 | private var _body_temp_txt:String = "$LOADING_BODY"; 235 | private var _title_temp_txt:String = "$LOADING_TITLE"; 236 | } 237 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUIMouse.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | #if FLX_MOUSE 4 | import openfl.display.Sprite; 5 | import flixel.FlxG; 6 | import flixel.input.mouse.FlxMouse; 7 | 8 | /** 9 | * A customized extension to FlxMouse that lets us add in accessibility stuff 10 | * like using the keyboard to control mouse moving/clicking 11 | */ 12 | class FlxUIMouse extends FlxMouse 13 | { 14 | // Set this to STOP tracking the mouse position from actual mouse input 15 | public var updateGlobalScreenPosition:Bool = true; 16 | 17 | public function new(CursorContainer:Sprite) 18 | { 19 | super(CursorContainer); 20 | } 21 | 22 | /** 23 | * Called by the internal game loop to update the mouse pointer's position in the game world. 24 | * Also updates the just pressed/just released flags. 25 | */ 26 | override function update():Void 27 | { 28 | #if (flixel < version("5.9.0")) 29 | final oldScreenX = _globalScreenX; 30 | final oldScreenY = _globalScreenY; 31 | #else 32 | final oldRawX = _rawX; 33 | final oldRawY = _rawY; 34 | #end 35 | 36 | super.update(); 37 | 38 | if (!updateGlobalScreenPosition) 39 | { 40 | #if (flixel < version("5.9.0")) 41 | _globalScreenX = oldScreenX; 42 | _globalScreenY = oldScreenY; 43 | #else 44 | _rawX = oldRawX; 45 | _rawY = oldRawY; 46 | #end 47 | updatePositions(); 48 | } 49 | } 50 | } 51 | #end 52 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUINumericStepper.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.addons.ui.FlxUI.NamedFloat; 4 | import flixel.addons.ui.interfaces.IFlxUIClickable; 5 | import flixel.addons.ui.interfaces.IFlxUIWidget; 6 | import flixel.addons.ui.interfaces.IHasParams; 7 | import flixel.FlxSprite; 8 | import flixel.text.FlxText; 9 | import flixel.util.FlxArrayUtil; 10 | import flixel.math.FlxPoint; 11 | import flixel.util.FlxStringUtil; 12 | 13 | class FlxUINumericStepper extends FlxUIGroup implements IFlxUIWidget implements IFlxUIClickable implements IHasParams 14 | { 15 | private var button_plus:FlxUITypedButton; 16 | private var button_minus:FlxUITypedButton; 17 | private var text_field:FlxText; 18 | 19 | public var stepSize:Float = 0; 20 | public var decimals(default, set):Int = 0; // Number of decimals 21 | public var min(default, set):Float = 0; 22 | public var max(default, set):Float = 10; 23 | public var value(default, set):Float = 0; 24 | public var stack(default, set):Int = STACK_HORIZONTAL; 25 | public var isPercent(default, set):Bool = false; 26 | 27 | public static inline var STACK_VERTICAL:Int = 0; 28 | public static inline var STACK_HORIZONTAL:Int = 1; 29 | 30 | public static inline var CLICK_EVENT:String = "click_numeric_stepper"; // click a numeric stepper button 31 | public static inline var EDIT_EVENT:String = "edit_numeric_stepper"; // edit the numeric stepper text field 32 | public static inline var CHANGE_EVENT:String = "change_numeric_stepper"; // do either of the above 33 | 34 | public var params(default, set):Array; 35 | 36 | private function set_params(p:Array):Array 37 | { 38 | params = p; 39 | return params; 40 | } 41 | 42 | public var skipButtonUpdate(default, set):Bool; 43 | 44 | private function set_skipButtonUpdate(b:Bool):Bool 45 | { 46 | skipButtonUpdate = b; 47 | button_plus.skipButtonUpdate = b; 48 | button_minus.skipButtonUpdate = b; 49 | // TODO: Handle input text 50 | return b; 51 | } 52 | 53 | private override function set_color(Value:Int):Int 54 | { 55 | color = Value; 56 | button_plus.color = Value; 57 | button_minus.color = Value; 58 | if ((text_field is FlxInputText)) 59 | { 60 | var fit:FlxInputText = cast text_field; 61 | fit.backgroundColor = Value; 62 | } 63 | else 64 | { 65 | text_field.color = Value; 66 | } 67 | return Value; 68 | } 69 | 70 | private function set_min(f:Float):Float 71 | { 72 | min = f; 73 | if (value < min) 74 | { 75 | value = min; 76 | } 77 | return min; 78 | } 79 | 80 | private function set_max(f:Float):Float 81 | { 82 | max = f; 83 | if (value > max) 84 | { 85 | value = max; 86 | } 87 | return max; 88 | } 89 | 90 | private function set_value(f:Float):Float 91 | { 92 | value = f; 93 | if (value < min) 94 | { 95 | value = min; 96 | } 97 | if (value > max) 98 | { 99 | value = max; 100 | } 101 | if (text_field != null) 102 | { 103 | var displayValue:Float = value; 104 | if (isPercent) 105 | { 106 | displayValue *= 100; 107 | text_field.text = Std.string(decimalize(displayValue, decimals)) + "%"; 108 | } 109 | else 110 | { 111 | text_field.text = decimalize(displayValue, decimals); 112 | } 113 | } 114 | return value; 115 | } 116 | 117 | private function set_decimals(i:Int):Int 118 | { 119 | decimals = i; 120 | if (i < 0) 121 | { 122 | decimals = 0; 123 | } 124 | value = value; 125 | return decimals; 126 | } 127 | 128 | private function set_isPercent(b:Bool):Bool 129 | { 130 | isPercent = b; 131 | value = value; 132 | return isPercent; 133 | } 134 | 135 | private function set_stack(s:Int):Int 136 | { 137 | stack = s; 138 | var btnSize:Int = 10; 139 | var offsetX:Int = 0; 140 | var offsetY:Int = 0; 141 | if ((text_field is FlxUIInputText)) 142 | { 143 | offsetX = 1; 144 | offsetY = 1; // border for input text 145 | } 146 | switch (stack) 147 | { 148 | case STACK_HORIZONTAL: 149 | btnSize = 2 + cast text_field.height; 150 | if (button_plus.height != btnSize) 151 | { 152 | button_plus.resize(btnSize, btnSize); 153 | } 154 | if (button_minus.height != btnSize) 155 | { 156 | button_minus.resize(btnSize, btnSize); 157 | } 158 | button_plus.x = offsetX + text_field.x + text_field.width; 159 | button_plus.y = -offsetY + text_field.y; 160 | button_minus.x = button_plus.x + button_plus.width; 161 | button_minus.y = button_plus.y; 162 | case STACK_VERTICAL: 163 | btnSize = 1 + cast text_field.height / 2; 164 | if (button_plus.height != btnSize) 165 | { 166 | button_plus.resize(btnSize, btnSize); 167 | } 168 | if (button_minus.height != btnSize) 169 | { 170 | button_minus.resize(btnSize, btnSize); 171 | } 172 | button_plus.x = offsetX + text_field.x + text_field.width; 173 | button_plus.y = -offsetY + text_field.y; 174 | button_minus.x = offsetX + text_field.x + text_field.width; 175 | button_minus.y = offsetY + text_field.y + (text_field.height - button_minus.height); 176 | } 177 | return stack; 178 | } 179 | 180 | private inline function decimalize(f:Float, digits:Int):String 181 | { 182 | var tens:Float = Math.pow(10, digits); 183 | return Std.string(Math.round(f * tens) / tens); 184 | } 185 | 186 | /** 187 | * This creates a new dropdown menu. 188 | * 189 | * @param X x position of the dropdown menu 190 | * @param Y y position of the dropdown menu 191 | * @param StepSize How big is the step 192 | * @param DefaultValue Optional default numerical value for the stepper to display 193 | * @param Min Optional Minimum values for the stepper 194 | * @param Max Optional Maximum and Minimum values for the stepper 195 | * @param Decimals Optional # of decimal places 196 | * @param Stack Stacking method 197 | * @param TextField Optional text field 198 | * @param ButtonPlus Optional button to use for plus 199 | * @param ButtonMinus Optional button to use for minus 200 | * @param IsPercent Whether to portray the number as a percentage 201 | */ 202 | public function new(X:Float = 0, Y:Float = 0, StepSize:Float = 1, DefaultValue:Float = 0, Min:Float = -999, Max:Float = 999, Decimals:Int = 0, 203 | Stack:Int = STACK_HORIZONTAL, ?TextField:FlxText, ?ButtonPlus:FlxUITypedButton, ?ButtonMinus:FlxUITypedButton, 204 | IsPercent:Bool = false) 205 | { 206 | super(X, Y); 207 | 208 | if (TextField == null) 209 | { 210 | TextField = new FlxUIInputText(0, 0, 25); 211 | } 212 | TextField.x = 0; 213 | TextField.y = 0; 214 | text_field = TextField; 215 | text_field.text = Std.string(DefaultValue); 216 | 217 | if ((text_field is FlxUIInputText)) 218 | { 219 | var fuit:FlxUIInputText = cast text_field; 220 | fuit.lines = 1; 221 | fuit.callback = _onInputTextEvent; // internal communication only 222 | fuit.broadcastToFlxUI = false; 223 | } 224 | 225 | stepSize = StepSize; 226 | decimals = Decimals; 227 | min = Min; 228 | max = Max; 229 | value = DefaultValue; 230 | isPercent = IsPercent; 231 | 232 | var btnSize:Int = 1 + cast TextField.height; 233 | 234 | if (ButtonPlus == null) 235 | { 236 | ButtonPlus = new FlxUITypedButton(0, 0); 237 | ButtonPlus.loadGraphicSlice9([FlxUIAssets.IMG_BUTTON_THIN], btnSize, btnSize, [FlxStringUtil.toIntArray(FlxUIAssets.SLICE9_BUTTON_THIN)], 238 | FlxUI9SliceSprite.TILE_NONE, -1, false, FlxUIAssets.IMG_BUTTON_SIZE, FlxUIAssets.IMG_BUTTON_SIZE); 239 | ButtonPlus.label = new FlxSprite(0, 0, FlxUIAssets.IMG_PLUS); 240 | } 241 | if (ButtonMinus == null) 242 | { 243 | ButtonMinus = new FlxUITypedButton(0, 0); 244 | ButtonMinus.loadGraphicSlice9([FlxUIAssets.IMG_BUTTON_THIN], btnSize, btnSize, [FlxStringUtil.toIntArray(FlxUIAssets.SLICE9_BUTTON_THIN)], 245 | FlxUI9SliceSprite.TILE_NONE, -1, false, FlxUIAssets.IMG_BUTTON_SIZE, FlxUIAssets.IMG_BUTTON_SIZE); 246 | ButtonMinus.label = new FlxSprite(0, 0, FlxUIAssets.IMG_MINUS); 247 | } 248 | 249 | button_plus = ButtonPlus; 250 | button_minus = ButtonMinus; 251 | 252 | add(text_field); 253 | add(button_plus); 254 | add(button_minus); 255 | 256 | button_plus.onUp.callback = _onPlus; 257 | button_plus.broadcastToFlxUI = false; 258 | 259 | button_minus.onUp.callback = _onMinus; 260 | button_minus.broadcastToFlxUI = false; 261 | 262 | stack = Stack; 263 | } 264 | 265 | private function _onInputTextEvent(text:String, action:String):Void 266 | { 267 | if (text == "") 268 | { 269 | text = Std.string(min); 270 | } 271 | 272 | var numDecimals:Int = 0; 273 | for (i in 0...text.length) 274 | { 275 | var char = text.charAt(i); 276 | if (char == ".") 277 | { 278 | numDecimals++; 279 | } 280 | } 281 | 282 | var justAddedDecimal = (numDecimals == 1 && text.indexOf(".") == text.length - 1); 283 | 284 | // if I just added a decimal don't treat that as having changed the value just yet 285 | if (!justAddedDecimal) 286 | { 287 | value = Std.parseFloat(text); 288 | _doCallback(EDIT_EVENT); 289 | _doCallback(CHANGE_EVENT); 290 | } 291 | } 292 | 293 | private function _onPlus():Void 294 | { 295 | value += stepSize; 296 | _doCallback(CLICK_EVENT); 297 | _doCallback(CHANGE_EVENT); 298 | } 299 | 300 | private function _onMinus():Void 301 | { 302 | value -= stepSize; 303 | _doCallback(CLICK_EVENT); 304 | _doCallback(CHANGE_EVENT); 305 | } 306 | 307 | private function _doCallback(event_name:String):Void 308 | { 309 | if (broadcastToFlxUI) 310 | { 311 | FlxUI.event(event_name, this, value, params); 312 | } 313 | } 314 | } 315 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUIPopup.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.addons.ui.interfaces.IFlxUIButton; 4 | import flixel.addons.ui.interfaces.IFlxUIState; 5 | import flixel.addons.ui.interfaces.IFlxUIWidget; 6 | import flixel.math.FlxPoint; 7 | import flixel.util.FlxDirectionFlags; 8 | 9 | class FlxUIPopup extends FlxUISubState implements IFlxUIWidget 10 | { 11 | public var name:String; 12 | 13 | public var broadcastToFlxUI:Bool = true; 14 | 15 | /**STUBS TO MAKE THE INTERFACE HAPPY:**/ 16 | public var immovable(default, set):Bool; 17 | 18 | private function set_immovable(Immovable:Bool):Bool 19 | { 20 | return immovable; 21 | } 22 | 23 | public var angle(default, set):Float; 24 | public var facing(default, set):FlxDirectionFlags; 25 | public var moves(default, set):Bool; 26 | public var offset(default, set):FlxPoint; 27 | public var origin(default, set):FlxPoint; 28 | public var scale(default, set):FlxPoint; 29 | public var velocity:FlxPoint; 30 | public var maxVelocity:FlxPoint; 31 | public var acceleration:FlxPoint; 32 | public var drag:FlxPoint; 33 | public var scrollFactor(default, set):FlxPoint; 34 | 35 | private function set_x(Value:Float):Float 36 | { 37 | return x = Value; 38 | } 39 | 40 | private function set_y(Value:Float):Float 41 | { 42 | return y = Value; 43 | } 44 | 45 | private function get_width():Float 46 | { 47 | return _width; 48 | } 49 | 50 | private function get_height():Float 51 | { 52 | return _height; 53 | } 54 | 55 | private function set_width(Value:Float):Float 56 | { 57 | return _width = Value; 58 | } 59 | 60 | private function set_height(Value:Float):Float 61 | { 62 | return _height = Value; 63 | } 64 | 65 | private function set_angle(Value:Float):Float 66 | { 67 | return angle = Value; 68 | } 69 | 70 | private function set_alpha(Value:Float):Float 71 | { 72 | return alpha = Value; 73 | } 74 | 75 | private function set_facing(Value:FlxDirectionFlags):FlxDirectionFlags 76 | { 77 | return facing = Value; 78 | } 79 | 80 | private function set_moves(Value:Bool):Bool 81 | { 82 | return moves = Value; 83 | } 84 | 85 | private function set_offset(Value:FlxPoint):FlxPoint 86 | { 87 | return offset = Value; 88 | } 89 | 90 | private function set_origin(Value:FlxPoint):FlxPoint 91 | { 92 | return origin = Value; 93 | } 94 | 95 | private function set_scale(Value:FlxPoint):FlxPoint 96 | { 97 | return scale = Value; 98 | } 99 | 100 | private function set_scrollFactor(Value:FlxPoint):FlxPoint 101 | { 102 | return scrollFactor = Value; 103 | } 104 | 105 | public function reset(X:Float, Y:Float):Void 106 | { 107 | setPosition(X, Y); 108 | } 109 | 110 | public function setPosition(X:Float = 0, Y:Float = 0):Void 111 | { 112 | x = X; 113 | y = Y; 114 | } 115 | 116 | public var x(default, set):Float = 0; 117 | public var y(default, set):Float = 0; 118 | 119 | public var params:Array = null; 120 | 121 | public var alpha(default, set):Float = 1; 122 | 123 | public var width(get, set):Float; 124 | public var height(get, set):Float; 125 | 126 | private var _width:Float = 0; 127 | private var _height:Float = 0; 128 | 129 | public static inline var CLICK_EVENT:String = "click_popup"; 130 | 131 | /**************************************/ 132 | public override function create():Void 133 | { 134 | if (_xml_id == "") 135 | { 136 | _xml_id = FlxUIAssets.XML_DEFAULT_POPUP_ID; 137 | } 138 | 139 | scrollFactor = FlxPoint.get(0, 0); 140 | getTextFallback = myGetTextFallback; 141 | 142 | super.create(); 143 | 144 | if (_quickSetupParams != null) 145 | { 146 | _doQuickSetup(); 147 | } 148 | 149 | scrollFactor.set(0, 0); 150 | _ui.setScrollFactor(0, 0); 151 | } 152 | 153 | /** 154 | * Assuming you use the default format, puts this information in the popup. 155 | * This function ONLY works if you are using the default_popup.xml, OR your 156 | * custom xml contains the following assets: 157 | * 2 texts, ids: "title","body" 158 | * 3 buttons, ids: "btn0","btn1","btn2" 159 | * 3 modes, ids: "1btn","2btn","3btn" 160 | * @param title title text 161 | * @param body body text 162 | * @param button_labels up to three button labels - if fewer, shows less buttons 163 | */ 164 | public function quickSetup(title:String, body:String, button_labels:Array):Void 165 | { 166 | /* if this sub state isn't active yet, it just stores the params and then 167 | * does the real work as soon as it's created. 168 | * So call this, then activate it! 169 | */ 170 | 171 | _quickSetupParams = {title: title, body: body, button_labels: button_labels}; 172 | } 173 | 174 | public override function getEvent(id:String, sender:IFlxUIWidget, data:Dynamic, ?eventParams:Array):Void 175 | { 176 | if (eventParams == null) 177 | { 178 | if (params != null) 179 | { 180 | eventParams = []; 181 | } 182 | } 183 | if (params != null) 184 | { 185 | eventParams = eventParams.concat(params); 186 | } 187 | 188 | switch (id) 189 | { 190 | case FlxUITypedButton.CLICK_EVENT: 191 | var str = ""; 192 | if (eventParams != null) 193 | { 194 | if ((eventParams[0] is String)) 195 | { 196 | str = Std.string(eventParams[0]); 197 | } 198 | 199 | var buttonAmount:Int = Std.int(eventParams[0]); 200 | if (str == "affirm" || str == "cancel" || str == "alt") 201 | { 202 | if ((_parentState is IFlxUIState)) 203 | { 204 | // This fixes a bug where the event was being sent to this popup rather than the state that created it 205 | castParent().getEvent(CLICK_EVENT, this, buttonAmount, eventParams); 206 | } 207 | else 208 | { 209 | // This is a generic fallback in case something goes wrong 210 | FlxUI.event(CLICK_EVENT, this, buttonAmount, eventParams); 211 | } 212 | close(); 213 | } 214 | } 215 | } 216 | super.getEvent(id, sender, data, eventParams); 217 | } 218 | 219 | private function castParent():IFlxUIState 220 | { 221 | return cast _parentState; 222 | } 223 | 224 | private var _quickSetupParams:{title:String, body:String, button_labels:Array} = null; 225 | 226 | // This function is passed into the UI object as a default in case the user is not using FireTongue 227 | 228 | private function myGetTextFallback(flag:String, context:String = "ui", safe:Bool = true):String 229 | { 230 | switch (flag) 231 | { 232 | case "$POPUP_YES": 233 | return "Yes"; 234 | case "$POPUP_NO": 235 | return "No"; 236 | case "$POPUP_OK": 237 | return "Ok"; 238 | case "$POPUP_CANCEL": 239 | return "Cancel"; 240 | case "$POPUP_TITLE_DEFAULT": 241 | return "Alert!"; 242 | case "$POPUP_BODY_DEFAULT": 243 | return 244 | "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam consectetur vehicula pellentesque. Phasellus at blandit augue. Suspendisse vel leo ut elit imperdiet eleifend ut quis purus. Quisque imperdiet turpis vitae justo hendrerit molestie. Quisque tempor ante eget posuere viverra."; 245 | } 246 | return flag; 247 | } 248 | 249 | private function _doQuickSetup():Void 250 | { 251 | if (_ui.hasAsset("title")) 252 | { 253 | var text_title:FlxUIText = cast _ui.getAsset("title"); 254 | text_title.text = _quickSetupParams.title; 255 | } 256 | if (_ui.hasAsset("body")) 257 | { 258 | var text_body:FlxUIText = cast _ui.getAsset("body"); 259 | text_body.text = _quickSetupParams.body; 260 | } 261 | 262 | _doQuickSetupButtons(); 263 | 264 | // cleanup 265 | _quickSetupParams.button_labels = null; 266 | _quickSetupParams = null; 267 | } 268 | 269 | private function _doQuickSetupButtons():Void 270 | { 271 | var arr:Array = ["btn0", "btn1", "btn2"]; 272 | var i:Int = 0; 273 | 274 | switch (_quickSetupParams.button_labels.length) 275 | { 276 | case 1: 277 | _ui.setMode("1btn"); 278 | case 2: 279 | _ui.setMode("2btn"); 280 | case 3: 281 | _ui.setMode("3btn"); 282 | } 283 | 284 | for (btn in arr) 285 | { 286 | var the_btn:IFlxUIButton; 287 | if (_ui.hasAsset(btn)) 288 | { 289 | the_btn = cast _ui.getAsset(btn); 290 | if (_quickSetupParams.button_labels.length > i) 291 | { 292 | var btnlabel:String = _quickSetupParams.button_labels[i]; 293 | var newlabel:String = btnlabel; 294 | 295 | // localize common flags: 296 | switch (btnlabel) 297 | { 298 | case "", "", "": 299 | btnlabel = btnlabel.substr(1, btnlabel.length - 2).toUpperCase(); // carve off the "<>", so "yes", "no", etc 300 | newlabel = "$POPUP_" + btnlabel; // make it "$POPUP_YES", "$POPUP_NO", etc 301 | newlabel = _ui.getText(newlabel, "ui", false); // localize it 302 | if (newlabel == null || newlabel == "") 303 | { // if failed 304 | newlabel = btnlabel; 305 | } 306 | btnlabel = newlabel; 307 | } 308 | 309 | U.setButtonLabel(the_btn, newlabel); 310 | } 311 | } 312 | i++; 313 | } 314 | } 315 | } 316 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUIRegion.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.addons.ui.interfaces.IFlxUIWidget; 4 | import flixel.addons.ui.interfaces.IResizable; 5 | import flixel.FlxCamera; 6 | import flixel.FlxSprite; 7 | import flixel.util.FlxColor; 8 | 9 | /** 10 | * A scalable object with width and height that isn't used for display purposes 11 | */ 12 | class FlxUIRegion extends FlxSprite implements IFlxUIWidget implements IResizable 13 | { 14 | public var broadcastToFlxUI:Bool = true; 15 | 16 | public var name:String; 17 | 18 | public function new(X:Float = 0, Y:Float = 0, W:Float = 16, H:Float = 16) 19 | { 20 | super(X, Y); 21 | makeGraphic(1, 1, FlxColor.TRANSPARENT); 22 | if (H < 1) 23 | { 24 | H = 1; 25 | } 26 | if (W < 1) 27 | { 28 | W = 1; 29 | } 30 | resize(W, H); 31 | } 32 | 33 | public function resize(w:Float, h:Float):Void 34 | { 35 | width = w; 36 | height = h; 37 | 38 | #if FLX_DEBUG 39 | debugBoundingBoxColor = FlxG.random.color().rgb; 40 | #end 41 | } 42 | 43 | #if FLX_DEBUG 44 | override public function drawDebugOnCamera(camera:FlxCamera) 45 | { 46 | var rect = getBoundingBox(camera); 47 | var gfx = beginDrawDebug(camera); 48 | 49 | gfx.beginFill(debugBoundingBoxColor, 0.5); 50 | gfx.drawRect(rect.x, rect.y, rect.width, rect.height); 51 | 52 | endDrawDebug(camera); 53 | } 54 | #end 55 | } 56 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUISlider.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | #if FLX_MOUSE 4 | import flixel.addons.ui.FlxSlider; 5 | import flixel.addons.ui.interfaces.IFlxUIWidget; 6 | 7 | #if !flixel_addons #error "haxelib flixel-addons required for FlxUISlider" #end 8 | 9 | class FlxUISlider extends FlxSlider implements IFlxUIWidget 10 | { 11 | public var name:String; 12 | 13 | public var broadcastToFlxUI:Bool = true; 14 | 15 | public static inline var CHANGE_EVENT:String = "change_slider"; // change in any way 16 | } 17 | #end 18 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUISprite.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.addons.ui.FlxUI.UIEventCallback; 4 | import flixel.addons.ui.interfaces.IFlxUIWidget; 5 | import flixel.addons.ui.interfaces.IResizable; 6 | import flixel.FlxSprite; 7 | import flixel.math.FlxPoint; 8 | import flixel.system.FlxAssets.FlxGraphicAsset; 9 | 10 | /** 11 | * Cheap extension of FlxSprite 12 | * @author Lars Doucet 13 | */ 14 | class FlxUISprite extends FlxSprite implements IFlxUIWidget implements IResizable 15 | { 16 | public var broadcastToFlxUI:Bool = true; 17 | 18 | // simple string ID, handy for identification, etc 19 | public var name:String; 20 | 21 | // pointer to the thing that "owns" it 22 | public var ptr_owner:Dynamic = null; 23 | 24 | // whether it has ever been recycled or not (useful for object pooling) 25 | public var recycled:Bool = false; 26 | 27 | public static inline var RESIZE_RATIO_X:Int = 0; 28 | public static inline var RESIZE_RATIO_Y:Int = 1; 29 | public static inline var RESIZE_RATIO_UNKNOWN:Int = -1; 30 | 31 | // what the image's aspect ratio is for rescaling by just X or just Y 32 | public var resize_ratio(default, set):Float; 33 | 34 | // whether the resize_ratio means X in terms of Y, or Y in terms of X 35 | public var resize_ratio_axis:Int = RESIZE_RATIO_Y; 36 | 37 | private function set_resize_ratio(r:Float):Float 38 | { 39 | resize_ratio = r; 40 | return r; 41 | } 42 | 43 | // resize about this point, so that after resizing this point in the object remains in the same place on screen 44 | public var resize_point(default, set):FlxPoint; 45 | 46 | private function set_resize_point(r:FlxPoint):FlxPoint 47 | { 48 | if (r != null) 49 | { 50 | resize_point = FlxPoint.get(); 51 | resize_point.x = r.x; 52 | resize_point.y = r.y; 53 | } 54 | return resize_point; 55 | } 56 | 57 | public function new(X:Float = 0, Y:Float = 0, SimpleGraphic:Dynamic = null) 58 | { 59 | super(X, Y, SimpleGraphic); 60 | } 61 | 62 | public function recycle(data:Dynamic):Void 63 | { 64 | recycled = true; 65 | // override per subclass 66 | } 67 | 68 | public function resize(w:Float, h:Float):Void 69 | { 70 | var old_width:Float = width; 71 | var old_height:Float = height; 72 | 73 | if (resize_ratio > 0) 74 | { 75 | var effective_ratio:Float = (w / h); 76 | if (Math.abs(effective_ratio - resize_ratio) > 0.0001) 77 | { 78 | if (resize_ratio_axis == RESIZE_RATIO_Y) 79 | { 80 | h = w * (1 / resize_ratio); 81 | } 82 | else 83 | { 84 | w = h * (1 / resize_ratio); 85 | } 86 | } 87 | } 88 | 89 | if (_originalKey != "" && _originalKey != null) 90 | { 91 | var newKey:String = U.loadScaledImage(_originalKey, w, h); 92 | if (newKey != "" && newKey != null) 93 | { 94 | loadFromScaledGraphic(newKey); 95 | } 96 | } 97 | 98 | var diff_w:Float = width - old_width; 99 | var diff_h:Float = height - old_height; 100 | 101 | if (resize_point != null) 102 | { 103 | var delta_x:Float = diff_w * resize_point.x; 104 | var delta_y:Float = diff_h * resize_point.y; 105 | x -= delta_x; 106 | y -= delta_y; 107 | } 108 | } 109 | 110 | public function loadGraphicAtScale(GraphicKey:String, W:Float, H:Float):Void 111 | { 112 | loadGraphic(GraphicKey, false); 113 | resize(W, H); 114 | } 115 | 116 | /** 117 | * Load an image from an embedded graphic file. 118 | * 119 | * @param Graphic The image you want to use. 120 | * @param Animated Whether the Graphic parameter is a single sprite or a row of sprites. 121 | * @param Width Optional, specify the width of your sprite (helps FlxSprite figure out what to do with non-square sprites or sprite sheets). 122 | * @param Height Optional, specify the height of your sprite (helps FlxSprite figure out what to do with non-square sprites or sprite sheets). 123 | * @param Unique Optional, whether the graphic should be a unique instance in the graphics cache. Default is false. 124 | * @param Key Optional, set this parameter if you're loading BitmapData. 125 | * @return This FlxSprite instance (nice for chaining stuff together, if you're into that). 126 | */ 127 | public override function loadGraphic(Graphic:FlxGraphicAsset, Animated:Bool = false, Width:Int = 0, Height:Int = 0, Unique:Bool = false, 128 | ?Key:String):FlxSprite 129 | { 130 | var sprite = super.loadGraphic(Graphic, Animated, Width, Height, Unique, Key); 131 | _originalKey = graphic.assetsKey; 132 | if (_originalKey == null) 133 | { 134 | _originalKey = graphic.key; 135 | } 136 | return sprite; 137 | } 138 | 139 | public override function destroy():Void 140 | { 141 | ptr_owner = null; 142 | super.destroy(); 143 | } 144 | 145 | private function loadFromScaledGraphic(Graphic:FlxGraphicAsset, Animated:Bool = false, Width:Int = 0, Height:Int = 0, Unique:Bool = false, 146 | ?Key:String):Void 147 | { 148 | super.loadGraphic(Graphic, Animated, Width, Height, Unique, Key); 149 | } 150 | 151 | private var _originalKey:String = ""; 152 | } 153 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUISpriteButton.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.addons.ui.interfaces.IFlxUIButton; 4 | import flixel.FlxSprite; 5 | import flixel.group.FlxSpriteGroup; 6 | import flixel.util.FlxColor; 7 | 8 | /** 9 | * This class extends FlxUISpriteButton and has a Sprite "label" 10 | * 11 | * Like all FlxUITypedButton's, it can work as a toggle button, and load 12 | * 9-slice sprites for its button images, and be dynamically resized 13 | * accordingly. 14 | */ 15 | class FlxUISpriteButton extends FlxUITypedButton implements IFlxUIButton 16 | { 17 | /** 18 | * Creates a new FlxUISpriteButton. 19 | * 20 | * @param X The X position of the button. 21 | * @param Y The Y position of the button. 22 | * @param Label The text that you want to appear on the button. 23 | * @param OnClick The function to call whenever the button is clicked. 24 | */ 25 | public function new(X:Float = 0, Y:Float = 0, ?Asset:FlxSprite, ?OnClick:Void->Void) 26 | { 27 | super(X, Y, OnClick); 28 | 29 | // Instead of "Label" we have "Asset" which is the id of the asset you want to load 30 | // If you're trying to push in a raw BitmapData object, add that to the cache first and pass in the key 31 | 32 | up_color = over_color = down_color = up_toggle_color = over_toggle_color = down_toggle_color = FlxColor.WHITE; 33 | 34 | if (Asset != null) 35 | { 36 | label = Asset; 37 | } 38 | } 39 | 40 | /**For IResizable:**/ 41 | public override function resize(W:Float, H:Float):Void 42 | { 43 | super.resize(W, H); 44 | autoCenterLabel(); 45 | } 46 | 47 | public override function autoCenterLabel():Void 48 | { 49 | if (label != null) 50 | { 51 | if ((label is FlxSpriteGroup)) 52 | { 53 | var g:FlxSpriteGroup = cast label; 54 | for (sprite in g.group.members) 55 | { // line up all their center points at 0,0 56 | sprite.x = (-sprite.width / 2); 57 | sprite.y = (-sprite.height / 2); 58 | } 59 | 60 | // Now we should have a stable width/height for the group 61 | 62 | var W:Float = g.width; 63 | var H:Float = g.height; 64 | 65 | for (sprite in g.members) 66 | { // center them all based on the stable width/height of group 67 | sprite.x = (W - sprite.width) / 2; 68 | sprite.y = (H - sprite.height) / 2; 69 | } 70 | } 71 | super.autoCenterLabel(); // center the label object itself 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUIState.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | #if flixel_addons 4 | import flixel.addons.transition.Transition; 5 | import flixel.addons.transition.FlxTransitionableState; 6 | #end 7 | import flixel.addons.ui.interfaces.ICursorPointable; 8 | import flixel.addons.ui.interfaces.IEventGetter; 9 | import flixel.addons.ui.interfaces.IFireTongue; 10 | import flixel.addons.ui.interfaces.IFlxUIState; 11 | import flixel.addons.ui.interfaces.IFlxUIWidget; 12 | import flixel.FlxG; 13 | import flixel.FlxState; 14 | import openfl.Assets; 15 | import openfl.events.Event; 16 | #if haxe4 17 | import haxe.xml.Access; 18 | #else 19 | import haxe.xml.Fast as Access; 20 | #end 21 | 22 | /** 23 | * This is a simple extension of FlxState that does two things: 24 | * 1) It implements the IFlxUIState interface 25 | * 2) Automatically creates a FlxUI objects from a single string id 26 | * 27 | * Usage: 28 | * Create a class that extends FlxUIState, override create, and 29 | * before you call super.create(), set _xml_id to the string id 30 | * of the corresponding UI xml file (leave off the extension). 31 | * 32 | * @author Lars Doucet 33 | */ 34 | #if flixel_addons 35 | class FlxUIState extends FlxTransitionableState implements IEventGetter implements IFlxUIState 36 | #else 37 | class FlxUIState extends FlxState implements IEventGetter implements IFlxUIState 38 | #end 39 | { 40 | public var destroyed:Bool; 41 | #if FLX_MOUSE 42 | public var cursor:FlxUICursor = null; 43 | public var hideCursorOnSubstate:Bool = false; 44 | private var _cursorHidden:Bool = false; 45 | #end 46 | /** 47 | * frontend for adding tooltips to things 48 | */ 49 | public var tooltips(default, null):FlxUITooltipManager; 50 | private var _xml_id:String = ""; // the xml file to load from assets 51 | #if (debug && sys) 52 | // If you want to do live reloading, set the path to your assets directory on your local disk here, 53 | // and it will load that instead of loading the xml specification from embedded assets 54 | // (only works on cpp/neko targets) 55 | // this should serve as a PREFIX to the _xml_id: 56 | // if full path="path/to/assets/xml/ui/foo.xml" and _xml_id="ui/foo.xml", then liveFilePath="path/to/assets/xml/" 57 | private var _liveFilePath:String = ""; 58 | #end 59 | private var _makeCursor:Bool; // whether to auto-construct a cursor and load default widgets into it 60 | private var _ui_vars:Map; 61 | private var _ui:FlxUI; 62 | private var _tongue:IFireTongue; 63 | public static var static_tongue:IFireTongue = null; 64 | // if this is not null, each state will grab this auto-magically 65 | // otherwise it's up to you to set _tongue before the UI stuff loads. 66 | #if (debug && sys) 67 | public static var static_liveFilePath:String = ""; 68 | // if this is not "", each state will grab this auto-magically 69 | // otherwise it's up to you to set _liveFilePath before the UI stuff loads. 70 | #end 71 | #if (debug && sys) 72 | public var reload_ui_on_asset_change(default, set):Bool; 73 | // setting this to true will add a listener to reload the UI when assets are updated ("openfl update " in OpenFL 2.0) 74 | // cpp/neko only 75 | #end 76 | // set this to true to make it automatically reload the UI when the window size changes 77 | public var reload_ui_on_resize:Bool = false; 78 | private var _reload:Bool = false; 79 | private var _reload_countdown:Int = 0; 80 | public var getTextFallback:String->String->Bool->String = null; 81 | 82 | #if (debug && sys) 83 | private function set_reload_ui_on_asset_change(b:Bool):Bool 84 | { 85 | // whether or not to reload UI when assets are updated 86 | if (b) 87 | Assets.addEventListener(Event.CHANGE, reloadUI); 88 | else 89 | Assets.removeEventListener(Event.CHANGE, reloadUI); 90 | return reload_ui_on_asset_change = b; 91 | } 92 | #end 93 | 94 | public override function create():Void 95 | { 96 | if (static_tongue != null) 97 | { 98 | _tongue = static_tongue; 99 | } 100 | 101 | #if (debug && sys) 102 | if (static_liveFilePath != null && static_liveFilePath != "") 103 | { 104 | _liveFilePath = static_liveFilePath; 105 | } 106 | #end 107 | 108 | #if FLX_MOUSE 109 | if (_makeCursor == true) 110 | { 111 | cursor = createCursor(); 112 | } 113 | #end 114 | 115 | tooltips = new FlxUITooltipManager(this); 116 | 117 | var liveFile:Access = null; 118 | 119 | #if (debug && sys) 120 | if (_liveFilePath != null && _liveFilePath != "") 121 | { 122 | try 123 | { 124 | liveFile = U.readAccess(U.fixSlash(_liveFilePath + _xml_id)); 125 | trace("liveFile = " + liveFile); 126 | } 127 | catch (msg:String) 128 | { 129 | FlxG.log.warn(msg); 130 | trace(msg); 131 | liveFile = null; 132 | } 133 | } 134 | _ui = createUI(null, this, null, _tongue, _liveFilePath); 135 | #else 136 | _ui = createUI(null, this, null, _tongue); 137 | #end 138 | add(_ui); 139 | 140 | if (getTextFallback != null) 141 | { 142 | _ui.getTextFallback = getTextFallback; 143 | } 144 | 145 | if (_xml_id != null && _xml_id != "") 146 | { 147 | var data:Access = null; 148 | var errorMsg:String = ""; 149 | 150 | if (liveFile == null) 151 | { 152 | try 153 | { 154 | data = U.xml(_xml_id); 155 | } 156 | catch (msg:String) 157 | { 158 | errorMsg = msg; 159 | } 160 | if (data == null) 161 | { 162 | try 163 | { 164 | data = U.xml(_xml_id, "xml", true, ""); // try again without default directory prepend 165 | } 166 | catch (msg2:String) 167 | { 168 | errorMsg += ", " + msg2; 169 | } 170 | } 171 | } 172 | 173 | if (data == null) 174 | { 175 | if (liveFile != null) 176 | { 177 | loadUIFromData(liveFile); 178 | } 179 | else 180 | { 181 | FlxG.log.error("FlxUISubState: Could not load _xml_id \"" + _xml_id + "\""); 182 | } 183 | } 184 | else 185 | { 186 | loadUIFromData(data); 187 | } 188 | } 189 | else 190 | { 191 | loadUIFromData(null); 192 | } 193 | 194 | #if FLX_MOUSE 195 | if (cursor != null && _ui != null) 196 | { // Cursor goes on top, of course 197 | add(cursor); 198 | cursor.addWidgetsFromUI(_ui); 199 | cursor.findVisibleLocation(0); 200 | } 201 | #end 202 | 203 | tooltips.init(); 204 | 205 | super.create(); 206 | 207 | cleanup(); 208 | } 209 | 210 | override public function update(elapsed:Float):Void 211 | { 212 | super.update(elapsed); 213 | if (tooltips != null) 214 | { 215 | tooltips.update(elapsed); 216 | } 217 | if (_reload) 218 | { 219 | if (_reload_countdown > 0) 220 | { 221 | _reload_countdown--; 222 | if (_reload_countdown == 0) 223 | { 224 | reloadUI(); 225 | } 226 | } 227 | } 228 | } 229 | 230 | @:access(flixel.addons.ui.FlxUI) 231 | private function cleanup():Void 232 | { 233 | // Clean up intermediate cached graphics that are no longer necessary 234 | _ui.cleanup(); 235 | } 236 | 237 | private function _cleanupUIVars():Void 238 | { 239 | if (_ui_vars != null) 240 | { 241 | for (key in _ui_vars.keys()) 242 | { 243 | _ui_vars.remove(key); 244 | } 245 | _ui_vars = null; 246 | } 247 | } 248 | 249 | public function setUIVariable(key:String, value:String):Void 250 | { 251 | if (_ui != null) 252 | { 253 | // if the UI is constructed, set the variable directly 254 | _ui.setVariable(key, value); 255 | } 256 | else 257 | { 258 | // if not, store it locally until the UI is constructed, then pass it in as it's being created 259 | if (_ui_vars == null) 260 | _ui_vars = new Map(); 261 | _ui_vars.set(key, value); 262 | } 263 | } 264 | 265 | public function resizeScreen(width:Float = 800, height:Float = 600):Void 266 | { 267 | /*#if sys 268 | //TODO: reimplement with next OpenFL 269 | FlxG.stage.resize(Std.int(width), Std.int(height)); 270 | onResize(Std.int(width), Std.int(height)); 271 | #end */ 272 | } 273 | 274 | public override function openSubState(SubState:FlxSubState):Void 275 | { 276 | #if FLX_MOUSE 277 | if (cursor != null && hideCursorOnSubstate && cursor.visible == true) 278 | { 279 | _cursorHidden = true; 280 | cursor.visible = false; 281 | } 282 | #end 283 | super.openSubState(SubState); 284 | } 285 | 286 | public override function closeSubState():Void 287 | { 288 | #if FLX_MOUSE 289 | if (cursor != null && hideCursorOnSubstate && _cursorHidden) 290 | { 291 | _cursorHidden = false; 292 | cursor.visible = true; 293 | } 294 | #end 295 | super.closeSubState(); 296 | } 297 | 298 | public override function onResize(Width:Int, Height:Int):Void 299 | { 300 | if (reload_ui_on_resize) 301 | { 302 | FlxG.resizeGame(Width, Height); 303 | _reload_countdown = 1; 304 | _reload = true; 305 | } 306 | } 307 | 308 | /** @since 2.1.0 */ 309 | public function onShowTooltip(t:FlxUITooltip):Void 310 | { 311 | // override per subclass 312 | } 313 | 314 | public override function destroy():Void 315 | { 316 | destroyed = true; 317 | 318 | if (_ui != null) 319 | { 320 | _ui.destroy(); 321 | remove(_ui, true); 322 | _ui = null; 323 | } 324 | 325 | if (tooltips != null) 326 | { 327 | tooltips.destroy(); 328 | tooltips = null; 329 | } 330 | 331 | super.destroy(); 332 | } 333 | 334 | public function forceFocus(b:Bool, thing:IFlxUIWidget):Void 335 | { 336 | if (_ui != null) 337 | { 338 | if (b) 339 | { 340 | _ui.focus = thing; 341 | } 342 | else 343 | { 344 | _ui.focus = null; 345 | } 346 | } 347 | } 348 | 349 | public function onCursorEvent(code:String, target:IFlxUIWidget):Void 350 | { 351 | getEvent(code, target, null); 352 | } 353 | 354 | public function getEvent(id:String, sender:Dynamic, data:Dynamic, ?params:Array):Void 355 | { 356 | // define per subclass 357 | } 358 | 359 | public function getRequest(id:String, sender:Dynamic, data:Dynamic, ?params:Array):Dynamic 360 | { 361 | // define per subclass 362 | return null; 363 | } 364 | 365 | public function getText(Flag:String, Context:String = "ui", Safe:Bool = true):String 366 | { 367 | if (_tongue != null) 368 | { 369 | return _tongue.get(Flag, Context, Safe); 370 | } 371 | if (getTextFallback != null) 372 | { 373 | return getTextFallback(Flag, Context, Safe); 374 | } 375 | return Flag; 376 | } 377 | 378 | /** 379 | * Creates a cursor. Makes it easy to override this function in your own FlxUIState. 380 | * @return 381 | */ 382 | private function createCursor():FlxUICursor 383 | { 384 | return new FlxUICursor(onCursorEvent); 385 | } 386 | 387 | // this makes it easy to override this function in your own FlxUIState, 388 | // in case you want to instantiate a custom class that extends FlxUI instead 389 | private function createUI(data:Access = null, ptr:IEventGetter = null, superIndex_:FlxUI = null, tongue_:IFireTongue = null, 390 | liveFilePath_:String = ""):FlxUI 391 | { 392 | var flxui = new FlxUI(data, ptr, superIndex_, tongue_, liveFilePath_, _ui_vars); 393 | _cleanupUIVars(); // clear out temporary _ui_vars variable if it was set 394 | return flxui; 395 | } 396 | 397 | // this makes it easy to override this function in your own FlxUIState, 398 | // in case you want to operate on data before it is loaded 399 | private function loadUIFromData(data:Access):Void 400 | { 401 | _ui.load(data); 402 | } 403 | 404 | private function reloadUI(?e:Event):Void 405 | { 406 | if (_ui != null) 407 | { 408 | remove(_ui, true); 409 | _ui.destroy(); 410 | _ui = null; 411 | } 412 | 413 | _ui = createUI(null, this, null, _tongue); 414 | add(_ui); 415 | 416 | var data:Access = U.xml(_xml_id); 417 | if (data != null) 418 | { 419 | loadUIFromData(data); 420 | } 421 | 422 | _reload = false; 423 | _reload_countdown = 0; 424 | } 425 | } 426 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUISubState.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.addons.ui.interfaces.IEventGetter; 4 | import flixel.addons.ui.interfaces.IFireTongue; 5 | import flixel.addons.ui.interfaces.IFlxUIState; 6 | import flixel.addons.ui.interfaces.IFlxUIWidget; 7 | import flixel.FlxBasic; 8 | import flixel.FlxG; 9 | import flixel.FlxSubState; 10 | import flixel.util.FlxColor; 11 | import flixel.math.FlxPoint; 12 | #if haxe4 13 | import haxe.xml.Access; 14 | #else 15 | import haxe.xml.Fast as Access; 16 | #end 17 | 18 | /** 19 | * This is a simple extension of FlxState that does two things: 20 | * 1) It implements the IEventGetter interface 21 | * 2) Automatically creates a FlxUI objects from a single string id 22 | * 23 | * Usage: 24 | * Create a class that extends FlxUIState, override create, and 25 | * before you call super.create(), set _xml_id to the string id 26 | * of the corresponding UI xml file (leave off the extension). 27 | * 28 | * @author Lars Doucet 29 | */ 30 | class FlxUISubState extends FlxSubState implements IFlxUIState 31 | { 32 | public var destroyed:Bool; 33 | 34 | #if FLX_MOUSE 35 | public var cursor:FlxUICursor = null; 36 | #end 37 | 38 | private var _makeCursor:Bool; // whether to auto-construct a cursor and load default widgets into it 39 | 40 | /** 41 | * frontend for adding tooltips to things 42 | */ 43 | public var tooltips(default, null):FlxUITooltipManager; 44 | 45 | private var _xml_id:String = ""; // the xml to load 46 | private var _ui:FlxUI; 47 | private var _tongue:IFireTongue; 48 | 49 | // set this to true to make it automatically reload the UI when the window size changes 50 | public var reload_ui_on_resize:Bool = false; 51 | 52 | private var _reload:Bool = false; 53 | private var _reload_countdown:Int = 0; 54 | 55 | public var getTextFallback:String->String->Bool->String = null; 56 | 57 | public function new(BGColor:FlxColor = 0) 58 | { 59 | super(BGColor); 60 | } 61 | 62 | public function forceScrollFactor(X:Float, Y:Float):Void 63 | { 64 | if (_ui != null) 65 | { 66 | for (w in _ui.group.members) 67 | { 68 | w.scrollFactor.set(X, Y); 69 | } 70 | if (_ui.scrollFactor != null) 71 | { 72 | _ui.scrollFactor.set(X, Y); 73 | } 74 | } 75 | } 76 | 77 | public function forceFocus(b:Bool, thing:IFlxUIWidget):Void 78 | { 79 | if (_ui != null) 80 | { 81 | if (b) 82 | { 83 | _ui.focus = thing; 84 | } 85 | else 86 | { 87 | _ui.focus = null; 88 | } 89 | } 90 | } 91 | 92 | public override function create():Void 93 | { 94 | if (FlxUIState.static_tongue != null) 95 | { 96 | _tongue = FlxUIState.static_tongue; 97 | } 98 | 99 | #if FLX_MOUSE 100 | if (_makeCursor == true) 101 | { 102 | cursor = createCursor(); 103 | } 104 | #end 105 | 106 | tooltips = new FlxUITooltipManager(this); 107 | 108 | _ui = createUI(null, this, null, _tongue); 109 | add(_ui); 110 | 111 | _ui.getTextFallback = getTextFallback; 112 | 113 | if (_xml_id != "" && _xml_id != null) 114 | { 115 | var data:Access = U.xml(_xml_id); 116 | if (data == null) 117 | { 118 | data = U.xml(_xml_id, "xml", true, ""); // try without default directory prepend 119 | } 120 | 121 | if (data == null) 122 | { 123 | #if debug 124 | FlxG.log.error("FlxUISubstate: Could not load _xml_id \"" + _xml_id + "\""); 125 | #end 126 | } 127 | else 128 | { 129 | _ui.load(data); 130 | } 131 | } 132 | else 133 | { 134 | _ui.load(null); 135 | } 136 | 137 | #if FLX_MOUSE 138 | if (cursor != null && _ui != null) 139 | { // Cursor goes on top, of course 140 | add(cursor); 141 | cursor.addWidgetsFromUI(_ui); 142 | cursor.findVisibleLocation(0); 143 | } 144 | 145 | FlxG.mouse.visible = true; 146 | #end 147 | 148 | tooltips.init(); 149 | 150 | super.create(); 151 | 152 | cleanup(); 153 | 154 | if ((_parentState is FlxUIState)) 155 | { 156 | reload_ui_on_resize = cast(_parentState, FlxUIState).reload_ui_on_resize; 157 | } 158 | } 159 | 160 | public function onCursorEvent(code:String, target:IFlxUIWidget):Void 161 | { 162 | getEvent(code, target, null); 163 | } 164 | 165 | public function onShowTooltip(t:FlxUITooltip):Void 166 | { 167 | // override per subclass 168 | } 169 | 170 | public override function onResize(Width:Int, Height:Int):Void 171 | { 172 | if (reload_ui_on_resize) 173 | { 174 | FlxG.resizeGame(Width, Height); 175 | _reload_countdown = 5; 176 | _reload = true; 177 | } 178 | } 179 | 180 | public override function update(elapsed:Float):Void 181 | { 182 | super.update(elapsed); 183 | tooltips.update(elapsed); 184 | if (_reload) 185 | { 186 | if (_reload_countdown > 0) 187 | { 188 | _reload_countdown--; 189 | if (_reload_countdown == 0) 190 | { 191 | reloadUI(); 192 | } 193 | } 194 | } 195 | } 196 | 197 | public override function destroy():Void 198 | { 199 | destroyed = true; 200 | 201 | if (tooltips != null) 202 | { 203 | tooltips.destroy(); 204 | tooltips = null; 205 | } 206 | 207 | if (_ui != null) 208 | { 209 | _ui.destroy(); 210 | remove(_ui, true); 211 | _ui = null; 212 | } 213 | 214 | super.destroy(); 215 | } 216 | 217 | public function getEvent(id:String, sender:IFlxUIWidget, data:Dynamic, ?params:Array):Void 218 | { 219 | // define per subclass 220 | } 221 | 222 | public function getRequest(id:String, sender:IFlxUIWidget, data:Dynamic, ?params:Array):Dynamic 223 | { 224 | // define per subclass 225 | return null; 226 | } 227 | 228 | public function getText(Flag:String, Context:String = "ui", Safe:Bool = true):String 229 | { 230 | if (_tongue != null) 231 | { 232 | return _tongue.get(Flag, Context, Safe); 233 | } 234 | if (getTextFallback != null) 235 | { 236 | return getTextFallback(Flag, Context, Safe); 237 | } 238 | return Flag; 239 | } 240 | 241 | @:access(flixel.addons.ui.FlxUI) 242 | private function cleanup():Void 243 | { 244 | // Clean up intermediate cached graphics that are no longer necessary 245 | _ui.cleanup(); 246 | } 247 | 248 | /** 249 | * Creates a cursor. Makes it easy to override this function in your own FlxUIState. 250 | * @return 251 | */ 252 | private function createCursor():FlxUICursor 253 | { 254 | return new FlxUICursor(onCursorEvent); 255 | } 256 | 257 | // this makes it easy to override this function in your own FlxUIState, 258 | // in case you want to instantiate a custom class that extends FlxUI instead 259 | private function createUI(data:Access = null, ptr:IEventGetter = null, superIndex_:FlxUI = null, tongue_:IFireTongue = null, 260 | liveFilePath_:String = ""):FlxUI 261 | { 262 | return new FlxUI(data, ptr, superIndex_, tongue_, liveFilePath_); 263 | } 264 | 265 | private function reloadUI():Void 266 | { 267 | if (_ui != null) 268 | { 269 | remove(_ui, true); 270 | _ui.destroy(); 271 | _ui = null; 272 | } 273 | 274 | _ui = createUI(null, this, null, _tongue); 275 | add(_ui); 276 | 277 | var data:Access = U.xml(_xml_id); 278 | _ui.load(data); 279 | 280 | _reload = false; 281 | _reload_countdown = 0; 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUITabMenu.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import openfl.geom.Rectangle; 4 | import flixel.addons.ui.interfaces.IEventGetter; 5 | import flixel.addons.ui.interfaces.IFlxUIButton; 6 | import flixel.addons.ui.interfaces.IFlxUIClickable; 7 | import flixel.addons.ui.interfaces.IFlxUIWidget; 8 | import flixel.addons.ui.interfaces.IResizable; 9 | import flixel.FlxSprite; 10 | import flixel.system.FlxAssets; 11 | import flixel.text.FlxText; 12 | import flixel.ui.FlxButton; 13 | import flixel.util.FlxArrayUtil; 14 | import flixel.math.FlxPoint; 15 | import flixel.util.FlxStringUtil; 16 | import flixel.util.FlxTimer; 17 | 18 | /** 19 | * @author Lars Doucet 20 | */ 21 | class FlxUITabMenu extends FlxUIGroup implements IResizable implements IFlxUIClickable implements IEventGetter 22 | { 23 | public static inline var CLICK_EVENT:String = "tab_menu_click"; 24 | 25 | public static inline var STACK_FRONT:String = "front"; // button goes in front of backing 26 | public static inline var STACK_BACK:String = "back"; // buton goes behind backing 27 | 28 | public var numTabs(get, never):Int; 29 | 30 | public function get_numTabs():Int 31 | { 32 | if (_tabs != null) 33 | { 34 | return _tabs.length; 35 | } 36 | return 0; 37 | } 38 | 39 | /**To make IEventGetter happy**/ 40 | public function getEvent(name:String, sender:IFlxUIWidget, data:Dynamic, ?params:Array):Void 41 | { 42 | // donothing 43 | } 44 | 45 | public function getRequest(name:String, sender:IFlxUIWidget, data:Dynamic, ?params:Array):Dynamic 46 | { 47 | // donothing 48 | return null; 49 | } 50 | 51 | /**For IFlxUIClickable**/ 52 | public var skipButtonUpdate(default, set):Bool; 53 | 54 | private function set_skipButtonUpdate(b:Bool):Bool 55 | { 56 | skipButtonUpdate = b; 57 | for (tab in _tabs) 58 | { 59 | var tabtyped:FlxUITypedButton = cast tab; 60 | tabtyped.skipButtonUpdate = b; 61 | } 62 | for (group in _tab_groups) 63 | { 64 | for (sprite in group.members) 65 | { 66 | if ((sprite is IFlxUIClickable)) 67 | { 68 | var widget:IFlxUIClickable = cast sprite; 69 | widget.skipButtonUpdate = b; 70 | } 71 | } 72 | } 73 | return b; 74 | } 75 | 76 | /**For IResizable**/ 77 | private override function get_width():Float 78 | { 79 | return _back.width; 80 | } 81 | 82 | private override function get_height():Float 83 | { 84 | var fbt = getFirstTab(); 85 | if (fbt != null) 86 | { 87 | return (_back.y + _back.height) - fbt.y; 88 | } 89 | return _back.height; 90 | } 91 | 92 | public function resize(W:Float, H:Float):Void 93 | { 94 | var ir:IResizable; 95 | if ((_back is IResizable)) 96 | { 97 | distributeTabs(W); 98 | ir = cast _back; 99 | var fbt:FlxUITypedButton = cast getFirstTab(); 100 | if (fbt != null) 101 | { 102 | ir.resize(W, H - fbt.get_height()); 103 | } 104 | else 105 | { 106 | ir.resize(W, H); 107 | } 108 | } 109 | else 110 | { 111 | distributeTabs(); 112 | } 113 | } 114 | 115 | public var selected_tab(get, set):Int; 116 | 117 | private function get_selected_tab():Int 118 | { 119 | return _selected_tab; 120 | } 121 | 122 | private function set_selected_tab(i:Int):Int 123 | { 124 | showTabInt(i); // this modifies _selected_tab/_selected_tab_id 125 | return _selected_tab; 126 | } 127 | 128 | public var selected_tab_id(get, set):String; 129 | 130 | private function get_selected_tab_id():String 131 | { 132 | return _selected_tab_id; 133 | } 134 | 135 | private function set_selected_tab_id(str:String):String 136 | { 137 | showTabId(str); // this modifies _selected_tab/_selected_tab_id 138 | return _selected_tab_id; 139 | } 140 | 141 | /***PUBLIC***/ 142 | public function new(?back_:FlxSprite, ?tabs_:Array, ?tab_names_and_labels_:Array<{name:String, label:String}>, ?tab_offset:FlxPoint, 143 | ?stretch_tabs:Bool = false, ?tab_spacing:Null = null, ?tab_stacking:Array = null) 144 | { 145 | super(); 146 | 147 | if (back_ == null) 148 | { 149 | // default, make this: 150 | back_ = new FlxUI9SliceSprite(0, 0, FlxUIAssets.IMG_CHROME_FLAT, new Rectangle(0, 0, 200, 200)); 151 | } 152 | 153 | _back = back_; 154 | add(_back); 155 | 156 | if (tabs_ == null) 157 | { 158 | if (tab_names_and_labels_ != null) 159 | { 160 | tabs_ = new Array(); 161 | 162 | // load default graphic data if only tab_names_and_labels are provided 163 | for (tdata in tab_names_and_labels_) 164 | { 165 | // set label and name 166 | var fb:FlxUIButton = new FlxUIButton(0, 0, tdata.label); 167 | 168 | // default style: 169 | fb.up_color = 0xffffff; 170 | fb.down_color = 0xffffff; 171 | fb.over_color = 0xffffff; 172 | fb.up_toggle_color = 0xffffff; 173 | fb.down_toggle_color = 0xffffff; 174 | fb.over_toggle_color = 0xffffff; 175 | 176 | fb.label.color = 0xFFFFFF; 177 | fb.label.setBorderStyle(OUTLINE); 178 | 179 | fb.name = tdata.name; 180 | 181 | // load default graphics 182 | var graphic_names:Array = [ 183 | FlxUIAssets.IMG_TAB_BACK, 184 | FlxUIAssets.IMG_TAB_BACK, 185 | FlxUIAssets.IMG_TAB_BACK, 186 | FlxUIAssets.IMG_TAB, 187 | FlxUIAssets.IMG_TAB, 188 | FlxUIAssets.IMG_TAB 189 | ]; 190 | var slice9tab:Array = FlxStringUtil.toIntArray(FlxUIAssets.SLICE9_TAB); 191 | var slice9_names:Array> = [slice9tab, slice9tab, slice9tab, slice9tab, slice9tab, slice9tab]; 192 | fb.loadGraphicSlice9(graphic_names, 0, 0, slice9_names, FlxUI9SliceSprite.TILE_NONE, -1, true); 193 | tabs_.push(fb); 194 | } 195 | } 196 | } 197 | 198 | _tabs = tabs_; 199 | _stretch_tabs = stretch_tabs; 200 | _tab_spacing = tab_spacing; 201 | _tab_stacking = tab_stacking; 202 | if (_tab_stacking == null) 203 | { 204 | _tab_stacking = [STACK_FRONT, STACK_BACK]; 205 | } 206 | _tab_offset = tab_offset; 207 | 208 | var i:Int = 0; 209 | var tab:FlxUITypedButton = null; 210 | for (t in _tabs) 211 | { 212 | tab = cast t; 213 | add(tab); 214 | tab.onUp.callback = _onTabEvent.bind(tab.name); 215 | i++; 216 | } 217 | 218 | distributeTabs(); 219 | 220 | _tab_groups = new Array(); 221 | } 222 | 223 | public override function destroy():Void 224 | { 225 | super.destroy(); 226 | U.clearArray(_tab_groups); 227 | U.clearArray(_tabs); 228 | _back = null; 229 | _tabs = null; 230 | _tab_groups = null; 231 | } 232 | 233 | public function getTab(?name:String, ?index:Null):IFlxUIButton 234 | { 235 | if (name != null) 236 | { 237 | for (tab in _tabs) 238 | { 239 | if (tab.name == name) 240 | { 241 | return tab; 242 | } 243 | } 244 | } 245 | if (index != null) 246 | { 247 | if (index < _tabs.length) 248 | { 249 | return _tabs[index]; 250 | } 251 | } 252 | return null; 253 | } 254 | 255 | public function getTabGroup(?name:String, ?index:Null):FlxUIGroup 256 | { 257 | if (name != null) 258 | { 259 | for (tabGroup in _tab_groups) 260 | { 261 | if (tabGroup.name == name) 262 | { 263 | return tabGroup; 264 | } 265 | } 266 | } 267 | if (index != null) 268 | { 269 | if (index < _tab_groups.length) 270 | { 271 | return _tab_groups[index]; 272 | } 273 | } 274 | return null; 275 | } 276 | 277 | public function getBack():FlxSprite 278 | { 279 | return _back; 280 | } 281 | 282 | public function replaceBack(newBack:FlxSprite):Void 283 | { 284 | var i:Int = members.indexOf(_back); 285 | if (i != -1) 286 | { 287 | var oldBack = _back; 288 | if ((newBack is IResizable)) 289 | { 290 | var ir:IResizable = cast newBack; 291 | ir.resize(oldBack.width, oldBack.height); 292 | } 293 | members[i] = newBack; 294 | newBack.x = oldBack.x; 295 | newBack.y = oldBack.y; 296 | oldBack.destroy(); 297 | } 298 | } 299 | 300 | public function addGroup(g:FlxUIGroup):Void 301 | { 302 | if (g == this) 303 | { 304 | return; // DO NOT ADD A GROUP TO ITSELF 305 | } 306 | 307 | if (!contains(g)) 308 | { // ONLY ADD IF IT DOESN'T EXIST 309 | g.y = (_back.y - y); 310 | add(g); 311 | _tab_groups.push(g); 312 | } 313 | 314 | // hide the new group 315 | _showOnlyGroup(""); 316 | 317 | // if this is our first group, show it right now 318 | if (_tab_groups.length == 1) 319 | { 320 | selected_tab = 0; 321 | } 322 | 323 | // refresh selected tab after group is added 324 | if (_selected_tab != -1) 325 | { 326 | selected_tab = _selected_tab; 327 | } 328 | } 329 | 330 | private function _onTabEvent(name:String):Void 331 | { 332 | showTabId(name); 333 | var tab = getTab(name); 334 | var params = (tab != null) ? tab.params : null; 335 | if (broadcastToFlxUI) 336 | { 337 | FlxUI.event(CLICK_EVENT, this, name, params); 338 | } 339 | } 340 | 341 | public function stackTabs():Void 342 | { 343 | var _backx:Float = _back.x; 344 | var _backy:Float = _back.y; 345 | 346 | group.remove(_back, true); 347 | 348 | var tab:FlxUITypedButton = null; 349 | for (t in _tabs) 350 | { 351 | tab = cast t; 352 | if (tab.toggled) 353 | { 354 | group.remove(tab, true); 355 | } 356 | } 357 | 358 | group.add(_back); 359 | 360 | for (t in _tabs) 361 | { 362 | tab = cast t; 363 | if (tab.toggled) 364 | { 365 | group.add(tab); 366 | } 367 | } 368 | 369 | // Put tab groups back on top 370 | for (group in _tab_groups) 371 | { 372 | var tempX:Float = group.x; 373 | var tempY:Float = group.y; 374 | remove(group, true); 375 | add(group); 376 | group.x = tempX; 377 | group.y = tempY; 378 | } 379 | 380 | _back.x = _backx; 381 | _back.y = _backy; 382 | } 383 | 384 | public function showTabId(name:String):Void 385 | { 386 | _selected_tab = -1; 387 | _selected_tab_id = ""; 388 | 389 | var i:Int = 0; 390 | for (tab in _tabs) 391 | { 392 | tab.toggled = false; 393 | tab.forceStateHandler(FlxUITypedButton.OUT_EVENT); 394 | if (tab.name == name) 395 | { 396 | tab.toggled = true; 397 | _selected_tab_id = name; 398 | _selected_tab = i; 399 | } 400 | i++; 401 | } 402 | 403 | _showOnlyGroup(name); 404 | stackTabs(); 405 | } 406 | 407 | /***PRIVATE***/ 408 | private var _back:FlxSprite; 409 | 410 | private var _tabs:Array; 411 | private var _tab_groups:Array; 412 | private var _stretch_tabs:Bool = false; 413 | private var _tab_spacing:Null = null; 414 | private var _tab_stacking:Array = null; 415 | private var _tab_offset:FlxPoint = null; 416 | 417 | private var _selected_tab_id:String = ""; 418 | private var _selected_tab:Int = -1; 419 | 420 | private function sortTabs(a:IFlxUIButton, b:IFlxUIButton):Int 421 | { 422 | if (a.name < b.name) 423 | { 424 | return -1; 425 | } 426 | else if (a.name > b.name) 427 | { 428 | return 1; 429 | } 430 | return -1; 431 | } 432 | 433 | private function showTabInt(i:Int):Void 434 | { 435 | if (i >= 0 && _tabs != null && _tabs.length > i) 436 | { 437 | var _tab:IFlxUIButton = _tabs[i]; 438 | var name:String = _tab.name; 439 | showTabId(name); 440 | } 441 | else 442 | { 443 | showTabId(""); 444 | } 445 | } 446 | 447 | private function _showOnlyGroup(name:String):Void 448 | { 449 | for (group in _tab_groups) 450 | { 451 | if (group.name == name) 452 | { 453 | group.visible = group.active = true; 454 | } 455 | else 456 | { 457 | group.visible = group.active = false; 458 | } 459 | } 460 | } 461 | 462 | private function getFirstTab():IFlxUIButton 463 | { 464 | var _the_tab:IFlxUIButton = null; 465 | if (_tabs != null && _tabs.length > 0) 466 | { 467 | _the_tab = _tabs[0]; 468 | } 469 | return _the_tab; 470 | } 471 | 472 | private function distributeTabs(W:Float = -1):Void 473 | { 474 | var xx:Float = 0; 475 | 476 | var tab_width:Float = 0; 477 | 478 | if (W == -1) 479 | { 480 | W = _back.width; 481 | } 482 | 483 | var diff_size:Float = 0; 484 | if (_stretch_tabs) 485 | { 486 | tab_width = W / _tabs.length; 487 | var tot_size:Float = (Std.int(tab_width) * _tabs.length); 488 | if (tot_size < W) 489 | { 490 | diff_size = (W - tot_size); 491 | } 492 | } 493 | 494 | _tabs.sort(sortTabs); 495 | 496 | var i:Int = 0; 497 | var firstHeight:Float = 0; 498 | 499 | var tab:FlxUITypedButton; 500 | for (t in _tabs) 501 | { 502 | tab = cast t; 503 | 504 | tab.x = x + xx; 505 | tab.y = y + 0; 506 | 507 | if (_tab_offset != null) 508 | { 509 | tab.x += _tab_offset.x; 510 | tab.y += _tab_offset.y; 511 | } 512 | 513 | if (_stretch_tabs) 514 | { 515 | var theHeight:Float = tab.get_height(); 516 | if (i != 0) 517 | { 518 | // when stretching, if resize_ratios are set, tabs can wind up with wrong heights since they might have different widths. 519 | // to solve this we cancel resize_ratios for all tabs except the first and make sure all subsequent tabs match the height 520 | // of the first tab 521 | theHeight = firstHeight; 522 | tab.resize_ratio = -1; 523 | } 524 | if (diff_size > 0) 525 | { 526 | tab.resize(tab_width + 1, theHeight); 527 | xx += (Std.int(tab_width) + 1); 528 | diff_size -= 1; 529 | } 530 | else 531 | { 532 | tab.resize(tab_width, theHeight); 533 | xx += Std.int(tab_width); 534 | } 535 | } 536 | else 537 | { 538 | if (_tab_spacing != null) 539 | { 540 | xx += tab.width + _tab_spacing; 541 | } 542 | else 543 | { 544 | xx += tab.width; 545 | } 546 | } 547 | if (i == 0) 548 | { 549 | firstHeight = tab.get_height(); // if we are stretching we will make everything match the height of the first tab 550 | } 551 | i++; 552 | } 553 | 554 | if (_tabs != null && _tabs.length > 0 && _tabs[0] != null) 555 | { 556 | _back.y = _tabs[0].y + _tabs[0].height - 2; 557 | if (_tab_offset != null) 558 | { 559 | _back.y -= _tab_offset.y; 560 | } 561 | } 562 | 563 | calcBounds(); 564 | } 565 | } 566 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUIText.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.addons.ui.FlxUI.UIEventCallback; 4 | import flixel.addons.ui.interfaces.IFlxUIWidget; 5 | import flixel.addons.ui.interfaces.IHasParams; 6 | import flixel.addons.ui.interfaces.IResizable; 7 | import flixel.FlxSprite; 8 | import flixel.text.FlxText; 9 | import openfl.text.TextField; 10 | 11 | /** 12 | * Simple extension to the basic text field class. 13 | * @author Lars Doucet 14 | */ 15 | class FlxUIText extends FlxText implements IResizable implements IFlxUIWidget implements IHasParams 16 | { 17 | public var broadcastToFlxUI:Bool = true; 18 | public var name:String; 19 | public var params(default, set):Array; 20 | public var minimumHeight(default, set):Float = 1; 21 | 22 | public function new(X:Float = 0, Y:Float = 0, FieldWidth:Float = 0, ?Text:String, Size:Int = 8, EmbeddedFont:Bool = true) 23 | { 24 | super(X, Y, FieldWidth, Text, Size, EmbeddedFont); 25 | } 26 | 27 | public function resize(w:Float, h:Float):Void 28 | { 29 | var sign:Int = 1; 30 | 31 | if (h < minimumHeight) 32 | { 33 | h = minimumHeight; 34 | } 35 | 36 | if (h < height) 37 | { 38 | sign = -1; 39 | } 40 | 41 | width = w; 42 | height = h; 43 | 44 | textField.width = width; 45 | 46 | var old_size:Int = size; 47 | var diff:Float = (height - graphic.bitmap.height); 48 | 49 | #if flash 50 | var oldText:String = text; 51 | if (oldText == "") 52 | { 53 | text = "T"; 54 | } 55 | diff = height - (Std.int(textField.textHeight) + 4); 56 | #end 57 | 58 | var failsafe:Int = 0; 59 | 60 | var numLines:Int = textField.numLines; 61 | 62 | while ((diff * sign) > 0 && failsafe < 999) 63 | { 64 | failsafe++; 65 | size += (1 * sign); 66 | if (sign > 0 && textField.numLines > numLines) // Failsafe in case the expanding text causes it to break to a new line 67 | { 68 | size -= (1 * sign); 69 | break; 70 | } 71 | _regen = true; 72 | calcFrame(true); 73 | 74 | #if flash 75 | diff = height - (Std.int(textField.textHeight) + 4); 76 | #else 77 | diff = (h - graphic.bitmap.height); 78 | #end 79 | 80 | diff = (h - graphic.bitmap.height); 81 | } 82 | 83 | #if flash 84 | text = oldText; 85 | #end 86 | 87 | if (failsafe >= 999) 88 | { 89 | FlxG.log.warn("Loop failsafe tripped while resizing FlxUIText to height(" + h + ")"); 90 | size = old_size; 91 | } 92 | 93 | width = w; 94 | height = h; 95 | 96 | _regen = true; 97 | calcFrame(true); 98 | } 99 | 100 | public function set_minimumHeight(H:Float):Float 101 | { 102 | if (H < 1) 103 | { 104 | H = 1; 105 | } 106 | minimumHeight = H; 107 | return minimumHeight; 108 | } 109 | 110 | public function set_params(p:Array):Array 111 | { 112 | params = p; 113 | return params; 114 | } 115 | 116 | public override function clone():FlxUIText 117 | { 118 | var newText = new FlxUIText(); 119 | newText.width = width; 120 | newText.height = height; 121 | 122 | var theFont:String = font; 123 | #if (flash || !openfl_legacy) 124 | theFont = FontFixer.fix(font); 125 | #end 126 | newText.setFormat(theFont, size, color); 127 | 128 | // for some reason, naively setting (f.alignment = alignment) causes cast errors! 129 | if (_defaultFormat != null && _defaultFormat.align != null) 130 | { 131 | newText.alignment = alignment; 132 | } 133 | newText.setBorderStyle(borderStyle, borderColor, borderSize, borderQuality); 134 | newText.text = text; 135 | return newText; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /flixel/addons/ui/FlxUITileTest.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import openfl.display.BitmapData; 4 | import openfl.geom.Point; 5 | import flixel.addons.ui.interfaces.IFlxUIWidget; 6 | import flixel.addons.ui.interfaces.IResizable; 7 | import flixel.math.FlxPoint; 8 | import flixel.util.FlxColor; 9 | 10 | /** 11 | * This is mostly just for testing purposes, it is NOT a replacement for FlxTileMap 12 | */ 13 | class FlxUITileTest extends FlxUISprite implements IResizable implements IFlxUIWidget 14 | { 15 | public var widthInTiles(get, never):Int; 16 | public var heightInTiles(get, never):Int; 17 | public var tileWidth(default, null):Int; 18 | public var tileHeight(default, null):Int; 19 | 20 | private function get_widthInTiles():Int 21 | { 22 | return _tilesWide; 23 | } 24 | 25 | private function get_heightInTiles():Int 26 | { 27 | return _tilesTall; 28 | } 29 | 30 | private var _tilesWide:Int = 2; 31 | private var _tilesTall:Int = 2; 32 | private var _color1:FlxColor = 0; 33 | private var _color2:FlxColor = 0; 34 | 35 | public var floorToEven:Bool = false; 36 | public var baseTileSize:Int = -1; 37 | 38 | public function new(X:Float, Y:Float, TileWidth:Int, TileHeight:Int, tilesWide:Int, tilesTall:Int, color1:FlxColor = 0x808080, color2:FlxColor = 0xc4c4c4, 39 | FloorToEven:Bool = false) 40 | { 41 | super(X, Y); 42 | 43 | tileWidth = TileWidth; 44 | tileHeight = TileHeight; 45 | 46 | _tilesWide = tilesWide; 47 | _tilesTall = tilesTall; 48 | _color1 = color1; 49 | _color2 = color2; 50 | 51 | floorToEven = FloorToEven; 52 | 53 | makeTiles(tileWidth, tileHeight, _tilesWide, _tilesTall, _color1, _color2); 54 | } 55 | 56 | private function makeTiles(tileWidth:Int, tileHeight:Int, tilesWide:Int, tilesTall:Int, color1:FlxColor = 0xff808080, color2:FlxColor = 0xffc4c4c4):Void 57 | { 58 | var size:FlxPoint = constrain(tileWidth * _tilesWide, tileHeight * _tilesTall); 59 | 60 | tileWidth = Std.int(size.x); 61 | tileHeight = Std.int(size.y); 62 | 63 | makeGraphic(tilesWide, tilesTall, color1); 64 | 65 | var canvas:BitmapData = pixels; 66 | 67 | var j:Int = 0; 68 | for (ix in 0...tilesWide) 69 | { 70 | for (iy in 0...tilesTall) 71 | { 72 | if (j % 2 == 0) 73 | { 74 | canvas.setPixel(ix, iy, color2); 75 | } 76 | j++; 77 | } 78 | if (tilesWide % 2 != 0) 79 | { 80 | j++; 81 | } 82 | } 83 | 84 | pixels = canvas; 85 | scale.set(tileWidth, tileHeight); 86 | updateHitbox(); 87 | } 88 | 89 | private function constrain(w:Float, h:Float):FlxPoint 90 | { 91 | var tileWidth = Std.int(w / _tilesWide); 92 | var tileHeight = Std.int(h / _tilesTall); 93 | 94 | if (tileWidth < tileHeight) 95 | { 96 | tileHeight = tileWidth; 97 | } 98 | else if (tileHeight < tileWidth) 99 | { 100 | tileWidth = tileHeight; 101 | } 102 | 103 | if (floorToEven) 104 | { 105 | if ((tileWidth % 2) == 1) 106 | { 107 | tileWidth -= 1; 108 | tileHeight = tileWidth; 109 | } 110 | } 111 | 112 | // if defined, force scaling to whole number multiple of tile sizes 113 | if (baseTileSize > 0) 114 | { 115 | tileWidth = Std.int(tileWidth / baseTileSize) * baseTileSize; 116 | tileHeight = tileWidth; 117 | } 118 | 119 | return new FlxPoint(tileWidth, tileHeight); 120 | } 121 | 122 | public override function resize(w:Float, h:Float):Void 123 | { 124 | makeTiles(tileWidth, tileHeight, _tilesWide, _tilesTall, _color1, _color2); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /flixel/addons/ui/FontDef.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import openfl.text.TextField; 4 | import openfl.text.TextFormat; 5 | import flixel.addons.ui.BorderDef; 6 | import flixel.text.FlxText; 7 | import flixel.util.FlxColor; 8 | import openfl.Assets; 9 | import openfl.text.TextFormatAlign; 10 | #if (openfl >= version("4.0.0")) 11 | import openfl.utils.AssetType; 12 | #end 13 | 14 | /** 15 | * ... 16 | * @author larsiusprime 17 | */ 18 | class FontDef 19 | { 20 | public var name:String; // the actual NAME of the font, say, "Verdana" 21 | public var size(get, set):Int; 22 | public var extension:String; // the extension of the font, usuall ".ttf" 23 | public var file:String; // the actual full path to the FILE of the font, say, "assets/fonts/verdana.ttf" 24 | public var format:TextFormat; // any necessary formatting information 25 | public var border:BorderDef; 26 | 27 | private static var EXTENSIONS:Array = [".ttf", ".otf"]; // supported font file extensions 28 | 29 | public function new(Name:String, Extension:String = ".ttf", File:String = "", ?Format:TextFormat, ?Border:BorderDef) 30 | { 31 | name = Name; 32 | extension = Extension; 33 | file = File; 34 | format = Format; 35 | if (format == null) 36 | { 37 | format = new TextFormat(); 38 | } 39 | border = Border; 40 | if (border == null) 41 | { 42 | border = new BorderDef(NONE, 0x000000); 43 | } 44 | } 45 | 46 | private function get_size():Int 47 | { 48 | if (format != null) 49 | { 50 | _size = Std.int(format.size); 51 | } 52 | return _size; 53 | } 54 | 55 | private function set_size(i:Int):Int 56 | { 57 | if (format != null) 58 | { 59 | format.size = i; 60 | } 61 | _size = i; 62 | return _size; 63 | } 64 | 65 | public function clone():FontDef 66 | { 67 | var newBorder = ((border == null) ? null : border.clone()); 68 | var newFormat = ((format == null) ? null : new TextFormat(format.font, format.size, format.color, format.bold, format.italic, format.underline, 69 | format.url, format.target, format.align, format.leftMargin, format.rightMargin, format.indent, format.leading)); 70 | if (format != null) 71 | { 72 | newFormat.letterSpacing = format.letterSpacing; 73 | } 74 | var newThis = new FontDef(name, extension, file, newFormat, newBorder); 75 | newThis.size = size; 76 | return newThis; 77 | } 78 | 79 | public static function copyFromTextField(t:TextField):FontDef 80 | { 81 | var dtf:TextFormat = t.defaultTextFormat; 82 | var fd = new FontDef(""); 83 | fd.fromStr(dtf.font); 84 | fd.format.font = dtf.font; 85 | fd.format.size = dtf.size; 86 | fd.format.color = dtf.color; 87 | fd.format.bold = dtf.bold; 88 | fd.format.italic = dtf.italic; 89 | fd.format.underline = dtf.underline; 90 | fd.format.url = dtf.url; 91 | fd.format.letterSpacing = dtf.letterSpacing; 92 | fd.format.leading = dtf.leading; 93 | fd.format.target = dtf.target; 94 | fd.format.align = dtf.align; 95 | return fd; 96 | } 97 | 98 | public static function copyFromFlxText(t:FlxText):FontDef 99 | { 100 | var fd = copyFromTextField(t.textField); 101 | fd.fromStr(t.font); 102 | fd.border.style = t.borderStyle; 103 | fd.border.color = t.borderColor; 104 | fd.border.quality = t.borderQuality; 105 | fd.border.size = t.borderSize; 106 | return fd; 107 | } 108 | 109 | public inline function applyTxt(textField:TextField):TextField 110 | { 111 | textField.setTextFormat(format); 112 | return textField; 113 | } 114 | 115 | public function applyFlx(flxText:FlxText):FlxText 116 | { 117 | var flxTxtAlign:FlxTextAlign = null; 118 | 119 | if (format.align != null) 120 | { 121 | flxTxtAlign = switch (format.align) 122 | { 123 | case TextFormatAlign.CENTER: FlxTextAlign.CENTER; 124 | case TextFormatAlign.LEFT: FlxTextAlign.LEFT; 125 | case TextFormatAlign.RIGHT: FlxTextAlign.RIGHT; 126 | case TextFormatAlign.JUSTIFY: FlxTextAlign.JUSTIFY; 127 | default: FlxTextAlign.LEFT; 128 | } 129 | } 130 | 131 | var font = (file == "" || file == null) ? null : file; 132 | 133 | flxText.setFormat(font, Std.int(format.size), format.color, flxTxtAlign, border.style, border.color); 134 | flxText.textField.defaultTextFormat.leading = format.leading; 135 | flxText.textField.defaultTextFormat.letterSpacing = format.letterSpacing; 136 | return flxText; 137 | } 138 | 139 | public function apply(?textField:TextField, ?flxText:FlxText):Void 140 | { 141 | if (textField != null) 142 | { 143 | applyTxt(textField); 144 | } 145 | if (flxText != null) 146 | { 147 | applyFlx(flxText); 148 | } 149 | } 150 | 151 | /** 152 | * Given a str like "verdanab.ttf", reverse-engineer the basic font properties 153 | * @param str a string name of a font, such as "verdanab.ttf" 154 | */ 155 | public function fromStr(str:String, recursion:Int = 0):Void 156 | { 157 | if (recursion > 3) 158 | { 159 | return; // no infinite loops, please 160 | } 161 | 162 | #if (flash || !openfl_legacy) 163 | str = FontFixer.fix(str); 164 | #end 165 | 166 | var style = getFontStyle(str); 167 | setFontStyle(style); 168 | 169 | var extension:String = ""; 170 | 171 | for (ext in EXTENSIONS) 172 | { 173 | if (str.indexOf(ext) != -1) 174 | { // if it has a particular extension 175 | if (Assets.exists(str + extension, AssetType.FONT)) 176 | { 177 | name = StringTools.replace(str, extension, ""); 178 | file = str; 179 | extension = ext; 180 | break; 181 | } 182 | } 183 | } 184 | 185 | // can't find the font entry 186 | if (extension == "") 187 | { // ...because there was no extension? 188 | for (ext in EXTENSIONS) 189 | { 190 | if (Assets.exists(str + ext, AssetType.FONT)) 191 | { // try adding each extension on and seeing if it works 192 | extension = ext; // if that works, we'll go with that extension 193 | name = str; 194 | file = str + extension; 195 | extension = ext; 196 | break; 197 | } 198 | } 199 | } 200 | else 201 | { // there was an extension, but we had another problem 202 | str = stripFontExtensions(str); 203 | var fontStyle = getFontStyle(str); 204 | if (fontStyle != "") 205 | { // it had a style character 206 | str = str.substr(str.length - 1, 1); // strip off the style char 207 | fromStr(str, recursion + 1); // try again with this 208 | return; 209 | } 210 | else 211 | { // it had no style character 212 | fromStr(str, recursion + 1); // try again with this 213 | return; 214 | } 215 | } 216 | 217 | setFontStyle(style); 218 | } 219 | 220 | private var _size:Int = 0; 221 | 222 | /** 223 | * If a recognized font extension exists, remove it from the font str 224 | * @param str font + extension, ie "verdanab.ttf" 225 | * @return font - extension, ie "verdanab" 226 | */ 227 | private function stripFontExtensions(str:String):String 228 | { 229 | if (str == null) 230 | return str; 231 | for (ext in EXTENSIONS) 232 | { 233 | if (str != null && str.indexOf(ext) != -1) 234 | { 235 | str = StringTools.replace(str, ext, ""); 236 | } 237 | } 238 | return str; 239 | } 240 | 241 | private function getFontExtension(str:String):String 242 | { 243 | if (str == null) 244 | return ""; 245 | for (ext in EXTENSIONS) 246 | { 247 | if (str.indexOf(ext) != -1) 248 | { 249 | return ext; 250 | } 251 | } 252 | return str; 253 | } 254 | 255 | private function fixFontName():Void 256 | { 257 | var fontStyle:String = getFontStyle(file); 258 | var extension = getFontExtension(file); 259 | var fontbase = stripFontExtensions(file); 260 | if (fontStyle != "") 261 | { 262 | fontbase = fontbase.substr(0, fontbase.length - 1); 263 | } 264 | var styleStr:String = ""; 265 | if (format.bold && format.italic) 266 | { 267 | styleStr = "z"; 268 | } 269 | else if (format.bold) 270 | { 271 | styleStr = "b"; 272 | } 273 | else if (format.italic) 274 | { 275 | styleStr = "i"; 276 | } 277 | // format.font = fontbase + styleStr + extension; 278 | file = fontbase + styleStr + extension; 279 | } 280 | 281 | /** 282 | * See if a style is "baked" into the font str, and if so return it 283 | * @param str font string, ie, "verdanab", "verdanai", "verdanaz" 284 | * @return "b" for bold, "i" for italic, "z" for bold-italic, "" for normal 285 | */ 286 | private function getFontStyle(str:String):String 287 | { 288 | if (str == null) 289 | return ""; 290 | str = stripFontExtensions(str); 291 | var lastChar:String = str.substr(str.length - 1, 1); 292 | if (lastChar != "" && lastChar != null) 293 | { 294 | lastChar = lastChar.toLowerCase(); 295 | switch (lastChar) 296 | { 297 | case "b": 298 | return "b"; 299 | case "i": 300 | return "i"; 301 | case "z": 302 | return "z"; 303 | default: 304 | return ""; 305 | } 306 | } 307 | return ""; 308 | } 309 | 310 | public function setFontStyle(str:String):Void 311 | { 312 | str = str.toLowerCase(); 313 | switch (str) 314 | { 315 | case "b", "bold": 316 | format.bold = true; 317 | format.italic = false; 318 | case "i", "italic": 319 | format.bold = false; 320 | format.italic = true; 321 | case "z", "bi", "ib", "bold-italic", "bolditalic", "italicbold", "all", "both": 322 | format.bold = true; 323 | format.italic = true; 324 | default: 325 | format.bold = false; 326 | format.italic = false; 327 | } 328 | fixFontName(); 329 | } 330 | 331 | public static function fromXML(data:Xml):FontDef 332 | { 333 | var fontFace:String = U.xml_str(data, "font"); 334 | var fontStyle:String = U.xml_str(data, "style"); 335 | var fontFile:String = null; 336 | if (fontFace != "") 337 | { 338 | fontFile = FlxUI.font(fontFace, fontStyle); 339 | } 340 | var fontStyle:String = U.xml_str(data, "style"); 341 | var fontSize:Int = FlxUI.fontSize(fontFile, U.xml_i(data, "size", 8)); 342 | var fontColor:FlxColor = U.xml_color(data, "color", true, 0xFFFFFFFF); 343 | var fontAlign:String = U.xml_str(data, "align"); 344 | var align = switch (fontAlign.toLowerCase()) 345 | { 346 | case "center": TextFormatAlign.CENTER; 347 | case "left": TextFormatAlign.LEFT; 348 | case "right": TextFormatAlign.RIGHT; 349 | case "justify": TextFormatAlign.JUSTIFY; 350 | default: TextFormatAlign.LEFT; 351 | } 352 | var fd:FontDef = new FontDef(U.xml_str(data, "font"), ".ttf", fontFile); 353 | fd.format.color = fontColor; 354 | fd.format.size = fontSize; 355 | fd.format.align = align; 356 | fd.size = fontSize; 357 | fd.setFontStyle(fontStyle); 358 | fd.border = BorderDef.fromXML(data); 359 | return fd; 360 | } 361 | 362 | public function toString():String 363 | { 364 | return "{name:" 365 | + name 366 | + ",size:" 367 | + size 368 | + ",file:" 369 | + file 370 | + ",extension:" 371 | + extension 372 | + ",format:" 373 | + format 374 | + ",border:" 375 | + border 376 | + "}"; 377 | } 378 | } 379 | -------------------------------------------------------------------------------- /flixel/addons/ui/FontFixer.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import openfl.Assets; 4 | #if (openfl >= version("4.0.0")) 5 | import openfl.utils.AssetType; 6 | #end 7 | 8 | /** 9 | * A really simple little class that solves an annoying problem with Flash font file names 10 | * @author larsiusprime 11 | */ 12 | class FontFixer 13 | { 14 | private static var name2File:Map; 15 | 16 | private static function init():Void 17 | { 18 | if (name2File == null) 19 | { 20 | name2File = new Map(); 21 | } 22 | } 23 | 24 | public static function fix(font:String):String 25 | { 26 | init(); 27 | if (font.indexOf(".ttf") == -1) 28 | { 29 | if (name2File.exists(font)) 30 | { 31 | font = name2File.get(font); 32 | } 33 | } 34 | return font; 35 | } 36 | 37 | public static function add(file:String, name:String = ""):String 38 | { 39 | init(); 40 | if (name != "" && name2File.exists(name)) 41 | { 42 | return name2File.get(name); 43 | } 44 | 45 | if (!Assets.exists(file, AssetType.FONT)) 46 | { 47 | return file; 48 | } 49 | 50 | var font = Assets.getFont(file); 51 | if (font == null) 52 | { 53 | return file; 54 | } 55 | 56 | if (name == "") 57 | { 58 | name = font.fontName; 59 | } 60 | #if flash 61 | // edge case for flash: if we've got a mangled font file like "assets/fonts/Verdana Bold.ttf", strip it down to "Verdana Bold" and look up 62 | // the correct font file name 63 | if (name == null && (file.indexOf("/") != -1 || file.indexOf(".ttf") != -1 || file.indexOf(".otf") != -1)) 64 | { 65 | var lastSlash = file.lastIndexOf("/"); 66 | var tempf = file.substr(lastSlash + 1, file.length - (lastSlash + 1)); 67 | tempf = StringTools.replace(tempf, ".ttf", ""); 68 | tempf = StringTools.replace(tempf, ".otf", ""); 69 | if (name2File.exists(tempf)) 70 | { 71 | return name2File.get(tempf); 72 | } 73 | } 74 | #end 75 | name2File.set(name, file); 76 | return fix(file); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /flixel/addons/ui/StrNameLabel.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.addons.ui.StrNameLabel; 4 | import flixel.util.FlxStringUtil; 5 | 6 | class StrNameLabel 7 | { 8 | public var name:String; 9 | public var label:String; 10 | 11 | public function new(Name:String = "", Label:String = "") 12 | { 13 | name = Name; 14 | label = Label; 15 | } 16 | 17 | public function copy():StrNameLabel 18 | { 19 | return new StrNameLabel(name, label); 20 | } 21 | 22 | public static function sortByLabel(a:StrNameLabel, b:StrNameLabel):Int 23 | { 24 | if (a.label < b.label) 25 | { 26 | return -1; 27 | } 28 | if (a.label > b.label) 29 | { 30 | return 1; 31 | } 32 | return 0; 33 | } 34 | 35 | public static function sortByName(a:StrNameLabel, b:StrNameLabel):Int 36 | { 37 | if (a.name < b.name) 38 | { 39 | return -1; 40 | } 41 | if (a.name > b.name) 42 | { 43 | return 1; 44 | } 45 | return 0; 46 | } 47 | 48 | public function toString():String 49 | { 50 | return FlxStringUtil.getDebugString([LabelValuePair.weak("name", name), LabelValuePair.weak("label", label)]); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /flixel/addons/ui/SwatchData.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui; 2 | 3 | import flixel.util.FlxArrayUtil; 4 | import flixel.util.FlxColor; 5 | import flixel.util.FlxDestroyUtil.IFlxDestroyable; 6 | 7 | /** 8 | * ... 9 | * @author Lars A. Doucet 10 | */ 11 | class SwatchData implements IFlxDestroyable 12 | { 13 | public var name:String; 14 | public var colors:Array; 15 | 16 | // The "main four" are now getter/setters so you can have an underlying colors array with arbitrary # of colors 17 | public var hilight(get, set):FlxColor; 18 | public var midtone(get, set):FlxColor; 19 | public var shadowMid(get, set):FlxColor; 20 | public var shadowDark(get, set):FlxColor; 21 | 22 | public function setColor(i:Int, Value:FlxColor):FlxColor 23 | { 24 | if (colors == null) 25 | { 26 | colors = []; 27 | } 28 | colors[i] = Value; 29 | return Value; 30 | } 31 | 32 | public function getColor(i:Int):FlxColor 33 | { 34 | if (colors.length >= i) 35 | { 36 | return colors[i]; 37 | } 38 | return 0xff000000; 39 | } 40 | 41 | /**GETTERs/SETTERS**/ 42 | private function get_hilight():FlxColor 43 | { 44 | return getColor(0); 45 | } 46 | 47 | private function set_hilight(Value:FlxColor):FlxColor 48 | { 49 | if (colors == null) 50 | { 51 | colors = []; 52 | } 53 | colors[0] = Value; 54 | return Value; 55 | } 56 | 57 | private function get_midtone():FlxColor 58 | { 59 | return getColor(1); 60 | } 61 | 62 | private function set_midtone(Value:FlxColor):FlxColor 63 | { 64 | if (colors == null) 65 | { 66 | colors = []; 67 | } 68 | colors[1] = Value; 69 | return Value; 70 | } 71 | 72 | private function get_shadowMid():FlxColor 73 | { 74 | return getColor(2); 75 | } 76 | 77 | private function set_shadowMid(Value:FlxColor):FlxColor 78 | { 79 | if (colors == null) 80 | { 81 | colors = []; 82 | } 83 | colors[2] = Value; 84 | return Value; 85 | } 86 | 87 | private function get_shadowDark():FlxColor 88 | { 89 | return getColor(3); 90 | } 91 | 92 | private function set_shadowDark(Value:FlxColor):FlxColor 93 | { 94 | if (colors == null) 95 | { 96 | colors = []; 97 | } 98 | colors[3] = Value; 99 | return Value; 100 | } 101 | 102 | public function destroy():Void 103 | { 104 | FlxArrayUtil.clearArray(colors); 105 | colors = null; 106 | } 107 | 108 | public function new(Name:String, ?Colors:Array) 109 | { 110 | if (Colors == null) 111 | { 112 | Colors = [0xffffffff, 0xff888888, 0xff444444, 0xff000000]; 113 | } 114 | name = Name; 115 | colors = Colors; 116 | } 117 | 118 | public function copy():SwatchData 119 | { 120 | var colorsCopy:Array = colors != null ? colors.copy() : null; 121 | return new SwatchData(name, colorsCopy); 122 | } 123 | 124 | public function toString():String 125 | { 126 | var str:String = "("; 127 | var i:Int = 0; 128 | if (colors != null) 129 | { 130 | for (colorInt in colors) 131 | { 132 | str += colorInt.toWebString(); 133 | if (i != colors.length - 1) 134 | { 135 | str += ","; 136 | } 137 | i++; 138 | } 139 | } 140 | else 141 | { 142 | str += "null"; 143 | } 144 | str += ",name=" + name + ")"; 145 | return str; 146 | } 147 | 148 | // Get the total raw difference in colors from another color swatch 149 | 150 | public function getRawDifference(?other:SwatchData, ?otherColors:Array, ?IgnoreInvisible:Bool = false):Int 151 | { 152 | var listA:Array = colors; 153 | if (colors != null) 154 | { 155 | listA = colors; 156 | } 157 | else 158 | { 159 | listA = []; 160 | } 161 | 162 | var listB:Array = null; 163 | if (other != null) 164 | { 165 | listB = other.colors; 166 | } 167 | else 168 | { 169 | if (otherColors != null) 170 | { 171 | listB = otherColors; 172 | } 173 | else 174 | { 175 | listB = []; 176 | } 177 | } 178 | 179 | var bigList:Array; 180 | var smallList:Array; 181 | 182 | if (listA.length < listB.length) 183 | { 184 | bigList = listB; 185 | smallList = listA; 186 | } 187 | else 188 | { 189 | bigList = listA; 190 | smallList = listB; 191 | } 192 | 193 | var totalDiff:Int = 0; 194 | for (i in 0...smallList.length) 195 | { 196 | var ignore:Bool = false; 197 | if (IgnoreInvisible && (bigList[i] == 0x00000000 || smallList[i] == 0x00000000)) 198 | { 199 | if (listA[i] == 0x00000000) 200 | { 201 | ignore = true; 202 | } 203 | } 204 | if (!ignore) 205 | { 206 | totalDiff += getRGBdelta(bigList[i], smallList[i]); // get raw RGB delta 207 | } 208 | } 209 | 210 | var lengthDiff:Int = bigList.length - smallList.length; 211 | if (lengthDiff != 0) 212 | { 213 | totalDiff += ((3 * 0xFF) * lengthDiff); 214 | } 215 | 216 | return totalDiff; 217 | } 218 | 219 | public function doColorsEqual(?other:SwatchData, ?otherColors:Array):Bool 220 | { 221 | var otherArray:Array = null; 222 | if (other != null) 223 | { 224 | otherArray = other.colors; 225 | } 226 | else 227 | { 228 | if (otherColors != null) 229 | { 230 | otherArray = otherColors; 231 | } 232 | } 233 | 234 | if (otherArray == null) 235 | { 236 | return colors == null; 237 | } 238 | else if (colors == null) 239 | { 240 | return otherArray == null; 241 | } 242 | 243 | if (otherArray.length != colors.length) 244 | { 245 | return false; 246 | } 247 | for (i in 0...colors.length) 248 | { 249 | if (colors[i] != otherArray[i]) 250 | { 251 | return false; 252 | } 253 | } 254 | return true; 255 | } 256 | 257 | private function getRGBdelta(a:Int, b:Int):Int 258 | { 259 | var ra:Int = a >> 16 & 0xFF; 260 | var ga:Int = a >> 8 & 0xFF; 261 | var ba:Int = a & 0xFF; 262 | 263 | var rb:Int = b >> 16 & 0xFF; 264 | var gb:Int = b >> 8 & 0xFF; 265 | var bb:Int = b & 0xFF; 266 | 267 | return Std.int(Math.abs(ra - rb) + Math.abs(ga - gb) + Math.abs(ba - bb)); 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /flixel/addons/ui/interfaces/ICursorPointable.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui.interfaces; 2 | 3 | /** 4 | * The cursor can point to one of these 5 | * @author Lars Doucet 6 | */ 7 | interface ICursorPointable {} 8 | -------------------------------------------------------------------------------- /flixel/addons/ui/interfaces/IEventGetter.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui.interfaces; 2 | 3 | interface IEventGetter 4 | { 5 | public function getEvent(name:String, sender:IFlxUIWidget, data:Dynamic, ?params:Array):Void; 6 | 7 | public function getRequest(name:String, sender:IFlxUIWidget, data:Dynamic, ?params:Array):Dynamic; 8 | } 9 | -------------------------------------------------------------------------------- /flixel/addons/ui/interfaces/IFireTongue.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui.interfaces; 2 | 3 | /** 4 | * An interface to match FireTongue, so we can use this without making 5 | * a full dependency 6 | * @author Lars Doucet 7 | */ 8 | interface IFireTongue 9 | { 10 | public function get(flag:String, context:String = "data", safe:Bool = true):String; 11 | public function getFont(str:String):String; 12 | public function getFontSize(str:String, size:Int):Int; 13 | 14 | public var locale(default, null):String; 15 | } 16 | -------------------------------------------------------------------------------- /flixel/addons/ui/interfaces/IFlxUIButton.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui.interfaces; 2 | 3 | import openfl.display.BitmapData; 4 | import flixel.addons.ui.FlxUI9SliceSprite; 5 | import flixel.addons.ui.FlxUIText; 6 | import flixel.FlxSprite; 7 | import flixel.system.FlxAssets; 8 | import flixel.ui.FlxButton; 9 | import flixel.util.FlxColor; 10 | import flixel.util.FlxDestroyUtil.IFlxDestroyable; 11 | import flixel.math.FlxPoint; 12 | 13 | /** 14 | * This interface keeps me from having to use a Dynamic variable to point to a value holding a FlxUITypedButton 15 | * that could be either a FlxUIButton or a FlxUISpriteButton 16 | * @author larsiusprime 17 | */ 18 | @:access(flixel.ui.FlxButton) 19 | interface IFlxUIButton extends IFlxUIWidget extends IHasParams extends IFlxDestroyable 20 | { 21 | public var up_color:Null; 22 | public var over_color:Null; 23 | public var down_color:Null; 24 | 25 | public var up_toggle_color:Null; 26 | public var over_toggle_color:Null; 27 | public var down_toggle_color:Null; 28 | 29 | public var up_visible:Bool; 30 | public var over_visible:Bool; 31 | public var down_visible:Bool; 32 | 33 | public var up_toggle_visible:Bool; 34 | public var over_toggle_visible:Bool; 35 | public var down_toggle_visible:Bool; 36 | 37 | public var resize_ratio:Float; 38 | public var resize_point:FlxPoint; 39 | 40 | public var has_toggle:Bool; 41 | public var toggled(default, set):Bool; 42 | 43 | public var toggle_label(default, set):FlxSprite; 44 | 45 | public var autoResizeLabel:Bool; 46 | 47 | public var justMousedOver(get, never):Bool; 48 | public var mouseIsOver(get, never):Bool; 49 | public var mouseIsOut(get, never):Bool; 50 | public var justMousedOut(get, never):Bool; 51 | 52 | public function autoCenterLabel():Void; 53 | public function loadGraphicSlice9(assets:Array = null, W:Int = 80, H:Int = 20, slice9:Array> = null, 54 | Tile:Int = FlxUI9SliceSprite.TILE_NONE, Resize_Ratio:Float = -1, isToggle:Bool = false, src_w:Int = 0, src_h:Int = 0, 55 | frame_indeces:Array = null):Void; 56 | public function loadGraphicsMultiple(assets:Array, Key:String = ""):Void; 57 | public function loadGraphicsUpOverDown(asset:Dynamic, for_toggle:Bool = false, ?key:String):Void; 58 | public function forceStateHandler(event:String):Void; 59 | 60 | #if (flixel >= version("5.7.0")) 61 | public var status(default, set):FlxButtonState; 62 | #else 63 | public var status(default, set):Int; 64 | #end 65 | } 66 | -------------------------------------------------------------------------------- /flixel/addons/ui/interfaces/IFlxUIClickable.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui.interfaces; 2 | 3 | interface IFlxUIClickable 4 | { 5 | public var skipButtonUpdate(default, set):Bool; 6 | } 7 | -------------------------------------------------------------------------------- /flixel/addons/ui/interfaces/IFlxUIState.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui.interfaces; 2 | 3 | interface IFlxUIState extends IEventGetter 4 | { 5 | public function forceFocus(b:Bool, thing:IFlxUIWidget):Void; 6 | public var tooltips(default, null):FlxUITooltipManager; 7 | #if FLX_MOUSE 8 | public var cursor:FlxUICursor; 9 | #end 10 | private var _tongue:IFireTongue; 11 | } 12 | -------------------------------------------------------------------------------- /flixel/addons/ui/interfaces/IFlxUIWidget.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui.interfaces; 2 | 3 | import flixel.addons.ui.FlxUI.UIEventCallback; 4 | import flixel.FlxSprite; 5 | 6 | /** 7 | * ... 8 | * @author Lars Doucet 9 | */ 10 | interface IFlxUIWidget extends IFlxSprite 11 | { 12 | public var name:String; 13 | public var width(get, set):Float; 14 | public var height(get, set):Float; 15 | 16 | /** 17 | * If true, will issue FlxUI.event() and FlxUI.request() calls 18 | */ 19 | public var broadcastToFlxUI:Bool; 20 | } 21 | -------------------------------------------------------------------------------- /flixel/addons/ui/interfaces/IHasParams.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui.interfaces; 2 | 3 | interface IHasParams 4 | { 5 | public var params(default, set):Array; 6 | private function set_params(p:Array):Array; 7 | } 8 | -------------------------------------------------------------------------------- /flixel/addons/ui/interfaces/ILabeled.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui.interfaces; 2 | 3 | import flixel.addons.ui.FlxUIText; 4 | import flixel.text.FlxText; 5 | 6 | /** 7 | * ... 8 | * @author Lars Doucet 9 | */ 10 | interface ILabeled 11 | { 12 | function getLabel():FlxUIText; 13 | function setLabel(t:FlxUIText):FlxUIText; 14 | } 15 | -------------------------------------------------------------------------------- /flixel/addons/ui/interfaces/IResizable.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui.interfaces; 2 | 3 | /** 4 | * ... 5 | * @author Lars Doucet 6 | */ 7 | interface IResizable 8 | { 9 | function resize(w:Float, h:Float):Void; 10 | public var width(get, set):Float; 11 | public var height(get, set):Float; 12 | } 13 | -------------------------------------------------------------------------------- /flixel/addons/ui/system/macros/FlxUIDefines.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.ui.system.macros; 2 | 3 | #if macro 4 | import haxe.macro.Compiler; 5 | import haxe.macro.Context; 6 | import haxe.macro.Expr.Position; 7 | 8 | // private enum UserAddonDefines {} 9 | // private enum HelperAddonDefines {} 10 | 11 | /** 12 | * The purpose of these "defines" classes is mainly to properly communicate version compatibility 13 | * among flixel libs, we shouldn't be overly concerned with backwards compatibility, but we do want 14 | * to know when a change breaks compatibility between Flixel-UI and Flixel. 15 | * 16 | * @since 2.6.0 17 | */ 18 | @:allow(flixel.system.macros.FlxDefines) 19 | @:access(flixel.system.macros.FlxDefines) 20 | class FlxUIDefines 21 | { 22 | /** 23 | * Called from `flixel.system.macros.FlxDefines` on versions 5.6.0 or later 24 | */ 25 | public static function run() 26 | { 27 | #if !display 28 | checkCompatibility(); 29 | #end 30 | } 31 | 32 | static function checkCompatibility() 33 | { 34 | #if (flixel < version("5.3.1")) 35 | FlxDefines.abortVersion("Flixel", "5.3.1 or newer", "flixel", (macro null).pos); 36 | #end 37 | } 38 | 39 | static function isValidUserDefine(define:Any) 40 | { 41 | return false; 42 | } 43 | 44 | static function abortVersion(dependency:String, supported:String, found:String, pos:Position) 45 | { 46 | abort('Flixel-UI: Unsupported $dependency version! Supported versions are $supported (found ${Context.definedValue(found)}).', pos); 47 | } 48 | 49 | static function abort(message:String, pos:Position) 50 | { 51 | Context.fatalError(message, pos); 52 | } 53 | } 54 | #end -------------------------------------------------------------------------------- /haxelib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flixel-ui", 3 | "url" : "https://github.com/HaxeFlixel/flixel-ui", 4 | "license": "MIT", 5 | "tags": ["game", "openfl", "flash", "neko", "cpp", "android", "ios", "cross"], 6 | "description": "A UI library for Flixel", 7 | "version": "2.6.4", 8 | "releasenote": "Compatibility with Flixel 6.0.0", 9 | "contributors": ["haxeflixel", "larsiusprime", "Gama11", "GeoKureli"] 10 | } 11 | -------------------------------------------------------------------------------- /hxformat.json: -------------------------------------------------------------------------------- 1 | { 2 | "lineEnds": { 3 | "leftCurly": "both", 4 | "rightCurly": "both", 5 | "objectLiteralCurly": { 6 | "leftCurly": "after" 7 | } 8 | }, 9 | "sameLine": { 10 | "ifElse": "next", 11 | "doWhile": "next", 12 | "tryBody": "next", 13 | "tryCatch": "next" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /include.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /release.bat: -------------------------------------------------------------------------------- 1 | 7z a -tzip -r -x!.git -x!.gitignore -x!.travis.yml -x!release.bat flixel-ui.zip -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | 7z a -tzip -r -x!.git -x!.gitignore -x!.travis.yml -x!release.bat flixel-ui.zip --------------------------------------------------------------------------------