Animated buttons.

150 views
Skip to first unread message

Daniel Gerson

unread,
Aug 13, 2013, 12:08:14 PM8/13/13
to pl...@googlegroups.com
Okay, so I need to create buttons that behave in an animated way. The buttons must consist of a symbol and background layers, and bounce around in a particular way by tripleplay.Animator.

I need to know whether it's worthwhile using the tripleplay ui elements to achieve this? Will I be fighting the layout engine? given that the buttons must be able to:
1) arbitrarily switch their z-order.
2) Need to arrive at particular layouts, then depending on which buttons are enabled/disabled have to move to the next layouts.
3) if the buttons are part of particular groups, they must be able to switch to be part of different groups in different layouts, which will be tweened between.
4) Even the symbol and the background elements must on occasion be separately animatable.

thoughts? approaches? is this beyond the scope of tripleplay ui?

Seems to me I can:
a) Go my own way.
b) Extend tripleplay to achieve this
c) Go an in-between route. pulling ui elements in and out of layouts.

Given that I'm no expert on the tripleplay ui, I thougtht I'd put this out there for comment.

Regards
DMG


Michael Bayne

unread,
Aug 13, 2013, 12:52:00 PM8/13/13
to pl...@googlegroups.com
It would not be that hard to either write your own layout manager, or
use AbsoluteLayout and update your constraints after animating things.
Since you apparently know where you want your elements to be (because
you're animating them), absolute layout will just follow your cues
when they layout is invalidated and revalidated.

You will undoubtedly bump into some rough edges, but it's probably
easier to work around those than to throw everything out and build
your own ui from layers and pointer listeners.

-- m...@samskivert.com

Michael Bayne

unread,
Aug 13, 2013, 12:56:20 PM8/13/13
to pl...@googlegroups.com
> On Aug 13, 2013, at 9:08 AM, Daniel Gerson <daniel...@gmail.com> wrote:
>
> 1) arbitrarily switch their z-order.

TPUI doesn't care about z-order so you can fiddle it to your heart's content.

> 2) Need to arrive at particular layouts, then depending on which buttons are enabled/disabled have to move to the next layouts.

Not sure what you mean by this.

> 3) if the buttons are part of particular groups, they must be able to switch to be part of different groups in different layouts, which will be tweened between.

When transitioning, you can remove buttons from their old group, start
an animation that adds them to the screen layer, tweens their
position, and then removes them from the screen layer and adds them to
their new target group (with the appropriate AbsoluteLayout position
constraints).

> 4) Even the symbol and the background elements must on occasion be separately animatable.

Not sure what you mean by this either. What's a symbol versus a
background element? Are you talking about flump animations?

-- m...@samskivert.com

Daniel Gerson

unread,
Aug 13, 2013, 2:26:15 PM8/13/13
to pl...@googlegroups.com
Thanx for your response.

> 2) Need to arrive at particular layouts, then depending on which buttons are enabled/disabled have to move to the next layouts.

Not sure what you mean by this.

This was merely a summary (probably rushed and badly put) of what has to happen.
What I really meant was: it would be ideal if the existing layout manager tools could help organize the beginning (A) and final (B) layout positions, based on styles/groups/layouts... but then not interfere with the process of how the various buttons decide to get from (A) to (B), which would be animated.

So answering your previous question: 

Since you apparently know where you want your elements to be (because
you
're animating them), absolute layout will just follow your cues
when they layout is invalidated and revalidated.

Not exactly, we would like to employ the layout system to determine (A) and (B), which we only have a general idea of where we want the widgets (as any UI designer does based on contextual constraints).
But given (A) and (B), we do know how we would like to transition between these two points.
 

> 4) Even the symbol and the background elements must on occasion be separately animatable.

Not sure what you mean by this either. What's a symbol versus a
background element? Are you talking about flump animations?

Hmmm... I'm not thinking they would be flump animations at the current time... although that would be a nice option to reserve, don't put ideas in my head! :-P.
But if you clicked a button and the symbol/icon inside did a simple flip/rotation... that's more of what I'm getting at.

I know that the icons that Buttons support are generic Images, but not so familiar with the background to buttons, if I can substitute another Image there, and how that effects the layout architecture etc.

I'm on page with you that it would be better to work within the current system. Just good to get a thumbs up and know about potential gotchas ahead of time :-)

I'm assuming that during the animation, we wouldn't call Interface.paint(), and then reconnect it on completion. Then probably also have to disconnect the unitSlot mechanism during animation, or some such disabling (without greying out) etc...

... but if you're confident, then I simply have more reading to do.


DMG

Daniel Gerson

