Saturday, 2 February 2013

A Lesson from Java's Swing

So whenever possible, I like to apply things I learn in my hobby programming to my professional programming. Conversely though, sometimes I am inspired by the design of parts of icedtea-web (the project I work on at Red Hat). To be fair, this is more the design of Java's Swing library, but it got me thinking.

The menu code in Lanarts was pragmatic but also hackish. It piggy-backed the normal event loop and each menu was a pseudo-level. That meant there was a bunch of classes that inherited from GameInst that were only part of the menu code. The menu code was created based off these objects being planted into the pseudo-level, configured with callbacks to wire the menu logic and drawing, and just enough menu placement logic code so that things were spaced sanely on different resolutions.

Taking a Swing at a better design

Although it wasn't the first time I used Swing, recently while having to assemble a dialogue box with nothing but Swing layout managers, it struck me that this could be a good approach for Lanarts user interfaces. While Swing has a large number of obscure layouts, a comment struck me that I forget the source of: "Using GridLayout and BorderLayout you can create pretty much any interface". So I coded the equivalent of these in Lua. This resulted in two small classes:

1. InstanceLine:
Arranges objects in rows, this is similar to Java's GridLayout, but is designed to be especially convenient if you just want a single row.
2. InstanceBox:
Objects are added based on relative position; a value 0 to 1 is used for x & y coordinates. Using this layout you can easily align something against the center-top of a box, and another component on the center-bottom, for example.
Using these classes nested together, flexible layouts can be created with a lot less mucking around with coordinates. The x & y positions of each menu component are now calculated each time they are drawn, instead of being fixed absolute values. This allows each layout to only store relative positions, making logic simpler. As well components can be created without their locations having to be known at the time of creation.

The GameInst structure was abandoned as well, and instead a simple event loop was created in Lua.

It was really fun to code, and ended up being a large improvement. Here is a picture of the result with debugging code turned on:


Note this looks exactly like it did before -- not bad for a complete reprogramming in Lua!

The elegance with which it could be programmed made me feel a lot more confident in Lanarts ability to act as an effective moddable engine. I was able to code it in Lua with only take very brief breaks to quickly add a missing function or two on the C++ side.

One surprising inspiration I got is to have a similar mechanism for the level generation. A nested tree of randomly generated layouts could produce very interesting results!

No comments:

Post a Comment