From: wiml@milton.u.washington.edu (William Lewis)
Newsgroups: comp.lang.objective-c,comp.windows.misc,comp.sys.next.programmer
Subject: Alternative GUI class hierarchies?
Date: 27 Dec 92 06:37:24 GMT
Article-I.D.: u.1992Dec27.063724.15059
Followup-To: comp.windows.misc,comp.lang.objective-c
Organization: University of Washington, Seattle


   Recently I've been pondering the construction of an object-oriented
GUI toolkit (particularly, using gcc-objc over X, but that detail is 
irrelevant), trying to combine the best attributes of the X intrinsics
and NeXTstep (the two OO GUI toolkits I'm familiar with). One thing that
strikes me as inelegant about both toolkits is the View/Cell
distinction (in X, the Widget/Gadget distinction). Although I understand
the utility of a "lightweight view" for menu selections and so forth,
I've never really liked it. I've thought of two possible solutions.

   The first one is really just a workaround. Instead of having
separate hierarchies for "heavyweight" and "lightweight" objects, each
object could select at instantiation time whether it should be lightweight
or not. "Views" ("widgets") who are "lightweight" would have to 
communicate with their closest "heavyweight" ancestor to ask for
events, drawing requests, to determine the (x,y) offset at which
to draw (since in X at least, drawing coordinates are relative to the
destination drawable --- transformation matrices could be very useful
here) and so forth. This would require a little more work on the part
of object authors, however, to handle both cases; and it still wouldn't
simplify the client's structure much (only the display server's). 

   The other idea is to divide the object hierarchy even more strictly,
so that any given object can *only* be in one or another subhierarchy.
Basically, I'm thinking of dividing all graphical objects into two
types: those which enclose an area, and those which draw things in
an area. Only area-enclosing objects would receive events from the
display server and mouse. Area-enclosing objects would be allowed to do 
a little drawing, say a frame and a background, but nothing complex 
like text.  Under X, for instance, "enclosing" objects would (possibly) 
have their own window, but "drawing" objects would never have a window.
   Immediately, the question is "but what about objects that both
enclose area, *and* draw things in that area? Like buttons, sliders,
text-boxes, menus ... pretty much everything in fact." For these,
I would have a *third* object which "owns" and manages the enclosing
and the drawing objects. For example, a Button object might own
a SqareEnclosure object and a Text (or SmallImage) object. Only
the enclosure and the text objects would have a visible manifestation. 
The application programmer would interact only with the Button object,
but the Button object would use the other two objects to actually
do its work. This strikes me as having many advantages. Because each
UI element is more modular, it's easy to swap the subparts around:
the same Button class could be used for a button with a text label,
a button with an iconic label, or a button with some application-defined
image, without changing the Button class at all. Similarly, square
buttons, rounded buttons, and hexagonal buttons can be created by
writing a new "enclosure" class and causing the Button to use that
class instead of the "SquareEnclosure". I think this advantage is
applicable to other common UI objects as well.
   The main *disadvantage* is that, in one sense, I've worsened the
original problem: there are now *more* objects floating around in the
application program than there are in the usual scenario! Three objects 
just for a button; more for anything more complex. However, I think this
might not be so bad, because
     - The individual objects are simpler. There are probably also
fewer distinct classes in use at any given time, which could reduce the
RSS of the application.
     - If written well, the Enclosure class could offer much greater
control over server-side resource use. The idea of having each object
select whether it;s lightweight or heavyweight could be used here as well. 
     - Changing the "look" of an application -- say, from Motif-y to
Next-ish to Mac-like --- might involve changing only the Enclosures
and some drawers (like sliders), leaving many application-defined
objects alone. This would have to be designed in, though.
     - In Objective-C, all objects are individually dynamically
allocated. But with some tweaking, it should be possible to allocate 
space for a Button and both of its slave objects in one *alloc() call.
The space would be freed when the Button was freed; the Button would
have the responsibility of calling its component objects' -free methods
before it deallocates itself. ([Object free] would have to be rewritten
to check for this sort of situation, of course.) 
   I think that combining objects in this way would make the increase
in the number of objects much less harmful, since the number of
malloc() blocks would be the same, or even reduced. It would also
improve the locality of reference when responding to events.

   So, what do you think? Too many objects? Already been tried
and discarded? Penny-wise and pound foolish? 
   Followups have been directed to comp.windows.misc and 
comp.lang.objective-c. Edit as appropriate.

     

[P.S.: Some time ago I posted on comp.lang.objective-c about the 
possibility of writing a NextStep-like GUI ObjC toolkit as soon as
gcc 2.3.1 was widely available. I carelessly lost some of the replies,
though... GNU has started work on their own toolkit, but if anyone 
still wants to discuss anything, mail me and I'll try not to lose
your message this time...]

-- 
email: wiml@u.washington.edu             |  Home:  Seattle, Washington   |
     (William Lewis)                     |  47 41' 15" N   122 42' 58" W | 
NeXTmail: wiml@ingalls.cs.washington.edu `-------------------------------'
        --*-- Member, Coalition to Preserve Semantic Vacuity --*--
Newsgroups: comp.lang.postscript