The idea behind this may have been sound: isolate the information about a state relevant only for display from that relevant to other uses. However, in this case, it didn't seem wise to start splitting the data so early. Something like this must be done eventually, however, since it might be worthwhile to add additional ``views'' of the state outside of the single graphical one. For example, a tree-structured view that the user can rearrange might also be desired, in which case splitting the data like this would be a worthwhile technique.
In my second attempt, I combined the two classes and included information about things like canvas object IDs in a single State class. This was a wrong turn because it would not support multiple views of the same database---each state could only be responsible for a single set of objects on a single canvas. The canvas, in fact, was a global variable.
In my third attempt, I split the State class into two, the State class, which has information about the state---its name, position, shape, etc.---and the StateImage class, which has information about where the state is currently being displayed---the canvas, the object IDs on that canvas, etc.
In this attempt, I tried a scheme for positioning states relative to a state's parent. The idea was that when a state moved, all of its children were translated implicitly. There were a number of problems with this. First, this made it very time-consuming to display a set of states, since a fairly complex operation had to take place to figure out where one actually was. Rather than try to recompute each position completely from scratch, I computed each state's position and size based only on its parent's position and size, making sure to do this in a breadth-first manner. It was a problem to keep this cache consistent.
Another problem was what to do with the root of a particular window. It did not have a displayed parent, so where would its geometry be derived from? You could create a dummy parent with a given geometry that responded to the root's requests, but this seemed problematic. Instead, I tried treating the root state of each window separately. The root state would have its geometry handed to it, and all the others would be instructed to position themselves relative to this. A problem was making sure that the children were always up-to-date, since they had to be told to position themselves explicitly, effectively removing the utility of scheme to take care of positioning automatically.
In the fourth attempt, I simplified the position model. Now, instead of defining the upper left-hand corner of a state as a fraction of the way from the upper left-hand corner of its parent, I defined it as an absolute distance from the upper left-hand corner of its parent. Width and height which, until the fourth attempt, were defined as fractions of the width and height of the parent, were now given in absolute coordinates. However, this scheme suffered from most of the problems of the last: maintaining consistency remained a problem. Whenever the position of a state was changed, this change was noticed and passed down to the children, which would be told to reposition themselves.
All of this recomputation and cache-coherency maintenance made for very slow code. It was clear that to make the program run with any reasonable speed, something different was required. Eventually, all of this relative position nonsense was replaced by an absolute positioning scheme, modulo the pan and zoom of the current view. But transforming all a view's objects uniformly is much easier than doing each differently, so this turned out to be a partial solution to the speed problem.
Written by Stephen Edwards.