Monday, April 30, 2012

Smalltalk meets Cubism


Everytime I meet up with Alexandre Bergel at a Smalltalk conference, we talk about Mondrian. And I always ask him a question: "Why is it that every time I see Mondrian, it's always about Rectangles?" In some ways, it's appropriate that Mondrian is always about rectangles. Google Mondrian, and the first images you'll see are all about rectangles. Nearly all of the artwork associated with Piet Mondrian is a love affair with rectangles.

Anyway, I thought it was time to put up or shut up. I want a new question to bug Alexandre about when we cross paths in the future. So I decided to play a little. I wasn't interested in rewriting all that Mondrian is. I just wanted to experiment a little with other polyshapes to express multiple simultaneous attributes of subjects I was trying to visualize. Mostly, I was interested in playing with MeshGradients using Cairo, because I was curious if I could find an interesting problem I could use mesh gradients with.

If you google Cubism, you'll see the artwork that I was inspired by. According to Wikipedia

In cubist artworks, objects are broken up, analyzed, and re-assembled in an abstracted form—instead of depicting objects from one viewpoint, the artist depicts the subject from a multitude of viewpoints to represent the subject in a greater context.

That sounded exactly like what I was trying to do. I published my couple-day-prototype in the Open Repository in a package called TAG-Cubist.  I realized in playing with this how it's not just about rectangles (of course), but how important layout of the per-subject-graphics is. I didn't do anything, other than present then in a tiled format. I'll leave that kind of thing to others. Here are screencaptures of the four example methods I put on the Portfolio class (a Portfolio is a collection of similar drawings for a group of different subjects).

Some of the methods found in the Portfolio object, showing clockwise, from noon high position: LoC, inst var ref count, selector size, argument count, and bytecodes.

Some of the top-level packages found in my image, showing clockwise, from noon high position: prerequisites, defined classes, extended classes.
Classes found in the ArithmeticValue class hierarchy, showing clockwise, from noon high position: methods, inst vars, refs to globals, global refs to the class (attributes suggested by Bob Hartwig, thanks!).

Top-level bundles in my image, showing clockwise, from noon high position: child packages, child bundles, prerequisites, comment size, defined classes, methods of defined classes, extended classes, extension methods.

If I was to go on playing, I'd basically start to reinvent Mondrian. Which is not something I really wanted to do. I might play with the way the shape is generated some more, make it more of a star graph (whereas it's a sort of spider plot right now). And I'd definitely figure out how to do a legend plot.

Wednesday, April 11, 2012

Cairo 1.12.0

A couple weeks ago, the good folks that give us Cairo announced that version 1.12.0 is ready for consumption.

In the last couple weeks, at sundry moments, I've been updating the VisualWorks binding to it, and playing with it some. There's some exciting news and some not-yet-good news. First, the good.

Doing a build for Linux was quite simple. And that allowed me to update/play right away. You can build it yourself, or ask me, I'm curious how portable the binaries I built are for consumption.

On of the exciting things new in 1.12.0 is at long last, Mesh Gradients. Mesh gradients are the "you can do anything with it" gradient. They can be used to simulate any other kind of gradient. Radial and Linear gradients can be done with them (Cairo gives us first class versions of these already). You can also do the elusive conical gradient.


Here'a round one (they don't have to be round) which varies evenly on hue. This can be fun to build pie charts with. Or you can build a conical gradient useful for doing highlighting masks after clipping to a shape


You can do more complex things with them, such as display map data, but I didn't find any simple ones to read and map to mesh (if anyone knows of some, let me know). Other than cones I haven't done to much with the meshes yet. But I'm excited to figure out what kinds of data visualization one could do with them for an application that might be written with VisualWorks. I have an idea of something, but... that'll have to wait for a later post if it works out.