unread,
Aug 14, 2013, 12:22:04 PM8/14/13
to pl...@googlegroups.com
So the plan is as follows:

1) Configure widgets into layout-A (using a variety of groups and layout managers)
2) Record all absolute positions of widgets multiplying their parent layers' matrices.
3) Configure widgets into layout-B (using a variety of groups and layout managers)
4) Record all absolute positions of widgets 
5) Record all matrices of TPGroups, then set all these to the identity matrix.
6) Let Animator lose on widgets, animating and tweaning their absolute values.
7) Restore the original matrices of TPGroups.

Originally I thought that I was going to pop the buttons out of their groups in step (5), but it's probably harder to put the buttons back in their original state.

What gives me pause here, is that any variation of the above screams hackiness to me. It's like I'm fighting the API in a way that it was never intended. I have to record the state of the internals, tear them down, then build them up again in a way that preserves what ever the internals of the layout managers/groups expect.

Hopefully this post better highlights my concerns in my hastily composed prior messages. Obviously my preference is to both not reinvent the wheel, but also to avoid hackiness. I fully accept that I may have missed obvious solutions, which is why I'm posting here for confirmation.

DMG

Daniel Gerson

unread,
Aug 14, 2013, 12:47:16 PM8/14/13
to pl...@googlegroups.com
I guess I don't need to *record* and *restore* the positions of the groups.
If the TPGroups could *set all to identity* and then *re-layout*, then I should be in the expected position.
Seems I should be adding the identity functionality to tripleplay, so it's part of the contract I can expect?

Why does it help to think out loud? :-)

DMG

Michael Bayne

unread,
Aug 14, 2013, 1:24:10 PM8/14/13
to pl...@googlegroups.com

On Wed, Aug 14, 2013 at 9:22 AM, Daniel Gerson <daniel...@gmail.com> wrote:
Hopefully this post better highlights my concerns in my hastily composed prior messages. Obviously my preference is to both not reinvent the wheel, but also to avoid hackiness. I fully accept that I may have missed obvious solutions, which is why I'm posting here for confirmation.

Yeah, this sounds like a giant hack and is definitely a bad idea.

If you need to use the TPUI layout mechanisms, rather than animating from hard coded layout to hard coded layout, then you're probably well into the realm of "this is going to be more trouble than it's worth".

The best recommendation I can make is to create a "grand unified layout manager" which lays out all of your widgets in a single group, but according to the same principles as the existing TPUI layout managers. Then have that layout manager handle the tweening when you transition from one configuration to another.

You can pass the information you need via the Element.Constraint mechanism. This will be a little weird, because you're going to have a giant list of widgets and then you need to reconstruct the hierarchy via the information passed in those widgets' constraints, but you can cheat and make a parallel layout hierarchy in the constraints if you really need it:

class GroupConstraint extends Element.Constraint {
  public final boolean horiz;
  public final List<Element<?>> elems = new ArrayList<>();
}

GroupConstraint hgroup = new GroupConstraint(true);
Label label = ...;
Button button = ...;
hgroup.elems.add(label);
hgroup.elems.add(button);

Group group = new Group(new GrandUnifiedLayout());
group.add(label.setConstraint(hgroup));
group.add(button.setConstraint(hgroup));

You might be better off not using the "nested groups" model and using something more like iOS's springs where the layout is flat and you just say "this should be up against the top", and "this should be up against that", and "these should be the same width", etc.

Unfortunately, no matter how you slice it, this will be a lot of work, but this is the "right" way to do it, from the standpoint of TPUI.

You could also fork TPUI, and try to work in some notion of animating things, but you'll be running up against the problem that TPUI was not designed for this, and trying to animate widgets that are being pulled out of groups and put into other groups is going to be filled with little disasters.

One other thing you should be wary of is not to "animate" the size of a Label or other text widget, otherwise you'll trigger hundreds of expensive text recalculations. TPUI was designed with the assumption that you'd layout the size of your text once and it would rarely change. So if you smoothly tween a button from 100px to 200px, it's going to create and garbage collect thousands of images and kill performance. You can safely tween translation, but tweening size is dangerous.

Daniel Gerson

unread,
Aug 14, 2013, 1:37:22 PM8/14/13
to pl...@googlegroups.com
Thanx for a lengthy (and obviously thoughtful) response.
It's evening here, and I can't look at it immediately, but will ponder over it I'm sure before too long.

Thanx again.

DMG

Daniel Gerson

unread,
Aug 14, 2013, 6:50:39 PM8/14/13
to pl...@googlegroups.com
Well, since either an absolute layout strategy OR a grand unified layout strategy, are both essentially starting from scratch as far as layout is concerned...

