Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SimianLogic/13d42824f4205798591a750269be8ff7 to your computer and use it in GitHub Desktop.
Save SimianLogic/13d42824f4205798591a750269be8ff7 to your computer and use it in GitHub Desktop.
flixel ui exporter thoughts
Does Haxe-UI use sprite sheets?
Can you nest containers? Widgets within widgets? Or is this a FlxUI object?
I've typically leaned towards runtime instantiation (the "Code test" in the RPG UI demo). In this case I'd read in the JSON and instantiate hax-ui elements according to the naming conventions.
I might make a go at wiring up a demo of this (I've done a bit of Haxe in the past).
Are you thinking you'd modify the photoshop generator to output layout XML files?
You'd need some way to mark up the additional attributes (as you wouldn't want to add these after export as re-exporting would blow away your changes)
I think it would make sense to export the metadata from Photoshop that makes sense without jumping through too many hoops and extend your
layout loader to support "metadata" files. Like, I'm thinking you'd have the PS-generated layout file that gets completely blown away/recreated each time
and then you'd have a separate myfile_metadata.xml that you hand author and hand update to add supplemental data.
peeking through
https://github.com/HaxeFlixel/flixel-ui
IMPLEMENTATION NOTES
widget -- i call these containers
name -- layer/group name
x/y -- yep, is haxe y-up or y-down?
use_def -- maybe not needed with machine-generated layouts?
group -- not sure i understand what this is for
visible -- seems like a runtime property, not a definition property
active -- seems like a runtime property, not a definition property
round -- not sure i understand what this is for
anchor -- i usually implment this is a param vs a child node but i have systems for reading/exporting these already
param -- trivial to implement (use text layers with a naming schema)
tooltip -- trivial to implement (use text layers with a naming schema)
size tags -- TODO
locale -- not sure i fully understand these, but could probably fake it with a container + text layers OR have a photoshop folder with "replacement" text files if it's mostly text files this is used for and just export the deltas
definition/default/include
these seem hard to implement, but maybe not needed for machine-generated layouts? seems like this is for file/org sanity
inject
is this used for file org or for nested symbols a-la flash? i've typically done this at runtime with placeholder, but the same idea would be really easy just using a different naming tag on a placeholder rect
group
not sure i fully understand the difference between group/widget but I kind of use them interchangeably
the way I usually implement this is that a group is a container node that can have children whereas a widget is a container node with a predefined set of children
can groups be nested? or do you only allow a single layer hierarchy?
align
TODO
position
TODO
layout
i usually handle this at runtime. i'll usually have variant PSDs for each layout (i.e. _ipad_landscape vs _iphone_portrait or whatever) and then just tell my runtime asset importer to always use the layout files with that postfix
not sure how i would support this at export-time... would probably handle this as a separate build script but would need to think about it some more
mode
this is an interesting approach -- i solve this in a completely different way using tabs and aliases. in my system a tab is a container with multiple states that just turns whole state trees on/off when you set a state. i'll typically just duplicate the assets across states as needed and give them the same names using an alias prefix. so if 2 different states have "play_icon" the subsequent ones will be called "alias_play_icon" and just use the same underlying asset. this is a bit more expensive in that all the states have to be "loaded" into the display tree but I doubt that's the bottleneck.
change
could support this at export time using a change_prefix and processing these last (and computing deltas)
WIDGETS
image -- default for any image layer
color? not sure
group? not sure
smooth? not sure
resize_ratio?
resize_point? --i currently support setting pivots, could probably "force" pivots into specific named edges
9slice -- scale9_
tile? not sure
region -- placeholder_
button -- btn_
text_x/text_y -- i just have text layers as a child component for things like this
label -- in my usual system this would be a property of the child textfield. what's the difference between this and child text nodes?
code? not sure
resize attr? not sure
params? not sure
button_toggle -- i usally implement these as a tab group with buttons inside for each state
checkbox -- haven't used, but should be easy
text -- default for any text layer
border attributes? not sure
context? not sure
code? not sure
text_input -- haven't used, but should be easy -- i.e. "input_textfieldname" instead of "textfieldname"
password_mode -- would probably just be an alias -- i.e. "password_textfieldname" instead of "input_textfieldname"
force_case? not sure
filter? not sure
context? not sure
code? not sure
radio_group -- haven't used, but should be easy
tabbed_menu -- i imagine our definitions of a "tab" are quite different but I have a way i currently do tabs
line -- would just be a sprite in my system
numeric_stepper -- not sure what this means
dropdown -- i think this would be straightforward
tilegrid -- i've implemented this in the past but not in my "default" set of definitions usually
Most of the Alignment/Localization stuff looks hard to implement at export time.
@larsiusprime
Copy link