The not-yet-good news is that so far, I only have this working on Linux. The build method I've used in the past, doesn't seem to work with this new version (it could just as well be that I'm now running Lion and newer versions of Xcode). I did manage to grab a binary from someone who had built just prior to release. While that worked for many things, it crashed when using the MeshGradient stuff. And the same goes for Windows so far. I hope to do some looking and have more/better news on these fronts in the weeks to come.

A Post STIC Talk Thought


At STIC I gave a talk about Skins. Skins are a way of separating display behavior from widgets, and trying to rectify some of what we see as "no longer sound" design decisions. At one point, I had put this graphic up on the screenfollowed by this one


It describes the central, fatter role, we're trying to give widgets we develop with the Skin mindset in mind. The one thing this kind of Widget does not do, is actual drawing.

I was asked later on "so, if we wanted to do some new widgets in with this newer GUI approach, how would we do this? Would we make a new skin?

The answer is no. Or at least, most likely not. The whole point of separating the drawing behavior into stateless policy objects, is to deal with having a single widget object, that can be rendered in different look and feels. But for most custom widget development, you don't care about different looks. You're not trying to ape Windows or OSX or something else, the look of your widget tends to be uniform. And so you don't need the whole separation/decoupling that a skin approach provides. You just have your Widget do it's own #displayOn: method.


Monday, March 12, 2012

Apple's MVC Song

While prepping for my talk at STIC about Skins, I stumbled across this homemade song and video from the folks at Apple about Model-View-Controller. The first minute or so is skippable, but the lyrics are cute once the song starts. Look for the Smalltalk hat tip at 4.14.



What's (again) interesting to me is how fungible the controller aspect is. Every MVC framework you meet treats Controller a little differently. Everyone agrees that core state and ui presentation should be separated. Makes good design sense for a variety of reasons. The devils in how you bridge or connect the two. And everyone then calls this Controller. It would have been better to have renamed the pattern Model-View-Connector

Tuesday, January 17, 2012

TAG-MemoryUsage

Prompted by a discussion in the VWNC mailing list, I decided to write a little tool to help me see where and how much memory is being used by what objects.

Unable to display content. Adobe Flash is required.

Friday, January 13, 2012

Some Edgy Reification

Ever had that experience where you're working on something, and it just feels like something's missing? You muddle on for a while. You begin to suspect there's an object whispering in the digital ether to come into being. When it works out (it doesn't always), I've found it to be one of the more rewarding experiences along the Zen Path of All Objects All The Time.

Working with GUIs and widgets and layout, an object I get to know real well is Rectangle. It's a pretty classic object that you find in many a class library, Smalltalk or otherwise. When working with widget trees and layout, rectangles make a lot of sense, because they store (directly or indirectly) the data you need to approximate most widget's layouts (e.g. top, left, bottom, and right). But when it comes to actually working with layout, my experience has been that often just Rectangles are sub optimal.

Generally, the types of behavior Rectangle supports are methods that work with all or most of the 4 implied values of a rectangle. But much of layout involves dealing with just one side of a rectangle. When we're left aligning some rectangles, we care about their left first, and then possibly all of their rights. So we often see code that looks like

newBox := bounds left + someDelta @ bounds top extent: bounds extent.

We didn't want to have to care about tops or extents.

We could do
aBox left: aBox left + someDelta

but I see less of this pattern actually.

A more involved example (no code) involves determining the bottomRight corner of a rectangle for a widget that may or may not have scrollbars around it. First we check if we need to move the right in for a scrollbar, and do so by the thickness if necessary. Then we use that width to determine if we need to show a horizontal scrollbar now. And now if we adjusted for that, we have to check one more time to see if we didn't need a vertical scrollbar before but do now. We care about first the right side, then the bottom side, then the right side.

Another pattern I've seen is that there are many types of widgets and layouts that can be either vertical or horizontal. A row layout container and column layout container are very similar, but one works along the x axis and the other the y axis. Consider a chunk of code that given a list of rectangles, stretch their widths from the leftmost to the rightmost, proportionately by their current widths.

| sumWidth scalar lastRight |
sumWidth := aBoxList inject: 0 into: [:sum :each | sum + each width].
scalar := sumWidth / (aBoxList last right - aBoxList first left).
lastRight := aBoxList first left.aBoxList do:
[:each |
each left: lastRight.
each right: (lastRight := each width * scalar + each left)]


If I want to reuse that same algorithm to work in a vertical direction, I get to copy/paste it and modify as such

| sumHeight scalar lastRight |
sumHeight := aBoxList inject: 0 into: [:sum :each | sum + each height].
scalar := sumHeight / (aBoxList last bottom - aBoxList first top).
lastBottom := aBoxList first top.aBoxList do:
[:each |
each top: lastBottom.
each bottom: (lasBottom := each height * scalar + each top)]


