czyzby / gdx-lml

:octocat: LibGDX utility libraries.
Apache License 2.0
159 stars 25 forks source link

Creating a view without adding actors to Stage. #21

Closed jpsgamboa closed 8 years ago

jpsgamboa commented 8 years ago

I like the way we can use LmlView and #createView() with actor injection. I find it a good way to centralize all the actions and actors I need in a class that are relevant to that view only, via @LmlActorand @LmlAction.

AbstractLmlView takes hold of the stage's draw, act, etc. methods, so I created a class implementing LmlViewand ActionContainerto achieve a similar behavior while keeping the control of the stage's methods. This works great for displaying windows, dialogs or any Actors that are independent from the underlying scene: ViewWhichExtendsMyAbstractClass view = lmlParser.createView(ViewWhichExtendsMyAbstractClass.class, template.lml);

This immediately displays the template and I get control of every actor and method if I simply define them with @LmlActor and @LmlAction inside that class.

Now, what if I want this same injection without adding the Actors to the stage? Or, in my case, what if I want to add the Actor to a Tableor a Containeralready in the Stage?

With LmlView#parseTemplate() and a separate ActionContainer I can get access to the actors via lmlParser.getActorsMappedByIds() but this gets tiring fast and does not allow me to centralize relevant LmlActionsand LmlActorsin the same class. I'm finding it much more practical to use annotations.

The question: Is the any class besides LmlView that I can implement to get my LmlActions and LmlActors parsed without adding them to the Stage? Or some other solution I'm missing?

(Sorry for the long intro but it's in hopes that you correct me if I'm thinking the wrong way)

czyzby commented 8 years ago

Implementing LmlView is purely optional, I'm pretty sure of that. You can ask LmlParser to create any class with LML annotations, and instead of relying on LmlParser to fill your stage, just keep references to root actors and add them manually. For example:

class MyClass {
  @LmlActor("root") Table table;

  public void doSomethingWithRoot() {
    // ...
  }
}
<table id="root">
   ...
</table>
MyClass my = lmlParser.createView(MyClass.class, template);
my.doSomethingWithRoot();

You can try it out let me know if there are any issues.

However, keep in mind that LmlParser doesn't just add actors to stage. If you set some additional settings (like initial x and y) or if the actor requires special treatment (like Dialog with its showing methods), LmlParser will keep that in mind. LmlUtilities#appendActorsToStage might prove useful.

czyzby commented 8 years ago

Use latest snapshot. Previous version did not support custom views with ActionContainer and ActorConsumer, as it was assumed that with no ID from LmlView, there is no sensible way of adding them to the parser. From now on, simple class name (without package) will be used if LmlView is not implemented.

jpsgamboa commented 8 years ago

Thanks! To be clear, "MyClass" needs to implement ActionContainerand ActorConsumerfor LmlParser to parse it?

Can confirm LmlActions are getting properly called. I'll need to test it better later, since I'm out of time for now. Meanwhile feel free to close this and I'll get back to you if the need arises.

czyzby commented 8 years ago

No. It can implement ActionContainer or ActorConsumer (or both). If you don't implement any LML-specific interfaces, @LmlInject, @LmlBefore, @LmlActor and @LmlAfter are still processed - you just cannot pass any actions with this view class. Of course, you can still add ActionContainers and ActorConsumers to the parser manually, but then again - using AbstractLmlView is the fastest way to do this.