I'm going to try bolt http://www.miglayout.com/ onto Tripleplay. It's used for both Swing and SWT layouts, has no dependencies on them and allows for a BSD license.
In fact they have a cool osx style dock demo for swing that suggests it can molded to fit with an animation framework...
...although I haven't yet looked at the code because it's 1am. (I was thinking about this UI problem the whole time spent this evening helping a friend with a best-man speech he needed to prepare).

Will start tomorrow.

DMG

Michael Bayne

unread,
Aug 14, 2013, 6:58:41 PM8/14/13
to pl...@googlegroups.com

On Wed, Aug 14, 2013 at 3:50 PM, Daniel Gerson <daniel...@gmail.com> wrote:
I'm going to try bolt http://www.miglayout.com/ onto Tripleplay. It's used for both Swing and SWT layouts, has no dependencies on them and allows for a BSD license.

Looks cool!

-- m...@samskivert.com

Daniel Gerson

unread,
Aug 29, 2013, 8:16:25 PM8/29/13
to pl...@googlegroups.com
So I've spent quite a bit of time exploring Tripleplay UI and documented as best I could my understanding here.


On the positive, I have managed to hack together the MigLayout code into TriplePlay (and I do mean hack). For my pains I have dubbed the project Migraine. :-)

To the extent that I've tested it utilizing simplistic examples of functionality from Tripleplay and the MigLayout system, it actually does work in the static mode.

Feel free to download it and switch between vanilla MigLayout, or my attemps at animation with the Migraine mode by switching the enum.

However, I'm am still aways away from achieving my goal of having multiple layout systems coexisting while animating. Battered and bruised, I am still waying up my options about whether it's worth struggling on or creating my own simplistic button system.

I'm sure most of my problems are still because I don't have a good intuition about TPUI. I'm uncertain of the flow between validation/invalidation, deleting caches, recreating backgrounds, _ldata, hints/root.pack, what happens immediately vs later in .paint() etc... I still don't even have a good intuition about the role of preferred size. Does that mean that a widget will accept being made to an other size? Do the hints represent the maximum size available to a widget? Or borders? The degrees of freedom in my understanding leave me a little overwhelmed.

I'm not completely in the dark, but it's definitely a fuzzy understanding. Not quite sure where to go from here. Wish I had a clearer idea of the questions I needed to ask.

Regards
DMG

Michael Bayne

unread,
Aug 30, 2013, 1:46:39 PM8/30/13
to pl...@googlegroups.com

On Thu, Aug 29, 2013 at 5:16 PM, Daniel Gerson <daniel...@gmail.com> wrote:
I'm sure most of my problems are still because I don't have a good intuition about TPUI. I'm uncertain of the flow between validation/invalidation, deleting caches, recreating backgrounds, _ldata, hints/root.pack, what happens immediately vs later in .paint() etc... I still don't even have a good intuition about the role of preferred size. Does that mean that a widget will accept being made to an other size? Do the hints represent the maximum size available to a widget? Or borders? The degrees of freedom in my understanding leave me a little overwhelmed.

Not that it will necessarily clear everything up, but here's the general idea:

The preferred size mechanism is mainly used when you pack() a Root. That computes the Root's preferred size and then sets its size based on the preferred size and whatever constraints you provided (like packToWidth or packToHeight). Because the calculation of preferred size involves a bunch of work, the elements try to cache whatever they can to avoid redoing that work when they are later laid out. All this work happens synchronously when you call pack().

From there, the Root is still invalid. On the next call to paint(), the Root sees that it's not valid, and calls validate() on itself, which calls layout() on itself and marks itself valid. The layout() method in a Container (Elements, Group, etc.) delegates to its LayoutManager which usually makes use of the preferred size information from its elements to lay them out according to whatever policy. It then calls setSize() and setLocation() on the elements to actually position them, and then calls validate() on each element in turn. For "leaf" elements this just marks them valid, for nested containers, this repeats the whole layout process.

When an element changes (like you click a button) it invalidates itself, which climbs up the hierarchy invalidating the element's parent, all the way up to the root. Then on the next paint() call, the root will validate() itself again. However this time, if the bounds of the elements don't change, most of the other elements in the hierarchy will not change size and will thus not be marked invalid, so when validate() is called on them, it's a NOOP.