It gets even funner when you're working with points and have to transpose all of the constant x values for constant y values.

The Free Dictionary defines reification as
To regard or treat (an abstraction) as if it had concrete or material existence.

What I found working with these types of problems was that there was an object for a Rectangle's edge that really wanted to come into being. RectangleEdge is an abstract class defining the API, and polymorphic subclasses for TopEdge, LeftEdge, RightEdge, and BottomEdge take care of the particulars. Having an object which reifies the edge of a rectangle allows us to talk about rectangle manipulation at a higher level for many problems.

What follows is an overview of the classes' use and APIs. Followed by a revisit of the above examples, but using edges.

Creation


A particular edge can created by sending leftEdge, rightEdge, bottomEdge, or topEdge to an instance a Rectangle.

aRectangle bottomEdge

Or by sending the message of: to a given EdgeClass
BottomEdge of: aRectangle


A selection of some of the handier high level messages that allow us to talk about rectangle edges more directly

Accessing
complementDistance
"How far apart are I and my complement (opposite) edge?"
position
"The placement value for this edge along either the x or y axis as appropriate."
position: aNumber
"Modify my target rectangle such that the edge I reify is now at aNumber."

Adjusting
-= aDelta
"Modify my position so that it is my current position minus aDelta."
+= aDelta
"Modify my position so that it is the sum of aDelta and my current position."
lineUpWith: anEdge
"Change my position so that I line up with anEdge."

Other Edges
adjacentEdges
"Return the edges that are normal or perpendicular to me."
complementEdge
"Answer the edge of my box that is opposite of me."
sameEdgeOf: aRectangle
"Return the equivalent edge of aRectangle to me."

Testing
attractsEdge: anEdge
"Answer whether I'm the kind of edge that would want to be considered in concert with anEdge for alignment purposes."
linesUpWith: anEdge
"Do I associate with anEdge in alignment considerations?"

There's more than these, but these seemed some of the more obvious. I actually came up with these classes when I first came to work at Cincom and was working on the failed next generation UIPainter with Vassili Bykov called "Splash". Having reified edges was a big help in doing snap to alignment and other interactive layout operations. And I've been using it with the work on skins (see the description of doing scrollbar layout above). And have been using it with layout prototypes on beyond the current Panel idea found in VisualWorks. It's likely it will finally be integrated in a build near you, before our next release.

Circling back around to the original examples, I now write code like

aBox rightEdge -= self scrollbarThickness


I think this makes the code more expressive of what I'm doing, instead of being lost in how I'm trying to manipulate a rectangle to get the same result. The layout algorithm is even more interesting. Parameterizing the code shown with which edge classes to use, one can make it work for either horizontal or vertical manipulation, by just changing one variable:

| sum scalar lastPosition edgeClass |
edgeClass := LeftEdge.sum := aBoxList inject: 0
into: [:sum :each | sum + (edgeClass of: each) complementDistance].
scalar := sum /
((edgeClass of: aBoxList last) complementEdge position - (edgeClass of: aBoxList first) position).
last := (edgeClass of: aBoxList first) position.aBoxList do:
[:each |
| lowEdge |
lowEdge := (edgeClass of: each) position: last.
lowEdge complementEdge
position: (last := lowEdge complementDistance * scalar + lowEdge position)]


This reified Edge object has enabled me to build layout algorithms that can be configured to work in either the x or y directions without having to have lots of code duplication.

Thursday, December 8, 2011

Call for STIC Talk Input

I think I'm going to submit a talk proposal to STIC for the March conference. There are lots of UI/Tools related things I could try and talk about, however there's only 45 minutes given for a talk slot. So I'm putting out a call for talk input. If you are coming to STIC this year, and have to listen to me for 45 minutes, what would I talk about to make the best use of your time?

Some possible thoughts that have crossed my mind:


  • Here's how Skins work, the issues involved, and where we want to go with them

  • Where 15 years of the VW UI framework has gotten us, how we got here, what we don't like, what we do like, and what we want to fix, and how

  • 10000 ft view of how VisualWorks UI framework fits together, do's and don'ts

  • Rolling your own widgets. The old way. And the new way.

  • Stand at the front of the room and let people throw bread rolls at me



or something completely different?

Private or public responses are fine, and thanks for them.