So first off, my project is this (Flixel-UI):
https://github.com/haxeflixel/flixel-ui

Which should not be mistaken with this (HaxeUI using the flixel backend):
https://github.com/haxeui/haxeui-flixel

Flixel-UI is a fairly straightforward retained-mode UI system that is basically just a slightly cleaned up version of what I wrote for myself for the Defender's Quest series. The main appeal of it was to have something that is basically made entirely of native flixel objects. You can generate XML markup and then have it load a FlxUI object that gets populated with widgets (IFlxUIWidgets).

FlxUI's are containers, and can contain other FlxUI's. IFlxUIWidgets can be just about anything, but the primitives are basically FlxUISprite and FlxUIGroup. We have all sorts of widgets like text, numsteppers, regular sprites, 9-slice sprites, buttons, chrome, all the usual stuff. There's also a simple event model and some basic state management.

Are you thinking you'd modify the photoshop generator to output layout XML files?

That's the most straightforward way. But FlxUI's can also be generated in code, so we could generate instantiation haxe code too. I'd probably start with the layout XML as that's what I usually wind up making.

notes on this:

IMPLEMENTATION NOTES
widget			-- i call these containers
	name		-- layer/group name
	x/y			-- yep, is haxe y-up or y-down?
	use_def		-- maybe not needed with machine-generated layouts?
	group		-- not sure i understand what this is for
	visible		-- seems like a runtime property, not a definition property
	active		-- seems like a runtime property, not a definition property
	round		-- not sure i understand what this is for
	
	anchor			-- i usually implment this is a param vs a child node but i have systems for reading/exporting these already
	param			-- trivial to implement (use text layers with a naming schema)
	tooltip			-- trivial to implement (use text layers with a naming schema)
	size tags		-- TODO
	locale			-- not sure i fully understand these, but could probably fake it with a container + text layers OR have a photoshop folder with "replacement" text files if it's mostly text files this is used for and just export the deltas

widget here (IFlxUIWidget) is a thin interface that indicates something that can be added to a FlxUI object. It can either be a container (some variant of FlxGroup) or a non-container (some variant of FlxSprite). All of the "FlxUI" prefixed classes take some underlying "Flx" base class and add all the stuff the UI system needs.

x/y -- Haxe is just the programming language so it doesn't care. In Flixel specifically (as well as OpenFL), 0,0 is upper left and 100,100 is bottom right. So +y is down and +x is right.

use_def -- it kind of depends. It's mostly used right now to keep your xml from being too super verbose, letting you define, say, a button skin and 9-slice grid and button label font in one place and then just reference it in your widget instances. If you do all your layout in photoshoop you might have enough information to skip this, but it still might be necessary. Have to play with it.

group -- this indicates which container the widget belongs to. In the markup you can either define group children like this:

<group id="a">
    <sprite id="spr"/>
</group>

or like this:

<group id="a"/>
<sprite id="spr" group="a"/>

visible/active -- generally runtime properties, but sometimes you might want a layout to start with hidden elements that you plan on turning on later. Same with active, if you have invisible buttons you probably don't want them to be clickable, either. One could probably set it up so that you could choose to use the layer visibility property to set visibility on e.g. groups. Probably not necessary for basic layouts.

round -- so when you mark stuff up yourself, you'll often put in not exact x/y values, but say x=othersprite.x+somethingelse.width/2 or whatever. When you do that you tend to get fractional values, and depending on the render mode that can look really ugly. So you can put in a "round" attribute like round="true" (or round="down") to insist on integer values.