The LayoutData class encapsulates the results of all the calculations done when validating/laying out an element. It has all of the resolved Style values, and in the case of a TextWidget, it has the TextLayout. Once a widget is validated and laid out, none of that is needed (if it becomes needed because the widget is made invalid, it is totally recomputed). So at the end of layout() there's a call to clearLayoutData(). Unfortunately, things are never so simple, so there are a bunch of other calls to clearLayoutData() because it's possible to compute and cache layout data before the element is actually validated and laid out, but then cause that cached layout data to become invalid by changing the element in one way or another, so care has to be taken to avoid reusing stale layout data. This is all a little bit of a mess and could probably be made simpler and more robust if I had two or three days to pore over the code, fill my head with all the hundreds of ways that things interact, and then shake it all out into something more sensible.

Preferred size can be violated if you create a pathologically sized UI, but if you're not doing something bogus, then preferred sizes should generally be honored. Hints are used for things like wrapping text and wrapping elements in the FlowLayout. Most layouts try to keep the hints up to date as chunks are taken out of the hint space, but that's not always possible and so it's possible to create layouts that just never work out well.

One thing I've kept a strict handle on is that layout always happens in one pass. Swing and other UI toolkits cop out in a lot of cases and just relayout a whole UI when they paint themselves into a corner, and you can get nasty situations where layout loops infinitely, and the whole thing is damned messy and even harder to understand. By always doing things in one pass, you can't handle every possible layout (to properly do that would require a full fledged constraint solver, which in theory MigLayout uses), but you get 99% of the layouts you're likely to want, and the 1% fails immediately and obviously and you can work around it by providing hints with Layout.Constraint or using different layout managers.

-- m...@samskivert.com

Daniel Gerson

unread,
Aug 30, 2013, 2:11:11 PM8/30/13
to pl...@googlegroups.com


On Friday, August 30, 2013 7:46:39 PM UTC+2, Michael Bayne wrote:

On Thu, Aug 29, 2013 at 5:16 PM, Daniel Gerson <daniel...@gmail.com> wrote:
I'm sure most of my problems are still because I don't have a good intuition about TPUI. I'm uncertain of the flow between validation/invalidation, deleting caches, recreating backgrounds, _ldata, hints/root.pack, what happens immediately vs later in .paint() etc... I still don't even have a good intuition about the role of preferred size. Does that mean that a widget will accept being made to an other size? Do the hints represent the maximum size available to a widget? Or borders? The degrees of freedom in my understanding leave me a little overwhelmed.

Not that it will necessarily clear everything up, but here's the general idea:


Thanx! That does help a lot, even by locking down understandings of certain points.
What do you think about my stacktrace logging at the bottom of the documentation? Scary no? ;-)
But I couldn't have even begun to come to grips with it all without that.

So to clarify one or two points.
1) Hints are essentially starting points for subelements' layout managers so they don't have to solve preferredSize from scratch. They represent the size the parent thinks the child ought to be.
2) The preferredSize is essentially a communication from the element to it's parent about it's dimensions when it plans to draw itself. However, the layout manager gets the final say when it calls setBounds on the element during the layout phase.

clearLayoutData has bitten me... but I think I'm starting to make sense of everything.

Much obliged!! :-)

Daniel Gerson

unread,
Sep 3, 2013, 10:07:45 AM9/3/13
to pl...@googlegroups.com
So everything works as intended. The Migraine example has 2 layouts it animates between, and it animates the button you click on.

I would've created a gwt demo and link, but unfortunately MigLayout depends on ~4 java.io JRE classes etc that I don't have the patience to
remove at the moment, as we're targeting android.

Thanks a lot for the help :-)
DMG

Valerio Malara

unread,
Sep 5, 2013, 8:52:52 AM9/5/13
to pl...@googlegroups.com
I would like to ask a question about animated buttons, hoping that I'm not off-topic, I need to create a simple animation (I'm currently using just the playn libraries), when the mouse is over the button it need to look as has been pressed.
It's an easy to images animation but I can't find a method that do not require the mouse click, how can I sort it out?


Daniel Gerson

unread,
Sep 5, 2013, 12:27:17 PM9/5/13
to pl...@googlegroups.com
sounds like standard triple play can do what you need.

https://github.com/dmg46664/playn/wiki

Daniel Gerson

unread,
Sep 5, 2013, 5:24:20 PM9/5/13
to pl...@googlegroups.com

It's an easy to images animation but I can't find a method that do not require the mouse click, how can I sort it out?


Sorry, can you explain what you mean by "does not require a mouse click"?
If you use tripleplay and need a button to look like it's pressed without a mouse, take a look at the inherited method of the tripleplay.ui.Button class .onPressed from ClickableTextWidget.

You'll have to expose this to be called in your subclass.

DMG
 
Reply all
Reply to author
Forward
0 new messages