1) Components of aggregates should always be inside the bounding boxes of the aggregates. That is, you should not make the :left of an aggregate be 40, and then the left of its only component be (+ 40 offset). This will make the bounding box of the aggregate too far to the left (because its left ignored the offset), and the component will be too far right. The solution here is to make the left of the aggregate the value that you want, like (+ parent-left offset), and then make the component inherit that left. Of course, if you have several components which all have different lefts, then this concern applies only to the leftmost component. 2) An aggrelist will set the :left and :top slots of the item-prototypes with appropriate formulas if you specify the :direction as :vertical or :horizontal. In fact, it will even override the formulas that you put in the :left and :top slots. So if you want your own :left and :top formulas in your item-prototype, you have to set the :direction of the aggrelist to NIL. 3) It is usually not necessary to specify the :width and :height of an aggregate. There are default formulas in these slots that look at all the components of the aggregate and compute the appropriate dimensions. The only time you would want to calculate them by hand is if you were doing centering or something that required circular constraints on the dimensions of an aggregate and its components. However, it is often useful to specify the :height and :width of an aggrelist and its :item-prototypes if these values are known. For example, if you had an aggrelist and frequently changed the first item (component), then when its height and width changes, the rest of the components have to be re-layed out because the first item changed dimensions (suposedly), and thus the positions of the items after it will change. If you are only changing the string of the first item, then its height will not change, so you should make it a constant or some formula that does not depend on the text's :height slot. (opal:string-height font "Random String") will return the same value as a text's :height slot, but it will not be reevaluated every time the string changes. 4) You have to put formulas in the components of an aggregadget. Even though you computed the :left and :top correctly for the aggregadget, the default left and top for the component is still 0,0. 5) Don't set the :window slot of a graphical object (or a gadget) 6) G-value the :value slot of a gadget before s-valuing it (in order to initialize the default formula). You may not set an initial value for the :value slot at create-instance time because you will override the default formula. 7) Don't set the :aggregate slot of a window at create-instance time. Instead, s-value it after the window has been created. 8) When you want to remove all the components from an aggregate, this will NOT work: (dolist (comp (get-values agg :components)) (opal:remove-component agg comp)) This does not work because remove-components is destructive, and after the first component is removed, your pointer is no longer pointing to the front of the components list. You have to use copy-list when getting the list of components from the aggregate. (Believe it or not, I have run into this problem 3 times!) To: Andrew.Mickish@spice.cs.cmu.edu Subject: Re: Tutorial Date: Wed, 14 Aug 91 11:15:36 EDT Message-Id: <10829.682182936@cs.utk.edu> From: bvz@cs.utk.edu I agree that emphasizing explanations and philosophy is the best way to go. In teaching my graphical interfaces class last fall, I found that the students struggled with many of the concepts, and they have to master the concepts before they can worry about the code. Students seemed particularly confused by the distinction between inheritance and aggregate hierarchies, and were quite confused by aggregate hierarchies in general. They also needed to be led slowly through constraints. I think that object systems and constraints are new ways of programming that most people just aren't familiar with (constraints involve declarative rather than imperative programming and two types of object hierarchies get people confused). It would also be a good idea to discuss the prototype-instance system and describe how it differs from the class-instance system. I think that if people understand the high-level concepts embodied by garnet before they start using it, they will have an easier time learning the syntax and how to use it. I definitely wouldn't dive into details because there is so much minute detail in Garnet that people will probably just get lost. It is best that they acquire the detail bit by bit, and that they have a general framework they can use to organize the detail. The high-level concepts that I would hit are: 1) prototype-instance systems: describe inheritance, message-passing, and the differences between class-instance and prototype-instance systems. 2) aggregate vs. inheritance hierarchies: the students in my class had trouble with what information flows down the inheritance hierarchy and what information flows down the aggregate hierarchy--I told them that relationships (defined by constraints), color, filling-style, line-style, draw-function, and width and height attributes often flowed down the inheritance hierarchy, and that position and visibility attributes typically flowed down the aggregate hierarchy. An important notion that I tried to get across was that relationships could be inherited (e.g., I am offset 5 pixels from the top of my parent), but that the data that was plugged into these relationships often came down the aggregate hierarchy; 3) constraints: what they are and uses for them. Give lots of examples of when they should and shouldn't be used); 4) the interactors model: you should describe the logic between the separation of behavior and graphics. Most people are accustomed to widgets in which the behavior and graphics are tightly intertwined, and thus inseparable); and 5) the retained object model: this can be brief, but people should understand the notion of "registering" objects with the window manager. Brad