locale -- hmm, this is a bit tricky. Basically this is pretty similar to the if tags. If a certain locale, attributes should be this instead. This is checked at load time for the UI. But this lets me define things like, "If german use a smaller font here and make the text field wider"

definition/default/include -- yeah, see above.

inject -- this is just a "dumber" version of definition/include. You just straight up copy and paste the referenced file's contents right at the location of the node, without any fancy processing. Used for file org / verbosity and working around edge cases that include/defintion wasn't ideal for (typically platform-specific stuff like loading in button defs for the PSVita version, etc)

group -- as mentioned before, a widget is just anything that can be added to the UI scene graph. The default for "sprites" in flixel (and thus Flixel-ui) is that sprites are terminal objects, you can't add anything to them. Groups on the other hand you can nest as much as you want, and you can put groups inside of groups. Buttons, Text, and Sprites all ultimately inherit from FlxSprite. When I need to make a complex object that itself can have children, I just wrap it in a group or use something that already inherits from group.

layout -- we can probably skip this for now. This was a sort of speculatively added feature that I probably don't need anymore but happen to be using it in one scene so it sticks around for legacy purposes.

mode -- yeah this is just a quick and dirty way of saying "when you invoke this mode change, all these variables get set to these values". It's cheap & sloppy but gets the job done so far.

other stuff:
buttons: Flixel buttons do some fancy stuff with their label, so it's not easy to just treat a button as a dumb group. Without getting too far into the weeds, you can have three basic kinds of labels in flixel-ui:

  • a text label (with consistent size and font and content for up/down/over states, but variable color for each one if you like)
  • a sprite label (like an icon)
  • a group label (automatically generated if you specify a sprite label and a text label, it wraps them in a group and sets the group as the label)

code -- when you see this, it's related to the text string value an ties into my localization library, Firetongue. So I set text="$HELLO" code="u" that means, fetch the locale-specific version of "hello", and then apply this code to it: "u", which in this case means "make the text uppercase." It's just localization formatting metadata and can be an attribute anywhere you have a string being set.

params -- these are variables that are sent to the event system when you click the button. The most common case is just a single string value.

numeric stepper -- this is that little widget where you have an up arrow, a down arrow, and a text field with a number in it. So you can click the "stepper" buttons to increment/decrement the number variable, or type in the value directly (with numeric autovalidation). In practice it's a group with two buttons and a text field.

REGARDING ALIGNMENT/POSITION:
If you're laying stuff out in a photoshop document, you probably are less concerned with making everything super ultra responsive, and even if you are it's overkill to make that interface handle that. Instead, what I do these days is make use of a "point" system when I'm setting my coordinates.

So what I might do is make my photoshop document say, 1920x1080 wide. Then I lay out a bunch of sprites and text fields to keep it simple, On export, I not only record the x/y width/height values, but also put the value "pt" after each one. And then I define the size of a point as, say, 1080/screenHeight. This way, I define one base layout, and everything automatically scales up or down in proportion to the actual resolution the game is running at (though the proportions are fixed). This is what I do right now in DQ. When I can see how things are laid out visually, I don't really need to do the mental gymnastics of "this button is flush right to this other button + 10". I can just see that and do it directly. I do all the alignment fiddle faddle when I DON'T have visual aids so I don't mind it not being a solved problem in photoshoppy layouts.

@larsiusprime
Copy link

One approach I might have -- a solution to the "keep metadata / definitions / etc that are hard to express in photoshop", but without having to hand code them in to a generated file and worry about them getting blown away on each export.

You have two files. master_ui.xml and generated_ui.xml.
The former contains all the definitions, metadata, etc, all the stuff that's awkward to do via a Photoshop layout. Then it has an inject tag that references the generated_ui.xml, which is copy-pasted directly at a specific location inside of it. Then the only stuff in generated_ui.xml is layout stuff that's natural & appropriate for the Photoshop system to use.

Hand written stuff goes in the hand written file, generated stuff goes in the generated file. Game loads the master file, it pops in the generated file, loads the whole shebang. Export to one's heart content to the generated file and never kill the hand written stuff.

Any issues with that approach?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment