czyzby/gdx-lml

Tag Creation At Runtime

Hellgasm opened this issue · 14 comments

Hello,

I want to create an actor for a tag specified in a string using LML. Then I will add as children to some actor (group) in actor hierarchy. For example string contains "button" I want to create a Button. I am not sure if I'm using proper way to doing this.

I use:

parser.getSyntax().getTagProvider(myStr)

to get tag provider object. Then I try to use create method of tag provider to create a LmlTag object. It requires some odd parameters like parent and rawTagData. As I'm not the parser itself how can I get a LmlTag reference to a parent object? I tried to pass null. Also I don't have any idea that what rawTagData is and what it's used for as I couldn't find any examples or documentation on it (a concrete example for this would be the best).

If I ever get this working then I will use getActor() method of this LmlTag to create the desired actor.

I need your advices on this, please.

You don't have to reference internal APIs, just use LmlParser like you would for a file. You can pass any valid LML string to the parser and it will return an array of parsed actors.

// Pseudo-code for parsing a button tag in runtime:
Button button = (Button) lmlParser.parseTemplate("<button />").get(0)

By the way, LML is just a wrapper over Scene2D. If you need to create complex actors in runtime, you might as well use Scene2D actors directly.

Does that solve your problem?

I'm already using my parser to parse a template file, I thought it maintained some internal state.
Could this also be possible with my way using internal APIs ? It was completely wrong?

And what did you mean with complex actor?

Edit:
I'm adding my new actor to the target group by iterating from root until I find it. I get root with with mainView.getStage().getRoot(). Is there a LML-way of doing this insertion easier?

Sorry if I asked too much but I have to use lml to be able to continue using libgdx atm.

I think I'm starting to understand your use case. Are you trying to spawn additional actors while your original template is being parsed? Seems like you're trying to add a custom tag or a macro. Here you can find some examples of custom attributes, tags and macros added to an existing LML parser. Please go through gdx-lml-examples project and the wiki to get a good grasp of what's possible in LML.

As far as usage examples go, all existing actor and macro tags are using this API, and they all seem to be commented, so you could start there.

Is there a LML-way of doing this insertion easier?

Yes, using @LmlInject and @LmlActor annotations. See this tutorial and this chapter of the wiki.

Sorry if I asked too much but I have to use lml to be able to continue using libgdx atm.

Not a problem, but out of curiosity, why would you have to use LML? Legacy project?

@Hellgasm Did it help you solve your issue? Can I close this issue or is there anything else you'd like to ask?

Is there a way to partially parse a given string and return position? For example I want to parse until I find a Window and A button, then I will have current position in given string.

Not a problem, but out of curiosity, why would you have to use LML? Legacy project?

It seems easiest way to separate logic and UI in my current libgdx project.

Is there a way to partially parse a given string and return position? For example I want to parse until I find a Window and A button, then I will have current position in given string.

That's usually what macros are for, they allow you to capture the content between their tags and parse them pretty much in any way you want or need. See the official looping macros for some good examples how can you "schedule" parsing of additional content within the same LML template.

It seems easiest way to separate logic and UI in my current libgdx project.

Makes sense, this is what LML was originally developed for.

Isn't there a way to implement this without modifying my templateString? For example hooking certain parser functions or using functions like parseInt, etc. to manually parse at each step?

I'm afraid you would have to extend and modify some internal APIs. What is your exact use case though? Maybe there's an easier way to achieve what you're trying to do.

Well it's exactly as I said. I need to parse until I find something. I may subclass and override stuff in my own parser implementation using your interface.

That's how you're trying to implement it, I'm wondering what's the reason behind it. You don't just parse text for the sake of parsing, do you? :) Anyway, I'd try implementing some custom macros first, and they're not flexible enough - try subclassing internal parser APIs. I'll close this issue for now, but don't hesitate to ask more questions in this thread or another issue.

Using your parser I get a hierarchy of actors (actor tree, graph or whatever you call it). This is very nice but what if I also want to do the reverse? Normally one could be able to get token stream back from the parse tree (or just me lol). I want to reflect modifications I made on actor hierarchy on the template string. I tried to do it manually, using DFS traversal of actor tree and find every element in template string. If I could find the appropriate place, I would make some deletions/insertions or whatever required to the template string. But there are many elements in the tree which don't correspend to any tags in template. For example there is a thing in Window named Window$1, probably a member type named like this because of proguard or whatever as I work from gradle. Maybe I can just skip unknown elements and still achieve this but it seems like very bad design choice for my purposes. So I can't decide what to do at this point.

Currently there is no way to convert Scene2D actors back to LML templates. I could see some potential use cases - like saving dynamic UI layouts or migrating from plain Scene2D code to LML - but this is a major feature that is unlikely to be implemented. As you already noticed, LibGDX internals can get pretty convoluted and it is very difficult to provide a solutions without a few compromises.

Again, what is your core problem? And by that I mean the goals on the level of the application/game, not what you're currently trying to achieve. If I understood the kind of product you're trying to build and why are you having these problems, maybe I could be more helpful.

...like saving dynamic UI layouts...

Yeah that's what I need to do. I would manually find position and insert/delete the changes if there wasn't hinderance from implicit elements like ones in Window tag as I mentioned.

Unless the UI is very complex, I'd save the positions/configurations of specific actors in preferences and restore them after loading the initial layout with LML. I'm afraid you have to implement that manually.